@@ -32,6 +32,8 @@ public function testImmutability(): void
3232 self ::assertNotSame ($ schema , $ schema ->minItems (1 ));
3333 self ::assertNotSame ($ schema , $ schema ->maxItems (1 ));
3434 self ::assertNotSame ($ schema , $ schema ->contains ('test ' ));
35+ self ::assertNotSame ($ schema , $ schema ->minContains ('test ' , 1 ));
36+ self ::assertNotSame ($ schema , $ schema ->maxContains ('test ' , 1 ));
3537 self ::assertNotSame ($ schema , $ schema ->uniqueItems ());
3638 self ::assertNotSame ($ schema , $ schema ->filter (static fn (mixed $ value ) => true ));
3739 self ::assertNotSame ($ schema , $ schema ->map (static fn (mixed $ value ) => $ value ));
@@ -550,6 +552,246 @@ public function testParseWithInvalidContains(): void
550552 }
551553 }
552554
555+ public function testParseWithValidMinContains (): void
556+ {
557+ $ dateTime1 = new \DateTimeImmutable ('2024-01-20T09:15:00+00:00 ' );
558+ $ dateTime2 = new \DateTimeImmutable ('2024-01-21T09:15:00+00:00 ' );
559+
560+ $ input = [$ dateTime1 , $ dateTime2 , $ dateTime2 ];
561+
562+ $ schema = (new ArraySchema (new DateTimeSchema ()))->minContains ($ dateTime2 , 2 );
563+
564+ self ::assertSame ($ input , $ schema ->parse ($ input ));
565+ }
566+
567+ public function testParseWithValidMinContainsWithEqualButNotSame (): void
568+ {
569+ $ dateTime1 = new \DateTimeImmutable ('2024-01-20T09:15:00+00:00 ' );
570+ $ dateTime2 = new \DateTimeImmutable ('2024-01-21T09:15:00+00:00 ' );
571+
572+ $ dateTime2Equal = new \DateTimeImmutable ('2024-01-21T09:15:00+00:00 ' );
573+
574+ $ input = [$ dateTime1 , $ dateTime2 , $ dateTime2Equal ];
575+
576+ $ schema = (new ArraySchema (new DateTimeSchema ()))->minContains ($ dateTime2Equal , 2 , false );
577+
578+ self ::assertSame ($ input , $ schema ->parse ($ input ));
579+ }
580+
581+ public function testParseWithInvalidMinContainsWithEqualButNotSameAndStrictFalse (): void
582+ {
583+ $ dateTime1 = new \DateTimeImmutable ('2024-01-20T09:15:00+00:00 ' );
584+ $ dateTime2 = new \DateTimeImmutable ('2024-01-21T09:15:00+00:00 ' );
585+
586+ $ dateTime2Equal = new \DateTimeImmutable ('2024-01-21T09:15:00+00:00 ' );
587+
588+ $ dateTime2Equal2 = new \DateTimeImmutable ('2024-01-21T09:15:00+00:00 ' );
589+
590+ $ input = [$ dateTime1 , $ dateTime2 , $ dateTime2Equal2 ];
591+
592+ $ schema = (new ArraySchema (new DateTimeSchema ()))->minContains ($ dateTime2Equal , 2 , false );
593+
594+ try {
595+ (new ArraySchema (new DateTimeSchema ()))->minContains ($ dateTime2Equal , 2 )->parse ($ input );
596+
597+ throw new \Exception ('code should not be reached ' );
598+ } catch (ErrorsException $ errorsException ) {
599+ self ::assertSame (
600+ [
601+ [
602+ 'path ' => '' ,
603+ 'error ' => [
604+ 'code ' => 'array.minContains ' ,
605+ 'template ' => '{{given}} contains {{contains}} {{containsCount}} times, min {{minContains}} required ' ,
606+ 'variables ' => [
607+ 'contains ' => json_decode (json_encode ($ dateTime2Equal ), true ),
608+ 'containsCount ' => 0 ,
609+ 'given ' => json_decode (json_encode ($ input ), true ),
610+ 'minContains ' => 2 ,
611+ ],
612+ ],
613+ ],
614+ ],
615+ $ errorsException ->errors ->jsonSerialize ()
616+ );
617+ }
618+
619+ self ::assertSame ($ input , $ schema ->parse ($ input ));
620+ }
621+
622+ public function testParseWithInvalidMinContainsWithStrictFalseAndNonMatchingValues (): void
623+ {
624+ $ dateTime1 = new \DateTimeImmutable ('2024-01-20T09:15:00+00:00 ' );
625+ $ dateTime2 = new \DateTimeImmutable ('2024-01-21T09:15:00+00:00 ' );
626+ $ dateTime3 = new \DateTimeImmutable ('2024-01-22T09:15:00+00:00 ' );
627+
628+ $ dateTime2Equal = new \DateTimeImmutable ('2024-01-21T09:15:00+00:00 ' );
629+
630+ $ input = [$ dateTime1 , $ dateTime2 , $ dateTime3 ];
631+
632+ $ schema = (new ArraySchema (new DateTimeSchema ()))->minContains ($ dateTime2Equal , 2 , false );
633+
634+ try {
635+ $ schema ->parse ($ input );
636+
637+ throw new \Exception ('code should not be reached ' );
638+ } catch (ErrorsException $ errorsException ) {
639+ self ::assertSame (
640+ [
641+ [
642+ 'path ' => '' ,
643+ 'error ' => [
644+ 'code ' => 'array.minContains ' ,
645+ 'template ' => '{{given}} contains {{contains}} {{containsCount}} times, min {{minContains}} required ' ,
646+ 'variables ' => [
647+ 'contains ' => json_decode (json_encode ($ dateTime2Equal ), true ),
648+ 'containsCount ' => 1 ,
649+ 'given ' => json_decode (json_encode ($ input ), true ),
650+ 'minContains ' => 2 ,
651+ ],
652+ ],
653+ ],
654+ ],
655+ $ errorsException ->errors ->jsonSerialize ()
656+ );
657+ }
658+ }
659+
660+ public function testParseWithInvalidMinContains (): void
661+ {
662+ $ dateTime1 = new \DateTimeImmutable ('2024-01-20T09:15:00+00:00 ' );
663+ $ dateTime2 = new \DateTimeImmutable ('2024-01-21T09:15:00+00:00 ' );
664+
665+ $ input = [$ dateTime1 , $ dateTime2 , $ dateTime1 ];
666+
667+ $ schema = (new ArraySchema (new DateTimeSchema ()))->minContains ($ dateTime2 , 2 );
668+
669+ try {
670+ $ schema ->parse ($ input );
671+
672+ throw new \Exception ('code should not be reached ' );
673+ } catch (ErrorsException $ errorsException ) {
674+ self ::assertSame (
675+ [
676+ [
677+ 'path ' => '' ,
678+ 'error ' => [
679+ 'code ' => 'array.minContains ' ,
680+ 'template ' => '{{given}} contains {{contains}} {{containsCount}} times, min {{minContains}} required ' ,
681+ 'variables ' => [
682+ 'contains ' => json_decode (json_encode ($ dateTime2 ), true ),
683+ 'containsCount ' => 1 ,
684+ 'given ' => json_decode (json_encode ($ input ), true ),
685+ 'minContains ' => 2 ,
686+ ],
687+ ],
688+ ],
689+ ],
690+ $ errorsException ->errors ->jsonSerialize ()
691+ );
692+ }
693+ }
694+
695+ public function testParseWithValidMaxContains (): void
696+ {
697+ $ dateTime1 = new \DateTimeImmutable ('2024-01-20T09:15:00+00:00 ' );
698+ $ dateTime2 = new \DateTimeImmutable ('2024-01-21T09:15:00+00:00 ' );
699+
700+ $ input = [$ dateTime1 , $ dateTime2 , $ dateTime2 ];
701+
702+ $ schema = (new ArraySchema (new DateTimeSchema ()))->maxContains ($ dateTime2 , 2 );
703+
704+ self ::assertSame ($ input , $ schema ->parse ($ input ));
705+ }
706+
707+ public function testParseWithValidMaxContainsWithEqualButNotSame (): void
708+ {
709+ $ dateTime1 = new \DateTimeImmutable ('2024-01-20T09:15:00+00:00 ' );
710+ $ dateTime2 = new \DateTimeImmutable ('2024-01-21T09:15:00+00:00 ' );
711+
712+ $ dateTime2Equal = new \DateTimeImmutable ('2024-01-21T09:15:00+00:00 ' );
713+
714+ $ input = [$ dateTime1 , $ dateTime2 , $ dateTime2Equal ];
715+
716+ $ schema = (new ArraySchema (new DateTimeSchema ()))->maxContains ($ dateTime2Equal , 2 , false );
717+
718+ self ::assertSame ($ input , $ schema ->parse ($ input ));
719+ }
720+
721+ public function testParseWithInvalidMaxContainsWithEqualButNotSameAndStrictFalse (): void
722+ {
723+ $ dateTime1 = new \DateTimeImmutable ('2024-01-20T09:15:00+00:00 ' );
724+ $ dateTime2 = new \DateTimeImmutable ('2024-01-21T09:15:00+00:00 ' );
725+
726+ $ dateTime2Equal = new \DateTimeImmutable ('2024-01-21T09:15:00+00:00 ' );
727+
728+ $ input = [$ dateTime1 , $ dateTime2 , $ dateTime2Equal ];
729+
730+ $ schema = (new ArraySchema (new DateTimeSchema ()))->maxContains ($ dateTime2Equal , 1 , false );
731+
732+ self ::assertSame ($ input , (new ArraySchema (new DateTimeSchema ()))->maxContains ($ dateTime2Equal , 1 )->parse ($ input ));
733+
734+ try {
735+ $ schema ->parse ($ input );
736+
737+ throw new \Exception ('code should not be reached ' );
738+ } catch (ErrorsException $ errorsException ) {
739+ self ::assertSame (
740+ [
741+ [
742+ 'path ' => '' ,
743+ 'error ' => [
744+ 'code ' => 'array.maxContains ' ,
745+ 'template ' => '{{given}} contains {{contains}} {{containsCount}} times, max {{maxContains}} allowed ' ,
746+ 'variables ' => [
747+ 'contains ' => json_decode (json_encode ($ dateTime2Equal ), true ),
748+ 'containsCount ' => 2 ,
749+ 'given ' => json_decode (json_encode ($ input ), true ),
750+ 'maxContains ' => 1 ,
751+ ],
752+ ],
753+ ],
754+ ],
755+ $ errorsException ->errors ->jsonSerialize ()
756+ );
757+ }
758+ }
759+
760+ public function testParseWithInvalidMaxContains (): void
761+ {
762+ $ dateTime1 = new \DateTimeImmutable ('2024-01-20T09:15:00+00:00 ' );
763+ $ dateTime2 = new \DateTimeImmutable ('2024-01-21T09:15:00+00:00 ' );
764+
765+ $ input = [$ dateTime1 , $ dateTime2 , $ dateTime2 , $ dateTime2 , $ dateTime2 ];
766+
767+ $ schema = (new ArraySchema (new DateTimeSchema ()))->maxContains ($ dateTime2 , 2 );
768+
769+ try {
770+ $ schema ->parse ($ input );
771+
772+ throw new \Exception ('code should not be reached ' );
773+ } catch (ErrorsException $ errorsException ) {
774+ self ::assertSame (
775+ [
776+ [
777+ 'path ' => '' ,
778+ 'error ' => [
779+ 'code ' => 'array.maxContains ' ,
780+ 'template ' => '{{given}} contains {{contains}} {{containsCount}} times, max {{maxContains}} allowed ' ,
781+ 'variables ' => [
782+ 'contains ' => json_decode (json_encode ($ dateTime2 ), true ),
783+ 'containsCount ' => 4 ,
784+ 'given ' => json_decode (json_encode ($ input ), true ),
785+ 'maxContains ' => 2 ,
786+ ],
787+ ],
788+ ],
789+ ],
790+ $ errorsException ->errors ->jsonSerialize ()
791+ );
792+ }
793+ }
794+
553795 public function testParseWithValidIncludes (): void
554796 {
555797 $ dateTime1 = new \DateTimeImmutable ('2024-01-20T09:15:00+00:00 ' );
0 commit comments