Skip to content

Commit ee6e3be

Browse files
authored
chore: adds unit testing relevance functions (#579)
* chore: adds unit testing relevance functions * Addition of unit test for requestOptions
1 parent 823dc93 commit ee6e3be

File tree

5 files changed

+250
-0
lines changed

5 files changed

+250
-0
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace Algolia\AlgoliaSearch\Exceptions;
4+
5+
final class ObjectNotFoundException extends AlgoliaException
6+
{
7+
}

src/SearchIndex.php

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
use Algolia\AlgoliaSearch\Config\SearchConfig;
66
use Algolia\AlgoliaSearch\Exceptions\MissingObjectId;
77
use Algolia\AlgoliaSearch\Exceptions\NotFoundException;
8+
use Algolia\AlgoliaSearch\Exceptions\ObjectNotFoundException;
9+
use Algolia\AlgoliaSearch\RequestOptions\RequestOptionsFactory;
810
use Algolia\AlgoliaSearch\Response\BatchIndexingResponse;
911
use Algolia\AlgoliaSearch\Response\IndexingResponse;
1012
use Algolia\AlgoliaSearch\RequestOptions\RequestOptions;
@@ -633,6 +635,95 @@ public function exists()
633635
return true;
634636
}
635637

638+
/**
639+
* Find object by the given $callback.
640+
* Options can be passed in $requestOptions body:
641+
* - query (string): pass a query
642+
* - paginate (bool): choose if you want to iterate through all the
643+
* documents (true) or only the first page (false). Default is true.
644+
*
645+
* Usage:
646+
*
647+
* $index->findObject(
648+
* function($object) { return $object['objectID'] === 'foo'; },
649+
* array(
650+
* 'query' => 'bar',
651+
* 'paginate' => false,
652+
* 'hitsPerPage' => 50,
653+
* )
654+
* );
655+
*
656+
* @param callable $callback The callback used to find the object
657+
* Takes an array as parameter and returns a boolean
658+
* @param array<string, int|string|array>|RequestOptions $requestOptions array of options or RequestOptions object
659+
*
660+
* @return array<string, int|string|array>
661+
*
662+
* @throws ObjectNotFoundException
663+
*/
664+
public function findObject($callback, $requestOptions = array())
665+
{
666+
$query = '';
667+
$paginate = true;
668+
$page = 0;
669+
$requestOptionsFactory = new RequestOptionsFactory($this->config);
670+
671+
if (is_array($requestOptions)) {
672+
if (array_key_exists('query', $requestOptions)) {
673+
$query = $requestOptions['query'];
674+
unset($requestOptions['query']);
675+
}
676+
677+
if (array_key_exists('paginate', $requestOptions)) {
678+
$paginate = $requestOptions['paginate'];
679+
unset($requestOptions['paginate']);
680+
}
681+
}
682+
683+
$requestOptions = $requestOptionsFactory->create($requestOptions);
684+
685+
while (true) {
686+
$requestOptions->addBodyParameter('page', $page);
687+
688+
$result = $this->search($query, $requestOptions);
689+
foreach ($result['hits'] as $key => $hit) {
690+
if ($callback($hit)) {
691+
return array(
692+
'object' => $hit,
693+
'position' => $key,
694+
'page' => $page,
695+
);
696+
}
697+
}
698+
699+
$hasNextPage = $page + 1 < $result['nbPages'];
700+
if (!$paginate || !$hasNextPage) {
701+
throw new ObjectNotFoundException('Object not found');
702+
}
703+
704+
$page++;
705+
}
706+
}
707+
708+
/**
709+
* Retrieve the given object position in a set of results.
710+
*
711+
* @param array<string, array|string|int> $result The set of results you want to iterate in
712+
* @param string $objectID The objectID you want to find
713+
*
714+
* @return int
715+
*/
716+
public static function getObjectPosition($result, $objectID)
717+
{
718+
foreach ($result['hits'] as $key => $hit) {
719+
if ($hit['objectID'] === $objectID) {
720+
return $key;
721+
}
722+
}
723+
724+
return -1;
725+
}
726+
636727
private function copyTo($tmpIndexName, $requestOptions = array())
637728
{
638729
$apiResponse = $this->api->write(

tests/Integration/AlgoliaIntegrationTestCase.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,4 +132,20 @@ protected static function newClient($config = array())
132132
'objectID' => '3484',
133133
),
134134
);
135+
136+
public $companies = array(
137+
array('company' => 'Algolia', 'name' => 'Julien Lemoine', 'objectID' => 'julien-lemoine'),
138+
array('company' => 'Algolia', 'name' => 'Nicolas Dessaigne', 'objectID' => 'nicolas-dessaigne'),
139+
array('company' => 'Amazon', 'name' => 'Jeff Bezos', 'objectID' => '1234'),
140+
array('company' => 'Apple', 'name' => 'Steve Jobs', 'objectID' => '1235'),
141+
array('company' => 'Apple', 'name' => 'Steve Wozniak', 'objectID' => '1236'),
142+
array('company' => 'Arista Networks', 'name' => 'Jayshree Ullal', 'objectID' => '1237'),
143+
array('company' => 'Google', 'name' => 'Larry Page', 'objectID' => '1238'),
144+
array('company' => 'Google', 'name' => 'Rob Pike', 'objectID' => '1239'),
145+
array('company' => 'Google', 'name' => 'Serguey Brin', 'objectID' => '1240'),
146+
array('company' => 'Microsoft', 'name' => 'Bill Gates', 'objectID' => '1241'),
147+
array('company' => 'SpaceX', 'name' => 'Elon Musk', 'objectID' => '1242'),
148+
array('company' => 'Tesla', 'name' => 'Elon Musk', 'objectID' => '1243'),
149+
array('company' => 'Yahoo', 'name' => 'Marissa Mayer', 'objectID' => '1244'),
150+
);
135151
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
namespace Algolia\AlgoliaSearch\Tests\Integration;
4+
5+
use Algolia\AlgoliaSearch\SearchIndex;
6+
7+
class SearchIndexTest extends AlgoliaIntegrationTestCase
8+
{
9+
protected function setUp()
10+
{
11+
parent::setUp();
12+
13+
if (!isset(static::$indexes['main'])) {
14+
static::$indexes['main'] = self::safeName('general-index-mgmt');
15+
}
16+
}
17+
18+
public function testFindObject()
19+
{
20+
$index = static::getClient()->initIndex(static::$indexes['main']);
21+
$index->saveObjects($this->companies);
22+
23+
$res = $index->search('Algolia');
24+
$this->assertEquals(SearchIndex::getObjectPosition($res, 'nicolas-dessaigne'), 0);
25+
$this->assertEquals(SearchIndex::getObjectPosition($res, 'julien-lemoine'), 1);
26+
$this->assertEquals(SearchIndex::getObjectPosition($res, ''), -1);
27+
28+
try {
29+
$index->findObject(function () { return false; });
30+
} catch (\Exception $e) {
31+
$this->assertInstanceOf('Algolia\AlgoliaSearch\Exceptions\ObjectNotFoundException', $e);
32+
}
33+
34+
$found = $index->findObject(function () { return true; });
35+
$this->assertEquals($found['position'], 0);
36+
$this->assertEquals($found['page'], 0);
37+
38+
$callback = function ($obj) {
39+
return array_key_exists('company', $obj) && 'Apple' === $obj['company'];
40+
};
41+
42+
try {
43+
$index->findObject($callback, array('query' => 'algolia'));
44+
} catch (\Exception $e) {
45+
$this->assertInstanceOf('Algolia\AlgoliaSearch\Exceptions\ObjectNotFoundException', $e);
46+
}
47+
48+
try {
49+
$index->findObject($callback, array('query' => '', 'paginate' => false, 'hitsPerPage' => 5));
50+
} catch (\Exception $e) {
51+
$this->assertInstanceOf('Algolia\AlgoliaSearch\Exceptions\ObjectNotFoundException', $e);
52+
}
53+
54+
$obj = $index->findObject($callback, array('query' => '', 'paginate' => true, 'hitsPerPage' => 5));
55+
$this->assertEquals($obj['position'], 0);
56+
$this->assertEquals($obj['page'], 2);
57+
}
58+
}

