Skip to content

Commit fed4e04

Browse files
committed
Add search response fake helpers
1 parent a5e8a52 commit fed4e04

8 files changed

Lines changed: 158 additions & 10 deletions

File tree

src/Documents/Document.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@ public function __construct(
1818
protected array $source,
1919
) {}
2020

21+
/**
22+
* Create a fake document instance.
23+
*
24+
* @param array<string, mixed> $source
25+
*/
26+
public static function fake(string $id = '1', array $source = []): static
27+
{
28+
return new static($id, $source);
29+
}
30+
2131
/**
2232
* Get the document identifier.
2333
*/

src/Search/Hit.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,35 @@ public function __construct(
1818
protected array $hit,
1919
) {}
2020

21+
/**
22+
* Create a fake search hit instance.
23+
*
24+
* @param Document|array<string, mixed> $source
25+
* @param array<string, mixed> $attributes
26+
*/
27+
public static function fake(Document|array $source = [], string $index = 'test', string $id = '1', ?float $score = null, array $attributes = []): static
28+
{
29+
if ($source instanceof Document) {
30+
$id = $source->id();
31+
$source = $source->source();
32+
}
33+
34+
if (array_key_exists('_source', $source) || array_key_exists('_id', $source)) {
35+
return new static(array_merge([
36+
'_index' => $index,
37+
'_id' => $id,
38+
'_score' => $score,
39+
], $source, $attributes));
40+
}
41+
42+
return new static(array_merge([
43+
'_index' => $index,
44+
'_id' => $id,
45+
'_score' => $score,
46+
'_source' => $source,
47+
], $attributes));
48+
}
49+
2150
/**
2251
* Get the index name for the hit.
2352
*/

src/Search/SearchResponse.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace DirectoryTree\OpenSearchAdapter\Search;
44

5+
use DirectoryTree\OpenSearchAdapter\Documents\Document;
6+
57
/**
68
* @see https://docs.opensearch.org/latest/api-reference/search-apis/search/
79
*/
@@ -16,6 +18,28 @@ public function __construct(
1618
protected array $response,
1719
) {}
1820

21+
/**
22+
* Create a fake search response instance.
23+
*
24+
* @param array<int, Document|Hit|array<string, mixed>> $hits
25+
*/
26+
public static function fake(array $hits = [], string $index = 'test'): static
27+
{
28+
return new static([
29+
'hits' => [
30+
'total' => [
31+
'value' => count($hits),
32+
'relation' => 'eq',
33+
],
34+
'hits' => array_map(fn (Document|Hit|array $hit, int $position) => match (true) {
35+
$hit instanceof Hit => $hit->raw(),
36+
$hit instanceof Document => Hit::fake($hit, $index)->raw(),
37+
default => Hit::fake($hit, $index, (string) ($position + 1))->raw(),
38+
}, array_values($hits), array_keys(array_values($hits))),
39+
],
40+
]);
41+
}
42+
1943
/**
2044
* Get the search hits.
2145
*

src/Testing/Fakes/FakeDocumentManager.php

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,22 +42,16 @@ class FakeDocumentManager implements DocumentManagerInterface
4242
*/
4343
protected array $searched = [];
4444

45-
/**
46-
* The response that should be returned for searches.
47-
*/
48-
protected SearchResponse $response;
49-
5045
/**
5146
* Create a new fake document manager instance.
5247
*/
53-
public function __construct()
54-
{
55-
$this->response = new SearchResponse([
48+
public function __construct(
49+
protected SearchResponse $response = new SearchResponse([
5650
'hits' => [
5751
'hits' => [],
5852
],
59-
]);
60-
}
53+
]),
54+
) {}
6155

