diff --git a/tests/Dataset.php b/tests/Dataset.php index 0c415cb..50f1ab0 100644 --- a/tests/Dataset.php +++ b/tests/Dataset.php @@ -8,6 +8,7 @@ use Cerbero\JsonParser\Sources\Psr7Request; use DirectoryIterator; use Generator; use Mockery; +use Pest\Expectation; /** * The dataset provider. @@ -176,6 +177,107 @@ final class Dataset } } + /** + * Retrieve the dataset to test single lazy pointers + * + * @return Generator + */ + public static function forSingleLazyPointers(): Generator + { + $json = fixture('json/complex_object.json'); + $sequenceByPointer = [ + '' => [ + fn ($value, $key) => $key->toBe('id')->and($value->value)->toBe('0001'), + fn ($value, $key) => $key->toBe('type')->and($value->value)->toBe('donut'), + fn ($value, $key) => $key->toBe('name')->and($value->value)->toBe('Cake'), + fn ($value, $key) => $key->toBe('ppu')->and($value->value)->toBe(0.55), + fn ($value, $key) => $key->toBe('batters')->and($value->value)->toBeInstanceOf(Parser::class), + fn ($value, $key) => $key->toBe('topping')->and($value->value)->toBeInstanceOf(Parser::class), + ], + '/batters/batter/-' => [ + fn ($value, $key) => $key->toBe(0)->and($value->value)->toBeInstanceOf(Parser::class), + fn ($value, $key) => $key->toBe(1)->and($value->value)->toBeInstanceOf(Parser::class), + fn ($value, $key) => $key->toBe(2)->and($value->value)->toBeInstanceOf(Parser::class), + fn ($value, $key) => $key->toBe(3)->and($value->value)->toBeInstanceOf(Parser::class), + ], + '/topping/-' => [ + fn ($value, $key) => $key->toBe(0)->and($value->value)->toBeInstanceOf(Parser::class), + fn ($value, $key) => $key->toBe(1)->and($value->value)->toBeInstanceOf(Parser::class), + fn ($value, $key) => $key->toBe(2)->and($value->value)->toBeInstanceOf(Parser::class), + fn ($value, $key) => $key->toBe(3)->and($value->value)->toBeInstanceOf(Parser::class), + fn ($value, $key) => $key->toBe(4)->and($value->value)->toBeInstanceOf(Parser::class), + fn ($value, $key) => $key->toBe(5)->and($value->value)->toBeInstanceOf(Parser::class), + fn ($value, $key) => $key->toBe(6)->and($value->value)->toBeInstanceOf(Parser::class), + ], + ]; + + foreach ($sequenceByPointer as $pointer => $sequence) { + yield [$json, $pointer, $sequence]; + } + } + + /** + * Retrieve the dataset to test multiple lazy pointers + * + * @return Generator + */ + public static function forMultipleLazyPointers(): Generator + { + $json = fixture('json/complex_object.json'); + $sequenceByPointer = [ + '/topping,/batters' => [ + fn ($value, $key) => $key->toBe('batters')->and($value->value)->toBeInstanceOf(Parser::class), + fn ($value, $key) => $key->toBe('topping')->and($value->value)->toBeInstanceOf(Parser::class), + ], + '/topping/-,/batters/batter' => [ + fn ($value, $key) => $key->toBe('batter')->and($value->value)->toBeInstanceOf(Parser::class), + fn ($value, $key) => $key->toBe(0)->and($value->value)->toBeInstanceOf(Parser::class), + fn ($value, $key) => $key->toBe(1)->and($value->value)->toBeInstanceOf(Parser::class), + fn ($value, $key) => $key->toBe(2)->and($value->value)->toBeInstanceOf(Parser::class), + fn ($value, $key) => $key->toBe(3)->and($value->value)->toBeInstanceOf(Parser::class), + fn ($value, $key) => $key->toBe(4)->and($value->value)->toBeInstanceOf(Parser::class), + fn ($value, $key) => $key->toBe(5)->and($value->value)->toBeInstanceOf(Parser::class), + fn ($value, $key) => $key->toBe(6)->and($value->value)->toBeInstanceOf(Parser::class), + ], + ]; + + foreach ($sequenceByPointer as $pointers => $sequence) { + yield [$json, explode(',', $pointers), $sequence]; + } + } + + /** + * Retrieve the dataset to test recursive lazy loading + * + * @return Generator + */ + public static function forRecursiveLazyLoading(): Generator + { + $json = fixture('json/complex_object.json'); + $expectedByKeys = [ + 'batters,batter' => [ + ['id' => '1001', 'type' => 'Regular'], + ['id' => '1002', 'type' => 'Chocolate'], + ['id' => '1003', 'type' => 'Blueberry'], + ['id' => '1004', 'type' => 'Devil\'s Food'], + ], + 'topping' => [ + ['id' => '5001', 'type' => 'None'], + ['id' => '5002', 'type' => 'Glazed'], + ['id' => '5005', 'type' => 'Sugar'], + ['id' => '5007', 'type' => 'Powdered Sugar'], + ['id' => '5006', 'type' => 'Chocolate with Sprinkles'], + ['id' => '5003', 'type' => 'Chocolate'], + ['id' => '5004', 'type' => 'Maple'], + ], + ]; + + foreach ($expectedByKeys as $keys => $expected) { + $keys = explode(',', $keys); + yield [$json, '/' . $keys[0], $keys, $expected]; + } + } + /** * Retrieve the dataset to test syntax errors * diff --git a/tests/Feature/PointersTest.php b/tests/Feature/PointersTest.php index 98917e5..f75683b 100644 --- a/tests/Feature/PointersTest.php +++ b/tests/Feature/PointersTest.php @@ -11,11 +11,11 @@ it('throws an exception when providing an invalid JSON pointer', function (strin ->toThrow(InvalidPointerException::class, "The string [$pointer] is not a valid JSON pointer"); })->with(Dataset::forInvalidPointers()); -it('supports single JSON pointers', function (string $json, string $pointer, array $parsed) { +it('loads JSON from a single JSON pointer', function (string $json, string $pointer, array $parsed) { expect(JsonParser::parse($json)->pointer($pointer))->toPointTo($parsed); })->with(Dataset::forSinglePointers()); -it('supports multiple JSON pointers', function (string $json, array $pointers, array $parsed) { +it('loads JSON from multiple JSON pointers', function (string $json, array $pointers, array $parsed) { expect(JsonParser::parse($json)->pointers($pointers))->toPointTo($parsed); })->with(Dataset::forMultiplePointers()); @@ -24,6 +24,18 @@ it('can intersect pointers with wildcards', function (string $json, array $point })->with(Dataset::forIntersectingPointersWithWildcards()); it('throws an exception when two pointers intersect', function (string $json, array $pointers, string $message) { - expect(fn () => JsonParser::parse($json)->pointers($pointers)->traverse()) + expect(fn () => JsonParser::parse($json)->pointers($pointers)) ->toThrow(IntersectingPointersException::class, $message); })->with(Dataset::forIntersectingPointers()); + +it('lazy loads JSON from a single lazy JSON pointer', function (string $json, string $pointer, array $sequence) { + expect(JsonParser::parse($json)->lazyPointer($pointer))->sequence(...$sequence); +})->with(Dataset::forSingleLazyPointers()); + +it('lazy loads JSON from multiple lazy JSON pointers', function (string $json, array $pointers, array $sequence) { + expect(JsonParser::parse($json)->lazyPointers($pointers))->sequence(...$sequence); +})->with(Dataset::forMultipleLazyPointers()); + +it('lazy loads JSON recursively', function (string $json, string $pointer, array $keys, array $expected) { + expect(JsonParser::parse($json)->lazyPointer($pointer))->toLazyLoadRecursively($keys, $expected); +})->with(Dataset::forRecursiveLazyLoading()); diff --git a/tests/Pest.php b/tests/Pest.php index 81730b8..a85408c 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -1,5 +1,7 @@ extend('toPointTo', function (array $expected) { return expect($actual)->toBe($expected); }); + +/** + * Expect that values defined by lazy JSON pointers are parsed correctly + * + * @param array $expected + * @return Expectation + */ +expect()->extend('toLazyLoadRecursively', function (array $keys, array $expected) { + foreach ($this->value as $key => $value) { + expect($value)->toBeInstanceOf(Parser::class); + + if (is_null($expectedKey = array_shift($keys))) { + expect($key)->toBeInt()->and($value)->toParseTo($expected[$key]); + } else { + expect($key)->toBe($expectedKey)->and($value)->toLazyLoadRecursively($keys, $expected); + } + } +});