@@ -657,18 +657,20 @@ public function testGetCardIdFailed(): void {
657657 }
658658
659659 #[\PHPUnit \Framework \Attributes \DataProvider(methodName: 'dataTestSearch ' )]
660- public function testSearch (string $ pattern , array $ properties , array $ options , array $ expected ): void {
661- /** @var VCard $vCards */
660+ public function testSearch (string $ pattern , array $ properties , array $ options , array $ expectedUris , array $ expectedNeedles ): void {
662661 $ vCards = [];
662+
663663 $ vCards [0 ] = new VCard ();
664- $ vCards [0 ]->add (new Text ($ vCards [0 ], 'UID ' , 'uid ' ));
664+ $ vCards [0 ]->add (new Text ($ vCards [0 ], 'UID ' , 'uid-0 ' ));
665665 $ vCards [0 ]->add (new Text ($ vCards [0 ], 'FN ' , 'John Doe ' ));
666666 $ vCards [0 ]->add (new Text ($ vCards [0 ], 'CLOUD ' , 'john@nextcloud.com ' ));
667+
667668 $ vCards [1 ] = new VCard ();
668- $ vCards [1 ]->add (new Text ($ vCards [1 ], 'UID ' , 'uid ' ));
669+ $ vCards [1 ]->add (new Text ($ vCards [1 ], 'UID ' , 'uid-1 ' ));
669670 $ vCards [1 ]->add (new Text ($ vCards [1 ], 'FN ' , 'John M. Doe ' ));
671+
670672 $ vCards [2 ] = new VCard ();
671- $ vCards [2 ]->add (new Text ($ vCards [2 ], 'UID ' , 'uid ' ));
673+ $ vCards [2 ]->add (new Text ($ vCards [2 ], 'UID ' , 'uid-2 ' ));
672674 $ vCards [2 ]->add (new Text ($ vCards [2 ], 'FN ' , 'find without options ' ));
673675 $ vCards [2 ]->add (new Text ($ vCards [2 ], 'CLOUD ' , 'peter_pan@nextcloud.com ' ));
674676
@@ -690,180 +692,120 @@ public function testSearch(string $pattern, array $properties, array $options, a
690692 $ vCardIds [] = $ query ->getLastInsertId ();
691693 }
692694
693- $ query = $ this ->db ->getQueryBuilder ();
694- $ query ->insert ($ this ->dbCardsPropertiesTable )
695- ->values (
696- [
697- 'addressbookid ' => $ query ->createNamedParameter (0 ),
698- 'cardid ' => $ query ->createNamedParameter ($ vCardIds [0 ]),
699- 'name ' => $ query ->createNamedParameter ('FN ' ),
700- 'value ' => $ query ->createNamedParameter ('John Doe ' ),
701- 'preferred ' => $ query ->createNamedParameter (0 )
702- ]
703- );
704- $ query ->executeStatement ();
705- $ query = $ this ->db ->getQueryBuilder ();
706- $ query ->insert ($ this ->dbCardsPropertiesTable )
707- ->values (
708- [
709- 'addressbookid ' => $ query ->createNamedParameter (0 ),
710- 'cardid ' => $ query ->createNamedParameter ($ vCardIds [0 ]),
711- 'name ' => $ query ->createNamedParameter ('CLOUD ' ),
712- 'value ' => $ query ->createNamedParameter ('John@nextcloud.com ' ),
713- 'preferred ' => $ query ->createNamedParameter (0 )
714- ]
715- );
716- $ query ->executeStatement ();
717- $ query = $ this ->db ->getQueryBuilder ();
718- $ query ->insert ($ this ->dbCardsPropertiesTable )
719- ->values (
720- [
721- 'addressbookid ' => $ query ->createNamedParameter (0 ),
722- 'cardid ' => $ query ->createNamedParameter ($ vCardIds [1 ]),
723- 'name ' => $ query ->createNamedParameter ('FN ' ),
724- 'value ' => $ query ->createNamedParameter ('John M. 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 [2 ]),
735- 'name ' => $ query ->createNamedParameter ('FN ' ),
736- 'value ' => $ query ->createNamedParameter ('find without options ' ),
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 [2 ]),
747- 'name ' => $ query ->createNamedParameter ('CLOUD ' ),
748- 'value ' => $ query ->createNamedParameter ('peter_pan@nextcloud.com ' ),
749- 'preferred ' => $ query ->createNamedParameter (0 )
750- ]
751- );
752- $ query ->executeStatement ();
695+ $ propertyRows = [
696+ [$ vCardIds [0 ], 'FN ' , 'John Doe ' ],
697+ [$ vCardIds [0 ], 'CLOUD ' , 'John@nextcloud.com ' ],
698+ [$ vCardIds [1 ], 'FN ' , 'John M. Doe ' ],
699+ [$ vCardIds [2 ], 'FN ' , 'find without options ' ],
700+ [$ vCardIds [2 ], 'CLOUD ' , 'peter_pan@nextcloud.com ' ],
701+ ];
702+
703+ foreach ($ propertyRows as [$ cardId , $ name , $ value ]) {
704+ $ query = $ this ->db ->getQueryBuilder ();
705+ $ query ->insert ($ this ->dbCardsPropertiesTable )
706+ ->values (
707+ [
708+ 'addressbookid ' => $ query ->createNamedParameter (0 ),
709+ 'cardid ' => $ query ->createNamedParameter ($ cardId ),
710+ 'name ' => $ query ->createNamedParameter ($ name ),
711+ 'value ' => $ query ->createNamedParameter ($ value ),
712+ 'preferred ' => $ query ->createNamedParameter (0 ),
713+ ]
714+ );
715+ $ query ->executeStatement ();
716+ }
753717
754718 $ result = $ this ->backend ->search (0 , $ pattern , $ properties , $ options );
755719
756- // check result
757- $ this ->assertSame (count ($ expected ), count ($ result ));
758- $ found = [];
759- foreach ($ result as $ r ) {
760- foreach ($ expected as $ exp ) {
761- if ($ r ['uri ' ] === $ exp [0 ] && strpos ($ r ['carddata ' ], $ exp [1 ]) > 0 ) {
762- $ found [$ exp [1 ]] = true ;
763- break ;
764- }
765- }
766- }
720+ $ this ->assertCount (count ($ expectedUris ), $ result );
767721
768- $ this ->assertSame (count ($ expected ), count ($ found ));
722+ $ actualUris = array_map (static fn (array $ row ): string => $ row ['uri ' ], $ result );
723+ sort ($ actualUris );
724+ $ expectedSortedUris = $ expectedUris ;
725+ sort ($ expectedSortedUris );
726+
727+ $ this ->assertSame ($ expectedSortedUris , $ actualUris , 'Search returned unexpected URIs ' );
728+
729+ $ expectedByUri = array_combine ($ expectedUris , $ expectedNeedles );
730+ $ this ->assertIsArray ($ expectedByUri );
731+
732+ foreach ($ result as $ row ) {
733+ $ this ->assertArrayHasKey ($ row ['uri ' ], $ expectedByUri , 'Unexpected URI in search result ' );
734+ $ this ->assertNotFalse (
735+ strpos ($ row ['carddata ' ], $ expectedByUri [$ row ['uri ' ]]),
736+ 'Returned carddata does not contain expected fragment for ' . $ row ['uri ' ]
737+ );
738+ }
769739 }
770740
771741 public static function dataTestSearch (): array {
772742 return [
773- 'basic FN search ' => [
774- 'John ' ,
775- ['FN ' ],
776- [],
777- [
778- ['uri0 ' , 'John Doe ' ],
779- ['uri1 ' , 'John M. Doe ' ],
780- ],
743+ 'basic FN match ' => [
744+ 'pattern ' => 'John ' ,
745+ 'properties ' => ['FN ' ],
746+ 'options ' => [],
747+ 'expectedUris ' => ['uri0 ' , 'uri1 ' ],
748+ 'expectedNeedles ' => ['John Doe ' , 'John M. Doe ' ],
781749 ],
782750 'partial FN match ' => [
783- 'M. Doe ' ,
784- ['FN ' ],
785- [],
786- [
787- ['uri1 ' , 'John M. Doe ' ],
788- ],
751+ 'pattern ' => 'M. Doe ' ,
752+ 'properties ' => ['FN ' ],
753+ 'options ' => [],
754+ 'expectedUris ' => ['uri1 ' ],
755+ 'expectedNeedles ' => ['John M. Doe ' ],
789756 ],
790- 'substring FN match ' => [
791- 'Do ' ,
792- ['FN ' ],
793- [],
794- [
795- ['uri0 ' , 'John Doe ' ],
796- ['uri1 ' , 'John M. Doe ' ],
797- ],
757+ 'substring FN match ' => [
758+ 'pattern ' => 'Do ' ,
759+ 'properties ' => ['FN ' ],
760+ 'options ' => [],
761+ 'expectedUris ' => ['uri0 ' , 'uri1 ' ],
762+ 'expectedNeedles ' => ['John Doe ' , 'John M. Doe ' ],
798763 ],
799- 'duplicate matches across FN and CLOUD return one result per card ' => [
800- 'John ' ,
801- ['FN ' , 'CLOUD ' ],
802- [],
803- [
804- ['uri0 ' , 'John Doe ' ],
805- ['uri1 ' , 'John M. Doe ' ],
806- ],
764+ 'search across multiple properties returns one result per card ' => [
765+ 'pattern ' => 'John ' ,
766+ 'properties ' => ['FN ' , 'CLOUD ' ],
767+ 'options ' => [],
768+ 'expectedUris ' => ['uri0 ' , 'uri1 ' ],
769+ 'expectedNeedles ' => ['John Doe ' , 'John M. Doe ' ],
807770 ],
808771 'case-insensitive search ' => [
809- 'john ' ,
810- ['FN ' ],
811- [],
812- [
813- ['uri0 ' , 'John Doe ' ],
814- ['uri1 ' , 'John M. Doe ' ],
815- ],
772+ 'pattern ' => 'john ' ,
773+ 'properties ' => ['FN ' ],
774+ 'options ' => [],
775+ 'expectedUris ' => ['uri0 ' , 'uri1 ' ],
776+ 'expectedNeedles ' => ['John Doe ' , 'John M. Doe ' ],
816777 ],
817- 'limit 1 returns first matching card ' => [
818- 'john ' ,
819- ['FN ' ],
820- ['limit ' => 1 ],
821- [
822- ['uri0 ' , 'John Doe ' ],
823- ],
778+ 'limit ' => [
779+ 'pattern ' => 'john ' ,
780+ 'properties ' => ['FN ' ],
781+ 'options ' => ['limit ' => 1 ],
782+ 'expectedUris ' => ['uri0 ' ],
783+ 'expectedNeedles ' => ['John Doe ' ],
824784 ],
825- 'limit 1 with offset 1 returns second matching card ' => [
826- 'john ' ,
827- ['FN ' ],
828- ['limit ' => 1 , 'offset ' => 1 ],
829- [
830- ['uri1 ' , 'John M. Doe ' ],
831- ],
785+ 'limit with offset ' => [
786+ 'pattern ' => 'john ' ,
787+ 'properties ' => ['FN ' ],
788+ 'options ' => ['limit ' => 1 , 'offset ' => 1 ],
789+ 'expectedUris ' => ['uri1 ' ],
790+ 'expectedNeedles ' => ['John M. Doe ' ],
832791 ],
833- 'underscore is escaped by default in CLOUD search ' => [
834- '_ ' ,
835- ['CLOUD ' ],
836- [],
837- [
838- ['uri2 ' , 'find without options ' ],
839- ],
792+ 'underscore is escaped by default ' => [
793+ 'pattern ' => '_ ' ,
794+ 'properties ' => ['CLOUD ' ],
795+ 'options ' => [],
796+ 'expectedUris ' => ['uri2 ' ],
797+ 'expectedNeedles ' => ['find without options ' ],
840798 ],
841- 'wildcards are honored when escape_like_param is false ' => [
842- '%_% ' ,
843- ['CLOUD ' ],
844- ['escape_like_param ' => false ],
845- [
846- ['uri0 ' , 'John Doe ' ],
847- ['uri2 ' , 'find without options ' ],
848- ],
799+ 'underscore wildcard search when escape_like_param is false ' => [
800+ 'pattern ' => '%_% ' ,
801+ 'properties ' => ['CLOUD ' ],
802+ 'options ' => ['escape_like_param ' => false ],
803+ 'expectedUris ' => ['uri0 ' , 'uri2 ' ],
804+ 'expectedNeedles ' => ['John Doe ' , 'find without options ' ],
849805 ],
850806 ];
851807 }
852808
853- public static function dataTestSearch (): array {
854- return [
855- ['John ' , ['FN ' ], [], [['uri0 ' , 'John Doe ' ], ['uri1 ' , 'John M. Doe ' ]]],
856- ['M. Doe ' , ['FN ' ], [], [['uri1 ' , 'John M. Doe ' ]]],
857- ['Do ' , ['FN ' ], [], [['uri0 ' , 'John Doe ' ], ['uri1 ' , 'John M. Doe ' ]]],
858- 'check if duplicates are handled correctly ' => ['John ' , ['FN ' , 'CLOUD ' ], [], [['uri0 ' , 'John Doe ' ], ['uri1 ' , 'John M. Doe ' ]]],
859- 'case insensitive ' => ['john ' , ['FN ' ], [], [['uri0 ' , 'John Doe ' ], ['uri1 ' , 'John M. Doe ' ]]],
860- 'limit ' => ['john ' , ['FN ' ], ['limit ' => 1 ], [['uri0 ' , 'John Doe ' ]]],
861- 'limit and offset ' => ['john ' , ['FN ' ], ['limit ' => 1 , 'offset ' => 1 ], [['uri1 ' , 'John M. Doe ' ]]],
862- 'find "_" escaped ' => ['_ ' , ['CLOUD ' ], [], [['uri2 ' , 'find without options ' ]]],
863- 'find not empty CLOUD ' => ['%_% ' , ['CLOUD ' ], ['escape_like_param ' => false ], [['uri0 ' , 'John Doe ' ], ['uri2 ' , 'find without options ' ]]],
864- ];
865- }
866-
867809 public function testGetCardUri (): void {
868810 $ query = $ this ->db ->getQueryBuilder ();
869811 $ query ->insert ($ this ->dbCardsTable )
0 commit comments