6256
/**
6357
* Set the search response returned by the fake.

tests/Unit/Documents/DocumentTest.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@
1313
$this->assertNull($document->get('missing'));
1414
});
1515

16+
test('fake document can be created', function () {
17+
$document = Document::fake('123456', ['title' => 'book']);
18+
19+
expect($document->id())->toBe('123456')
20+
->and($document->source())->toBe(['title' => 'book']);
21+
});
22+
1623
test('array casting', function () {
1724
$document = new Document('1', ['title' => 'test']);
1825

tests/Unit/Documents/FakeDocumentManagerTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,9 @@
8484

8585
$documents->assertSearched('posts', $request);
8686
});
87+
88+
test('fake document manager can be constructed with a search response', function () {
89+
$documents = new FakeDocumentManager($response = SearchResponse::fake());
90+
91+
expect($documents->search('posts', new SearchRequest))->toBe($response);
92+
});

tests/Unit/Search/HitTest.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,38 @@
5454
$this->assertSame('test', $this->hit->index());
5555
});
5656

57+
test('fake hit can be created from source', function () {
58+
$hit = Hit::fake(['title' => 'foo'], index: 'posts', id: '123', score: 4.2);
59+
60+
expect($hit->index())->toBe('posts')
61+
->and($hit->id())->toBe('123')
62+
->and($hit->score())->toBe(4.2)
63+
->and($hit->source())->toBe(['title' => 'foo']);
64+
});
65+
66+
test('fake hit can be created from a document', function () {
67+
$hit = Hit::fake(Document::fake('123', ['title' => 'foo']), index: 'posts');
68+
69+
expect($hit->index())->toBe('posts')
70+
->and($hit->id())->toBe('123')
71+
->and($hit->source())->toBe(['title' => 'foo']);
72+
});
73+
74+
test('fake hit can be created from raw hit attributes', function () {
75+
$hit = Hit::fake([
76+
'_index' => 'articles',
77+
'_id' => 'post-1',
78+
'_score' => 4.2,
79+
'_source' => [
80+
'title' => 'First',
81+
],
82+
]);
83+
84+
expect($hit->index())->toBe('articles')
85+
->and($hit->id())->toBe('post-1')
86+
->and($hit->score())->toBe(4.2);
87+
});
88+
5789
test('document can be retrieved', function () {
5890
$this->assertEquals(
5991
new Document('1', ['title' => 'foo']),

tests/Unit/Search/SearchResponseTest.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace DirectoryTree\OpenSearchAdapter\Tests\Unit\Search;
44

5+
use DirectoryTree\OpenSearchAdapter\Documents\Document;
56
use DirectoryTree\OpenSearchAdapter\Search\Aggregation;
67
use DirectoryTree\OpenSearchAdapter\Search\Hit;
78
use DirectoryTree\OpenSearchAdapter\Search\SearchResponse;
@@ -190,3 +191,48 @@
190191
],
191192
], $searchResponse->raw());
192193
});
194+
195+
test('fake response can be created without hits', function () {
196+
$searchResponse = SearchResponse::fake();
197+
198+
expect($searchResponse->hits())->toBe([])
199+
->and($searchResponse->total())->toBe(0);
200+
});
201+
202+
test('fake response can be created with documents', function () {
203+
$searchResponse = SearchResponse::fake([
204+
new Document('1', ['title' => 'First']),
205+
new Document('2', ['title' => 'Second']),
206+
], 'posts');
207+
208+
expect($searchResponse->total())->toBe(2)
209+
->and($searchResponse->hits()[0]->index())->toBe('posts')
210+
->and($searchResponse->hits()[0]->id())->toBe('1')
211+
->and($searchResponse->hits()[0]->source())->toBe(['title' => 'First']);
212+
});
213+
214+
test('fake response can be created with source arrays', function () {
215+
$searchResponse = SearchResponse::fake([
216+
['title' => 'First'],
217+
]);
218+
219+
expect($searchResponse->hits()[0]->id())->toBe('1')
220+
->and($searchResponse->hits()[0]->source())->toBe(['title' => 'First']);
221+
});
222+
223+
test('fake response can be created with raw hits', function () {
224+
$searchResponse = SearchResponse::fake([
225+
[
226+
'_index' => 'articles',
227+
'_id' => 'post-1',
228+
'_score' => 4.2,
229+
'_source' => [
230+
'title' => 'First',
231+
],
232+
],
233+
]);
234+
235+
expect($searchResponse->hits()[0]->index())->toBe('articles')
236+
->and($searchResponse->hits()[0]->id())->toBe('post-1')
237+
->and($searchResponse->hits()[0]->score())->toBe(4.2);
238+
});

0 commit comments

Comments
 (0)