@@ -681,18 +681,20 @@ public function testGetCardIdFailed(): void {
681681 }
682682
683683 #[\PHPUnit \Framework \Attributes \DataProvider(methodName: 'dataTestSearch ' )]
684- public function testSearch (string $ pattern , array $ properties , array $ options , array $ expected ): void {
685- /** @var VCard $vCards */
684+ public function testSearch (string $ pattern , array $ properties , array $ options , array $ expectedUris , array $ expectedNeedles ): void {
686685 $ vCards = [];
686+
687687 $ vCards [0 ] = new VCard ();
688- $ vCards [0 ]->add (new Text ($ vCards [0 ], 'UID ' , 'uid ' ));
688+ $ vCards [0 ]->add (new Text ($ vCards [0 ], 'UID ' , 'uid-0 ' ));
689689 $ vCards [0 ]->add (new Text ($ vCards [0 ], 'FN ' , 'John Doe ' ));
690690 $ vCards [0 ]->add (new Text ($ vCards [0 ], 'CLOUD ' , 'john@nextcloud.com ' ));
691+
691692 $ vCards [1 ] = new VCard ();
692- $ vCards [1 ]->add (new Text ($ vCards [1 ], 'UID ' , 'uid ' ));
693+ $ vCards [1 ]->add (new Text ($ vCards [1 ], 'UID ' , 'uid-1 ' ));
693694 $ vCards [1 ]->add (new Text ($ vCards [1 ], 'FN ' , 'John M. Doe ' ));
695+
694696 $ vCards [2 ] = new VCard ();
695- $ vCards [2 ]->add (new Text ($ vCards [2 ], 'UID ' , 'uid ' ));
697+ $ vCards [2 ]->add (new Text ($ vCards [2 ], 'UID ' , 'uid-2 ' ));
696698 $ vCards [2 ]->add (new Text ($ vCards [2 ], 'FN ' , 'find without options ' ));
697699 $ vCards [2 ]->add (new Text ($ vCards [2 ], 'CLOUD ' , 'peter_pan@nextcloud.com ' ));
698700
@@ -714,95 +716,117 @@ public function testSearch(string $pattern, array $properties, array $options, a
714716 $ vCardIds [] = $ query ->getLastInsertId ();
715717 }
716718
717- $ query = $ this ->db ->getQueryBuilder ();
718- $ query ->insert ($ this ->dbCardsPropertiesTable )
719- ->values (
720- [
721- 'addressbookid ' => $ query ->createNamedParameter (0 ),
722- 'cardid ' => $ query ->createNamedParameter ($ vCardIds [0 ]),
723- 'name ' => $ query ->createNamedParameter ('FN ' ),
724- 'value ' => $ query ->createNamedParameter ('John Doe ' ),
725- 'preferred ' => $ query ->createNamedParameter (0 )
726- ]
727- );
728- $ query ->executeStatement ();
729- $ query = $ this ->db ->getQueryBuilder ();
730- $ query ->insert ($ this ->dbCardsPropertiesTable )
731- ->values (
732- [
733- 'addressbookid ' => $ query ->createNamedParameter (0 ),
734- 'cardid ' => $ query ->createNamedParameter ($ vCardIds [0 ]),
735- 'name ' => $ query ->createNamedParameter ('CLOUD ' ),
736- 'value ' => $ query ->createNamedParameter ('John@nextcloud.com ' ),
737- 'preferred ' => $ query ->createNamedParameter (0 )
738- ]
739- );
740- $ query ->executeStatement ();
741- $ query = $ this ->db ->getQueryBuilder ();
742- $ query ->insert ($ this ->dbCardsPropertiesTable )
743- ->values (
744- [
745- 'addressbookid ' => $ query ->createNamedParameter (0 ),
746- 'cardid ' => $ query ->createNamedParameter ($ vCardIds [1 ]),
747- 'name ' => $ query ->createNamedParameter ('FN ' ),
748- 'value ' => $ query ->createNamedParameter ('John M. Doe ' ),
749- 'preferred ' => $ query ->createNamedParameter (0 )
750- ]
751- );
752- $ query ->executeStatement ();
753- $ query = $ this ->db ->getQueryBuilder ();
754- $ query ->insert ($ this ->dbCardsPropertiesTable )
755- ->values (
756- [
757- 'addressbookid ' => $ query ->createNamedParameter (0 ),
758- 'cardid ' => $ query ->createNamedParameter ($ vCardIds [2 ]),
759- 'name ' => $ query ->createNamedParameter ('FN ' ),
760- 'value ' => $ query ->createNamedParameter ('find without options ' ),
761- 'preferred ' => $ query ->createNamedParameter (0 )
762- ]
763- );
764- $ query ->executeStatement ();
765- $ query = $ this ->db ->getQueryBuilder ();
766- $ query ->insert ($ this ->dbCardsPropertiesTable )
767- ->values (
768- [
769- 'addressbookid ' => $ query ->createNamedParameter (0 ),
770- 'cardid ' => $ query ->createNamedParameter ($ vCardIds [2 ]),
771- 'name ' => $ query ->createNamedParameter ('CLOUD ' ),
772- 'value ' => $ query ->createNamedParameter ('peter_pan@nextcloud.com ' ),
773- 'preferred ' => $ query ->createNamedParameter (0 )
774- ]
775- );
776- $ query ->executeStatement ();
719+ $ propertyRows = [
720+ [$ vCardIds [0 ], 'FN ' , 'John Doe ' ],
721+ [$ vCardIds [0 ], 'CLOUD ' , 'John@nextcloud.com ' ],
722+ [$ vCardIds [1 ], 'FN ' , 'John M. Doe ' ],
723+ [$ vCardIds [2 ], 'FN ' , 'find without options ' ],
724+ [$ vCardIds [2 ], 'CLOUD ' , 'peter_pan@nextcloud.com ' ],
725+ ];
726+
727+ foreach ($ propertyRows as [$ cardId , $ name , $ value ]) {
728+ $ query = $ this ->db ->getQueryBuilder ();
729+ $ query ->insert ($ this ->dbCardsPropertiesTable )
730+ ->values (
731+ [
732+ 'addressbookid ' => $ query ->createNamedParameter (0 ),
733+ 'cardid ' => $ query ->createNamedParameter ($ cardId ),
734+ 'name ' => $ query ->createNamedParameter ($ name ),
735+ 'value ' => $ query ->createNamedParameter ($ value ),
736+ 'preferred ' => $ query ->createNamedParameter (0 ),
737+ ]
738+ );
739+ $ query ->executeStatement ();
740+ }
777741
778742 $ result = $ this ->backend ->search (0 , $ pattern , $ properties , $ options );
779743
780- // check result
781- $ this ->assertSame (count ($ expected ), count ($ result ));
782- $ found = [];
783- foreach ($ result as $ r ) {
784- foreach ($ expected as $ exp ) {
785- if ($ r ['uri ' ] === $ exp [0 ] && strpos ($ r ['carddata ' ], $ exp [1 ]) > 0 ) {
786- $ found [$ exp [1 ]] = true ;
787- break ;
788- }
789- }
790- }
744+ $ this ->assertCount (count ($ expectedUris ), $ result );
745+
746+ $ actualUris = array_map (static fn (array $ row ): string => $ row ['uri ' ], $ result );
747+ sort ($ actualUris );
748+ $ expectedSortedUris = $ expectedUris ;
749+ sort ($ expectedSortedUris );
750+
751+ $ this ->assertSame ($ expectedSortedUris , $ actualUris , 'Search returned unexpected URIs ' );
791752
792- $ this ->assertSame (count ($ expected ), count ($ found ));
753+ $ expectedByUri = array_combine ($ expectedUris , $ expectedNeedles );
754+ $ this ->assertIsArray ($ expectedByUri );
755+
756+ foreach ($ result as $ row ) {
757+ $ this ->assertArrayHasKey ($ row ['uri ' ], $ expectedByUri , 'Unexpected URI in search result ' );
758+ $ this ->assertNotFalse (
759+ strpos ($ row ['carddata ' ], $ expectedByUri [$ row ['uri ' ]]),
760+ 'Returned carddata does not contain expected fragment for ' . $ row ['uri ' ]
761+ );
762+ }
793763 }
794764
795765 public static function dataTestSearch (): array {
796766 return [
797- ['John ' , ['FN ' ], [], [['uri0 ' , 'John Doe ' ], ['uri1 ' , 'John M. Doe ' ]]],
798- ['M. Doe ' , ['FN ' ], [], [['uri1 ' , 'John M. Doe ' ]]],
799- ['Do ' , ['FN ' ], [], [['uri0 ' , 'John Doe ' ], ['uri1 ' , 'John M. Doe ' ]]],
800- 'check if duplicates are handled correctly ' => ['John ' , ['FN ' , 'CLOUD ' ], [], [['uri0 ' , 'John Doe ' ], ['uri1 ' , 'John M. Doe ' ]]],
801- 'case insensitive ' => ['john ' , ['FN ' ], [], [['uri0 ' , 'John Doe ' ], ['uri1 ' , 'John M. Doe ' ]]],
802- 'limit ' => ['john ' , ['FN ' ], ['limit ' => 1 ], [['uri0 ' , 'John Doe ' ]]],
803- 'limit and offset ' => ['john ' , ['FN ' ], ['limit ' => 1 , 'offset ' => 1 ], [['uri1 ' , 'John M. Doe ' ]]],
804- 'find "_" escaped ' => ['_ ' , ['CLOUD ' ], [], [['uri2 ' , 'find without options ' ]]],
805- 'find not empty CLOUD ' => ['%_% ' , ['CLOUD ' ], ['escape_like_param ' => false ], [['uri0 ' , 'John Doe ' ], ['uri2 ' , 'find without options ' ]]],
767+ 'basic FN match ' => [
768+ 'pattern ' => 'John ' ,
769+ 'properties ' => ['FN ' ],
770+ 'options ' => [],
771+ 'expectedUris ' => ['uri0 ' , 'uri1 ' ],
772+ 'expectedNeedles ' => ['John Doe ' , 'John M. Doe ' ],
773+ ],
774+ 'partial FN match ' => [
775+ 'pattern ' => 'M. Doe ' ,
776+ 'properties ' => ['FN ' ],
777+ 'options ' => [],
778+ 'expectedUris ' => ['uri1 ' ],
779+ 'expectedNeedles ' => ['John M. Doe ' ],
780+ ],
781+ 'substring FN match ' => [
782+ 'pattern ' => 'Do ' ,
783+ 'properties ' => ['FN ' ],
784+ 'options ' => [],
785+ 'expectedUris ' => ['uri0 ' , 'uri1 ' ],
786+ 'expectedNeedles ' => ['John Doe ' , 'John M. Doe ' ],
787+ ],
788+ 'search across multiple properties returns one result per card ' => [
789+ 'pattern ' => 'John ' ,
790+ 'properties ' => ['FN ' , 'CLOUD ' ],
791+ 'options ' => [],
792+ 'expectedUris ' => ['uri0 ' , 'uri1 ' ],
793+ 'expectedNeedles ' => ['John Doe ' , 'John M. Doe ' ],
794+ ],
795+ 'case-insensitive search ' => [
796+ 'pattern ' => 'john ' ,
797+ 'properties ' => ['FN ' ],
798+ 'options ' => [],
799+ 'expectedUris ' => ['uri0 ' , 'uri1 ' ],
800+ 'expectedNeedles ' => ['John Doe ' , 'John M. Doe ' ],
801+ ],
802+ 'limit ' => [
803+ 'pattern ' => 'john ' ,
804+ 'properties ' => ['FN ' ],
805+ 'options ' => ['limit ' => 1 ],
806+ 'expectedUris ' => ['uri0 ' ],
807+ 'expectedNeedles ' => ['John Doe ' ],
808+ ],
809+ 'limit with offset ' => [
810+ 'pattern ' => 'john ' ,
811+ 'properties ' => ['FN ' ],
812+ 'options ' => ['limit ' => 1 , 'offset ' => 1 ],
813+ 'expectedUris ' => ['uri1 ' ],
814+ 'expectedNeedles ' => ['John M. Doe ' ],
815+ ],
816+ 'underscore is escaped by default ' => [
817+ 'pattern ' => '_ ' ,
818+ 'properties ' => ['CLOUD ' ],
819+ 'options ' => [],
820+ 'expectedUris ' => ['uri2 ' ],
821+ 'expectedNeedles ' => ['find without options ' ],
822+ ],
823+ 'underscore wildcard search when escape_like_param is false ' => [
824+ 'pattern ' => '%_% ' ,
825+ 'properties ' => ['CLOUD ' ],
826+ 'options ' => ['escape_like_param ' => false ],
827+ 'expectedUris ' => ['uri0 ' , 'uri2 ' ],
828+ 'expectedNeedles ' => ['John Doe ' , 'find without options ' ],
829+ ],
806830 ];
807831 }
808832
0 commit comments