Skip to content

Commit

Permalink
Add JSON Parser (nelmio#919)
Browse files Browse the repository at this point in the history
Closes nelmio#825
  • Loading branch information
reinfi authored and theofidry committed Apr 8, 2018
1 parent 5a2c270 commit b7a0e66
Show file tree
Hide file tree
Showing 16 changed files with 341 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ for 2.x, head [here](https://github.com/nelmio/alice/tree/2.x)**.
1. [Creating Fixtures](doc/complete-reference.md#creating-fixtures)
1. [YAML](doc/complete-reference.md#yaml)
1. [PHP](doc/complete-reference.md#php)
1. [JSON](doc/complete-reference.md#json)
1. [Fixture Ranges](doc/complete-reference.md#fixture-ranges)
1. [Fixture Lists](doc/complete-reference.md#fixture-lists)
1. [Fixture Reference](doc/complete-reference.md#fixture-reference)
Expand Down
13 changes: 13 additions & 0 deletions doc/complete-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
1. [Creating Fixtures](#creating-fixtures)
1. [YAML](#yaml)
1. [PHP](#php)
1. [JSON](#json)
1. [Fixture Ranges](#fixture-ranges)
1. [Fixture Reference](#fixture-reference)
1. [Fixture Lists](#fixture-lists)
Expand Down Expand Up @@ -70,7 +71,19 @@ return [
];
```

### JSON

You can also specify fixtures in a JSON file:

```json
{
"Nelmio\\Alice\\support\\models\\User": {
"user0": {
"fullname": "John Doe"
}
}
}
```

## Fixture Ranges

Expand Down
5 changes: 5 additions & 0 deletions fixtures/Integration/dummy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"\\stdClass": {
"dummy{1..2}": {}
}
}
5 changes: 5 additions & 0 deletions fixtures/Parser/FileListProviderTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ public function provideYamlList()
return FilesReference::getYamlList();
}

public function provideJsonList()
{
return FilesReference::getJsonList();
}

public function provideUnsupportedList()
{
return FilesReference::getUnsupportedList();
Expand Down
7 changes: 7 additions & 0 deletions fixtures/Parser/files/json/basic.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"Nelmio\\Alice\\support\\models\\User": {
"user0": {
"fullname": "John Doe"
}
}
}
1 change: 1 addition & 0 deletions fixtures/Parser/files/json/empty.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
1 change: 1 addition & 0 deletions fixtures/Parser/files/json/invalid.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{
4 changes: 4 additions & 0 deletions src/Bridge/Symfony/Resources/config/parser.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@
<tag name="nelmio_alice.file_parser" />
</service>

<service id="nelmio_alice.file_parser.chainable.json" class="Nelmio\Alice\Parser\Chainable\JsonParser">
<tag name="nelmio_alice.file_parser" />
</service>

</services>

</container>
2 changes: 2 additions & 0 deletions src/Loader/NativeLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@
use Nelmio\Alice\GeneratorInterface;
use Nelmio\Alice\IsAServiceTrait;
use Nelmio\Alice\ObjectSet;
use Nelmio\Alice\Parser\Chainable\JsonParser;
use Nelmio\Alice\Parser\Chainable\PhpParser;
use Nelmio\Alice\Parser\Chainable\YamlParser;
use Nelmio\Alice\Parser\IncludeProcessor\DefaultIncludeProcessor;
Expand Down Expand Up @@ -313,6 +314,7 @@ protected function createParser(): ParserInterface
$registry = new ParserRegistry([
new YamlParser(new SymfonyYamlParser()),
new PhpParser(),
new JsonParser(),
]);

return new RuntimeCacheParser(
Expand Down
69 changes: 69 additions & 0 deletions src/Parser/Chainable/JsonParser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

/*
* This file is part of the Alice package.
*
* (c) Nelmio <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Nelmio\Alice\Parser\Chainable;

use Nelmio\Alice\IsAServiceTrait;
use Nelmio\Alice\Parser\ChainableParserInterface;
use Nelmio\Alice\Throwable\Exception\InvalidArgumentExceptionFactory;
use Nelmio\Alice\Throwable\Exception\Parser\ParseExceptionFactory;
use Nelmio\Alice\Throwable\Exception\Parser\UnparsableFileException;

final class JsonParser implements ChainableParserInterface
{
use IsAServiceTrait;

private const REGEX = '/.{1,}\.json$/i';

/**
* @inheritdoc
*/
public function canParse(string $file): bool
{
if (false === stream_is_local($file)) {
return false;
}

return 1 === preg_match(self::REGEX, $file);
}

/**
* {@inheritDoc}
*
* @param string $file Local JSON file
*
* @throws UnparsableFileException
*/
public function parse(string $file): array
{
if (false === file_exists($file)) {
throw InvalidArgumentExceptionFactory::createForFileCouldNotBeFound($file);
}

try {
$data = json_decode(file_get_contents($file), true);

if (null === $data) {
throw ParseExceptionFactory::createForInvalidJson($file);
}

return $data;
} catch (\Exception $exception) {
if ($exception instanceof UnparsableFileException) {
throw $exception;
}

throw ParseExceptionFactory::createForUnparsableFile($file, 0, $exception);
}
}
}
12 changes: 12 additions & 0 deletions src/Throwable/Exception/Parser/ParseExceptionFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,18 @@ public static function createForInvalidYaml(string $file, int $code = 0, \Throwa
);
}

public static function createForInvalidJson(string $file, int $code = 0, \Throwable $previous = null): UnparsableFileException
{
return new UnparsableFileException(
sprintf(
'The file "%s" does not contain valid JSON.',
$file
),
$code,
$previous
);
}

private function __construct()
{
}
Expand Down
15 changes: 15 additions & 0 deletions tests/Loader/LoaderIntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,21 @@ public function testLoadFiles()
);
}

public function testLoadJsonFile()
{
$objects = $this->loader->loadFiles([
self::FIXTURES_FILES_DIR.'/dummy.json',
])->getObjects();

$this->assertEquals(
[
'dummy1' => new stdClass(),
'dummy2' => new stdClass(),
],
$objects
);
}

public function testLoadRecursiveFiles()
{
$objects = $this->loader->loadFiles([
Expand Down
154 changes: 154 additions & 0 deletions tests/Parser/Chainable/JsonParserTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
<?php

/*
* This file is part of the Alice package.
*
* (c) Nelmio <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Nelmio\Alice\Parser\Chainable;

use Nelmio\Alice\Parser\ChainableParserInterface;
use Nelmio\Alice\Parser\FileListProviderTrait;
use PHPUnit\Framework\TestCase;
use ReflectionClass;

/**
* @covers \Nelmio\Alice\Parser\Chainable\PhpParser
*/
class JsonParserTest extends TestCase
{
use FileListProviderTrait;

private static $dir;

/**
* @var JsonParser
*/
private $parser;

/**
* @inheritdoc
*/
public static function setUpBeforeClass()
{
parent::setUpBeforeClass();

self::$dir = __DIR__.'/../../../fixtures/Parser/files/json';
}

/**
* @inheritdoc
*/
public static function tearDownAfterClass()
{
self::$dir = null;

parent::tearDownAfterClass();
}

/**
* @inheritdoc
*/
public function setUp()
{
$this->parser = new JsonParser();
}

public function testIsAChainableParser()
{
$this->assertTrue(is_a(JsonParser::class, ChainableParserInterface::class, true));
}

public function testIsNotClonable()
{
$this->assertFalse((new ReflectionClass(JsonParser::class))->isCloneable());
}

/**
* @dataProvider provideJsonList
*/
public function testCanParseJsonFiles(string $file, array $expectedParsers)
{
$actual = $this->parser->canParse($file);
$expected = (in_array(get_class($this->parser), $expectedParsers));

$this->assertEquals($expected, $actual);
}

/**
* @dataProvider providePhpList
*/
public function testCanNotParsePhpFiles(string $file)
{
$actual = $this->parser->canParse($file);

$this->assertFalse($actual);
}

/**
* @dataProvider provideYamlList
*/
public function testCannotParseYamlFiles(string $file)
{
$actual = $this->parser->canParse($file);

$this->assertFalse($actual);
}

/**
* @dataProvider provideUnsupportedList
*/
public function testCannotParseUnsupportedFiles(string $file)
{
$actual = $this->parser->canParse($file);

$this->assertFalse($actual);
}

/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The file "/nowhere.json" could not be found.
*/
public function testThrowsAnExceptionIfFileDoesNotExist()
{
$this->parser->parse('/nowhere.json');
}

public function testReturnsParsedFileContent()
{
$actual = $this->parser->parse(self::$dir.'/basic.json');

$this->assertSame(
[
'Nelmio\Alice\support\models\User' => [
'user0' => [
'fullname' => 'John Doe',
],
],
],
$actual
);
}

public function testParsingEmptyFileResultsInEmptySet()
{
$actual = $this->parser->parse(self::$dir.'/empty.json');

$this->assertSame([], $actual);
}

/**
* @expectedException \Nelmio\Alice\Throwable\Exception\Parser\UnparsableFileException
* @expectedExceptionMessageRegExp /^The file ".+\/invalid\.json" does not contain valid JSON\.$/
*/
public function testThrowsAnExceptionIfInvalidJson()
{
$this->parser->parse(self::$dir.'/invalid.json');
}
}
10 changes: 10 additions & 0 deletions tests/Parser/Chainable/PhpParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,16 @@ public function testCannotParseYamlFiles(string $file)
$this->assertFalse($actual);
}

/**
* @dataProvider provideJsonList
*/
public function testCannotParseJsonFiles(string $file)
{
$actual = $this->parser->canParse($file);

$this->assertFalse($actual);
}

/**
* @dataProvider provideUnsupportedList
*/
Expand Down
10 changes: 10 additions & 0 deletions tests/Parser/Chainable/YamlParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,16 @@ public function testCanParseYamlFiles(string $file, array $expectedParsers)
$this->assertEquals($expected, $actual);
}

/**
* @dataProvider provideJsonList
*/
public function testCannotParseJsonFiles(string $file)
{
$actual = $this->parser->canParse($file);

$this->assertFalse($actual);
}

/**
* @dataProvider provideUnsupportedList
*/
Expand Down
Loading

0 comments on commit b7a0e66

Please sign in to comment.