From fe140df88cf85ff8d31262d3459df8445b668a40 Mon Sep 17 00:00:00 2001 From: Russ Michell Date: Mon, 27 Jun 2016 07:30:10 +1200 Subject: [PATCH] NEW: Fixes #5 - Added integration tests. - Removed redundant JSON fixtures. - Updated docs accordingly. --- CONTRIBUTING.md | 8 +- README.md | 27 ++----- _config.php | 2 +- code/backends/PostgresJSONBackend.php | 2 +- code/models/fieldtypes/JSONText.php | 49 ++++++------ docs/en/configuration.md | 5 +- docs/en/usage.md | 16 ++-- tests/JSONTextBasicTest.php | 55 +++++++------ tests/JSONTextIntegrationTest.php | 96 +++++++++++++++++++++++ tests/JSONTextQueryTest.php | 92 +++++++--------------- tests/fixtures/json/empty.json | 0 tests/fixtures/json/hash_deep.json | 29 ------- tests/fixtures/json/hash_mixed.json | 26 ------ tests/fixtures/json/hash_simple.json | 13 --- tests/fixtures/json/invalid.json | 13 --- tests/fixtures/yml/MyAwesomeJSONModel.yml | 7 ++ 16 files changed, 212 insertions(+), 228 deletions(-) create mode 100755 tests/JSONTextIntegrationTest.php delete mode 100755 tests/fixtures/json/empty.json delete mode 100755 tests/fixtures/json/hash_deep.json delete mode 100755 tests/fixtures/json/hash_mixed.json delete mode 100755 tests/fixtures/json/hash_simple.json delete mode 100755 tests/fixtures/json/invalid.json create mode 100644 tests/fixtures/yml/MyAwesomeJSONModel.yml diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f536c0d..1867d36 100755 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,9 @@ # Contributing -Contributions in the form of suggestions, PR's and beer are *always* welcome. +This module is written to PSR-2, follows Semver and uses namespacing. + +Contributions in the form of suggestions and PR's with regard to the above are *always welcome* +as is beer is most formats, apart from that stuff called "craft beer" which is so hoppy, I could be drinking +mushed Daffodils and not know the difference. + + diff --git a/README.md b/README.md index 582bbb5..a383153 100755 --- a/README.md +++ b/README.md @@ -14,14 +14,13 @@ JSON storage, querying and modification. ## Features -* Write JSON to a standard `DBField` subclass. -* Query JSON via simple accessors, Postgres-like operators or JSONPath expressions. -* Selectively return data as JSON, Arrays or cast to SilverStripe `Varchar`, `Int`, `Float` or `Boolean` objects. -* Selectively update specific portions of your source JSON, using JSONPath expressions. +* Query custom JSON data via simple accessors, Postgres-like operators or [JSONPath](http://goessner.net/articles/JsonPath/) expressions. +* Selectively return queries as JSON, Array or cast to SilverStripe `Varchar`, `Int`, `Float` or `Boolean` objects. +* Selectively update portions of your source JSON, using [JSONPath](http://goessner.net/articles/JsonPath/) expressions. ## Introduction -The module exposes a fully featured JSON query and update API, that allows developers to use XPath-like queries via [JSONPath](http://goessner.net/articles/JsonPath/) +The module exposes a fully featured JSON query and update API allowing developers to use XPath-like queries via [JSONPath](http://goessner.net/articles/JsonPath/) or [Postgres' JSON operators](https://www.postgresql.org/docs/9.5/static/functions-json.html) (with some differences, see below) to query and update JSON data. In Postgres both the `->` and `->>` operators act as string and integer key matchers on a JSON array or object respectively. The module @@ -29,7 +28,7 @@ however treats both source types the same - they are after all *both JSON* so `- *regardless* of the "type" of source JSON stored. The `#>` **Path Matcher** operator can act as an object or a text matcher, but the module wishes to simplify things and as such the `#>` operator is *just a simple path matcher*. -Regardless of the type of query in-use you can set what form you'd like the data returned in via the `setReturnType()` method, on a query by query basis. +Regardless of the type of query in-use you can set what type you'd like the data returned in via the `setReturnType()` method, on a query by query basis. Legitimate types are: @@ -44,7 +43,7 @@ If using `SilverStripe`, the module will automatically cast the result(s) to one * `Float` * `Varchar` -If there are multiple results, the output will be an indexed array containing a single-value array for each result found. +If there are multiple results from a query, the output will be an indexed array containing a single-value array for each result found. The module also allows developers to selectively *update* all, or just parts of the source JSON, via JSONPath expressions. @@ -67,14 +66,6 @@ See: [Configuration Docs](docs/en/configuration.md). See: [Usage Docs](docs/en/usage.md). -## Stability - -This is currently *alpha software*. At time of writing (June 2016) there is -support for the `->` (Int matcher), `->>` (String matcher) and `#>` (Path matcher) operators and although well-tested, -they are far from complete. - -This leads me to.. - ## Contributing If you've been using Postgres or MySQL with its JSON functions for some time, @@ -89,11 +80,7 @@ Please include all details, no matter how small. If it were *your module*, what ## Credits * [Axel Anceau](https://github.com/Peekmo/) for his packaging-up of the pretty amazing JSONPath implementation by [Stefan Goessner](https://code.google.com/archive/p/jsonpath/) -* [Stefan Goessner](https://code.google.com/archive/p/jsonpath/) for the original work on JSONPath dating back to 2005! - -## TODO - -* Lose the fugly way that data is queried via `$this->dbObject()` +* [Stefan Goessner](https://code.google.com/archive/p/jsonpath/) for the original work on JSONPath dating back to 2005! ## Author diff --git a/_config.php b/_config.php index 163f6e1..5a461be 100755 --- a/_config.php +++ b/_config.php @@ -4,5 +4,5 @@ * @package jsontext */ -define('MODULE_NAME', 'JSON Text'); +define('MODULE_NAME', 'JSONText'); define('MODULE_DIR', __DIR__); diff --git a/code/backends/PostgresJSONBackend.php b/code/backends/PostgresJSONBackend.php index 7fe95e2..0ddce65 100755 --- a/code/backends/PostgresJSONBackend.php +++ b/code/backends/PostgresJSONBackend.php @@ -14,7 +14,6 @@ namespace JSONText\Backends; use JSONText\Exceptions\JSONTextException; -use JSONText\Fields\JSONText; class PostgresJSONBackend extends JSONBackend { @@ -70,6 +69,7 @@ public function matchOnPath() throw new JSONTextException($msg); } + //$this->jsonText->getJSONStore() $operandAsArray = $this->jsonText->toArray($this->operand); // Empty is OK..could've been accidental... diff --git a/code/models/fieldtypes/JSONText.php b/code/models/fieldtypes/JSONText.php index cab4947..0bdf398 100755 --- a/code/models/fieldtypes/JSONText.php +++ b/code/models/fieldtypes/JSONText.php @@ -14,7 +14,7 @@ * * * static $db = [ - * 'MyJSONStructure' => 'JSONText' + * 'MyJSONStructure' => '\JSONText\Fields\JSONText' * ]; * * @@ -23,7 +23,6 @@ * @package silverstripe-jsontext * @subpackage fields * @author Russell Michell - * @todo Rename query() to getValue() that accepts optional param $expr (for JSONPath queries) */ namespace JSONText\Fields; @@ -107,8 +106,8 @@ public function requireField() 'type' => 'text', 'parts' => $parts ]; - - DB::require_field($this->tableName, $this->name, $values); + + \DB::require_field($this->tableName, $this->name, $values); } /** @@ -148,14 +147,6 @@ public function setReturnType($type) return $this; } - /** - * @return string - */ - public function getReturnType() - { - return $this->returnType; - } - /** * Returns the value of this field as an iterable. * @@ -164,16 +155,16 @@ public function getReturnType() */ public function getJSONStore() { - if (!$json = $this->getValue()) { - return new \Peekmo\JsonPath\JsonStore('[]'); + if (!$value = $this->getValue()) { + return new JsonStore('[]'); } - if (!$this->isJson($json)) { + if (!$this->isJson($value)) { $msg = 'DB data is munged.'; throw new JSONTextException($msg); } - - $this->jsonStore = new \Peekmo\JsonPath\JsonStore($json); + + $this->jsonStore = new JsonStore($value); return $this->jsonStore; } @@ -366,7 +357,7 @@ public function query($operator, $operand = null) } $validType = ($isEx ? self::JSONTEXT_QUERY_JSONPATH : self::JSONTEXT_QUERY_OPERATOR); - if ($marshalled = $this->marshallQuery(func_get_args(), $validType)) { + if ($marshalled = $this->marshallQuery(func_get_args(), $validType, $this->getJSONStore())) { return $this->returnAsType($marshalled); } @@ -423,9 +414,6 @@ private function marshallQuery($args, $type = 1) */ public function setValue($value, $record = null, $expr = '') { - // Deal with standard SS behaviour - parent::setValue($value, $record); - if (empty($expr)) { $this->value = $value; } else { @@ -434,13 +422,16 @@ public function setValue($value, $record = null, $expr = '') throw new JSONTextException($msg); } - if (!$this->jsonStore->set($expr, $value)) { + if (!$this->getJSONStore()->set($expr, $value)) { $msg = 'Failed to properly set custom data to the JSONStore in ' . __FUNCTION__; throw new JSONTextException($msg); } $this->value = $this->jsonStore->toString(); } + + // Deal with standard SS behaviour + parent::setValue($this->value, $record); return $this; } @@ -455,7 +446,7 @@ public function setValue($value, $record = null, $expr = '') private function returnAsType($data) { $data = (array) $data; - $type = $this->getReturnType(); + $type = $this->returnType; if ($type === 'array') { if (!count($data)) { return []; @@ -485,18 +476,24 @@ private function returnAsType($data) } /** - * Create an instance of {@link JSONBackend} according to the value of JSONText::backend defined by SS config. + * Create an instance of {@link JSONBackend} according to the value of JSONText::backend defined in SS config. * * @param string operand * @return JSONBackend + * @throws JSONTextException */ protected function createBackendInst($operand) { $backend = $this->config()->backend; - $dbBackendClass = ucfirst($backend) . 'JSONBackend'; + $dbBackendClass = '\JSONText\Backends\\' . ucfirst($backend) . 'JSONBackend'; + + if (!class_exists($dbBackendClass)) { + $msg = 'JSONText backend class ' . $dbBackendClass . ' not found.'; + throw new JSONTextException($msg); + } return \Injector::inst()->createWithArgs( - '\JSONText\Backends\\' . $dbBackendClass, [ + $dbBackendClass, [ $operand, $this ]); diff --git a/docs/en/configuration.md b/docs/en/configuration.md index 1e1a8e3..d8d134a 100755 --- a/docs/en/configuration.md +++ b/docs/en/configuration.md @@ -7,4 +7,7 @@ do this via standard SS config in your project's `mysite/_config/config.yml` fil backend: postgres -Note: The module default is to use `postgres` which is also the only backend that will work at the moment. +Notes: + +* The module uses namespacing so take this into account when calling any part of the module's public API. +* The module default is to use `postgres` which is also the only backend that will work at the moment. diff --git a/docs/en/usage.md b/docs/en/usage.md index 6f10749..9fbd715 100755 --- a/docs/en/usage.md +++ b/docs/en/usage.md @@ -48,7 +48,7 @@ A small handful of simple query methods `first()`, `last()` and `nth()` exist fo { private static $db = [ - 'MyJSON' => 'JSONText' + 'MyJSON' => '\JSONText\Fields\JSONText' ]; /* @@ -86,7 +86,7 @@ You can also use Postgres-like JSON querying syntax, for querying more complex J class MyOtherDataObject extends DataObject { private static $db = [ - 'MyJSON' => 'JSONText' + 'MyJSON' => '\JSONText\Fields\JSONText' ]; /** @@ -144,7 +144,7 @@ See: [Table of JSONPath expressions](jsonpath.md) }'; private static $db = [ - 'MyJSON' => 'JSONText' + 'MyJSON' => '\JSONText\Fields\JSONText' ]; public function requireDefaultRecords() @@ -152,7 +152,7 @@ See: [Table of JSONPath expressions](jsonpath.md) parent::requireDefaultRecords(); if (!$this->MyJSON) { - $this->setValue($this->stubJSON); + $this->setField($this->MyJSON, $this->stubJSON); } } @@ -193,8 +193,8 @@ See: [Table of JSONPath expressions](jsonpath.md) ## Updating and Modifying JSON -No self-respecting JSON query solution is complete without the ability to selectively modify -nested JSON data and sub-nodes. The module overloads `setValue()` to accept an optional 3rd parameter, a valid JSONPath +No self-respecting JSON query solution would be complete without the ability to selectively modify +nested JSON data. The module overloads `setValue()` to accept an optional 3rd parameter, a valid JSONPath expression. If the expression matches >1 JSON nodes, then that result is expressed as an indexed array, and each matching @@ -218,7 +218,7 @@ node will be modified with the data passed to `setValue()` as the standard `$val }'; private static $db = [ - 'MyJSON' => 'JSONText' + 'MyJSON' => '\JSONText\Fields\JSONText' ]; public function requireDefaultRecords() @@ -226,7 +226,7 @@ node will be modified with the data passed to `setValue()` as the standard `$val parent::requireDefaultRecords(); if (!$this->MyJSON) { - $this->setValue($this->stubJSON); + $this->setField($this->MyJSON, $this->stubJSON); } } diff --git a/tests/JSONTextBasicTest.php b/tests/JSONTextBasicTest.php index c7948da..bdd69a9 100755 --- a/tests/JSONTextBasicTest.php +++ b/tests/JSONTextBasicTest.php @@ -17,14 +17,18 @@ class JSONTextBasicTest extends SapphireTest */ protected $fixtures = [ 'array' => 'tests/fixtures/json/array.json', - 'object' => 'tests/fixtures/json/object.json', - 'invalid' => 'tests/fixtures/json/invalid.json' + 'object' => 'tests/fixtures/json/object.json' ]; + /** + * @var \JSONText\Fields\JSONText + */ + protected $sut; + /** * JSONTextTest constructor. * - * Modify fixtures property to be able to run on PHP <5.6 without use of constant in class property which 5.6+ allows + * Modifies fixtures property to be able to run on PHP <5.6 without use of constant in class property which 5.6+ allows */ public function __construct() { @@ -33,23 +37,34 @@ public function __construct() } } - public function testgetValueAsIterable() + /** + * Setup the System Under Test for this test suite. + */ + public function setUp() { - $field = JSONText\Fields\JSONText::create('MyJSON'); - $field->setValue($this->getFixture('invalid')); - $this->setExpectedException('\JSONText\Exceptions\JSONTextException'); - $this->assertEquals(['chinese' => 'great wall'], $field->getJSONStore()); + parent::setUp(); + + $this->sut = JSONText\Fields\JSONText::create('MyJSON'); + } - $field = JSONText\Fields\JSONText::create('MyJSON'); + public function testGetValueAsJSONStore() + { + $field = $this->sut; + $field->setValue(''); - $this->assertEquals([], $field->getJSONStore()); + $this->assertEquals([], $field->getStoreAsArray()); + + $field->setValue('{'); + $this->setExpectedException('\JSONText\Exceptions\JSONTextException'); + $field->getJSONStore(); } public function testFirst() { + $field = $this->sut; + // Test: Source data is simple JSON array // Return type: Array - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('array'); $field->setValue($this->getFixture('array')); $this->assertInternalType('array', $field->first()); @@ -58,7 +73,6 @@ public function testFirst() // Test: Source data is simple JSON array // Return type: JSON - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('json'); $field->setValue($this->getFixture('array')); $this->assertInternalType('string', $field->first()); @@ -66,7 +80,6 @@ public function testFirst() // Test: Source data is simple JSON array // Return type: SilverStripe - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('silverstripe'); $field->setValue($this->getFixture('array')); $this->assertInternalType('array', $field->first()); @@ -74,14 +87,12 @@ public function testFirst() $this->assertEquals('great wall', $field->first()[0]->getValue()); // Test: Empty - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('array'); $field->setValue(''); $this->assertInternalType('array', $field->first()); $this->assertCount(0, $field->first()); // Test: Invalid - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('array'); $field->setValue('{'); $this->setExpectedException('\JSONText\Exceptions\JSONTextException'); @@ -90,9 +101,10 @@ public function testFirst() public function testLast() { + $field = $this->sut; + // Test: Source data is simple JSON array // Return type: Array - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('array'); $field->setValue($this->getFixture('array')); $this->assertInternalType('array', $field->last()); @@ -101,7 +113,6 @@ public function testLast() // Test: Source data is simple JSON array // Return type: JSON - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('json'); $field->setValue($this->getFixture('array')); $this->assertInternalType('string', $field->last()); @@ -109,7 +120,6 @@ public function testLast() // Test: Source data is simple JSON array // Return type: SilverStripe - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('silverstripe'); $field->setValue($this->getFixture('array')); $this->assertInternalType('array', $field->last()); @@ -117,14 +127,12 @@ public function testLast() $this->assertEquals(33.3333, $field->last()[6]->getValue()); // Test: Empty - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('array'); $field->setValue(''); $this->assertInternalType('array', $field->last()); $this->assertCount(0, $field->last()); // Test: Invalid - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('array'); $field->setValue('{'); $this->setExpectedException('\JSONText\Exceptions\JSONTextException'); @@ -133,9 +141,10 @@ public function testLast() public function testNth() { + $field = $this->sut; + // Test: Source data is simple JSON array // Return type: Array - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('array'); $field->setValue($this->getFixture('array')); $this->assertInternalType('array', $field->nth(1)); @@ -144,7 +153,6 @@ public function testNth() // Test: Source data is simple JSON array // Return type: JSON - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('json'); $field->setValue($this->getFixture('array')); $this->assertInternalType('string', $field->nth(1)); @@ -152,7 +160,6 @@ public function testNth() // Test: Source data is simple JSON array // Return type: SilverStripe - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('silverstripe'); $field->setValue($this->getFixture('array')); $this->assertInternalType('array', $field->nth(1)); @@ -160,14 +167,12 @@ public function testNth() $this->assertEquals(true, $field->nth(1)[1]->getValue()); // Test: Empty - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('array'); $field->setValue(''); $this->assertInternalType('array', $field->nth(1)); $this->assertCount(0, $field->nth(1)); // Test: Invalid - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('array'); $field->setValue('{'); $this->setExpectedException('\JSONText\Exceptions\JSONTextException'); diff --git a/tests/JSONTextIntegrationTest.php b/tests/JSONTextIntegrationTest.php new file mode 100755 index 0000000..3ce049a --- /dev/null +++ b/tests/JSONTextIntegrationTest.php @@ -0,0 +1,96 @@ + + */ + +use JSONText\Fields; +use JSONText\Exceptions; + +class JSONTextIntegrationTest extends SapphireTest +{ + + /** + * @var string + */ + protected static $fixture_file = '/tests/fixtures/yml/MyAwesomeJSONModel.yml'; + + /** + * Modifies fixtures property to be able to run on PHP <5.6 without use of constant in class property which 5.6+ allows + */ + public function __construct() + { + self::$fixture_file = MODULE_DIR . '/tests/fixtures/yml/MyAwesomeJSONModel.yml'; + } + + /** + * Tests JSONText::setValue() by means of a simple JSONPath expression operating on a nested JSON array + * on a saved DataObject record. + */ + public function testSetValueOnNestedArray() + { + $model = $this->objFromFixture('MyAwesomeJSONModel', 'json-as-object'); + $expression = '$.cars.american.[0]'; + $field = $model->dbObject('MyJSON'); + + // What's the value at $expression now? (JSON as return type is the default) + $this->assertEquals('["buick"]', $field->query($expression)); + + // How about now? + $field->setValue('ford', null, $expression); + $model->setField('MyJSON', $field->getValue()); + $model->write(); + $this->assertEquals('["ford"]', $field->query($expression)); + + // And now? (With chaining) + $field + ->setValue('chrysler', null, $expression) + ->setReturnType('array'); + + $model->setField('MyJSON', $field->getValue()); + $model->write(); + $this->assertEquals(['chrysler'], $field->query($expression)); + } + + /** + * Tests JSONText::setValue() by means of a simple JSONPath expression operating on a simple, un-nested JSON array + * on a saved DataObject record. + */ + public function testSetValueOnUnNestedArray() + { + $model = $this->objFromFixture('MyAwesomeJSONModel', 'json-as-array'); + $expression = '$.[0]'; + $field = $model->dbObject('MyJSON'); + + // What's the value at $expression now? (JSON as return type is the default) + $this->assertEquals('["buick"]', $field->query($expression)); + + // How about now? + $field->setValue('ford', null, $expression); + $model->setField('MyJSON', $field->getValue()); + $model->write(); + $this->assertEquals('["ford"]', $field->query($expression)); + + // And now? (With chaining) + $field + ->setValue('chrysler', null, $expression) + ->setReturnType('array'); + + $model->setField('MyJSON', $field->getValue()); + $model->write(); + $this->assertEquals(['chrysler'], $field->query($expression)); + } + +} + +/** + * @package silverstripe-jsontext + */ +class MyAwesomeJSONModel extends DataObject +{ + private static $db = [ + 'MyJSON' => '\JSONText\Fields\JSONText' + ]; +} \ No newline at end of file diff --git a/tests/JSONTextQueryTest.php b/tests/JSONTextQueryTest.php index 40deb44..d0c2ccf 100755 --- a/tests/JSONTextQueryTest.php +++ b/tests/JSONTextQueryTest.php @@ -5,31 +5,10 @@ * @subpackage fields * @author Russell Michell * @todo Add tests where source data is a JSON array, not just a JSON object - * @todo $this->clearFixtures(); in setUp() - * @todo Use same source data instead of repeating for each test - * @todo See the PHPUnit @dataProvider annotaton ala * * */ -/** - * @dataProvider additionProvider - */ -/*public function testAdd($a, $b, $expected) -{ - $this->assertEquals($expected, $a + $b); -} - -public function additionProvider() -{ - return [ - [0, 0, 0], - [0, 1, 1], - [1, 0, 1], - [1, 1, 3] - ]; -}*/ - use JSONText\Fields; use JSONText\Exceptions; @@ -44,6 +23,11 @@ class JSONTextQueryTest extends SapphireTest 'invalid' => 'tests/fixtures/json/invalid.json' ]; + /** + * @var \JSONText\Fields\JSONText + */ + protected $sut; + /** * JSONTextTest constructor. * @@ -56,6 +40,16 @@ public function __construct() } } + /** + * Setup the System Under Test for this test suite. + */ + public function setUp() + { + parent::setUp(); + + $this->sut = JSONText\Fields\JSONText::create('MyJSON'); + } + /** * Tests query() by means of the integer Postgres Int match operator: '->' * @@ -63,10 +57,11 @@ public function __construct() */ public function testQueryWithMatchOnInt() { + $field = $this->sut; + // Data Source: Array // Return Type: ARRAY // Operator: "->" (Int) - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('array'); $field->setValue($this->getFixture('array')); $this->assertEquals([2 => 'trabant'], $field->query('->', 2)); @@ -74,7 +69,6 @@ public function testQueryWithMatchOnInt() // Data Source: Array // Return Type: JSON // Operator: "->" (Int) - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('json'); $field->setValue($this->getFixture('array')); $this->assertEquals('{"2":"trabant"}', $field->query('->', 2)); @@ -84,7 +78,6 @@ public function testQueryWithMatchOnInt() // Return Type: SILVERSTRIPE // Operator: "->" (Int) // SS Type: Float - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('silverstripe'); $field->setValue($this->getFixture('array')); $this->assertInternalType('array', $field->query('->', 3)); @@ -95,7 +88,6 @@ public function testQueryWithMatchOnInt() // Return Type: SILVERSTRIPE // Operator: "->" (Int) // SS Type: Boolean - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('silverstripe'); $field->setValue($this->getFixture('array')); $this->assertInternalType('array', $field->query('->', 1)); @@ -106,7 +98,6 @@ public function testQueryWithMatchOnInt() // Return Type: SILVERSTRIPE // Operator: "->" (Int) // SS Type: Int - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('silverstripe'); $field->setValue($this->getFixture('array')); $this->assertInternalType('array', $field->query('->', 5)); @@ -117,7 +108,6 @@ public function testQueryWithMatchOnInt() // Return Type: SILVERSTRIPE // Operator: "->" (Int) // SS Type: Varchar - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('silverstripe'); $field->setValue($this->getFixture('array')); $this->assertInternalType('array', $field->query('->', 4)); @@ -125,26 +115,22 @@ public function testQueryWithMatchOnInt() $this->assertEquals('buick', $field->query('->', 4)[4]->getValue()); // Test: Empty #1 - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('array'); $field->setValue(''); $this->assertInternalType('array', $field->query('->', 3)); $this->assertCount(0, $field->query('->', 3)); - // Test: Empty #2 - $field = JSONText\Fields\JSONText::create('MyJSON'); + // Test: Invalid #1 $field->setReturnType('array'); $field->setValue('["morris"]'); $this->assertEquals([], $field->query('->', 17)); - // Test: Invalid #1 - $field = JSONText\Fields\JSONText::create('MyJSON'); + // Test: Invalid #2 $field->setReturnType('array'); - $field->setValue('["trabant"]'); - $this->assertEquals([], $field->query('->', 1)); + $field->setValue('["ass"]'); + $this->assertEquals(['ass'], $field->query('->', 0)); - // Test: Invalid #2 - $field = JSONText\Fields\JSONText::create('MyJSON'); + // Test: Invalid #3 $field->setReturnType('array'); $field->setValue('{'); $this->setExpectedException('\JSONText\Exceptions\JSONTextException'); @@ -156,10 +142,11 @@ public function testQueryWithMatchOnInt() */ public function testQueryWithMatchOnStr() { + $field = $this->sut; + // Data Source: Object // Return Type: ARRAY // Operator: "->>" (String) - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('array'); $field->setValue($this->getFixture('object')); $this->assertEquals(['Subaru' => 'Impreza'], $field->query('->>', 'Subaru')); @@ -171,7 +158,6 @@ public function testQueryWithMatchOnStr() // Data Source: Object // Return Type: JSON // Operator: "->>" (String) - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('json'); $field->setValue($this->getFixture('object')); $this->assertEquals('{"Subaru":"Impreza"}', $field->query('->>', 'Subaru')); @@ -184,7 +170,6 @@ public function testQueryWithMatchOnStr() // Return Type: SilverStripe // Operator: "->>" (String) // SS Type: Varchar - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('silverstripe'); $field->setValue($this->getFixture('object')); $this->assertInternalType('array', $field->query('->>', 'Subaru')); @@ -195,7 +180,6 @@ public function testQueryWithMatchOnStr() // Return Type: SilverStripe // Operator: "->>" (String) // SS Type: Boolean - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('silverstripe'); $field->setValue($this->getFixture('object')); $this->assertInternalType('array', $field->query('->>', 'beer tastes good')); @@ -206,7 +190,6 @@ public function testQueryWithMatchOnStr() // Return Type: SilverStripe // Operator: "->>" (String) // SS Type: Float - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('silverstripe'); $field->setValue($this->getFixture('object')); $this->assertInternalType('array', $field->query('->>', 'how sure are you')); @@ -217,7 +200,6 @@ public function testQueryWithMatchOnStr() // Return Type: SilverStripe // Operator: "->>" (String) // SS Type: Int - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('silverstripe'); $field->setValue($this->getFixture('object')); $this->assertInternalType('array', $field->query('->>', 'how high')); @@ -228,7 +210,6 @@ public function testQueryWithMatchOnStr() // Return Type: SilverStripe // Operator: "->>" (String) // SS Type: N/A Nested sub-array example, expect an array - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('silverstripe'); $field->setValue($this->getFixture('object')); $this->assertInternalType('array', $field->query('->>', 'planes')['planes']); @@ -238,26 +219,22 @@ public function testQueryWithMatchOnStr() $this->assertInstanceOf('Varchar', $field->query('->>', 'planes')['planes']['russian'][1]); // Test: Empty #1 - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('array'); $field->setValue(''); $this->assertInternalType('array', $field->query('->>', 'planes')); $this->assertCount(0, $field->query('->', 3)); // Test: Empty #2 - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('array'); $field->setValue('["morris"]'); $this->assertEquals([], $field->query('->', 17)); // Test: Invalid #1 - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('array'); $field->setValue('["trabant"]'); $this->assertEquals([], $field->query('->', 1)); // Test: Invalid #2 - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('array'); $field->setValue('{'); $this->setExpectedException('\JSONText\Exceptions\JSONTextException'); @@ -269,11 +246,12 @@ public function testQueryWithMatchOnStr() */ public function testQueryWithMatchOnPath() { + $field = $this->sut; + // Data Source: Object // Return Type: ARRAY // Operator: "#>" (Path) // Expect: Array due to duplicate keys in different parts of the source data - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('array'); $field->setValue($this->getFixture('object')); $this->assertEquals( @@ -285,7 +263,6 @@ public function testQueryWithMatchOnPath() // Return Type: JSON // Operator: "#>" (Path) // Expect: Array due to duplicate keys in different parts of the source data - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('json'); $field->setValue($this->getFixture('object')); $this->assertEquals( @@ -297,7 +274,6 @@ public function testQueryWithMatchOnPath() // Return Type: SILVERSTRIPE // Operator: "#>" (Path) // Expect: Array due to duplicate keys in different parts of the source data - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('silverstripe'); $field->setValue($this->getFixture('object')); $this->assertInternalType('array', $field->query('#>', '{"japanese":"fast"}')); @@ -317,7 +293,6 @@ public function testQueryWithMatchOnPath() // Return Type: ARRAY // Operator: "#>" (Path) // Expect: Direct scalar comparison assertion - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('array'); $field->setValue($this->getFixture('object')); $this->assertEquals(['airbus'], $field->query('#>', '{"planes":"french"}')); @@ -326,7 +301,6 @@ public function testQueryWithMatchOnPath() // Return Type: JSON // Operator: "#>" (Path) // Expect: Direct scalar comparison assertion - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('json'); $field->setValue($this->getFixture('object')); $this->assertEquals('["airbus"]', $field->query('#>', '{"planes":"french"}')); @@ -335,7 +309,6 @@ public function testQueryWithMatchOnPath() // Return Type: SILVERSTRIPE // Operator: "#>" (Path) // Expect: Direct scalar comparison assertion (Varchar) - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('silverstripe'); $field->setValue($this->getFixture('object')); $this->assertInternalType('array', $field->query('#>', '{"planes":"french"}')); @@ -346,7 +319,6 @@ public function testQueryWithMatchOnPath() // Return Type: SILVERSTRIPE // Operator: "#>" (Path) // Expect: Direct scalar comparison assertion (Float) - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('silverstripe'); $field->setValue($this->getFixture('object')); @@ -361,7 +333,6 @@ public function testQueryWithMatchOnPath() // Return Type: SILVERSTRIPE // Operator: "#>" (Path) // Expect: Direct scalar comparison assertion (Int) - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('silverstripe'); $field->setValue($this->getFixture('object')); @@ -376,7 +347,6 @@ public function testQueryWithMatchOnPath() // Return Type: SILVERSTRIPE // Operator: "#>" (Path) // Expect: Direct scalar comparison assertion (Boolean) - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('silverstripe'); $field->setValue($this->getFixture('object')); @@ -388,20 +358,17 @@ public function testQueryWithMatchOnPath() $this->assertEquals(1, array_values($res[0])[0]->getValue()); // #1 Empty source data - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('array'); $field->setValue(''); $this->assertEquals([], $field->query('#>', '{"japanese":"fast"}')); // #2 JSON path not found - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('silverstripe'); $field->setValue($this->getFixture('object')); $this->assertNull($field->query('#>', '{"ints":"1"}')); // The "ints" key only has a single array as a value // #3 Invalid operand on RHS $this->setExpectedException('\JSONText\Exceptions\JSONTextException'); - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('array'); $field->setValue($this->getFixture('object')); $this->assertEquals(['Kawasaki' => 'KR1S250'], $field->query('#>', '{"japanese":"fast"')); @@ -414,11 +381,12 @@ public function testQueryWithMatchOnPath() */ public function testQueryWithMatchOnExpr() { + $field = $this->sut; + // Data Source: Object // Return Type: ARRAY // Expression: "$.." (Everything) // Expect: Array, obviously due to no. nodes in the source JSON - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('array'); $field->setValue($this->getFixture('object')); $this->assertInternalType('array', $field->query('$..')); @@ -428,7 +396,6 @@ public function testQueryWithMatchOnExpr() // Return Type: ARRAY // Expression: "$..japanese[*]" (An array of children of all keys matching "japanese") // Expect: Array - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('array'); $field->setValue($this->getFixture('object')); $this->assertCount(4, $field->query('$..japanese[*]')); @@ -443,7 +410,6 @@ public function testQueryWithMatchOnExpr() // Return Type: JSON // Expression: "$..japanese[*]" (An array of children of all keys matching "japanese") // Expect: JSON Array of JSON objects - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('json'); $field->setValue($this->getFixture('object')); $this->assertEquals( @@ -455,7 +421,6 @@ public function testQueryWithMatchOnExpr() // Return Type: Array // Expression: "$.cars.american[*]" (All entries in the american cars node) // Expect: Array - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('array'); $field->setValue($this->getFixture('object')); $this->assertEquals(['buick', 'oldsmobile'], $field->query('$.cars.american[*]')); @@ -465,7 +430,6 @@ public function testQueryWithMatchOnExpr() // Return Type: Array // Expression: "$.cars.american[*]" (All entries in the american cars node) // Expect: Array 0f SilverStripe types - $field = JSONText\Fields\JSONText::create('MyJSON'); $field->setReturnType('silverstripe'); $field->setValue($this->getFixture('object')); $this->assertInternalType('array', $field->query('$.cars.american[*]')); diff --git a/tests/fixtures/json/empty.json b/tests/fixtures/json/empty.json deleted file mode 100755 index e69de29..0000000 diff --git a/tests/fixtures/json/hash_deep.json b/tests/fixtures/json/hash_deep.json deleted file mode 100755 index f5e83c0..0000000 --- a/tests/fixtures/json/hash_deep.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "cars":{ - "american": - [ - "buick", - "oldsmobile" - ], - "british": - ["vauxhall","morris"] - }, - "planes":{ - "russian": - [ - "antonov", - "mig" - ], - "french":"airbus" - }, - "bikes":{ - "japanese":{ - "fast":{ - "Kawasaki":"KR1S250" - }, - "slow":{ - "Honda":"FS150" - } - } - } -} \ No newline at end of file diff --git a/tests/fixtures/json/hash_mixed.json b/tests/fixtures/json/hash_mixed.json deleted file mode 100755 index 1788164..0000000 --- a/tests/fixtures/json/hash_mixed.json +++ /dev/null @@ -1,26 +0,0 @@ - { - "books":{ - "british": - [ - { - "The Gruffalo": true, - "In The Night": false - } - ] - }, - "prime ministers": { - "australia": 2456, - "new zealand": 11, - "britain": 23 - }, - "GDP": { - "australia": 99.91, - "new zealand": 47.6, - "britain": 11.0 - }, - "Sport": { - "australia": "Aussie Rules", - "new zealand": "Rugby", - "britain": "Footy" - } - } \ No newline at end of file diff --git a/tests/fixtures/json/hash_simple.json b/tests/fixtures/json/hash_simple.json deleted file mode 100755 index 6d5d633..0000000 --- a/tests/fixtures/json/hash_simple.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "chinese": "great wall", - "american": [ - "buick", - "oldsmobile", - "ford" - ], - "british": - [ - "vauxhall", - "morris" - ] -} \ No newline at end of file diff --git a/tests/fixtures/json/invalid.json b/tests/fixtures/json/invalid.json deleted file mode 100755 index 7acd045..0000000 --- a/tests/fixtures/json/invalid.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "chinese": - "great wall", - "american": - [ - "buick", - "oldsmobile", - "ford" - ], - "british": - [ - "vauxhall", - "morris" \ No newline at end of file diff --git a/tests/fixtures/yml/MyAwesomeJSONModel.yml b/tests/fixtures/yml/MyAwesomeJSONModel.yml new file mode 100644 index 0000000..7f8409e --- /dev/null +++ b/tests/fixtures/yml/MyAwesomeJSONModel.yml @@ -0,0 +1,7 @@ +MyAwesomeJSONModel: + json-as-object: + MyJSON: '{"cars":{"american":["buick","oldsmobile"]}}' + json-as-array: + MyJSON: '["buick","oldsmobile"]' + json-as-boolean: + MyJSON: 'true' \ No newline at end of file