json-parser/tests/Dataset.php

392 lines
13 KiB
PHP
Raw Normal View History

2022-11-07 23:45:07 +10:00
<?php
namespace Cerbero\JsonParser;
2023-02-25 20:46:41 +10:00
use Cerbero\JsonParser\Decoders\DecodedValue;
use Cerbero\JsonParser\Sources\Endpoint;
use Cerbero\JsonParser\Sources\Psr7Request;
2022-11-07 23:45:07 +10:00
use DirectoryIterator;
use Generator;
2023-02-25 20:46:41 +10:00
use Mockery;
2022-11-07 23:45:07 +10:00
/**
2023-02-25 20:46:41 +10:00
* The dataset provider.
2022-11-07 23:45:07 +10:00
*
*/
2023-02-26 20:03:45 +10:00
final class Dataset
2022-11-07 23:45:07 +10:00
{
/**
* Retrieve the dataset to test parsing
*
* @return Generator
*/
public static function forParsing(): Generator
{
foreach (self::fixtures() as $fixture) {
2022-11-13 17:08:57 +10:00
$name = $fixture->getBasename('.json');
2022-11-07 23:45:07 +10:00
yield [
2022-11-13 17:08:57 +10:00
file_get_contents($fixture->getRealPath()),
2023-02-06 18:18:14 +10:00
require fixture("parsing/{$name}.php"),
2022-11-07 23:45:07 +10:00
];
}
}
/**
2022-11-13 17:08:57 +10:00
* Retrieve the fixtures
2022-11-07 23:45:07 +10:00
*
2022-11-13 17:08:57 +10:00
* @return Generator<int, DirectoryIterator>
2022-11-07 23:45:07 +10:00
*/
2022-11-13 17:08:57 +10:00
protected static function fixtures(): Generator
2022-11-07 23:45:07 +10:00
{
2023-02-06 18:18:14 +10:00
foreach (new DirectoryIterator(fixture('json')) as $file) {
2022-11-13 17:08:57 +10:00
if (!$file->isDot()) {
yield $file;
2022-11-07 23:45:07 +10:00
}
}
}
2022-11-17 23:52:34 +10:00
2022-12-21 19:30:18 +10:00
/**
* Retrieve the dataset to test invalid pointers
*
* @return Generator
*/
public static function forInvalidPointers(): Generator
{
yield from ['abc', '/foo~2', '/~', ' '];
}
2022-11-17 23:52:34 +10:00
/**
* Retrieve the dataset to test single pointers
*
* @return Generator
*/
public static function forSinglePointers(): Generator
{
2023-02-06 18:18:14 +10:00
$singlePointers = require fixture('pointers/single_pointer.php');
2022-11-17 23:52:34 +10:00
foreach ($singlePointers as $fixture => $pointers) {
2023-02-06 18:18:14 +10:00
$json = file_get_contents(fixture("json/{$fixture}.json"));
2022-11-17 23:52:34 +10:00
foreach ($pointers as $pointer => $value) {
yield [$json, $pointer, $value];
}
}
}
2022-11-21 00:36:08 +10:00
/**
2022-12-21 19:30:18 +10:00
* Retrieve the dataset to test multiple pointers
2022-11-21 00:36:08 +10:00
*
* @return Generator
*/
2022-12-21 19:30:18 +10:00
public static function forMultiplePointers(): Generator
2022-11-21 00:36:08 +10:00
{
2023-02-06 18:18:14 +10:00
$multiplePointers = require fixture('pointers/multiple_pointers.php');
2022-12-21 19:30:18 +10:00
foreach ($multiplePointers as $fixture => $valueByPointers) {
2023-02-06 18:18:14 +10:00
$json = file_get_contents(fixture("json/{$fixture}.json"));
2022-12-21 19:30:18 +10:00
foreach ($valueByPointers as $pointers => $value) {
yield [$json, explode(',', $pointers), $value];
}
}
2022-11-21 00:36:08 +10:00
}
2023-02-25 20:46:41 +10:00
/**
* Retrieve the dataset to test intersecting pointers with wildcards
*
* @return Generator
*/
public static function forIntersectingPointersWithWildcards(): Generator
{
$json = fixture('json/complex_object.json');
$pointers = [
'/topping/6/type' => fn (string $value) => "$value @ /topping/6/type",
'/topping/-/type' => fn (string $value) => "$value @ /topping/-/type",
'/topping/0/type' => fn (string $value) => "$value @ /topping/0/type",
'/topping/2/type' => fn (string $value) => "$value @ /topping/2/type",
];
$parsed = [
'type' => [
'None @ /topping/0/type',
'Glazed @ /topping/-/type',
'Sugar @ /topping/2/type',
'Powdered Sugar @ /topping/-/type',
'Chocolate with Sprinkles @ /topping/-/type',
'Chocolate @ /topping/-/type',
'Maple @ /topping/6/type',
]
];
yield [$json, $pointers, $parsed];
}
2023-03-08 19:39:31 +10:00
/**
* Retrieve the dataset to test intersecting pointers
*
* @return Generator
*/
public static function forIntersectingPointers(): Generator
{
$json = fixture('json/complex_object.json');
$message = 'The pointers [%s] and [%s] are intersecting';
$pointersByIntersection = [
'/topping,/topping/0' => [
'/topping',
'/topping/0',
],
'/topping/0,/topping' => [
'/topping/0',
'/topping',
],
'/topping,/topping/-' => [
'/topping',
'/topping/-',
],
'/topping/-,/topping' => [
'/topping/-',
'/topping',
],
'/topping/0/type,/topping' => [
'/topping/0/type',
'/topping/-/type',
'/topping',
],
'/topping,/topping/-/type' => [
'/topping',
'/topping/-/type',
'/topping/0/type',
],
'/topping/-/type,/topping/-/type/baz' => [
'/topping/-/type',
'/topping/-/types',
'/topping/-/type/baz',
],
'/topping/-/type/baz,/topping/-/type' => [
'/topping/-/type/baz',
'/topping/-/type',
'/topping/-/types',
],
];
foreach ($pointersByIntersection as $intersection => $pointers) {
yield [$json, $pointers, vsprintf($message, explode(',', $intersection))];
}
}
2023-03-20 19:33:16 +10:00
/**
* 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];
}
}
2023-03-21 17:33:52 +10:00
/**
* Retrieve the dataset to test mixed pointers
*
* @return Generator
*/
public static function forMixedPointers(): Generator
{
$json = fixture('json/complex_object.json');
$pointersList = [
[
'/name' => fn (string $name) => "name_{$name}",
],
[
'/id' => fn (string $id) => "id_{$id}",
'/type' => fn (string $type) => "type_{$type}",
],
];
$lazyPointers = [
[
'/batters/batter' => fn (Parser $batter) => $batter::class,
],
[
'/batters' => fn (Parser $batters) => $batters::class,
'/topping' => fn (Parser $topping) => $topping::class,
],
];
$expected = [
[
'name' => 'name_Cake',
'batter' => Parser::class,
],
[
'id' => 'id_0001',
'type' => 'type_donut',
'batters' => Parser::class,
'topping' => Parser::class,
],
];
foreach ($pointersList as $index => $pointers) {
yield [$json, $pointers, $lazyPointers[$index], $expected[$index]];
}
}
2023-02-25 20:46:41 +10:00
/**
* Retrieve the dataset to test syntax errors
*
* @return Generator
*/
public static function forSyntaxErrors(): Generator
{
yield from require fixture('errors/syntax.php');
}
/**
* Retrieve the dataset to test decoding errors patching
*
* @return Generator
*/
public static function forDecodingErrorsPatching(): Generator
{
$patches = [null, 'baz', 123];
$json = '[1a, ""b, "foo", 3.1c4, falsed, null, [1, 2e], {"bar": 1, "baz"f: 2}]';
$patchJson = fn (mixed $patch) => [$patch, $patch, 'foo', $patch, $patch, null, $patch, $patch];
foreach ($patches as $patch) {
yield [$json, $patch, $patchJson($patch)];
}
$patch = fn (DecodedValue $decoded) => strrev($decoded->json);
$patched = ['a1', 'b""', 'foo', '4c1.3', 'deslaf', null, ']e2,1[', '}2:f"zab",1:"rab"{'];
yield [$json, fn () => $patch, $patched];
}
/**
* Retrieve the dataset to test sources requiring Guzzle
*
* @return Generator
*/
public static function forSourcesRequiringGuzzle(): Generator
{
$sources = [Endpoint::class, Psr7Request::class];
foreach ($sources as $source) {
yield Mockery::mock($source)
->makePartial()
->shouldAllowMockingProtectedMethods()
->shouldReceive('guzzleIsInstalled')
->andReturn(false)
->getMock();
}
}
2023-02-26 20:03:45 +10:00
/**
* Retrieve the dataset to test decoders
*
* @return Generator
*/
public static function forDecoders(): Generator
{
$json = '{"foo":"bar"}';
$values = [
true => ['foo' => 'bar'],
false => (object) ['foo' => 'bar'],
];
foreach ([true, false] as $decodesToArray) {
yield [$decodesToArray, $json, $values[$decodesToArray]];
}
}
2022-11-07 23:45:07 +10:00
}