@@ -582,6 +582,262 @@ public function testHandleImip(): void {
582582 $ result = $ manager ->handleIMip ($ userId , $ calendar ->serialize ());
583583 }
584584
585+ public function testHandleImipWithAbsentCreateOption (): void {
586+ // construct mock user calendar (no matching event found)
587+ $ userCalendar = $ this ->createMock (ITestCalendar::class);
588+ $ userCalendar ->expects (self ::once ())
589+ ->method ('isDeleted ' )
590+ ->willReturn (false );
591+ $ userCalendar ->expects (self ::exactly (2 ))
592+ ->method ('isWritable ' )
593+ ->willReturn (true );
594+ $ userCalendar ->expects (self ::once ())
595+ ->method ('search ' )
596+ ->willReturn ([]);
597+ // construct mock calendar manager and returns
598+ /** @var Manager&MockObject $manager */
599+ $ manager = $ this ->getMockBuilder (Manager::class)
600+ ->setConstructorArgs ([
601+ $ this ->coordinator ,
602+ $ this ->container ,
603+ $ this ->logger ,
604+ $ this ->time ,
605+ $ this ->secureRandom ,
606+ $ this ->userManager ,
607+ $ this ->serverFactory ,
608+ $ this ->propertyMapper ,
609+ ])
610+ ->onlyMethods (['getCalendarsForPrincipal ' , 'getPrimaryCalendar ' ])
611+ ->getMock ();
612+ $ manager ->expects (self ::once ())
613+ ->method ('getCalendarsForPrincipal ' )
614+ ->willReturn ([$ userCalendar ]);
615+ $ manager ->expects (self ::once ())
616+ ->method ('getPrimaryCalendar ' )
617+ ->willReturn (null );
618+ // construct parameters
619+ $ userId = 'attendee1 ' ;
620+ $ calendar = $ this ->vCalendar1a ;
621+ $ calendar ->add ('METHOD ' , 'REQUEST ' );
622+ // construct user calendar returns - should create new event
623+ $ userCalendar ->expects (self ::once ())
624+ ->method ('handleIMipMessage ' )
625+ ->with ($ userId , self ::callback (function ($ data ) {
626+ return str_contains ($ data , 'STATUS:TENTATIVE ' );
627+ }));
628+ // test method with absent=create option
629+ $ result = $ manager ->handleIMip ($ userId , $ calendar ->serialize (), [
630+ 'absent ' => 'create ' ,
631+ 'absentCreateStatus ' => 'tentative ' ,
632+ ]);
633+ // Assert
634+ $ this ->assertTrue ($ result );
635+ }
636+
637+ public function testHandleImipWithAbsentIgnoreOption (): void {
638+ // construct mock user calendar (no matching event found)
639+ $ userCalendar = $ this ->createMock (ITestCalendar::class);
640+ $ userCalendar ->expects (self ::once ())
641+ ->method ('isDeleted ' )
642+ ->willReturn (false );
643+ $ userCalendar ->expects (self ::once ())
644+ ->method ('isWritable ' )
645+ ->willReturn (true );
646+ $ userCalendar ->expects (self ::once ())
647+ ->method ('search ' )
648+ ->willReturn ([]);
649+ // construct mock calendar manager and returns
650+ /** @var Manager&MockObject $manager */
651+ $ manager = $ this ->getMockBuilder (Manager::class)
652+ ->setConstructorArgs ([
653+ $ this ->coordinator ,
654+ $ this ->container ,
655+ $ this ->logger ,
656+ $ this ->time ,
657+ $ this ->secureRandom ,
658+ $ this ->userManager ,
659+ $ this ->serverFactory ,
660+ $ this ->propertyMapper ,
661+ ])
662+ ->onlyMethods (['getCalendarsForPrincipal ' ])
663+ ->getMock ();
664+ $ manager ->expects (self ::once ())
665+ ->method ('getCalendarsForPrincipal ' )
666+ ->willReturn ([$ userCalendar ]);
667+ // construct logger returns - should log warning since event not found and absent=ignore
668+ $ this ->logger ->expects (self ::once ())->method ('warning ' )
669+ ->with ('iMip message could not be processed because no corresponding event was found in any calendar ' );
670+ // construct parameters
671+ $ userId = 'attendee1 ' ;
672+ $ calendar = $ this ->vCalendar1a ;
673+ $ calendar ->add ('METHOD ' , 'REQUEST ' );
674+ // test method with absent=ignore option
675+ $ result = $ manager ->handleIMip ($ userId , $ calendar ->serialize (), [
676+ 'absent ' => 'ignore ' ,
677+ ]);
678+ // Assert
679+ $ this ->assertFalse ($ result );
680+ }
681+
682+ public function testHandleImipWithAbsentCreateNoWritableCalendar (): void {
683+ // construct mock user calendar (not writable)
684+ $ userCalendar = $ this ->createMock (ITestCalendar::class);
685+ $ userCalendar ->expects (self ::exactly (2 ))
686+ ->method ('isDeleted ' )
687+ ->willReturn (false );
688+ $ userCalendar ->expects (self ::exactly (2 ))
689+ ->method ('isWritable ' )
690+ ->willReturn (false );
691+ // construct mock calendar manager and returns
692+ /** @var Manager&MockObject $manager */
693+ $ manager = $ this ->getMockBuilder (Manager::class)
694+ ->setConstructorArgs ([
695+ $ this ->coordinator ,
696+ $ this ->container ,
697+ $ this ->logger ,
698+ $ this ->time ,
699+ $ this ->secureRandom ,
700+ $ this ->userManager ,
701+ $ this ->serverFactory ,
702+ $ this ->propertyMapper ,
703+ ])
704+ ->onlyMethods (['getCalendarsForPrincipal ' , 'getPrimaryCalendar ' ])
705+ ->getMock ();
706+ $ manager ->expects (self ::once ())
707+ ->method ('getCalendarsForPrincipal ' )
708+ ->willReturn ([$ userCalendar ]);
709+ $ manager ->expects (self ::once ())
710+ ->method ('getPrimaryCalendar ' )
711+ ->willReturn (null );
712+ // construct logger returns
713+ $ this ->logger ->expects (self ::once ())->method ('warning ' )
714+ ->with ('iMip message could not be processed because no writable calendar was found ' );
715+ // construct parameters
716+ $ userId = 'attendee1 ' ;
717+ $ calendar = $ this ->vCalendar1a ;
718+ $ calendar ->add ('METHOD ' , 'REQUEST ' );
719+ // test method with absent=create option but no writable calendar
720+ $ result = $ manager ->handleIMip ($ userId , $ calendar ->serialize (), [
721+ 'absent ' => 'create ' ,
722+ 'absentCreateStatus ' => 'tentative ' ,
723+ ]);
724+ // Assert
725+ $ this ->assertFalse ($ result );
726+ }
727+
728+ public function testHandleImipWithAbsentCreateUsesPrimaryCalendar (): void {
729+ // construct mock user calendar (no matching event found)
730+ $ userCalendar = $ this ->createMock (ITestCalendar::class);
731+ $ userCalendar ->expects (self ::once ())
732+ ->method ('isDeleted ' )
733+ ->willReturn (false );
734+ $ userCalendar ->expects (self ::once ())
735+ ->method ('isWritable ' )
736+ ->willReturn (true );
737+ $ userCalendar ->expects (self ::once ())
738+ ->method ('search ' )
739+ ->willReturn ([]);
740+ // construct mock primary calendar
741+ $ primaryCalendar = $ this ->createMock (ITestCalendar::class);
742+ $ primaryCalendar ->expects (self ::once ())
743+ ->method ('isDeleted ' )
744+ ->willReturn (false );
745+ $ primaryCalendar ->expects (self ::once ())
746+ ->method ('isWritable ' )
747+ ->willReturn (true );
748+ // construct mock calendar manager and returns
749+ /** @var Manager&MockObject $manager */
750+ $ manager = $ this ->getMockBuilder (Manager::class)
751+ ->setConstructorArgs ([
752+ $ this ->coordinator ,
753+ $ this ->container ,
754+ $ this ->logger ,
755+ $ this ->time ,
756+ $ this ->secureRandom ,
757+ $ this ->userManager ,
758+ $ this ->serverFactory ,
759+ $ this ->propertyMapper ,
760+ ])
761+ ->onlyMethods (['getCalendarsForPrincipal ' , 'getPrimaryCalendar ' ])
762+ ->getMock ();
763+ $ manager ->expects (self ::once ())
764+ ->method ('getCalendarsForPrincipal ' )
765+ ->willReturn ([$ userCalendar ]);
766+ $ manager ->expects (self ::once ())
767+ ->method ('getPrimaryCalendar ' )
768+ ->willReturn ($ primaryCalendar );
769+ // construct parameters
770+ $ userId = 'attendee1 ' ;
771+ $ calendar = $ this ->vCalendar1a ;
772+ $ calendar ->add ('METHOD ' , 'REQUEST ' );
773+ // primary calendar should receive the event
774+ $ primaryCalendar ->expects (self ::once ())
775+ ->method ('handleIMipMessage ' )
776+ ->with ($ userId , self ::callback (function ($ data ) {
777+ return str_contains ($ data , 'STATUS:TENTATIVE ' );
778+ }));
779+ // test method with absent=create option
780+ $ result = $ manager ->handleIMip ($ userId , $ calendar ->serialize (), [
781+ 'absent ' => 'create ' ,
782+ 'absentCreateStatus ' => 'tentative ' ,
783+ ]);
784+ // Assert
785+ $ this ->assertTrue ($ result );
786+ }
787+
788+ public function testHandleImipWithAbsentCreateOverwritesExistingStatus (): void {
789+ // construct mock user calendar (no matching event found)
790+ $ userCalendar = $ this ->createMock (ITestCalendar::class);
791+ $ userCalendar ->expects (self ::once ())
792+ ->method ('isDeleted ' )
793+ ->willReturn (false );
794+ $ userCalendar ->expects (self ::exactly (2 ))
795+ ->method ('isWritable ' )
796+ ->willReturn (true );
797+ $ userCalendar ->expects (self ::once ())
798+ ->method ('search ' )
799+ ->willReturn ([]);
800+ // construct mock calendar manager and returns
801+ /** @var Manager&MockObject $manager */
802+ $ manager = $ this ->getMockBuilder (Manager::class)
803+ ->setConstructorArgs ([
804+ $ this ->coordinator ,
805+ $ this ->container ,
806+ $ this ->logger ,
807+ $ this ->time ,
808+ $ this ->secureRandom ,
809+ $ this ->userManager ,
810+ $ this ->serverFactory ,
811+ $ this ->propertyMapper ,
812+ ])
813+ ->onlyMethods (['getCalendarsForPrincipal ' , 'getPrimaryCalendar ' ])
814+ ->getMock ();
815+ $ manager ->expects (self ::once ())
816+ ->method ('getCalendarsForPrincipal ' )
817+ ->willReturn ([$ userCalendar ]);
818+ $ manager ->expects (self ::once ())
819+ ->method ('getPrimaryCalendar ' )
820+ ->willReturn (null );
821+ // construct parameters - calendar already has CONFIRMED status
822+ $ userId = 'attendee1 ' ;
823+ $ calendar = $ this ->vCalendar1a ;
824+ $ calendar ->add ('METHOD ' , 'REQUEST ' );
825+ // The original event has STATUS:CONFIRMED, but it should be overwritten to TENTATIVE
826+ $ userCalendar ->expects (self ::once ())
827+ ->method ('handleIMipMessage ' )
828+ ->with ($ userId , self ::callback (function ($ data ) {
829+ // Should contain TENTATIVE and not CONFIRMED
830+ return str_contains ($ data , 'STATUS:TENTATIVE ' ) && !str_contains ($ data , 'STATUS:CONFIRMED ' );
831+ }));
832+ // test method with absent=create option
833+ $ result = $ manager ->handleIMip ($ userId , $ calendar ->serialize (), [
834+ 'absent ' => 'create ' ,
835+ 'absentCreateStatus ' => 'tentative ' ,
836+ ]);
837+ // Assert
838+ $ this ->assertTrue ($ result );
839+ }
840+
585841 public function testhandleIMipRequestWithInvalidPrincipal () {
586842 $ invalidPrincipal = 'invalid-principal-uri ' ;
587843@@ -927,4 +1183,5 @@ public function testCheckAvailabilityWithMailtoPrefix(): void {
9271183 ];
9281184 $ this ->assertEquals ($ expected , $ actual );
9291185 }
1186+
9301187}
0 commit comments