Skip to content

Commit 078c820

Browse files
authored
Feature/Add PaginatedResult interface with required methods and tests (#27)
* Feature/Add PaginatedResult interface with required methods and tests * Feature/Add tests for CriteriaSource interface methods and documentation
1 parent 9e9f931 commit 078c820

File tree

3 files changed

+242
-0
lines changed

3 files changed

+242
-0
lines changed

src/Contracts/PaginatedResult.php

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace ComplexHeart\Domain\Criteria\Contracts;
6+
7+
/**
8+
* Interface PaginatedResult
9+
*
10+
* @author Unay Santisteban <[email protected]>
11+
*/
12+
interface PaginatedResult
13+
{
14+
/**
15+
* Get the items for the current page
16+
*
17+
* @return array<int, mixed>
18+
*/
19+
public function items(): array;
20+
21+
/**
22+
* Get total number of items across all pages
23+
*
24+
* @return int
25+
*/
26+
public function total(): int;
27+
28+
/**
29+
* Get items per page
30+
*
31+
* @return int
32+
*/
33+
public function perPage(): int;
34+
35+
/**
36+
* Get current page number (1-indexed)
37+
*
38+
* @return int
39+
*/
40+
public function currentPage(): int;
41+
42+
/**
43+
* Get last page number
44+
*
45+
* @return int
46+
*/
47+
public function lastPage(): int;
48+
49+
/**
50+
* Check if there are more pages after the current one
51+
*
52+
* @return bool
53+
*/
54+
public function hasMorePages(): bool;
55+
56+
/**
57+
* Get the count of items on current page
58+
*
59+
* @return int
60+
*/
61+
public function count(): int;
62+
63+
/**
64+
* Check if the current page is empty
65+
*
66+
* @return bool
67+
*/
68+
public function isEmpty(): bool;
69+
70+
/**
71+
* Check if the current page is not empty
72+
*
73+
* @return bool
74+
*/
75+
public function isNotEmpty(): bool;
76+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use ComplexHeart\Domain\Criteria\Contracts\CriteriaSource;
6+
7+
test('CriteriaSource interface exists and is accessible', function () {
8+
expect(interface_exists(CriteriaSource::class))->toBeTrue();
9+
});
10+
11+
test('CriteriaSource interface has all required methods', function () {
12+
$reflection = new ReflectionClass(CriteriaSource::class);
13+
14+
$expectedMethods = [
15+
'filterGroups',
16+
'orderType',
17+
'orderBy',
18+
'pageLimit',
19+
'pageOffset',
20+
'pageNumber',
21+
];
22+
23+
foreach ($expectedMethods as $method) {
24+
expect($reflection->hasMethod($method))
25+
->toBeTrue("Method '{$method}' should exist in CriteriaSource interface");
26+
}
27+
});
28+
29+
test('CriteriaSource methods have correct return types', function () {
30+
$reflection = new ReflectionClass(CriteriaSource::class);
31+
32+
$methodReturnTypes = [
33+
'filterGroups' => 'array',
34+
'orderType' => 'string',
35+
'orderBy' => 'string',
36+
'pageLimit' => 'int',
37+
'pageOffset' => 'int',
38+
'pageNumber' => 'int',
39+
];
40+
41+
foreach ($methodReturnTypes as $methodName => $expectedType) {
42+
$method = $reflection->getMethod($methodName);
43+
expect($method->hasReturnType())->toBeTrue("Method {$methodName} should have return type");
44+
45+
$returnType = $method->getReturnType();
46+
expect($returnType)->not->toBeNull("Method {$methodName} return type should not be null");
47+
48+
if ($returnType instanceof ReflectionNamedType) {
49+
expect($returnType->getName())->toBe($expectedType, "Method {$methodName} should return {$expectedType}");
50+
}
51+
}
52+
});
53+
54+
test('CriteriaSource is an interface not a class', function () {
55+
$reflection = new ReflectionClass(CriteriaSource::class);
56+
57+
expect($reflection->isInterface())->toBeTrue()
58+
->and($reflection->isTrait())->toBeFalse();
59+
});
60+
61+
test('CriteriaSource interface has correct namespace', function () {
62+
expect(CriteriaSource::class)
63+
->toBe('ComplexHeart\Domain\Criteria\Contracts\CriteriaSource');
64+
});
65+
66+
test('CriteriaSource filterGroups method has correct docblock return type', function () {
67+
$reflection = new ReflectionClass(CriteriaSource::class);
68+
$method = $reflection->getMethod('filterGroups');
69+
70+
$docComment = $method->getDocComment();
71+
expect($docComment)->toContain('@return array<array<array<string, mixed>>>');
72+
});
73+
74+
test('CriteriaSource orderType method documents valid values', function () {
75+
$reflection = new ReflectionClass(CriteriaSource::class);
76+
$method = $reflection->getMethod('orderType');
77+
78+
$docComment = $method->getDocComment();
79+
expect($docComment)->toContain('asc, desc, none or random');
80+
});
81+
82+
test('CriteriaSource pageOffset method documents default behavior', function () {
83+
$reflection = new ReflectionClass(CriteriaSource::class);
84+
$method = $reflection->getMethod('pageOffset');
85+
86+
$docComment = $method->getDocComment();
87+
expect($docComment)->toContain('default should be 0');
88+
});
89+
90+
test('CriteriaSource pageNumber method documents offset computation', function () {
91+
$reflection = new ReflectionClass(CriteriaSource::class);
92+
$method = $reflection->getMethod('pageNumber');
93+
94+
$docComment = $method->getDocComment();
95+
expect($docComment)->toContain('used to compute the offset');
96+
});
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use ComplexHeart\Domain\Criteria\Contracts\PaginatedResult;
6+
7+
test('PaginatedResult interface exists and is accessible', function () {
8+
expect(interface_exists(PaginatedResult::class))->toBeTrue();
9+
});
10+
11+
test('PaginatedResult interface has all required methods', function () {
12+
$reflection = new ReflectionClass(PaginatedResult::class);
13+
14+
$expectedMethods = [
15+
'items',
16+
'total',
17+
'perPage',
18+
'currentPage',
19+
'lastPage',
20+
'hasMorePages',
21+
'count',
22+
'isEmpty',
23+
'isNotEmpty',
24+
];
25+
26+
foreach ($expectedMethods as $method) {
27+
expect($reflection->hasMethod($method))
28+
->toBeTrue("Method '{$method}' should exist in PaginatedResult interface");
29+
}
30+
});
31+
32+
test('PaginatedResult methods have correct return types', function () {
33+
$reflection = new ReflectionClass(PaginatedResult::class);
34+
35+
$methodReturnTypes = [
36+
'items' => 'array',
37+
'total' => 'int',
38+
'perPage' => 'int',
39+
'currentPage' => 'int',
40+
'lastPage' => 'int',
41+
'hasMorePages' => 'bool',
42+
'count' => 'int',
43+
'isEmpty' => 'bool',
44+
'isNotEmpty' => 'bool',
45+
];
46+
47+
foreach ($methodReturnTypes as $methodName => $expectedType) {
48+
$method = $reflection->getMethod($methodName);
49+
expect($method->hasReturnType())->toBeTrue("Method {$methodName} should have return type");
50+
51+
$returnType = $method->getReturnType();
52+
expect($returnType)->not->toBeNull("Method {$methodName} return type should not be null");
53+
54+
if ($returnType instanceof ReflectionNamedType) {
55+
expect($returnType->getName())->toBe($expectedType, "Method {$methodName} should return {$expectedType}");
56+
}
57+
}
58+
});
59+
60+
test('PaginatedResult is an interface not a class', function () {
61+
$reflection = new ReflectionClass(PaginatedResult::class);
62+
63+
expect($reflection->isInterface())->toBeTrue()
64+
->and($reflection->isTrait())->toBeFalse();
65+
});
66+
67+
test('PaginatedResult interface has correct namespace', function () {
68+
expect(PaginatedResult::class)
69+
->toBe('ComplexHeart\Domain\Criteria\Contracts\PaginatedResult');
70+
});

0 commit comments

Comments
 (0)