diff --git a/src/Contracts/PaginatedResult.php b/src/Contracts/PaginatedResult.php new file mode 100644 index 0000000..c3a36e5 --- /dev/null +++ b/src/Contracts/PaginatedResult.php @@ -0,0 +1,76 @@ + + */ +interface PaginatedResult +{ + /** + * Get the items for the current page + * + * @return array + */ + public function items(): array; + + /** + * Get total number of items across all pages + * + * @return int + */ + public function total(): int; + + /** + * Get items per page + * + * @return int + */ + public function perPage(): int; + + /** + * Get current page number (1-indexed) + * + * @return int + */ + public function currentPage(): int; + + /** + * Get last page number + * + * @return int + */ + public function lastPage(): int; + + /** + * Check if there are more pages after the current one + * + * @return bool + */ + public function hasMorePages(): bool; + + /** + * Get the count of items on current page + * + * @return int + */ + public function count(): int; + + /** + * Check if the current page is empty + * + * @return bool + */ + public function isEmpty(): bool; + + /** + * Check if the current page is not empty + * + * @return bool + */ + public function isNotEmpty(): bool; +} diff --git a/tests/CriteriaSourceContractTest.php b/tests/CriteriaSourceContractTest.php new file mode 100644 index 0000000..1c3dcfd --- /dev/null +++ b/tests/CriteriaSourceContractTest.php @@ -0,0 +1,96 @@ +toBeTrue(); +}); + +test('CriteriaSource interface has all required methods', function () { + $reflection = new ReflectionClass(CriteriaSource::class); + + $expectedMethods = [ + 'filterGroups', + 'orderType', + 'orderBy', + 'pageLimit', + 'pageOffset', + 'pageNumber', + ]; + + foreach ($expectedMethods as $method) { + expect($reflection->hasMethod($method)) + ->toBeTrue("Method '{$method}' should exist in CriteriaSource interface"); + } +}); + +test('CriteriaSource methods have correct return types', function () { + $reflection = new ReflectionClass(CriteriaSource::class); + + $methodReturnTypes = [ + 'filterGroups' => 'array', + 'orderType' => 'string', + 'orderBy' => 'string', + 'pageLimit' => 'int', + 'pageOffset' => 'int', + 'pageNumber' => 'int', + ]; + + foreach ($methodReturnTypes as $methodName => $expectedType) { + $method = $reflection->getMethod($methodName); + expect($method->hasReturnType())->toBeTrue("Method {$methodName} should have return type"); + + $returnType = $method->getReturnType(); + expect($returnType)->not->toBeNull("Method {$methodName} return type should not be null"); + + if ($returnType instanceof ReflectionNamedType) { + expect($returnType->getName())->toBe($expectedType, "Method {$methodName} should return {$expectedType}"); + } + } +}); + +test('CriteriaSource is an interface not a class', function () { + $reflection = new ReflectionClass(CriteriaSource::class); + + expect($reflection->isInterface())->toBeTrue() + ->and($reflection->isTrait())->toBeFalse(); +}); + +test('CriteriaSource interface has correct namespace', function () { + expect(CriteriaSource::class) + ->toBe('ComplexHeart\Domain\Criteria\Contracts\CriteriaSource'); +}); + +test('CriteriaSource filterGroups method has correct docblock return type', function () { + $reflection = new ReflectionClass(CriteriaSource::class); + $method = $reflection->getMethod('filterGroups'); + + $docComment = $method->getDocComment(); + expect($docComment)->toContain('@return array>>'); +}); + +test('CriteriaSource orderType method documents valid values', function () { + $reflection = new ReflectionClass(CriteriaSource::class); + $method = $reflection->getMethod('orderType'); + + $docComment = $method->getDocComment(); + expect($docComment)->toContain('asc, desc, none or random'); +}); + +test('CriteriaSource pageOffset method documents default behavior', function () { + $reflection = new ReflectionClass(CriteriaSource::class); + $method = $reflection->getMethod('pageOffset'); + + $docComment = $method->getDocComment(); + expect($docComment)->toContain('default should be 0'); +}); + +test('CriteriaSource pageNumber method documents offset computation', function () { + $reflection = new ReflectionClass(CriteriaSource::class); + $method = $reflection->getMethod('pageNumber'); + + $docComment = $method->getDocComment(); + expect($docComment)->toContain('used to compute the offset'); +}); diff --git a/tests/PaginatedResultContractTest.php b/tests/PaginatedResultContractTest.php new file mode 100644 index 0000000..8973381 --- /dev/null +++ b/tests/PaginatedResultContractTest.php @@ -0,0 +1,70 @@ +toBeTrue(); +}); + +test('PaginatedResult interface has all required methods', function () { + $reflection = new ReflectionClass(PaginatedResult::class); + + $expectedMethods = [ + 'items', + 'total', + 'perPage', + 'currentPage', + 'lastPage', + 'hasMorePages', + 'count', + 'isEmpty', + 'isNotEmpty', + ]; + + foreach ($expectedMethods as $method) { + expect($reflection->hasMethod($method)) + ->toBeTrue("Method '{$method}' should exist in PaginatedResult interface"); + } +}); + +test('PaginatedResult methods have correct return types', function () { + $reflection = new ReflectionClass(PaginatedResult::class); + + $methodReturnTypes = [ + 'items' => 'array', + 'total' => 'int', + 'perPage' => 'int', + 'currentPage' => 'int', + 'lastPage' => 'int', + 'hasMorePages' => 'bool', + 'count' => 'int', + 'isEmpty' => 'bool', + 'isNotEmpty' => 'bool', + ]; + + foreach ($methodReturnTypes as $methodName => $expectedType) { + $method = $reflection->getMethod($methodName); + expect($method->hasReturnType())->toBeTrue("Method {$methodName} should have return type"); + + $returnType = $method->getReturnType(); + expect($returnType)->not->toBeNull("Method {$methodName} return type should not be null"); + + if ($returnType instanceof ReflectionNamedType) { + expect($returnType->getName())->toBe($expectedType, "Method {$methodName} should return {$expectedType}"); + } + } +}); + +test('PaginatedResult is an interface not a class', function () { + $reflection = new ReflectionClass(PaginatedResult::class); + + expect($reflection->isInterface())->toBeTrue() + ->and($reflection->isTrait())->toBeFalse(); +}); + +test('PaginatedResult interface has correct namespace', function () { + expect(PaginatedResult::class) + ->toBe('ComplexHeart\Domain\Criteria\Contracts\PaginatedResult'); +});