From fd35a200a0f10c42747a1b255a1ef4053225124e Mon Sep 17 00:00:00 2001 From: Art4 Date: Tue, 9 Jul 2024 16:31:08 +0200 Subject: [PATCH 01/23] improve test command --- composer.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 58a139b..d03e6ed 100644 --- a/composer.json +++ b/composer.json @@ -32,12 +32,17 @@ } }, "scripts": { - "codestyle": "php-cs-fixer fix --verbose --diff", + "codestyle": "php-cs-fixer fix", "coverage": "phpunit --coverage-html=\".phpunit.cache/code-coverage\"", "phpstan": "phpstan analyze --memory-limit 512M --configuration .phpstan.neon", "phpunit": "phpunit", "reuse-annotate": "pipx run reuse annotate src tests --license=\"GPL-3.0-or-later\" --copyright=\"2015-2023 Artur Weigandt https://wlabs.de/kontakt\" --recursive --exclude-year --copyright-style=\"spdx\"", - "reuse-lint": "pipx run reuse --suppress-deprecation lint" + "reuse-lint": "pipx run reuse --suppress-deprecation lint", + "test": [ + "@codestyle --verbose --diff", + "@phpstan", + "@phpunit" + ] }, "config": { "sort-packages": true From e616e2a1ee4d5fc08e7871f0b13565fa3864d7a7 Mon Sep 17 00:00:00 2001 From: Art4 Date: Tue, 9 Jul 2024 16:44:34 +0200 Subject: [PATCH 02/23] use ::class constants in tests --- tests/Functional/ErrorParsingTest.php | 43 ++++--- tests/Functional/ParsingTest.php | 163 ++++++++++++++------------ tests/Unit/V1/ErrorTest.php | 2 +- 3 files changed, 115 insertions(+), 93 deletions(-) diff --git a/tests/Functional/ErrorParsingTest.php b/tests/Functional/ErrorParsingTest.php index 08d480d..f3002f6 100644 --- a/tests/Functional/ErrorParsingTest.php +++ b/tests/Functional/ErrorParsingTest.php @@ -10,6 +10,13 @@ use Art4\JsonApiClient\Helper\Parser; use Art4\JsonApiClient\Tests\Fixtures\HelperTrait; +use Art4\JsonApiClient\V1\Document; +use Art4\JsonApiClient\V1\Error; +use Art4\JsonApiClient\V1\ErrorCollection; +use Art4\JsonApiClient\V1\ErrorLink; +use Art4\JsonApiClient\V1\ErrorSource; +use Art4\JsonApiClient\V1\Link; +use Art4\JsonApiClient\V1\Meta; use PHPUnit\Framework\TestCase; class ErrorParsingTest extends TestCase @@ -21,7 +28,7 @@ public function testParseErrors(): void $string = $this->getJsonString('09_errors.json'); $document = Parser::parseResponseString($string); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Document', $document); + $this->assertInstanceOf(Document::class, $document); $this->assertTrue($document->has('errors')); $this->assertFalse($document->has('meta')); $this->assertTrue($document->has('jsonapi')); @@ -30,18 +37,18 @@ public function testParseErrors(): void $this->assertFalse($document->has('data')); $errors = $document->get('errors'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ErrorCollection', $errors); + $this->assertInstanceOf(ErrorCollection::class, $errors); $this->assertCount(3, $errors->getKeys()); $this->assertTrue($errors->has('0')); $error0 = $errors->get('0'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Error', $error0); + $this->assertInstanceOf(Error::class, $error0); $this->assertCount(5, $error0->getKeys()); $this->assertTrue($error0->has('code')); $this->assertSame('123', $error0->get('code')); $this->assertTrue($error0->has('source')); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ErrorSource', $error0->get('source')); + $this->assertInstanceOf(ErrorSource::class, $error0->get('source')); $this->assertTrue($error0->has('source.pointer')); $this->assertSame('/data/attributes/first-name', $error0->get('source.pointer')); $this->assertTrue($error0->has('title')); @@ -49,18 +56,18 @@ public function testParseErrors(): void $this->assertTrue($error0->has('detail')); $this->assertSame('First name must contain at least three characters.', $error0->get('detail')); $this->assertTrue($error0->has('meta')); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Meta', $error0->get('meta')); + $this->assertInstanceOf(Meta::class, $error0->get('meta')); $this->assertSame('bar', $error0->get('meta.foo')); $this->assertTrue($errors->has('1')); $error1 = $errors->get('1'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Error', $error1); + $this->assertInstanceOf(Error::class, $error1); $this->assertCount(4, $error1->getKeys()); $this->assertTrue($error1->has('code')); $this->assertSame('225', $error1->get('code')); $this->assertTrue($error1->has('source')); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ErrorSource', $error1->get('source')); + $this->assertInstanceOf(ErrorSource::class, $error1->get('source')); $this->assertTrue($error1->has('source.pointer')); $this->assertSame('/data/attributes/password', $error1->get('source.pointer')); $this->assertTrue($error1->has('title')); @@ -71,12 +78,12 @@ public function testParseErrors(): void $this->assertTrue($errors->has('2')); $error2 = $errors->get('2'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Error', $error2); + $this->assertInstanceOf(Error::class, $error2); $this->assertCount(3, $error2->getKeys()); $this->assertTrue($error2->has('code')); $this->assertSame('226', $error2->get('code')); $this->assertTrue($error2->has('source')); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ErrorSource', $error2->get('source')); + $this->assertInstanceOf(ErrorSource::class, $error2->get('source')); $this->assertTrue($error2->has('source.pointer')); $this->assertSame('/data/attributes/password', $error2->get('source.pointer')); $this->assertTrue($error2->has('title')); @@ -91,7 +98,7 @@ public function testParseErrorWithLinks(): void $string = $this->getJsonString('10_error_with_links.json'); $document = Parser::parseResponseString($string); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Document', $document); + $this->assertInstanceOf(Document::class, $document); $this->assertTrue($document->has('errors')); $this->assertFalse($document->has('meta')); $this->assertTrue($document->has('jsonapi')); @@ -100,42 +107,42 @@ public function testParseErrorWithLinks(): void $this->assertFalse($document->has('data')); $errors = $document->get('errors'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ErrorCollection', $errors); + $this->assertInstanceOf(ErrorCollection::class, $errors); $this->assertCount(2, $errors->getKeys()); $this->assertTrue($errors->has('0')); $error0 = $errors->get('0'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Error', $error0); + $this->assertInstanceOf(Error::class, $error0); $this->assertCount(4, $error0->getKeys()); $this->assertTrue($error0->has('code')); $this->assertSame('123', $error0->get('code')); $this->assertTrue($error0->has('source')); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ErrorSource', $error0->get('source')); + $this->assertInstanceOf(ErrorSource::class, $error0->get('source')); $this->assertTrue($error0->has('source.pointer')); $this->assertSame('/data/attributes/first-name', $error0->get('source.pointer')); $this->assertTrue($error0->has('title')); $this->assertSame('Value is too short', $error0->get('title')); $this->assertTrue($error0->has('links')); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ErrorLink', $error0->get('links')); + $this->assertInstanceOf(ErrorLink::class, $error0->get('links')); $this->assertTrue($error0->has('links.about')); $this->assertSame('http://example.org/errors/123', $error0->get('links.about')); $this->assertTrue($errors->has('1')); $error1 = $errors->get('1'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Error', $error1); + $this->assertInstanceOf(Error::class, $error1); $this->assertCount(2, $error1->getKeys()); $this->assertTrue($error1->has('code')); $this->assertSame('124', $error1->get('code')); $this->assertTrue($error1->has('links')); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ErrorLink', $error1->get('links')); + $this->assertInstanceOf(ErrorLink::class, $error1->get('links')); $this->assertTrue($error1->has('links.about')); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Link', $error1->get('links.about')); + $this->assertInstanceOf(Link::class, $error1->get('links.about')); $this->assertTrue($error1->has('links.about.href')); $this->assertSame('http://example.org/errors/124', $error1->get('links.about.href')); $this->assertTrue($error1->has('links.meta')); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Link', $error1->get('links.meta')); + $this->assertInstanceOf(Link::class, $error1->get('links.meta')); $this->assertTrue($error1->has('links.meta.href')); $this->assertSame('http://example.org/meta', $error1->get('links.meta.href')); diff --git a/tests/Functional/ParsingTest.php b/tests/Functional/ParsingTest.php index ac3227f..a1c865a 100644 --- a/tests/Functional/ParsingTest.php +++ b/tests/Functional/ParsingTest.php @@ -13,7 +13,22 @@ use Art4\JsonApiClient\Input\ResponseStringInput; use Art4\JsonApiClient\Manager\ErrorAbortManager; use Art4\JsonApiClient\Tests\Fixtures\HelperTrait; +use Art4\JsonApiClient\V1\Attributes; +use Art4\JsonApiClient\V1\Document; +use Art4\JsonApiClient\V1\DocumentLink; use Art4\JsonApiClient\V1\Factory; +use Art4\JsonApiClient\V1\Jsonapi; +use Art4\JsonApiClient\V1\Link; +use Art4\JsonApiClient\V1\Meta; +use Art4\JsonApiClient\V1\Relationship; +use Art4\JsonApiClient\V1\RelationshipCollection; +use Art4\JsonApiClient\V1\RelationshipLink; +use Art4\JsonApiClient\V1\ResourceCollection; +use Art4\JsonApiClient\V1\ResourceIdentifier; +use Art4\JsonApiClient\V1\ResourceIdentifierCollection; +use Art4\JsonApiClient\V1\ResourceItem; +use Art4\JsonApiClient\V1\ResourceItemLink; +use Art4\JsonApiClient\V1\ResourceNull; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; @@ -55,15 +70,15 @@ public function testParseSimpleResourceWithDifferentParser(callable $parser): vo $resource = $document->get('data'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ResourceItem', $resource); + $this->assertInstanceOf(ResourceItem::class, $resource); $this->assertFalse($resource->has('meta')); $this->assertSame($resource->get('type'), 'articles'); $this->assertTrue($resource->has('id')); $this->assertSame($resource->get('id'), '1'); $this->assertTrue($resource->has('attributes')); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Attributes', $resource->get('attributes')); + $this->assertInstanceOf(Attributes::class, $resource->get('attributes')); $this->assertTrue($resource->has('relationships')); - $this->assertInstanceOf('Art4\JsonApiClient\V1\RelationshipCollection', $resource->get('relationships')); + $this->assertInstanceOf(RelationshipCollection::class, $resource->get('relationships')); } public function testParseSimpleResourceIdentifier(): void @@ -71,7 +86,7 @@ public function testParseSimpleResourceIdentifier(): void $string = $this->getJsonString('02_simple_resource_identifier.json'); $document = Parser::parseResponseString($string); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Document', $document); + $this->assertInstanceOf(Document::class, $document); $this->assertFalse($document->has('errors')); $this->assertFalse($document->has('meta')); $this->assertFalse($document->has('jsonapi')); @@ -81,7 +96,7 @@ public function testParseSimpleResourceIdentifier(): void $resource = $document->get('data'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ResourceIdentifier', $resource); + $this->assertInstanceOf(ResourceIdentifier::class, $resource); $this->assertFalse($resource->has('meta')); $this->assertSame($resource->get('type'), 'articles'); $this->assertSame($resource->get('id'), '1'); @@ -92,7 +107,7 @@ public function testParseResourceObject(): void $string = $this->getJsonString('03_resource_object.json'); $document = Parser::parseResponseString($string); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Document', $document); + $this->assertInstanceOf(Document::class, $document); $this->assertFalse($document->has('errors')); $this->assertFalse($document->has('meta')); $this->assertFalse($document->has('jsonapi')); @@ -102,7 +117,7 @@ public function testParseResourceObject(): void $resource = $document->get('data'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ResourceItem', $resource); + $this->assertInstanceOf(ResourceItem::class, $resource); $this->assertTrue($resource->has('meta')); $this->assertSame($resource->get('type'), 'articles'); $this->assertSame($resource->get('id'), '1'); @@ -111,30 +126,30 @@ public function testParseResourceObject(): void $meta = $resource->get('meta'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Meta', $meta); + $this->assertInstanceOf(Meta::class, $meta); $this->assertTrue($meta->has('foo')); $this->assertSame($meta->get('foo'), 'bar'); $attributes = $resource->get('attributes'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Attributes', $attributes); + $this->assertInstanceOf(Attributes::class, $attributes); $this->assertTrue($attributes->has('title')); $this->assertSame($attributes->get('title'), 'Rails is Omakase'); $collection = $resource->get('relationships'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\RelationshipCollection', $collection); + $this->assertInstanceOf(RelationshipCollection::class, $collection); $this->assertTrue($collection->has('author')); $author = $collection->get('author'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Relationship', $author); + $this->assertInstanceOf(Relationship::class, $author); $this->assertTrue($author->has('links')); $this->assertTrue($author->has('data')); $links = $author->get('links'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\RelationshipLink', $links); + $this->assertInstanceOf(RelationshipLink::class, $links); $this->assertTrue($links->has('self')); $this->assertSame($links->get('self'), '/articles/1/relationships/author'); $this->assertTrue($links->has('related')); @@ -142,12 +157,12 @@ public function testParseResourceObject(): void $data = $author->get('data'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ResourceIdentifier', $data); + $this->assertInstanceOf(ResourceIdentifier::class, $data); $this->assertSame($data->get('type'), 'people'); $this->assertSame($data->get('id'), '9'); $data = $author->get('data'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ResourceIdentifier', $data); + $this->assertInstanceOf(ResourceIdentifier::class, $data); $this->assertSame($data->get('type'), 'people'); $this->assertSame($data->get('id'), '9'); } @@ -157,7 +172,7 @@ public function testParseCompleteResourceObjectWithMultipleRelationships(): void $string = $this->getJsonString('04_complete_document_with_multiple_relationships.json'); $document = Parser::parseResponseString($string); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Document', $document); + $this->assertInstanceOf(Document::class, $document); $this->assertFalse($document->has('errors')); $this->assertFalse($document->has('meta')); $this->assertFalse($document->has('jsonapi')); @@ -168,7 +183,7 @@ public function testParseCompleteResourceObjectWithMultipleRelationships(): void /** @var Accessable */ $resources = $document->get('data'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ResourceCollection', $resources); + $this->assertInstanceOf(ResourceCollection::class, $resources); $this->assertTrue(count($resources->getKeys()) === 1); $this->assertSame($resources->getKeys(), [0]); @@ -188,28 +203,28 @@ public function testParseCompleteResourceObjectWithMultipleRelationships(): void /** @var Accessable */ $attributes = $resource->get('attributes'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Attributes', $attributes); + $this->assertInstanceOf(Attributes::class, $attributes); $this->assertTrue($attributes->has('title')); $this->assertSame($attributes->get('title'), 'JSON API paints my bikeshed!'); /** @var Accessable */ $collection = $resource->get('relationships'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\RelationshipCollection', $collection); + $this->assertInstanceOf(RelationshipCollection::class, $collection); $this->assertTrue($collection->has('author')); $this->assertTrue($collection->has('comments')); /** @var Accessable */ $author = $collection->get('author'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Relationship', $author); + $this->assertInstanceOf(Relationship::class, $author); $this->assertTrue($author->has('links')); $this->assertTrue($author->has('data')); /** @var Accessable */ $links = $author->get('links'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\RelationshipLink', $links); + $this->assertInstanceOf(RelationshipLink::class, $links); $this->assertTrue($links->has('self')); $this->assertSame($links->get('self'), 'http://example.com/articles/1/relationships/author'); $this->assertTrue($links->has('related')); @@ -218,21 +233,21 @@ public function testParseCompleteResourceObjectWithMultipleRelationships(): void /** @var Accessable */ $data = $author->get('data'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ResourceIdentifier', $data); + $this->assertInstanceOf(ResourceIdentifier::class, $data); $this->assertSame($data->get('type'), 'people'); $this->assertSame($data->get('id'), '9'); /** @var Accessable */ $comments = $collection->get('comments'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Relationship', $comments); + $this->assertInstanceOf(Relationship::class, $comments); $this->assertTrue($comments->has('links')); $this->assertTrue($comments->has('data')); /** @var Accessable */ $links = $comments->get('links'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\RelationshipLink', $links); + $this->assertInstanceOf(RelationshipLink::class, $links); $this->assertTrue($links->has('self')); $this->assertSame($links->get('self'), 'http://example.com/articles/1/relationships/comments'); $this->assertTrue($links->has('related')); @@ -241,34 +256,34 @@ public function testParseCompleteResourceObjectWithMultipleRelationships(): void /** @var Accessable */ $data_array = $comments->get('data'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ResourceIdentifierCollection', $data_array); + $this->assertInstanceOf(ResourceIdentifierCollection::class, $data_array); $this->assertCount(2, $data_array->getKeys()); /** @var Accessable */ $identifier = $data_array->get(0); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ResourceIdentifier', $identifier); + $this->assertInstanceOf(ResourceIdentifier::class, $identifier); $this->assertSame($identifier->get('type'), 'comments'); $this->assertSame($identifier->get('id'), '5'); /** @var Accessable */ $identifier = $data_array->get(1); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ResourceIdentifier', $identifier); + $this->assertInstanceOf(ResourceIdentifier::class, $identifier); $this->assertSame($identifier->get('type'), 'comments'); $this->assertSame($identifier->get('id'), '12'); /** @var Accessable */ $links = $resource->get('links'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ResourceItemLink', $links); + $this->assertInstanceOf(ResourceItemLink::class, $links); $this->assertTrue($links->has('self')); $this->assertSame($links->get('self'), 'http://example.com/articles/1'); /** @var Accessable */ $includes = $document->get('included'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ResourceCollection', $includes); + $this->assertInstanceOf(ResourceCollection::class, $includes); $this->assertSame($includes->getKeys(), [0, 1, 2]); $this->assertTrue($includes->has(0)); @@ -276,7 +291,7 @@ public function testParseCompleteResourceObjectWithMultipleRelationships(): void /** @var Accessable */ $include = $includes->get(0); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ResourceItem', $include); + $this->assertInstanceOf(ResourceItem::class, $include); $this->assertSame($include->get('type'), 'people'); $this->assertSame($include->get('id'), '9'); $this->assertTrue($include->has('attributes')); @@ -285,7 +300,7 @@ public function testParseCompleteResourceObjectWithMultipleRelationships(): void /** @var Accessable */ $attributes = $include->get('attributes'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Attributes', $attributes); + $this->assertInstanceOf(Attributes::class, $attributes); $this->assertTrue($attributes->has('first-name')); $this->assertSame($attributes->get('first-name'), 'Dan'); $this->assertTrue($attributes->has('last-name')); @@ -296,7 +311,7 @@ public function testParseCompleteResourceObjectWithMultipleRelationships(): void /** @var Accessable */ $links = $include->get('links'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ResourceItemLink', $links); + $this->assertInstanceOf(ResourceItemLink::class, $links); $this->assertTrue($links->has('self')); $this->assertSame($links->get('self'), 'http://example.com/people/9'); @@ -305,7 +320,7 @@ public function testParseCompleteResourceObjectWithMultipleRelationships(): void /** @var Accessable */ $include = $includes->get(1); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ResourceItem', $include); + $this->assertInstanceOf(ResourceItem::class, $include); $this->assertSame($include->get('type'), 'comments'); $this->assertSame($include->get('id'), '5'); $this->assertTrue($include->has('attributes')); @@ -313,20 +328,20 @@ public function testParseCompleteResourceObjectWithMultipleRelationships(): void $attributes = $include->get('attributes'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Attributes', $attributes); + $this->assertInstanceOf(Attributes::class, $attributes); $this->assertTrue($attributes->has('body')); $this->assertSame($attributes->get('body'), 'First!'); $links = $include->get('links'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ResourceItemLink', $links); + $this->assertInstanceOf(ResourceItemLink::class, $links); $this->assertTrue($links->has('self')); $this->assertSame($links->get('self'), 'http://example.com/comments/5'); $this->assertTrue($includes->has(2)); $include = $includes->get(2); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ResourceItem', $include); + $this->assertInstanceOf(ResourceItem::class, $include); $this->assertSame($include->get('type'), 'comments'); $this->assertSame($include->get('id'), '12'); $this->assertTrue($include->has('attributes')); @@ -334,13 +349,13 @@ public function testParseCompleteResourceObjectWithMultipleRelationships(): void $attributes = $include->get('attributes'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Attributes', $attributes); + $this->assertInstanceOf(Attributes::class, $attributes); $this->assertTrue($attributes->has('body')); $this->assertSame($attributes->get('body'), 'I like XML better'); $links = $include->get('links'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ResourceItemLink', $links); + $this->assertInstanceOf(ResourceItemLink::class, $links); $this->assertTrue($links->has('self')); $this->assertSame($links->get('self'), 'http://example.com/comments/12'); } @@ -350,25 +365,25 @@ public function testParsePaginationExample(): void $string = $this->getJsonString('06_pagination_example.json'); $document = Parser::parseResponseString($string); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Document', $document); + $this->assertInstanceOf(Document::class, $document); $this->assertTrue($document->has('data')); $this->assertTrue($document->has('links')); $this->assertTrue($document->has('meta')); $resource_collection = $document->get('data'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ResourceCollection', $resource_collection); + $this->assertInstanceOf(ResourceCollection::class, $resource_collection); $this->assertTrue($resource_collection->has(0)); $this->assertFalse($resource_collection->has(1)); $resource = $resource_collection->get(0); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ResourceItem', $resource); + $this->assertInstanceOf(ResourceItem::class, $resource); $this->assertFalse($resource->has('meta')); $this->assertSame($resource->get('type'), 'articles'); $this->assertSame($resource->get('id'), '3'); $this->assertTrue($resource->has('attributes')); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Attributes', $resource->get('attributes')); + $this->assertInstanceOf(Attributes::class, $resource->get('attributes')); $attributes = $resource->get('attributes'); @@ -383,7 +398,7 @@ public function testParsePaginationExample(): void $links = $document->get('links'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\DocumentLink', $links); + $this->assertInstanceOf(DocumentLink::class, $links); $this->assertTrue($links->has('self')); $this->assertSame($links->get('self'), 'http://example.com/articles?page[number]=3&page[size]=1'); $this->assertTrue($links->has('first')); @@ -401,37 +416,37 @@ public function testParseRelationshipExample(): void $string = $this->getJsonString('07_relationship_example_without_data.json'); $document = Parser::parseResponseString($string); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Document', $document); + $this->assertInstanceOf(Document::class, $document); $this->assertTrue($document->has('data')); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ResourceCollection', $document->get('data')); + $this->assertInstanceOf(ResourceCollection::class, $document->get('data')); $this->assertTrue($document->has('data.0')); $this->assertFalse($document->has('data.1')); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ResourceItem', $document->get('data.0')); + $this->assertInstanceOf(ResourceItem::class, $document->get('data.0')); $this->assertFalse($document->has('data.0.meta')); $this->assertSame($document->get('data.0.type'), 'articles'); $this->assertSame($document->get('data.0.id'), '1'); $this->assertTrue($document->has('data.0.attributes')); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Attributes', $document->get('data.0.attributes')); + $this->assertInstanceOf(Attributes::class, $document->get('data.0.attributes')); $this->assertTrue($document->has('data.0.attributes.title')); $this->assertSame($document->get('data.0.attributes.title'), 'JSON API paints my bikeshed!'); $this->assertTrue($document->has('data.0.relationships')); - $this->assertInstanceOf('Art4\JsonApiClient\V1\RelationshipCollection', $document->get('data.0.relationships')); + $this->assertInstanceOf(RelationshipCollection::class, $document->get('data.0.relationships')); $this->assertTrue($document->has('data.0.relationships.comments')); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Relationship', $document->get('data.0.relationships.comments')); + $this->assertInstanceOf(Relationship::class, $document->get('data.0.relationships.comments')); $this->assertCount(2, $document->get('data.0.relationships.comments')->getKeys()); $this->assertTrue($document->has('data.0.relationships.comments.meta')); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Meta', $document->get('data.0.relationships.comments.meta')); + $this->assertInstanceOf(Meta::class, $document->get('data.0.relationships.comments.meta')); $this->assertTrue($document->has('data.0.relationships.comments.meta.foo')); $this->assertSame($document->get('data.0.relationships.comments.meta.foo'), 'bar'); $this->assertTrue($document->has('data.0.relationships.comments.links')); - $this->assertInstanceOf('Art4\JsonApiClient\V1\RelationshipLink', $document->get('data.0.relationships.comments.links')); + $this->assertInstanceOf(RelationshipLink::class, $document->get('data.0.relationships.comments.links')); $this->assertTrue($document->has('data.0.relationships.comments.links.custom')); $this->assertSame($document->get('data.0.relationships.comments.links.custom'), 'http://example.com/articles/1/custom'); @@ -447,13 +462,13 @@ public function testParseRelationshipExample(): void $this->assertSame($document->get('data.0.relationships.comments.links.next'), 'http://example.com/articles/1/comments?page=2'); $this->assertTrue($document->has('data.0.relationships.comments.links.related')); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Link', $document->get('data.0.relationships.comments.links.related')); + $this->assertInstanceOf(Link::class, $document->get('data.0.relationships.comments.links.related')); $this->assertTrue($document->has('data.0.relationships.comments.links.related.href')); $this->assertSame($document->get('data.0.relationships.comments.links.related.href'), 'http://example.com/articles/1/comments'); $this->assertTrue($document->has('data.0.relationships.comments.links.related.meta')); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Meta', $document->get('data.0.relationships.comments.links.related.meta')); + $this->assertInstanceOf(Meta::class, $document->get('data.0.relationships.comments.links.related.meta')); $this->assertTrue($document->has('data.0.relationships.comments.links.related.meta.count')); $this->assertSame($document->get('data.0.relationships.comments.links.related.meta.count'), 10); @@ -464,37 +479,37 @@ public function testParseObjectLinksExample(): void $string = $this->getJsonString('08_object_links.json'); $document = Parser::parseResponseString($string); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Document', $document); + $this->assertInstanceOf(Document::class, $document); $this->assertTrue($document->has('links')); - $this->assertInstanceOf('Art4\JsonApiClient\V1\DocumentLink', $document->get('links')); + $this->assertInstanceOf(DocumentLink::class, $document->get('links')); $this->assertTrue($document->has('links.self')); $this->assertTrue($document->has('links.first')); $this->assertTrue($document->has('links.next')); $this->assertTrue($document->has('links.last')); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Link', $document->get('links.self')); + $this->assertInstanceOf(Link::class, $document->get('links.self')); $this->assertTrue($document->has('links.self.href')); $this->assertSame('?page[number]=1&page[size]=10', $document->get('links.self.href')); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Link', $document->get('links.first')); + $this->assertInstanceOf(Link::class, $document->get('links.first')); $this->assertTrue($document->has('links.first.href')); $this->assertSame('?page[number]=1&page[size]=10', $document->get('links.first.href')); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Link', $document->get('links.next')); + $this->assertInstanceOf(Link::class, $document->get('links.next')); $this->assertTrue($document->has('links.next.href')); $this->assertSame('?page[number]=2&page[size]=10', $document->get('links.next.href')); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Link', $document->get('links.last')); + $this->assertInstanceOf(Link::class, $document->get('links.last')); $this->assertTrue($document->has('links.last.href')); $this->assertSame('?page[number]=11&page[size]=10', $document->get('links.last.href')); $this->assertTrue($document->has('jsonapi')); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Jsonapi', $document->get('jsonapi')); + $this->assertInstanceOf(Jsonapi::class, $document->get('jsonapi')); $this->assertTrue($document->has('jsonapi.version')); $this->assertSame('1.0', $document->get('jsonapi.version')); $this->assertTrue($document->has('jsonapi.meta')); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Meta', $document->get('jsonapi.meta')); + $this->assertInstanceOf(Meta::class, $document->get('jsonapi.meta')); $this->assertTrue($document->has('jsonapi.meta.foo')); $this->assertSame('bar', $document->get('jsonapi.meta.foo')); } @@ -504,7 +519,7 @@ public function testParseResourceIdentifierWithMeta(): void $string = $this->getJsonString('11_resource_identifier_with_meta.json'); $document = Parser::parseResponseString($string); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Document', $document); + $this->assertInstanceOf(Document::class, $document); $this->assertFalse($document->has('errors')); $this->assertFalse($document->has('meta')); $this->assertFalse($document->has('jsonapi')); @@ -514,7 +529,7 @@ public function testParseResourceIdentifierWithMeta(): void $resource = $document->get('data'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ResourceIdentifier', $resource); + $this->assertInstanceOf(ResourceIdentifier::class, $resource); $this->assertTrue($resource->has('meta')); $this->assertTrue($resource->has('meta.foo')); $this->assertSame($resource->get('meta.foo'), 'bar'); @@ -527,7 +542,7 @@ public function testParseNullResource(): void $string = $this->getJsonString('12_null_resource.json'); $document = Parser::parseResponseString($string); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Document', $document); + $this->assertInstanceOf(Document::class, $document); $this->assertFalse($document->has('errors')); $this->assertFalse($document->has('meta')); $this->assertFalse($document->has('jsonapi')); @@ -537,7 +552,7 @@ public function testParseNullResource(): void $resource = $document->get('data'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ResourceNull', $resource); + $this->assertInstanceOf(ResourceNull::class, $resource); } public function testParseResourceIdentifierCollectionWithMeta(): void @@ -545,7 +560,7 @@ public function testParseResourceIdentifierCollectionWithMeta(): void $string = $this->getJsonString('13_collection_with_resource_identifier_with_meta.json'); $document = Parser::parseResponseString($string); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Document', $document); + $this->assertInstanceOf(Document::class, $document); $this->assertFalse($document->has('errors')); $this->assertFalse($document->has('meta')); $this->assertFalse($document->has('jsonapi')); @@ -554,19 +569,19 @@ public function testParseResourceIdentifierCollectionWithMeta(): void $this->assertTrue($document->has('data')); $collection = $document->get('data'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ResourceCollection', $collection); + $this->assertInstanceOf(ResourceCollection::class, $collection); $this->assertTrue($collection->has('0')); $resource0 = $collection->get('0'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ResourceIdentifier', $resource0); + $this->assertInstanceOf(ResourceIdentifier::class, $resource0); $this->assertSame($resource0->get('type'), 'articles'); $this->assertSame($resource0->get('id'), '1'); $this->assertTrue($collection->has('1')); $resource1 = $collection->get('1'); - $this->assertInstanceOf('Art4\JsonApiClient\V1\ResourceIdentifier', $resource1); + $this->assertInstanceOf(ResourceIdentifier::class, $resource1); $this->assertTrue($resource1->has('meta')); $this->assertTrue($resource1->has('meta.foo')); $this->assertSame($resource1->get('meta.foo'), 'bar'); @@ -579,7 +594,7 @@ public function testParseCreateResourceWithoutId(): void $string = $this->getJsonString('14_create_resource_without_id.json'); $document = Parser::parseRequestString($string); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Document', $document); + $this->assertInstanceOf(Document::class, $document); $this->assertSame(['data'], $document->getKeys()); } @@ -588,7 +603,7 @@ public function testParseCreateShortResourceWithoutId(): void $string = $this->getJsonString('15_create_resource_without_id.json'); $document = Parser::parseRequestString($string); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Document', $document); + $this->assertInstanceOf(Document::class, $document); $this->assertSame(['data'], $document->getKeys()); } @@ -604,7 +619,7 @@ public function testParseLinksInRelationshipsCorrectly(): void $string = $this->getJsonString('17_relationship_links.json'); $document = Parser::parseResponseString($string); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Document', $document); + $this->assertInstanceOf(Document::class, $document); $this->assertSame(['data'], $document->getKeys()); } @@ -613,7 +628,7 @@ public function testParseNormativeStatementsForVersion10Correctly(): void $string = $this->getJsonString('format_1.0/normative-statements.json'); $document = Parser::parseResponseString($string); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Document', $document); + $this->assertInstanceOf(Document::class, $document); $this->assertSame(['data', 'included', 'jsonapi'], $document->getKeys()); $this->assertSame('1.0', $document->get('jsonapi.version')); $this->assertInstanceOf(Accessable::class, $document->get('data')); @@ -627,7 +642,7 @@ public function testParseNormativeStatementsForVersion11Correctly(): void $string = $this->getJsonString('format_1.1/normative-statements.json'); $document = Parser::parseResponseString($string); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Document', $document); + $this->assertInstanceOf(Document::class, $document); $this->assertSame(['data', 'included', 'jsonapi'], $document->getKeys()); $this->assertSame('1.1', $document->get('jsonapi.version')); $this->assertInstanceOf(Accessable::class, $document->get('data')); @@ -641,7 +656,7 @@ public function testParseJsonApiObjectWithVersion11Correctly(): void $string = $this->getJsonString('18_jsonapi_object_with_ext_profile.json'); $document = Parser::parseResponseString($string); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Document', $document); + $this->assertInstanceOf(Document::class, $document); $this->assertSame(['meta', 'jsonapi'], $document->getKeys()); $this->assertInstanceOf(Accessable::class, $document->get('jsonapi')); $this->assertSame(['version'], $document->get('jsonapi')->getKeys()); diff --git a/tests/Unit/V1/ErrorTest.php b/tests/Unit/V1/ErrorTest.php index c3c9b22..9bcb2b9 100644 --- a/tests/Unit/V1/ErrorTest.php +++ b/tests/Unit/V1/ErrorTest.php @@ -49,7 +49,7 @@ public function testCreateWithObjectReturnsSelf(): void $error = new Error($object, $this->manager, $this->parent); - $this->assertInstanceOf('Art4\JsonApiClient\V1\Error', $error); + $this->assertInstanceOf(Error::class, $error); $this->assertInstanceOf(Accessable::class, $error); $this->assertSame($error->getKeys(), ['id', 'links', 'status', 'code', 'title', 'detail', 'source', 'meta']); From 07c1f61010ccf5014d69c8d0783321fbe950263f Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 18 Jul 2024 13:54:46 +0200 Subject: [PATCH 03/23] Allow unknown properties for forward compatability with JsonAPI 1.1 --- src/V1/Document.php | 44 +++++++++++++---------------- src/V1/Jsonapi.php | 20 +++++++------ tests/Functional/ParsingTest.php | 8 ++---- tests/Functional/SerializerTest.php | 5 ---- tests/Unit/V1/DocumentTest.php | 15 +++++----- tests/Unit/V1/JsonapiTest.php | 12 ++++---- 6 files changed, 47 insertions(+), 57 deletions(-) diff --git a/src/V1/Document.php b/src/V1/Document.php index 531b59f..ce71d02 100644 --- a/src/V1/Document.php +++ b/src/V1/Document.php @@ -40,32 +40,26 @@ protected function parse(mixed $object): void throw new ValidationException('The properties `data` and `errors` MUST NOT coexist in Document.'); } - if (property_exists($object, 'data')) { - $this->set('data', $this->parseData($object->data)); - } - - if (property_exists($object, 'meta')) { - $this->set('meta', $this->create('Meta', $object->meta)); - } - - if (property_exists($object, 'errors')) { - $this->set('errors', $this->create('ErrorCollection', $object->errors)); - } - - if (property_exists($object, 'included')) { - if (!property_exists($object, 'data')) { - throw new ValidationException('If Document does not contain a `data` property, the `included` property MUST NOT be present either.'); + foreach ($object as $key => $value) { + if ($key === 'data') { + $this->set('data', $this->parseData($value)); + } else if ($key === 'meta') { + $this->set('meta', $this->create('Meta', $value)); + } else if ($key === 'errors') { + $this->set('errors', $this->create('ErrorCollection', $value)); + } else if ($key === 'included') { + if (!property_exists($object, 'data')) { + throw new ValidationException('If Document does not contain a `data` property, the `included` property MUST NOT be present either.'); + } + + $this->set('included', $this->create('ResourceCollection', $object->included)); + } else if ($key === 'jsonapi') { + $this->set('jsonapi', $this->create('Jsonapi', $value)); + } else if ($key === 'links') { + $this->set('links', $this->create('DocumentLink', $value)); + } else { + $this->set($key, $value); } - - $this->set('included', $this->create('ResourceCollection', $object->included)); - } - - if (property_exists($object, 'jsonapi')) { - $this->set('jsonapi', $this->create('Jsonapi', $object->jsonapi)); - } - - if (property_exists($object, 'links')) { - $this->set('links', $this->create('DocumentLink', $object->links)); } } diff --git a/src/V1/Jsonapi.php b/src/V1/Jsonapi.php index 7c31c96..fa7c814 100644 --- a/src/V1/Jsonapi.php +++ b/src/V1/Jsonapi.php @@ -31,16 +31,18 @@ protected function parse(mixed $object): void throw new ValidationException('Jsonapi has to be an object, "' . gettype($object) . '" given.'); } - if (property_exists($object, 'version')) { - if (is_object($object->version) or is_array($object->version)) { - throw new ValidationException('property "version" cannot be an object or array, "' . gettype($object->version) . '" given.'); + foreach ($object as $key => $value) { + if ($key === 'version') { + if (is_object($value) or is_array($value)) { + throw new ValidationException('property "version" cannot be an object or array, "' . gettype($value) . '" given.'); + } + + $this->set('version', strval($value)); + } else if ($key === 'meta') { + $this->set('meta', $this->create('Meta', $value)); + } else { + $this->set($key, $value); } - - $this->set('version', strval($object->version)); - } - - if (property_exists($object, 'meta')) { - $this->set('meta', $this->create('Meta', $object->meta)); } } diff --git a/tests/Functional/ParsingTest.php b/tests/Functional/ParsingTest.php index a1c865a..786ea54 100644 --- a/tests/Functional/ParsingTest.php +++ b/tests/Functional/ParsingTest.php @@ -629,7 +629,7 @@ public function testParseNormativeStatementsForVersion10Correctly(): void $document = Parser::parseResponseString($string); $this->assertInstanceOf(Document::class, $document); - $this->assertSame(['data', 'included', 'jsonapi'], $document->getKeys()); + $this->assertSame(['jsonapi', 'data', 'included'], $document->getKeys()); $this->assertSame('1.0', $document->get('jsonapi.version')); $this->assertInstanceOf(Accessable::class, $document->get('data')); $this->assertCount(6, $document->get('data')->getKeys()); @@ -643,7 +643,7 @@ public function testParseNormativeStatementsForVersion11Correctly(): void $document = Parser::parseResponseString($string); $this->assertInstanceOf(Document::class, $document); - $this->assertSame(['data', 'included', 'jsonapi'], $document->getKeys()); + $this->assertSame(['jsonapi', 'data', 'included'], $document->getKeys()); $this->assertSame('1.1', $document->get('jsonapi.version')); $this->assertInstanceOf(Accessable::class, $document->get('data')); $this->assertCount(6, $document->get('data')->getKeys()); @@ -659,9 +659,7 @@ public function testParseJsonApiObjectWithVersion11Correctly(): void $this->assertInstanceOf(Document::class, $document); $this->assertSame(['meta', 'jsonapi'], $document->getKeys()); $this->assertInstanceOf(Accessable::class, $document->get('jsonapi')); - $this->assertSame(['version'], $document->get('jsonapi')->getKeys()); - // TODO #90: Add support for unknown properties - // $this->assertSame(['version', 'ext', 'profile'], $document->get('jsonapi')->getKeys()); + $this->assertSame(['version', 'ext', 'profile'], $document->get('jsonapi')->getKeys()); $this->assertSame('1.1', $document->get('jsonapi.version')); } } diff --git a/tests/Functional/SerializerTest.php b/tests/Functional/SerializerTest.php index 71d9fa7..97a9773 100644 --- a/tests/Functional/SerializerTest.php +++ b/tests/Functional/SerializerTest.php @@ -78,11 +78,6 @@ public function testParseJsonapiDataWithErrorAbortManager(string $filename, bool $document = $manager->parse($input); $expected = json_decode($string, true); - // TODO #90: Add support for unknown properties - //** @phpstan-ignore-next-line */ - unset($expected['jsonapi']['ext']); - //** @phpstan-ignore-next-line */ - unset($expected['jsonapi']['profile']); // Test full array $this->assertEquals( diff --git a/tests/Unit/V1/DocumentTest.php b/tests/Unit/V1/DocumentTest.php index d62ef94..e12f3ea 100644 --- a/tests/Unit/V1/DocumentTest.php +++ b/tests/Unit/V1/DocumentTest.php @@ -38,14 +38,15 @@ public function testCreateWithObjectReturnsSelf(): void { $object = new \stdClass(); $object->meta = new \stdClass(); - $object->ignore = 'this property must be ignored'; + $object->fc = 'test property for forward compatability'; $document = new Document($object, $this->manager, $this->parent); $this->assertInstanceOf(Document::class, $document); $this->assertInstanceOf(Accessable::class, $document); - $this->assertSame($document->getKeys(), ['meta']); + $this->assertSame($document->getKeys(), ['meta', 'fc']); $this->assertTrue($document->has('meta')); + $this->assertTrue($document->has('fc')); $this->assertInstanceOf(Accessable::class, $document->get('meta')); $this->assertFalse($document->has('data')); $this->assertFalse($document->has('errors')); @@ -63,26 +64,26 @@ public function testCreateWithAllPossibleValues(): void $object->data = new \stdClass(); $object->data->type = 'types'; $object->data->id = 'id'; + $object->meta = new \stdClass(); $object->included = []; $object->included[0] = new \stdClass(); $object->included[0]->type = 'types'; $object->included[0]->id = 'id'; - $object->links = new \stdClass(); $object->jsonapi = new \stdClass(); - $object->meta = new \stdClass(); - $object->ignore = 'this property must be ignored'; + $object->links = new \stdClass(); + $object->fc = 'test property for forward compatability'; $document = new Document($object, $this->manager, $this->parent); $this->assertInstanceOf(Document::class, $document); - $this->assertSame($document->getKeys(), ['data', 'meta', 'included', 'jsonapi', 'links']); + $this->assertSame($document->getKeys(), ['data', 'meta', 'included', 'jsonapi', 'links', 'fc']); $this->assertTrue($document->has('data')); $this->assertTrue($document->has('meta')); $this->assertFalse($document->has('errors')); $this->assertTrue($document->has('jsonapi')); $this->assertTrue($document->has('links')); $this->assertTrue($document->has('included')); - $this->assertFalse($document->has('ignore')); + $this->assertTrue($document->has('fc')); } /** diff --git a/tests/Unit/V1/JsonapiTest.php b/tests/Unit/V1/JsonapiTest.php index 6e26e38..9c74de0 100644 --- a/tests/Unit/V1/JsonapiTest.php +++ b/tests/Unit/V1/JsonapiTest.php @@ -42,18 +42,18 @@ public function testCreateWithObject(): void // This object MAY also contain a meta member, whose value is a meta object $object->meta = new \stdClass(); - // these properties must be ignored - $object->testobj = new \stdClass(); - $object->teststring = 'http://example.org/link'; + // test properties for forward compatability + $object->fcobj = new \stdClass(); + $object->fcstring = 'http://example.org/link'; $jsonapi = new Jsonapi($object, $this->manager, $this->parent); $this->assertInstanceOf(Jsonapi::class, $jsonapi); $this->assertInstanceOf(Accessable::class, $jsonapi); - $this->assertSame($jsonapi->getKeys(), ['version', 'meta']); + $this->assertSame($jsonapi->getKeys(), ['version', 'meta', 'fcobj', 'fcstring']); - $this->assertFalse($jsonapi->has('testobj')); - $this->assertFalse($jsonapi->has('teststring')); + $this->assertTrue($jsonapi->has('fcobj')); + $this->assertTrue($jsonapi->has('fcstring')); $this->assertTrue($jsonapi->has('version')); $this->assertSame($jsonapi->get('version'), '1.0'); $this->assertTrue($jsonapi->has('meta')); From a8f944c4c7cb2c7724f0e3454a8db6d0ec4c269c Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 18 Jul 2024 16:23:26 +0200 Subject: [PATCH 04/23] Refactor Document parsing --- composer.json | 2 +- src/V1/Document.php | 40 +++++++++++++++++----------------------- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/composer.json b/composer.json index d03e6ed..d3c1ba3 100644 --- a/composer.json +++ b/composer.json @@ -39,7 +39,7 @@ "reuse-annotate": "pipx run reuse annotate src tests --license=\"GPL-3.0-or-later\" --copyright=\"2015-2023 Artur Weigandt https://wlabs.de/kontakt\" --recursive --exclude-year --copyright-style=\"spdx\"", "reuse-lint": "pipx run reuse --suppress-deprecation lint", "test": [ - "@codestyle --verbose --diff", + "@codestyle --diff --dry-run", "@phpstan", "@phpunit" ] diff --git a/src/V1/Document.php b/src/V1/Document.php index ce71d02..3c997cd 100644 --- a/src/V1/Document.php +++ b/src/V1/Document.php @@ -40,26 +40,22 @@ protected function parse(mixed $object): void throw new ValidationException('The properties `data` and `errors` MUST NOT coexist in Document.'); } - foreach ($object as $key => $value) { - if ($key === 'data') { - $this->set('data', $this->parseData($value)); - } else if ($key === 'meta') { - $this->set('meta', $this->create('Meta', $value)); - } else if ($key === 'errors') { - $this->set('errors', $this->create('ErrorCollection', $value)); - } else if ($key === 'included') { - if (!property_exists($object, 'data')) { - throw new ValidationException('If Document does not contain a `data` property, the `included` property MUST NOT be present either.'); - } - - $this->set('included', $this->create('ResourceCollection', $object->included)); - } else if ($key === 'jsonapi') { - $this->set('jsonapi', $this->create('Jsonapi', $value)); - } else if ($key === 'links') { - $this->set('links', $this->create('DocumentLink', $value)); - } else { - $this->set($key, $value); - } + if (property_exists($object, 'included') and !property_exists($object, 'data')) { + throw new ValidationException('If Document does not contain a `data` property, the `included` property MUST NOT be present either.'); + } + + foreach (get_object_vars($object) as $key => $value) { + $value = match ($key) { + 'data' => $this->parseData($value), + 'meta' => $this->create('Meta', $value), + 'errors' => $this->create('ErrorCollection', $value), + 'included' => $this->create('ResourceCollection', $value), + 'jsonapi' => $this->create('Jsonapi', $value), + 'links' => $this->create('DocumentLink', $value), + default => $value, + }; + + $this->set($key, $value); } } @@ -80,11 +76,9 @@ public function get($key): mixed /** * Parse the data value * - * @param null|object|array $data Data value - * * @throws ValidationException If $data isn't null or an object */ - private function parseData($data): Accessable + private function parseData(mixed $data): Accessable { if ($data === null) { return $this->create('ResourceNull', $data); From a5cda9f5eb0f5f777a5603a1666946f1a951c3c0 Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 19 Jul 2024 08:15:34 +0200 Subject: [PATCH 05/23] Refactor Jsonapi parsing --- src/V1/Jsonapi.php | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/V1/Jsonapi.php b/src/V1/Jsonapi.php index fa7c814..6f575a7 100644 --- a/src/V1/Jsonapi.php +++ b/src/V1/Jsonapi.php @@ -31,18 +31,19 @@ protected function parse(mixed $object): void throw new ValidationException('Jsonapi has to be an object, "' . gettype($object) . '" given.'); } - foreach ($object as $key => $value) { - if ($key === 'version') { - if (is_object($value) or is_array($value)) { - throw new ValidationException('property "version" cannot be an object or array, "' . gettype($value) . '" given.'); - } - - $this->set('version', strval($value)); - } else if ($key === 'meta') { - $this->set('meta', $this->create('Meta', $value)); - } else { - $this->set($key, $value); - } + if (property_exists($object, 'version') and (is_object($object->version) or is_array($object->version))) { + throw new ValidationException('property "version" cannot be an object or array, "' . gettype($object->version) . '" given.'); + } + + foreach (get_object_vars($object) as $key => $value) { + $value = match ($key) { + /** @phpstan-ignore-next-line */ + 'version' => strval($value), + 'meta' => $this->create('Meta', $value), + default => $value, + }; + + $this->set($key, $value); } } From 052a189d94e7f99f99f5291c9beec580ed349d27 Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 19 Jul 2024 08:28:16 +0200 Subject: [PATCH 06/23] Refactor Attributes and RelationshipColletion --- src/V1/Attributes.php | 8 +------- src/V1/RelationshipCollection.php | 8 +------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/V1/Attributes.php b/src/V1/Attributes.php index f831f03..3f91124 100644 --- a/src/V1/Attributes.php +++ b/src/V1/Attributes.php @@ -35,13 +35,7 @@ protected function parse(mixed $object): void throw new ValidationException('These properties are not allowed in attributes: `type`, `id`, `relationships`, `links`'); } - $object_vars = get_object_vars($object); - - if (count($object_vars) === 0) { - return; - } - - foreach ($object_vars as $name => $value) { + foreach (get_object_vars($object) as $name => $value) { $this->set($name, $value); } } diff --git a/src/V1/RelationshipCollection.php b/src/V1/RelationshipCollection.php index 8e47d44..8709fa0 100644 --- a/src/V1/RelationshipCollection.php +++ b/src/V1/RelationshipCollection.php @@ -35,13 +35,7 @@ protected function parse(mixed $object): void throw new ValidationException('These properties are not allowed in attributes: `type`, `id`'); } - $object_vars = get_object_vars($object); - - if (count($object_vars) === 0) { - return; - } - - foreach ($object_vars as $name => $value) { + foreach (get_object_vars($object) as $name => $value) { if ($this->getParent()->has('attributes.' . $name)) { throw new ValidationException('"' . $name . '" property cannot be set because it exists already in parents Resource object.'); } From 0d952d619ff28c5f4a094919997de060e6fb2c7c Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 19 Jul 2024 08:50:11 +0200 Subject: [PATCH 07/23] Replace deprecated methods in PHPUnit --- tests/Fixtures/HelperTrait.php | 2 +- tests/Unit/Serializer/ArraySerializerTest.php | 12 ++++++------ tests/Unit/V1/DocumentLinkTest.php | 2 +- tests/Unit/V1/RelationshipCollectionTest.php | 2 +- tests/Unit/V1/RelationshipLinkTest.php | 10 +++++----- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/Fixtures/HelperTrait.php b/tests/Fixtures/HelperTrait.php index 8da7143..ee81781 100644 --- a/tests/Fixtures/HelperTrait.php +++ b/tests/Fixtures/HelperTrait.php @@ -166,7 +166,7 @@ public function setUpManagerMock(): void $this->manager->expects($this->any()) ->method('getFactory') - ->will($this->returnValue($factory)); + ->willReturn($factory); $this->manager->expects($this->any()) ->method('getParam') diff --git a/tests/Unit/Serializer/ArraySerializerTest.php b/tests/Unit/Serializer/ArraySerializerTest.php index e4b165c..d7e3b88 100644 --- a/tests/Unit/Serializer/ArraySerializerTest.php +++ b/tests/Unit/Serializer/ArraySerializerTest.php @@ -23,7 +23,7 @@ public function testSerialize(): void $object2 = new \stdClass(); $data = $this->createMock(Accessable::class); - $data->method('get')->will($this->returnValueMap([ + $data->method('get')->willReturnMap([ ['AccessObject', $object1], ['object', $object2], ['array', []], @@ -31,7 +31,7 @@ public function testSerialize(): void ['integer', 1], ['boolean', true], ['null', null], - ])); + ]); $data->method('getKeys')->willReturn([ 'AccessObject', 'object', @@ -64,14 +64,14 @@ public function testRecursiveSerialize(): void $stdObject->key = 'value'; $object1 = $this->createMock(Accessable::class); - $object1->method('get')->will($this->returnValueMap([ + $object1->method('get')->willReturnMap([ ['object', $stdObject], ['array', []], ['string', 'string'], ['integer', 1], ['boolean', true], ['null', null], - ])); + ]); $object1->method('getKeys')->willReturn([ 'object', 'array', @@ -82,9 +82,9 @@ public function testRecursiveSerialize(): void ]); $data = $this->createMock(Accessable::class); - $data->method('get')->will($this->returnValueMap([ + $data->method('get')->willReturnMap([ ['AccessObject', $object1], - ])); + ]); $data->method('getKeys')->willReturn([ 'AccessObject', ]); diff --git a/tests/Unit/V1/DocumentLinkTest.php b/tests/Unit/V1/DocumentLinkTest.php index da58837..77ea157 100644 --- a/tests/Unit/V1/DocumentLinkTest.php +++ b/tests/Unit/V1/DocumentLinkTest.php @@ -33,7 +33,7 @@ public function setUp(): void $this->parent->expects($this->any()) ->method('has') ->with('data') - ->will($this->returnValue(true)); + ->willReturn(true); } /** diff --git a/tests/Unit/V1/RelationshipCollectionTest.php b/tests/Unit/V1/RelationshipCollectionTest.php index 9982184..35a5d41 100644 --- a/tests/Unit/V1/RelationshipCollectionTest.php +++ b/tests/Unit/V1/RelationshipCollectionTest.php @@ -121,7 +121,7 @@ public function testCreateWithIdPropertyThrowsException(): void $item->expects($this->any()) ->method('has') ->with($this->equalTo('attributes')) - ->will($this->returnValue(false)); + ->willReturn(false); $object = new \stdClass(); $object->id = '5'; diff --git a/tests/Unit/V1/RelationshipLinkTest.php b/tests/Unit/V1/RelationshipLinkTest.php index 2962623..72ec59e 100644 --- a/tests/Unit/V1/RelationshipLinkTest.php +++ b/tests/Unit/V1/RelationshipLinkTest.php @@ -42,12 +42,12 @@ public function setUp(): void $this->relationship->expects($this->any()) ->method('has') ->with($this->equalTo('data')) - ->will($this->returnValue(true)); + ->willReturn(true); $this->relationship->expects($this->any()) ->method('get') ->with($this->equalTo('data')) - ->will($this->returnValue($collection)); + ->willReturn($collection); } /** @@ -136,7 +136,7 @@ public function testPaginationNotParsedIfRelationshipDataNotExists(): void $relationship->expects($this->any()) ->method('has') ->with($this->equalTo('data')) - ->will($this->returnValue(false)); + ->willReturn(false); $link = new RelationshipLink($object, $this->manager, $relationship); @@ -173,7 +173,7 @@ public function testPaginationNotParsedIfRelationshipIdentifierCollectionNotExis $relationship->expects($this->any()) ->method('has') ->with($this->equalTo('data')) - ->will($this->returnValue(true)); + ->willReturn(true); // Mock identifier item $data = $this->createMock(Accessable::class); @@ -181,7 +181,7 @@ public function testPaginationNotParsedIfRelationshipIdentifierCollectionNotExis $relationship->expects($this->any()) ->method('get') ->with($this->equalTo('data')) - ->will($this->returnValue($data)); + ->willReturn($data); $link = new RelationshipLink($object, $this->manager, $relationship); From c28e2a13aeabc3e819fbed8af1a2b61bf430d52c Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 19 Jul 2024 09:10:01 +0200 Subject: [PATCH 08/23] Add check for required properties in error objects --- CHANGELOG.md | 4 ++++ src/V1/Error.php | 4 ++++ tests/Unit/V1/ErrorTest.php | 24 ++++++++++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b22d1ab..6d97d92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Dropped support for PHP 7.4 and PHP 8.0 +### Fixed + +- Add check that an error object contains at least one of `id`, `links`, `status`, `code`, `title`, `detail`, `source` or `meta`. + ### Deprecated - `\Art4\Accessable::get()` will add `mixed` as a native return type declaration in 2.0.0, do the same in your implementation now to avoid errors. diff --git a/src/V1/Error.php b/src/V1/Error.php index cab0cd0..eb70ca2 100644 --- a/src/V1/Error.php +++ b/src/V1/Error.php @@ -33,6 +33,10 @@ protected function parse(mixed $object): void ); } + if (!property_exists($object, 'id') and !property_exists($object, 'links') and !property_exists($object, 'status') and !property_exists($object, 'code') and !property_exists($object, 'title') and !property_exists($object, 'detail') and !property_exists($object, 'source') and !property_exists($object, 'meta')) { + throw new ValidationException('An error object MUST contain at least one of: `id`, `links`, `status`, `code`, `title`, `detail`, `source` or `meta`.'); + } + if (property_exists($object, 'id')) { if (!is_string($object->id)) { throw new ValidationException( diff --git a/tests/Unit/V1/ErrorTest.php b/tests/Unit/V1/ErrorTest.php index 9bcb2b9..8d68134 100644 --- a/tests/Unit/V1/ErrorTest.php +++ b/tests/Unit/V1/ErrorTest.php @@ -161,4 +161,28 @@ public function testCreateDetailWithoutStringThrowsException(mixed $input): void $error = new Error($object, $this->manager, $this->parent); } + + /** + * An error object MAY have the following members, and MUST contain at least one of: + * - id + * - links + * - status + * - code + * - title + * - details + * - source + * - meta + */ + public function testCreateWithoutRequiredPropertiesThrowsException(): void + { + $object = new \stdClass(); + $object->description = 'error description'; + + $this->expectException(ValidationException::class); + $this->expectExceptionMessage( + 'An error object MUST contain at least one of: `id`, `links`, `status`, `code`, `title`, `detail`, `source` or `meta`.' + ); + + $error = new Error($object, $this->manager, $this->parent); + } } From 8cc6d02dd9d34b06530e4bfee7f1f232983a28fd Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 19 Jul 2024 09:56:04 +0200 Subject: [PATCH 09/23] Add error object without recommended properties --- tests/files/10_error_with_links.json | 12 +++++++----- .../19_error_without_recommended_properties.json | 10 ++++++++++ 2 files changed, 17 insertions(+), 5 deletions(-) create mode 100644 tests/files/19_error_without_recommended_properties.json diff --git a/tests/files/10_error_with_links.json b/tests/files/10_error_with_links.json index cedef92..c5dde86 100644 --- a/tests/files/10_error_with_links.json +++ b/tests/files/10_error_with_links.json @@ -1,15 +1,17 @@ { "errors": [ { - "code": "123", - "source": { "pointer": "/data/attributes/first-name" }, - "title": "Value is too short", + "code": "123", + "source": { + "pointer": "/data/attributes/first-name" + }, + "title": "Value is too short", "links": { "about": "http://example.org/errors/123" } - }, + }, { - "code": "124", + "code": "124", "links": { "about": { "href": "http://example.org/errors/124" diff --git a/tests/files/19_error_without_recommended_properties.json b/tests/files/19_error_without_recommended_properties.json new file mode 100644 index 0000000..0eca35a --- /dev/null +++ b/tests/files/19_error_without_recommended_properties.json @@ -0,0 +1,10 @@ +{ + "errors": [ + { + "description": "some description about the error" + } + ], + "jsonapi": { + "version": "1.0" + } +} From a12a4037ce71e6c74071c4a39e560b5bbd9df2ef Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 19 Jul 2024 09:56:43 +0200 Subject: [PATCH 10/23] Revert "Add check for required properties in error objects" This reverts commit c28e2a13aeabc3e819fbed8af1a2b61bf430d52c. See https://github.com/json-api/json-api/pull/1525#issuecomment-2238538306 --- CHANGELOG.md | 4 ---- src/V1/Error.php | 4 ---- tests/Unit/V1/ErrorTest.php | 24 ------------------------ 3 files changed, 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d97d92..b22d1ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,10 +11,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Dropped support for PHP 7.4 and PHP 8.0 -### Fixed - -- Add check that an error object contains at least one of `id`, `links`, `status`, `code`, `title`, `detail`, `source` or `meta`. - ### Deprecated - `\Art4\Accessable::get()` will add `mixed` as a native return type declaration in 2.0.0, do the same in your implementation now to avoid errors. diff --git a/src/V1/Error.php b/src/V1/Error.php index eb70ca2..cab0cd0 100644 --- a/src/V1/Error.php +++ b/src/V1/Error.php @@ -33,10 +33,6 @@ protected function parse(mixed $object): void ); } - if (!property_exists($object, 'id') and !property_exists($object, 'links') and !property_exists($object, 'status') and !property_exists($object, 'code') and !property_exists($object, 'title') and !property_exists($object, 'detail') and !property_exists($object, 'source') and !property_exists($object, 'meta')) { - throw new ValidationException('An error object MUST contain at least one of: `id`, `links`, `status`, `code`, `title`, `detail`, `source` or `meta`.'); - } - if (property_exists($object, 'id')) { if (!is_string($object->id)) { throw new ValidationException( diff --git a/tests/Unit/V1/ErrorTest.php b/tests/Unit/V1/ErrorTest.php index 8d68134..9bcb2b9 100644 --- a/tests/Unit/V1/ErrorTest.php +++ b/tests/Unit/V1/ErrorTest.php @@ -161,28 +161,4 @@ public function testCreateDetailWithoutStringThrowsException(mixed $input): void $error = new Error($object, $this->manager, $this->parent); } - - /** - * An error object MAY have the following members, and MUST contain at least one of: - * - id - * - links - * - status - * - code - * - title - * - details - * - source - * - meta - */ - public function testCreateWithoutRequiredPropertiesThrowsException(): void - { - $object = new \stdClass(); - $object->description = 'error description'; - - $this->expectException(ValidationException::class); - $this->expectExceptionMessage( - 'An error object MUST contain at least one of: `id`, `links`, `status`, `code`, `title`, `detail`, `source` or `meta`.' - ); - - $error = new Error($object, $this->manager, $this->parent); - } } From 4be2ed1c058bc43c43c6465d283b310b214fd9e5 Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 19 Jul 2024 10:49:29 +0200 Subject: [PATCH 11/23] Add FC for new properties in Error object --- src/V1/Error.php | 118 +++++++++++++++++------------------- tests/Unit/V1/ErrorTest.php | 18 ++++-- 2 files changed, 66 insertions(+), 70 deletions(-) diff --git a/src/V1/Error.php b/src/V1/Error.php index cab0cd0..b5346d3 100644 --- a/src/V1/Error.php +++ b/src/V1/Error.php @@ -33,71 +33,61 @@ protected function parse(mixed $object): void ); } - if (property_exists($object, 'id')) { - if (!is_string($object->id)) { - throw new ValidationException( - 'property "id" has to be a string, "' . - gettype($object->id) . '" given.' - ); + foreach (get_object_vars($object) as $key => $value) { + if ($key === 'id') { + if (!is_string($object->id)) { + throw new ValidationException( + 'property "id" has to be a string, "' . + gettype($object->id) . '" given.' + ); + } + + $this->set('id', strval($object->id)); + } elseif ($key === 'links') { + $this->set('links', $this->create('ErrorLink', $object->links)); + } elseif ($key === 'status') { + if (!is_string($object->status)) { + throw new ValidationException( + 'property "status" has to be a string, "' . + gettype($object->status) . '" given.' + ); + } + + $this->set('status', strval($object->status)); + } elseif ($key === 'code') { + if (!is_string($object->code)) { + throw new ValidationException( + 'property "code" has to be a string, "' . + gettype($object->code) . '" given.' + ); + } + + $this->set('code', strval($object->code)); + } elseif ($key === 'title') { + if (!is_string($object->title)) { + throw new ValidationException( + 'property "title" has to be a string, "' . + gettype($object->title) . '" given.' + ); + } + + $this->set('title', strval($object->title)); + } elseif ($key === 'detail') { + if (!is_string($object->detail)) { + throw new ValidationException( + 'property "detail" has to be a string, "' . + gettype($object->detail) . '" given.' + ); + } + + $this->set('detail', strval($object->detail)); + } elseif ($key === 'source') { + $this->set('source', $this->create('ErrorSource', $object->source)); + } elseif ($key === 'meta') { + $this->set('meta', $this->create('Meta', $object->meta)); + } else { + $this->set($key, $value); } - - $this->set('id', strval($object->id)); - } - - if (property_exists($object, 'links')) { - $this->set('links', $this->create('ErrorLink', $object->links)); - } - - if (property_exists($object, 'status')) { - if (!is_string($object->status)) { - throw new ValidationException( - 'property "status" has to be a string, "' . - gettype($object->status) . '" given.' - ); - } - - $this->set('status', strval($object->status)); - } - - if (property_exists($object, 'code')) { - if (!is_string($object->code)) { - throw new ValidationException( - 'property "code" has to be a string, "' . - gettype($object->code) . '" given.' - ); - } - - $this->set('code', strval($object->code)); - } - - if (property_exists($object, 'title')) { - if (!is_string($object->title)) { - throw new ValidationException( - 'property "title" has to be a string, "' . - gettype($object->title) . '" given.' - ); - } - - $this->set('title', strval($object->title)); - } - - if (property_exists($object, 'detail')) { - if (!is_string($object->detail)) { - throw new ValidationException( - 'property "detail" has to be a string, "' . - gettype($object->detail) . '" given.' - ); - } - - $this->set('detail', strval($object->detail)); - } - - if (property_exists($object, 'source')) { - $this->set('source', $this->create('ErrorSource', $object->source)); - } - - if (property_exists($object, 'meta')) { - $this->set('meta', $this->create('Meta', $object->meta)); } } diff --git a/tests/Unit/V1/ErrorTest.php b/tests/Unit/V1/ErrorTest.php index 9bcb2b9..0f3d74f 100644 --- a/tests/Unit/V1/ErrorTest.php +++ b/tests/Unit/V1/ErrorTest.php @@ -46,29 +46,35 @@ public function testCreateWithObjectReturnsSelf(): void $object->detail = 'detail'; $object->source = new \stdClass(); $object->meta = new \stdClass(); + $object->fc = 'test property for forward compatability'; $error = new Error($object, $this->manager, $this->parent); $this->assertInstanceOf(Error::class, $error); $this->assertInstanceOf(Accessable::class, $error); - $this->assertSame($error->getKeys(), ['id', 'links', 'status', 'code', 'title', 'detail', 'source', 'meta']); + $this->assertSame( + ['id', 'links', 'status', 'code', 'title', 'detail', 'source', 'meta', 'fc'], + $error->getKeys(), + ); $this->assertTrue($error->has('id')); - $this->assertSame($error->get('id'), 'id'); + $this->assertSame('id', $error->get('id')); $this->assertTrue($error->has('links')); $this->assertInstanceOf(Accessable::class, $error->get('links')); $this->assertTrue($error->has('status')); - $this->assertSame($error->get('status'), 'status'); + $this->assertSame('status', $error->get('status')); $this->assertTrue($error->has('code')); - $this->assertSame($error->get('code'), 'code'); + $this->assertSame('code', $error->get('code')); $this->assertTrue($error->has('title')); - $this->assertSame($error->get('title'), 'title'); + $this->assertSame('title', $error->get('title')); $this->assertTrue($error->has('detail')); - $this->assertSame($error->get('detail'), 'detail'); + $this->assertSame('detail', $error->get('detail')); $this->assertTrue($error->has('source')); $this->assertInstanceOf(Accessable::class, $error->get('source')); $this->assertTrue($error->has('meta')); $this->assertInstanceOf(Accessable::class, $error->get('meta')); + $this->assertTrue($error->has('fc')); + $this->assertSame('test property for forward compatability', $error->get('fc')); // test get() with not existing key throws an exception $this->assertFalse($error->has('something')); From 45d3997d5a677ac3f40d88cc7713efa17e7ebfda Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 19 Jul 2024 11:26:05 +0200 Subject: [PATCH 12/23] Fix phpstan errors --- src/V1/Error.php | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/V1/Error.php b/src/V1/Error.php index b5346d3..756bb08 100644 --- a/src/V1/Error.php +++ b/src/V1/Error.php @@ -35,56 +35,56 @@ protected function parse(mixed $object): void foreach (get_object_vars($object) as $key => $value) { if ($key === 'id') { - if (!is_string($object->id)) { + if (!is_string($value)) { throw new ValidationException( 'property "id" has to be a string, "' . - gettype($object->id) . '" given.' + gettype($value) . '" given.' ); } - $this->set('id', strval($object->id)); + $this->set('id', strval($value)); } elseif ($key === 'links') { - $this->set('links', $this->create('ErrorLink', $object->links)); + $this->set('links', $this->create('ErrorLink', $value)); } elseif ($key === 'status') { - if (!is_string($object->status)) { + if (!is_string($value)) { throw new ValidationException( 'property "status" has to be a string, "' . - gettype($object->status) . '" given.' + gettype($value) . '" given.' ); } - $this->set('status', strval($object->status)); + $this->set('status', strval($value)); } elseif ($key === 'code') { - if (!is_string($object->code)) { + if (!is_string($value)) { throw new ValidationException( 'property "code" has to be a string, "' . - gettype($object->code) . '" given.' + gettype($value) . '" given.' ); } - $this->set('code', strval($object->code)); + $this->set('code', strval($value)); } elseif ($key === 'title') { - if (!is_string($object->title)) { + if (!is_string($value)) { throw new ValidationException( 'property "title" has to be a string, "' . - gettype($object->title) . '" given.' + gettype($value) . '" given.' ); } - $this->set('title', strval($object->title)); + $this->set('title', strval($value)); } elseif ($key === 'detail') { - if (!is_string($object->detail)) { + if (!is_string($value)) { throw new ValidationException( 'property "detail" has to be a string, "' . - gettype($object->detail) . '" given.' + gettype($value) . '" given.' ); } - $this->set('detail', strval($object->detail)); + $this->set('detail', strval($value)); } elseif ($key === 'source') { - $this->set('source', $this->create('ErrorSource', $object->source)); + $this->set('source', $this->create('ErrorSource', $value)); } elseif ($key === 'meta') { - $this->set('meta', $this->create('Meta', $object->meta)); + $this->set('meta', $this->create('Meta', $value)); } else { $this->set($key, $value); } From 724b23f482e52870517235c956291ffe3d03d4ee Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 19 Jul 2024 11:57:21 +0200 Subject: [PATCH 13/23] Add FC in Error source objects --- src/V1/ErrorSource.php | 24 ++++++++++--------- tests/Unit/V1/ErrorSourceTest.php | 10 ++++---- .../20_error_with_source_header_property.json | 12 ++++++++++ 3 files changed, 31 insertions(+), 15 deletions(-) create mode 100644 tests/files/20_error_with_source_header_property.json diff --git a/src/V1/ErrorSource.php b/src/V1/ErrorSource.php index 30bb75f..4f7bd57 100644 --- a/src/V1/ErrorSource.php +++ b/src/V1/ErrorSource.php @@ -31,20 +31,22 @@ protected function parse(mixed $object): void throw new ValidationException('ErrorSource has to be an object, "' . gettype($object) . '" given.'); } - if (property_exists($object, 'pointer')) { - if (!is_string($object->pointer)) { - throw new ValidationException('property "pointer" has to be a string, "' . gettype($object->pointer) . '" given.'); - } + foreach (get_object_vars($object) as $key => $value) { + if ($key === 'pointer') { + if (!is_string($value)) { + throw new ValidationException('property "pointer" has to be a string, "' . gettype($value) . '" given.'); + } - $this->set('pointer', strval($object->pointer)); - } + $this->set('pointer', strval($value)); + } elseif ($key === 'parameter') { + if (!is_string($value)) { + throw new ValidationException('property "parameter" has to be a string, "' . gettype($value) . '" given.'); + } - if (property_exists($object, 'parameter')) { - if (!is_string($object->parameter)) { - throw new ValidationException('property "parameter" has to be a string, "' . gettype($object->parameter) . '" given.'); + $this->set('parameter', strval($value)); + } else { + $this->set($key, $value); } - - $this->set('parameter', strval($object->parameter)); } } diff --git a/tests/Unit/V1/ErrorSourceTest.php b/tests/Unit/V1/ErrorSourceTest.php index f6cab45..3b88920 100644 --- a/tests/Unit/V1/ErrorSourceTest.php +++ b/tests/Unit/V1/ErrorSourceTest.php @@ -43,19 +43,21 @@ public function testOnlyPointerParameterPropertiesExists(): void $object = new \stdClass(); $object->pointer = '/pointer'; $object->parameter = 'parameter'; - $object->ignore = 'must be ignored'; + $object->fc = 'test property for forward compatability'; $source = new ErrorSource($object, $this->manager, $this->parent); $this->assertInstanceOf(ErrorSource::class, $source); $this->assertInstanceOf(Accessable::class, $source); - $this->assertSame($source->getKeys(), ['pointer', 'parameter']); + $this->assertSame(['pointer', 'parameter', 'fc'], $source->getKeys()); $this->assertFalse($source->has('ignore')); $this->assertTrue($source->has('pointer')); - $this->assertSame($source->get('pointer'), '/pointer'); + $this->assertSame('/pointer', $source->get('pointer')); $this->assertTrue($source->has('parameter')); - $this->assertSame($source->get('parameter'), 'parameter'); + $this->assertSame('parameter', $source->get('parameter')); + $this->assertTrue($source->has('fc')); + $this->assertSame('test property for forward compatability', $source->get('fc')); // test get() with not existing key throws an exception $this->assertFalse($source->has('something')); diff --git a/tests/files/20_error_with_source_header_property.json b/tests/files/20_error_with_source_header_property.json new file mode 100644 index 0000000..89d4109 --- /dev/null +++ b/tests/files/20_error_with_source_header_property.json @@ -0,0 +1,12 @@ +{ + "errors": [ + { + "source": { + "header": "Content-Type" + } + } + ], + "jsonapi": { + "version": "1.1" + } +} From f5e37be54bd9660971e367ae41d0e9f7d53e037d Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 19 Jul 2024 12:35:22 +0200 Subject: [PATCH 14/23] Refactor Meta object --- src/V1/Meta.php | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/V1/Meta.php b/src/V1/Meta.php index ed68e0a..e03fbab 100644 --- a/src/V1/Meta.php +++ b/src/V1/Meta.php @@ -31,13 +31,7 @@ protected function parse(mixed $object): void throw new ValidationException('Meta has to be an object, "' . gettype($object) . '" given.'); } - $object_vars = get_object_vars($object); - - if (count($object_vars) === 0) { - return; - } - - foreach ($object_vars as $name => $value) { + foreach (get_object_vars($object) as $name => $value) { $this->set($name, $value); } } From ca0b5017b997456923f3a070d869b1dc98ca0960 Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 19 Jul 2024 12:59:46 +0200 Subject: [PATCH 15/23] Add FC in Relationship object --- src/V1/Relationship.php | 29 ++++++++++++++--------------- tests/Unit/V1/RelationshipTest.php | 7 +++++-- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/V1/Relationship.php b/src/V1/Relationship.php index 67444ee..944e331 100644 --- a/src/V1/Relationship.php +++ b/src/V1/Relationship.php @@ -35,24 +35,23 @@ protected function parse(mixed $object): void throw new ValidationException('A Relationship object MUST contain at least one of the following properties: links, data, meta'); } - if (property_exists($object, 'data')) { - if ($object->data === null) { - $this->set('data', $object->data); - } elseif (is_array($object->data)) { - $this->set('data', $this->create('ResourceIdentifierCollection', $object->data)); + foreach (get_object_vars($object) as $key => $value) { + if ($key === 'data') { + if ($value === null) { + $this->set('data', $value); + } elseif (is_array($value)) { + $this->set('data', $this->create('ResourceIdentifierCollection', $value)); + } else { + $this->set('data', $this->create('ResourceIdentifier', $value)); + } + } elseif ($key === 'meta') { + $this->set('meta', $this->create('Meta', $value)); + } elseif ($key === 'links') { + $this->set('links', $this->create('RelationshipLink', $value)); } else { - $this->set('data', $this->create('ResourceIdentifier', $object->data)); + $this->set($key, $value); } } - - if (property_exists($object, 'meta')) { - $this->set('meta', $this->create('Meta', $object->meta)); - } - - // Parse 'links' after 'data' - if (property_exists($object, 'links')) { - $this->set('links', $this->create('RelationshipLink', $object->links)); - } } /** diff --git a/tests/Unit/V1/RelationshipTest.php b/tests/Unit/V1/RelationshipTest.php index 3a28544..4df2280 100644 --- a/tests/Unit/V1/RelationshipTest.php +++ b/tests/Unit/V1/RelationshipTest.php @@ -38,15 +38,18 @@ public function testCreateWithObjectReturnsSelf(): void { $object = new \stdClass(); $object->meta = new \stdClass(); + $object->fc = 'test property for forward compatability'; $relationship = new Relationship($object, $this->manager, $this->parent); $this->assertInstanceOf(Relationship::class, $relationship); $this->assertInstanceOf(Accessable::class, $relationship); + $this->assertSame(['meta', 'fc'], $relationship->getKeys()); $this->assertTrue($relationship->has('meta')); - - $meta = $relationship->get('meta'); + $this->assertInstanceOf(Accessable::class, $relationship->get('meta')); + $this->assertTrue($relationship->has('fc')); + $this->assertSame('test property for forward compatability', $relationship->get('fc')); // test get() with not existing key throws an exception $this->assertFalse($relationship->has('something')); From 933173024b6dc3703ec07171eb5c02d1fbc55fde Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 19 Jul 2024 13:11:36 +0200 Subject: [PATCH 16/23] Add FC in ResourceIdentifier --- src/V1/ResourceIdentifier.php | 11 ++++++----- tests/Unit/V1/ResourceIdentifierTest.php | 11 ++++++++--- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/V1/ResourceIdentifier.php b/src/V1/ResourceIdentifier.php index 9950667..627c1ea 100644 --- a/src/V1/ResourceIdentifier.php +++ b/src/V1/ResourceIdentifier.php @@ -47,11 +47,12 @@ protected function parse(mixed $object): void throw new ValidationException('A resource id MUST be a string'); } - $this->set('type', $object->type); - $this->set('id', $object->id); - - if (property_exists($object, 'meta')) { - $this->set('meta', $this->create('Meta', $object->meta)); + foreach (get_object_vars($object) as $key => $value) { + if ($key === 'meta') { + $this->set('meta', $this->create('Meta', $value)); + } else { + $this->set($key, $value); + } } } diff --git a/tests/Unit/V1/ResourceIdentifierTest.php b/tests/Unit/V1/ResourceIdentifierTest.php index c0867f7..a5aed02 100644 --- a/tests/Unit/V1/ResourceIdentifierTest.php +++ b/tests/Unit/V1/ResourceIdentifierTest.php @@ -60,16 +60,21 @@ public function testCreateWithObjectAndMeta(): void $object->type = 'types'; $object->id = '159'; $object->meta = new \stdClass(); + $object->fc = 'test property for forward compatability'; $identifier = new ResourceIdentifier($object, $this->manager, $this->parent); $this->assertInstanceOf(ResourceIdentifier::class, $identifier); - $this->assertSame($identifier->get('type'), 'types'); - $this->assertSame($identifier->get('id'), '159'); + $this->assertSame(['type', 'id', 'meta', 'fc'], $identifier->getKeys()); + $this->assertTrue($identifier->has('type')); + $this->assertSame('types', $identifier->get('type')); + $this->assertTrue($identifier->has('id')); + $this->assertSame('159', $identifier->get('id')); $this->assertTrue($identifier->has('meta')); $this->assertInstanceOf(Accessable::class, $identifier->get('meta')); - $this->assertSame($identifier->getKeys(), ['type', 'id', 'meta']); + $this->assertTrue($identifier->has('fc')); + $this->assertSame('test property for forward compatability', $identifier->get('fc')); } /** From 850ca747585b3cdba5ba3a702495926225e717d2 Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 19 Jul 2024 13:41:34 +0200 Subject: [PATCH 17/23] Add FC for new properties in ResourceItem --- src/V1/ResourceItem.php | 26 +++++++++----------------- tests/Unit/V1/ResourceItemTest.php | 11 ++++++++--- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/V1/ResourceItem.php b/src/V1/ResourceItem.php index 570a210..bfaeb40 100644 --- a/src/V1/ResourceItem.php +++ b/src/V1/ResourceItem.php @@ -39,8 +39,6 @@ protected function parse(mixed $object): void throw new ValidationException('A resource type MUST be a string'); } - $this->set('type', $object->type); - if ( $this->getManager()->getParam('optional_item_id', false) === false or !$this->getParent()->has('data') // If parent has no `data` than parent is a ResourceCollection @@ -52,24 +50,18 @@ protected function parse(mixed $object): void if (!is_string($object->id)) { throw new ValidationException('A resource id MUST be a string'); } - - $this->set('id', $object->id); - } - - if (property_exists($object, 'meta')) { - $this->set('meta', $this->create('Meta', $object->meta)); } - if (property_exists($object, 'attributes')) { - $this->set('attributes', $this->create('Attributes', $object->attributes)); - } - - if (property_exists($object, 'relationships')) { - $this->set('relationships', $this->create('RelationshipCollection', $object->relationships)); - } + foreach (get_object_vars($object) as $key => $value) { + $value = match ($key) { + 'meta' => $this->create('Meta', $value), + 'attributes' => $this->create('Attributes', $value), + 'relationships' => $this->create('RelationshipCollection', $value), + 'links' => $this->create('ResourceItemLink', $value), + default => $value, + }; - if (property_exists($object, 'links')) { - $this->set('links', $this->create('ResourceItemLink', $object->links)); + $this->set($key, $value); } } diff --git a/tests/Unit/V1/ResourceItemTest.php b/tests/Unit/V1/ResourceItemTest.php index 44030be..6836333 100644 --- a/tests/Unit/V1/ResourceItemTest.php +++ b/tests/Unit/V1/ResourceItemTest.php @@ -78,13 +78,17 @@ public function testCreateWithFullObject(): void $object->attributes = new \stdClass(); $object->relationships = new \stdClass(); $object->links = new \stdClass(); + $object->fc = 'test property for forward compatability'; $item = new ResourceItem($object, $this->manager, $this->parent); $this->assertInstanceOf(ResourceItem::class, $item); - $this->assertSame($item->get('type'), 'type'); - $this->assertSame($item->get('id'), '789'); + $this->assertSame(['type', 'id', 'meta', 'attributes', 'relationships', 'links', 'fc'], $item->getKeys()); + $this->assertTrue($item->has('type')); + $this->assertSame('type', $item->get('type')); + $this->assertTrue($item->has('id')); + $this->assertSame('789', $item->get('id')); $this->assertTrue($item->has('meta')); $this->assertInstanceOf(Accessable::class, $item->get('meta')); $this->assertTrue($item->has('attributes')); @@ -93,7 +97,8 @@ public function testCreateWithFullObject(): void $this->assertInstanceOf(Accessable::class, $item->get('relationships')); $this->assertTrue($item->has('links')); $this->assertInstanceOf(Accessable::class, $item->get('links')); - $this->assertSame($item->getKeys(), ['type', 'id', 'meta', 'attributes', 'relationships', 'links']); + $this->assertTrue($item->has('fc')); + $this->assertSame('test property for forward compatability', $item->get('fc')); } /** From 6b0e7bd58b9602273754c037e7e65e4f5cf48456 Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 19 Jul 2024 13:47:54 +0200 Subject: [PATCH 18/23] replace deprecated PHPUnit methods --- tests/Fixtures/V1Factory.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Fixtures/V1Factory.php b/tests/Fixtures/V1Factory.php index 835c047..cc31f2d 100644 --- a/tests/Fixtures/V1Factory.php +++ b/tests/Fixtures/V1Factory.php @@ -9,6 +9,7 @@ namespace Art4\JsonApiClient\Tests\Fixtures; use Art4\JsonApiClient\Factory as FactoryInterface; +use PHPUnit\Framework\MockObject\MockBuilder; use PHPUnit\Framework\TestCase; final class V1Factory implements FactoryInterface @@ -33,11 +34,10 @@ public function __construct(TestCase $testcase) */ public function make($name, array $args = []) { - return $this->testcase->getMockBuilder(AccessableElement::class) + return (new MockBuilder($this->testcase, AccessableElement::class)) ->disableOriginalConstructor() ->disableOriginalClone() - ->disableArgumentCloning() - ->disallowMockingUnknownTypes() - ->getMock(); + ->getMock() + ; } } From cdc01685e8172ede57aa92509565214a1578b495 Mon Sep 17 00:00:00 2001 From: Art4 Date: Mon, 22 Jul 2024 09:47:02 +0200 Subject: [PATCH 19/23] Move invalid code examples into separate test folder --- tests/Functional/ParsingTest.php | 4 +++- tests/Functional/SerializerTest.php | 7 ------- .../resource_id_must_be_a_string.json} | 0 3 files changed, 3 insertions(+), 8 deletions(-) rename tests/files/{16_type_and_id_as_integer.json => invalid/resource_id_must_be_a_string.json} (100%) diff --git a/tests/Functional/ParsingTest.php b/tests/Functional/ParsingTest.php index 786ea54..e86f7b4 100644 --- a/tests/Functional/ParsingTest.php +++ b/tests/Functional/ParsingTest.php @@ -610,7 +610,9 @@ public function testParseCreateShortResourceWithoutId(): void public function testExceptionIfIdIsNotString(): void { $this->expectException(\Art4\JsonApiClient\Exception\ValidationException::class); - $string = $this->getJsonString('16_type_and_id_as_integer.json'); + $this->expectExceptionMessage('A resource id MUST be a string'); + + $string = $this->getJsonString('invalid/resource_id_must_be_a_string.json'); $document = Parser::parseResponseString($string); } diff --git a/tests/Functional/SerializerTest.php b/tests/Functional/SerializerTest.php index 97a9773..3e7447f 100644 --- a/tests/Functional/SerializerTest.php +++ b/tests/Functional/SerializerTest.php @@ -46,13 +46,6 @@ public static function jsonapiDataProvider(): array foreach ($filenames as $file) { $filename = str_replace($path, '', $file); - // Ignore files with errors - if (in_array($filename, [ - '16_type_and_id_as_integer.json', - ])) { - continue; - } - $files[] = [ $filename, in_array($filename, $requestFiles), diff --git a/tests/files/16_type_and_id_as_integer.json b/tests/files/invalid/resource_id_must_be_a_string.json similarity index 100% rename from tests/files/16_type_and_id_as_integer.json rename to tests/files/invalid/resource_id_must_be_a_string.json From a49b246f1040c729c8a60316761b63bf28aeb430 Mon Sep 17 00:00:00 2001 From: Art4 Date: Mon, 22 Jul 2024 10:04:58 +0200 Subject: [PATCH 20/23] Add parsing test with lid member in resource object and resouce identifier object --- tests/Functional/SerializerTest.php | 1 + tests/files/16_create_resource_with_lid.json | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 tests/files/16_create_resource_with_lid.json diff --git a/tests/Functional/SerializerTest.php b/tests/Functional/SerializerTest.php index 3e7447f..84aa03b 100644 --- a/tests/Functional/SerializerTest.php +++ b/tests/Functional/SerializerTest.php @@ -35,6 +35,7 @@ public static function jsonapiDataProvider(): array $requestFiles = [ '14_create_resource_without_id.json', '15_create_resource_without_id.json', + '16_create_resource_with_lid.json', ]; $filenames = glob($path . '*.json'); diff --git a/tests/files/16_create_resource_with_lid.json b/tests/files/16_create_resource_with_lid.json new file mode 100644 index 0000000..03d2668 --- /dev/null +++ b/tests/files/16_create_resource_with_lid.json @@ -0,0 +1,18 @@ +{ + "data": { + "type": "photos", + "lid": "2d81d40d-fa78-4d34-acd1-b66a39a343d5", + "attributes": { + "title": "Ember Hamster", + "src": "http://example.com/images/productivity.png" + }, + "relationships": { + "photographer": { + "data": { + "type": "people", + "id": "2d81d40d-fa78-4d34-acd1-b66a39a343d5" + } + } + } + } +} From 1eb644aa4eedee7d5ce4cb44d0caf15bf22bcfa3 Mon Sep 17 00:00:00 2001 From: Art4 Date: Mon, 22 Jul 2024 10:11:52 +0200 Subject: [PATCH 21/23] Add tests for describedby link --- tests/files/08_object_links.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/files/08_object_links.json b/tests/files/08_object_links.json index 7f5be83..1140bea 100644 --- a/tests/files/08_object_links.json +++ b/tests/files/08_object_links.json @@ -14,13 +14,16 @@ }, "links": { "self": { - "href": "http://parties.api/v1/parties/1" + "href": "https://parties.api/v1/parties/1" } } } ], "included": [], "links": { + "describedby": { + "href": "http://example.com/schemas/parties" + }, "self": { "href": "?page[number]=1&page[size]=10" }, From ebeb1b703dac91d604fdbab52c3026802f57a382 Mon Sep 17 00:00:00 2001 From: Art4 Date: Tue, 23 Jul 2024 16:41:42 +0200 Subject: [PATCH 22/23] Add parsing tests for atomic extension --- tests/Functional/ParsingTest.php | 10 +++++--- tests/Functional/SerializerTest.php | 10 ++++---- tests/files/01_simple_resource.json | 5 ++-- .../files/02_simple_resource_identifier.json | 2 +- .../18_jsonapi_object_with_ext_profile.json | 24 ++++++++++--------- tests/files/21_ext_atomic_operations.json | 17 +++++++++++++ tests/files/22_ext_atomic_results.json | 19 +++++++++++++++ 7 files changed, 63 insertions(+), 24 deletions(-) create mode 100644 tests/files/21_ext_atomic_operations.json create mode 100644 tests/files/22_ext_atomic_results.json diff --git a/tests/Functional/ParsingTest.php b/tests/Functional/ParsingTest.php index e86f7b4..ba252a5 100644 --- a/tests/Functional/ParsingTest.php +++ b/tests/Functional/ParsingTest.php @@ -65,6 +65,7 @@ public function testParseSimpleResourceWithDifferentParser(callable $parser): vo $this->assertFalse($document->has('meta')); $this->assertFalse($document->has('jsonapi')); $this->assertFalse($document->has('links')); + $this->assertFalse($document->has('relationships')); $this->assertFalse($document->has('included')); $this->assertTrue($document->has('data')); @@ -76,9 +77,12 @@ public function testParseSimpleResourceWithDifferentParser(callable $parser): vo $this->assertTrue($resource->has('id')); $this->assertSame($resource->get('id'), '1'); $this->assertTrue($resource->has('attributes')); - $this->assertInstanceOf(Attributes::class, $resource->get('attributes')); - $this->assertTrue($resource->has('relationships')); - $this->assertInstanceOf(RelationshipCollection::class, $resource->get('relationships')); + + $attributes = $resource->get('attributes'); + + $this->assertInstanceOf(Attributes::class, $attributes); + $this->assertTrue($attributes->has('title')); + $this->assertSame($attributes->get('title'), 'JSON API paints my bikeshed!'); } public function testParseSimpleResourceIdentifier(): void diff --git a/tests/Functional/SerializerTest.php b/tests/Functional/SerializerTest.php index 84aa03b..52dc412 100644 --- a/tests/Functional/SerializerTest.php +++ b/tests/Functional/SerializerTest.php @@ -47,7 +47,7 @@ public static function jsonapiDataProvider(): array foreach ($filenames as $file) { $filename = str_replace($path, '', $file); - $files[] = [ + $files[$filename] = [ $filename, in_array($filename, $requestFiles), ]; @@ -71,12 +71,10 @@ public function testParseJsonapiDataWithErrorAbortManager(string $filename, bool $document = $manager->parse($input); - $expected = json_decode($string, true); - // Test full array - $this->assertEquals( - $expected, - (new ArraySerializer(['recursive' => true]))->serialize($document), + $this->assertJsonStringEqualsJsonString( + $string, + json_encode((new ArraySerializer(['recursive' => true]))->serialize($document), JSON_PRETTY_PRINT), $filename ); } diff --git a/tests/files/01_simple_resource.json b/tests/files/01_simple_resource.json index 8a0f22b..7ceac62 100644 --- a/tests/files/01_simple_resource.json +++ b/tests/files/01_simple_resource.json @@ -3,8 +3,7 @@ "type": "articles", "id": "1", "attributes": { - }, - "relationships": { + "title": "JSON API paints my bikeshed!" } } -} \ No newline at end of file +} diff --git a/tests/files/02_simple_resource_identifier.json b/tests/files/02_simple_resource_identifier.json index 3d69729..6417e49 100644 --- a/tests/files/02_simple_resource_identifier.json +++ b/tests/files/02_simple_resource_identifier.json @@ -3,4 +3,4 @@ "type": "articles", "id": "1" } -} \ No newline at end of file +} diff --git a/tests/files/18_jsonapi_object_with_ext_profile.json b/tests/files/18_jsonapi_object_with_ext_profile.json index 04750b0..e576927 100644 --- a/tests/files/18_jsonapi_object_with_ext_profile.json +++ b/tests/files/18_jsonapi_object_with_ext_profile.json @@ -1,13 +1,15 @@ { - "meta": {}, - "jsonapi": { - "version": "1.1", - "ext": [ - "https://jsonapi.org/ext/atomic" - ], - "profile": [ - "http://example.com/profiles/flexible-pagination", - "http://example.com/profiles/resource-versioning" - ] - } + "meta": { + "note": "BC 1.0: A document MUST contain at least one of the following top-level members: data, errors, meta" + }, + "jsonapi": { + "version": "1.1", + "ext": [ + "https://jsonapi.org/ext/atomic" + ], + "profile": [ + "http://example.com/profiles/flexible-pagination", + "http://example.com/profiles/resource-versioning" + ] } +} diff --git a/tests/files/21_ext_atomic_operations.json b/tests/files/21_ext_atomic_operations.json new file mode 100644 index 0000000..100aec5 --- /dev/null +++ b/tests/files/21_ext_atomic_operations.json @@ -0,0 +1,17 @@ +{ + "atomic:operations": [ + { + "op": "add", + "href": "/blogPosts", + "data": { + "type": "articles", + "attributes": { + "title": "JSON API paints my bikeshed!" + } + } + } + ], + "meta": { + "note": "BC 1.0: A document MUST contain at least one of the following top-level members: data, errors, meta" + } +} diff --git a/tests/files/22_ext_atomic_results.json b/tests/files/22_ext_atomic_results.json new file mode 100644 index 0000000..e0677e6 --- /dev/null +++ b/tests/files/22_ext_atomic_results.json @@ -0,0 +1,19 @@ +{ + "atomic:results": [ + { + "data": { + "links": { + "self": "http://example.com/blogPosts/13" + }, + "type": "articles", + "id": "13", + "attributes": { + "title": "JSON API paints my bikeshed!" + } + } + } + ], + "meta": { + "note": "BC 1.0: A document MUST contain at least one of the following top-level members: data, errors, meta" + } +} From 19df2d6116d92e5ccb8f104300f65c0a11e5b7c8 Mon Sep 17 00:00:00 2001 From: Art4 Date: Tue, 23 Jul 2024 16:58:52 +0200 Subject: [PATCH 23/23] Add tests with new members in link objects --- .../23_links_object_with_all_members.json | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 tests/files/23_links_object_with_all_members.json diff --git a/tests/files/23_links_object_with_all_members.json b/tests/files/23_links_object_with_all_members.json new file mode 100644 index 0000000..fa63d0a --- /dev/null +++ b/tests/files/23_links_object_with_all_members.json @@ -0,0 +1,26 @@ +{ + "links": { + "self": { + "href": "http://example.com/schemas/parties", + "rel": "http://example.com/schemas/parties", + "describedby": "http://example.com/schemas/parties", + "title": "Parties", + "type": "party", + "hreflang": "en-GB", + "fc": "test property for forward compatability", + "@member": "@-Members MUST be ignored", + "meta": { + "count": 10 + } + }, + "related": { + "href": "http://example.com/schemas/parties" + }, + "describedby": { + "href": "http://example.com/schemas/parties" + } + }, + "meta": { + "note": "BC 1.0: A document MUST contain at least one of the following top-level members: data, errors, meta" + } +}