tests/Unit/SearchIndexTest.php

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?php
2+
3+
namespace Algolia\AlgoliaSearch\Tests\Unit;
4+
5+
use Algolia\AlgoliaSearch\Config\SearchConfig;
6+
use Algolia\AlgoliaSearch\RequestOptions\RequestOptionsFactory;
7+
use Algolia\AlgoliaSearch\SearchClient;
8+
use PHPUnit\Framework\TestCase;
9+
use PHPUnit_Framework_Assert as Assert;
10+
11+
class SearchIndexTest extends TestCase
12+
{
13+
public function testFindObject()
14+
{
15+
$config = SearchConfig::create('foo', 'bar');
16+
$requestOptionsFactory = new RequestOptionsFactory($config);
17+
18+
// Test without requestOptions
19+
$apiWrapperMock = $this->getMock('Algolia\AlgoliaSearch\RetryStrategy\ApiWrapperInterface');
20+
$apiWrapperMock->method('read')
21+
->with($this->anything(), $this->anything(), $this->callback(function ($requestOptions) {
22+
Assert::assertInstanceOf('Algolia\AlgoliaSearch\RequestOptions\RequestOptions', $requestOptions);
23+
Assert::assertEquals($requestOptions->getBody(), array('page' => 0, 'query' => ''));
24+
25+
return $requestOptions;
26+
}))
27+
->willReturn(array(
28+
'hits' => array(array('foo' => 'bar')),
29+
'nbPages' => 1,
30+
));
31+
32+
$client = new SearchClient($apiWrapperMock, $config);
33+
$client->initIndex('foo')->findObject(
34+
function () { return true; }
35+
);
36+
37+
// Test with requestOptions as an array
38+
$apiWrapperMock = $this->getMock('Algolia\AlgoliaSearch\RetryStrategy\ApiWrapperInterface');
39+
$apiWrapperMock->method('read')
40+
->with($this->anything(), $this->anything(), $this->callback(function ($requestOptions) {
41+
Assert::assertInstanceOf('Algolia\AlgoliaSearch\RequestOptions\RequestOptions', $requestOptions);
42+
Assert::assertEquals($requestOptions->getBody(), array('page' => 0, 'query' => 'foo', 'hitsPerPage' => 5));
43+
44+
return $requestOptions;
45+
}))
46+
->willReturn(array(
47+
'hits' => array(array('foo' => 'bar')),
48+
'nbPages' => 1,
49+
));
50+
51+
$client = new SearchClient($apiWrapperMock, $config);
52+
$client->initIndex('foo')->findObject(
53+
function () { return true; },
54+
array('query' => 'foo', 'hitsPerPage' => 5)
55+
);
56+
57+
// Test with requestOptions as a RequestOptions object
58+
$apiWrapperMock = $this->getMock('Algolia\AlgoliaSearch\RetryStrategy\ApiWrapperInterface');
59+
$apiWrapperMock->method('read')
60+
->with($this->anything(), $this->anything(), $this->callback(function ($requestOptions) {
61+
Assert::assertInstanceOf('Algolia\AlgoliaSearch\RequestOptions\RequestOptions', $requestOptions);
62+
Assert::assertEquals($requestOptions->getBody(), array('page' => 0, 'query' => ''));
63+
Assert::assertArraySubset(array('User-Agent' => 'blabla'), $requestOptions->getHeaders());
64+
65+
return $requestOptions;
66+
}))
67+
->willReturn(array(
68+
'hits' => array(array('foo' => 'bar')),
69+
'nbPages' => 1,
70+
));
71+
72+
$client = new SearchClient($apiWrapperMock, $config);
73+
$client->initIndex('foo')->findObject(
74+
function () { return true; },
75+
$requestOptionsFactory->create(array('User-Agent' => 'blabla'))
76+
);
77+
}
78+
}

0 commit comments

Comments
 (0)