From 91b143a3b5dce28ba1f537ed96f36faa94dede58 Mon Sep 17 00:00:00 2001 From: Salvatore Date: Wed, 6 Nov 2024 22:11:11 +0100 Subject: [PATCH] All required automated tests are in place. This commit closes #5 --- tests/operations/AddTest.php | 7 ++ tests/operations/CopyTest.php | 7 ++ tests/operations/MoveTest.php | 113 ++++++++++++++++++++++++ tests/operations/RemoveTest.php | 95 ++++++++++++++++++++ tests/operations/ReplaceTest.php | 121 +++++++++++++++++++++++++ tests/operations/TestTest.php | 146 +++++++++++++++++++++++++++++++ 6 files changed, 489 insertions(+) create mode 100644 tests/operations/MoveTest.php create mode 100644 tests/operations/RemoveTest.php create mode 100644 tests/operations/ReplaceTest.php create mode 100644 tests/operations/TestTest.php diff --git a/tests/operations/AddTest.php b/tests/operations/AddTest.php index bf53ea5..b1fcae9 100644 --- a/tests/operations/AddTest.php +++ b/tests/operations/AddTest.php @@ -14,12 +14,14 @@ use blancks\JsonPatch\json\handlers\BasicJsonHandler; use blancks\JsonPatch\json\handlers\JsonHandlerAwareTrait; use blancks\JsonPatch\operations\Add; +use blancks\JsonPatch\operations\PatchOperation; use blancks\JsonPatch\operations\PatchValidationTrait; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\UsesClass; use PHPUnit\Framework\TestCase; #[CoversClass(Add::class)] +#[CoversClass(PatchOperation::class)] #[UsesClass(PatchValidationTrait::class)] #[UsesClass(CrudTrait::class)] #[UsesClass(BasicJsonHandler::class)] @@ -42,6 +44,11 @@ protected function setUp(): void $this->Operation->setJsonHandler(new BasicJsonHandler); } + public function testGetOperation(): void + { + $this->assertSame('add', $this->Operation->getOperation()); + } + public function testValidate(): void { $this->expectNotToPerformAssertions(); diff --git a/tests/operations/CopyTest.php b/tests/operations/CopyTest.php index ba54638..185df67 100644 --- a/tests/operations/CopyTest.php +++ b/tests/operations/CopyTest.php @@ -16,12 +16,14 @@ use blancks\JsonPatch\json\handlers\BasicJsonHandler; use blancks\JsonPatch\json\handlers\JsonHandlerAwareTrait; use blancks\JsonPatch\operations\Copy; +use blancks\JsonPatch\operations\PatchOperation; use blancks\JsonPatch\operations\PatchValidationTrait; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\UsesClass; use PHPUnit\Framework\TestCase; #[CoversClass(Copy::class)] +#[CoversClass(PatchOperation::class)] #[UsesClass(PatchValidationTrait::class)] #[UsesClass(CrudTrait::class)] #[UsesClass(BasicJsonHandler::class)] @@ -46,6 +48,11 @@ protected function setUp(): void $this->Operation->setJsonHandler(new BasicJsonHandler); } + public function testGetOperation(): void + { + $this->assertSame('copy', $this->Operation->getOperation()); + } + public function testValidateHandlesValidPatchStructure(): void { $this->expectNotToPerformAssertions(); diff --git a/tests/operations/MoveTest.php b/tests/operations/MoveTest.php new file mode 100644 index 0000000..4e620e7 --- /dev/null +++ b/tests/operations/MoveTest.php @@ -0,0 +1,113 @@ +Operation = new Move(); + $this->Operation->setJsonHandler(new BasicJsonHandler); + } + + public function testGetOperation(): void + { + $this->assertSame('move', $this->Operation->getOperation()); + } + + public function testValidateWithValidPatchObject(): void + { + $move = new Move(); + $patch = (object) ['op' => 'move', 'path' => '/path/to/resource', 'from' => '/path/from/resource']; + $move->validate($patch); + $this->assertTrue(true); + } + + public function testValidateWithPatchObjectMissingFrom(): void + { + $this->expectException(InvalidPatchFromException::class); + /** @var object{op:string, path: string, from: string} $patch */ + $patch = (object) ['op' => 'move', 'path' => '/path/to/resource']; + $this->Operation->validate($patch); + } + + public function testValidateWithPatchObjectHavingInvalidFrom(): void + { + $this->expectException(MalformedPathException::class); + $patch = (object) ['op' => 'move', 'path' => '/path/to/resource', 'from' => 'invalid/from/path']; + $this->Operation->validate($patch); + } + + public function testApplyWithValidPatchObject(): void + { + $document = (object) [ + 'path' => (object) ['to' => (object) ['resource' => 'value1']], + 'path1' => (object) ['from' => (object) ['resource' => 'value2']] + ]; + $patch = (object) ['op' => 'move', 'path' => '/path/to/resource', 'from' => '/path1/from/resource']; + $this->Operation->apply($document, $patch); + $this->assertEquals('value2', $document->path->to->resource); + } + + public function testApplyWithPatchObjectMissingFrom(): void + { + $this->expectException(UnknownPathException::class); + $document = (object) ['path' => ['to' => ['resource' => 'value1']]]; + $patch = (object) ['op' => 'move', 'path' => '/path/to/resource', 'from' => '/path1/from/resource']; + $this->Operation->apply($document, $patch); + } + + public function testApplyWithPatchObjectHavingNonExistentFrom(): void + { + $this->expectException(UnknownPathException::class); + $document = (object) ['path' => ['to' => ['resource' => 'value1']]]; + $patch = (object) ['op' => 'move', 'path' => '/path/to/resource', 'from' => '/invalid/from/path']; + $this->Operation->apply($document, $patch); + } + + public function testGetRevertPatch(): void + { + $patch = (object) ['op' => 'move', 'path' => '/path/to/resource', 'from' => '/path/from/resource']; + $revertedPatch = $this->Operation->getRevertPatch($patch); + $expectedRevertedPatch = ['op' => 'move', 'from' => '/path/to/resource', 'path' => '/path/from/resource']; + $this->assertEquals($expectedRevertedPatch, $revertedPatch); + } +} diff --git a/tests/operations/RemoveTest.php b/tests/operations/RemoveTest.php new file mode 100644 index 0000000..8af97ba --- /dev/null +++ b/tests/operations/RemoveTest.php @@ -0,0 +1,95 @@ +Operation = new Remove(); + $this->Operation->setJsonHandler(new BasicJsonHandler); + } + + public function testGetOperation(): void + { + $this->assertSame('remove', $this->Operation->getOperation()); + } + + public function testValidateMethodWithValidPatch(): void + { + $validPatch = (object) ['op' => 'remove', 'path' => '/test/path']; + $this->Operation->validate($validPatch); + $this->expectNotToPerformAssertions(); + } + + public function testApply(): void + { + $document = ['fruit' => 'apple', 'color' => 'red']; + $patch = (object) ['op' => 'remove', 'path' => '/color']; + $this->Operation->apply($document, $patch); + $this->assertSame(['fruit' => 'apple'], $document); + } + + public function testApplyWithNonExistingKey(): void + { + $this->expectException(UnknownPathException::class); + $document = ['fruit' => 'apple', 'color' => 'red']; + $patch = (object) ['op' => 'remove', 'path' => '/nope']; + $this->Operation->apply($document, $patch); + } + + public function testGetRevertPatchWithPreviousValue(): void + { + $document = ['fruit' => 'apple', 'color' => 'red']; + $patch = (object) ['op' => 'remove', 'path' => '/color']; + $this->Operation->apply($document, $patch); + $revertPatch = $this->Operation->getRevertPatch($patch); + $this->assertSame(['op' => 'add', 'path' => '/color', 'value' => 'red'], $revertPatch); + } + + public function testGetRevertPatchWithoutPreviousValue(): void + { + $document = ['fruit' => 'apple', 'color' => 'red']; + $patch = (object) ['op' => 'remove', 'path' => '/flavour']; + $this->expectException(UnknownPathException::class); + $this->Operation->apply($document, $patch); + } +} diff --git a/tests/operations/ReplaceTest.php b/tests/operations/ReplaceTest.php new file mode 100644 index 0000000..1751095 --- /dev/null +++ b/tests/operations/ReplaceTest.php @@ -0,0 +1,121 @@ +Operation = new Replace(); + $this->Operation->setJsonHandler(new BasicJsonHandler); + } + + public function testGetOperation(): void + { + $this->assertSame('replace', $this->Operation->getOperation()); + } + + public function testValidPatch(): void + { + $this->expectNotToPerformAssertions(); + $patch = (object) ['op' => 'replace', 'path' => '/valid/path', 'value' => 'valid value']; + $this->Operation->validate($patch); + } + + public function testInvalidPatchThrowsException(): void + { + $this->expectException(InvalidPatchValueException::class); + + /** @var object{op:string, path: string, value: mixed} $patch */ + $patch = (object) [ + 'op' => 'replace', + 'path' => '/valid/path', + // value is missing + ]; + $this->Operation->validate($patch); + } + + public function testApplyToAssociativeDocumentWithValidReplacePatch(): void + { + $document = ['simpleKey' => 'simpleValue']; + $patch = (object) ['op' => 'replace', 'path' => '/simpleKey', 'value' => 'changedValue']; + $this->Operation->apply($document, $patch); + $this->assertSame('changedValue', $document['simpleKey']); + } + + public function testApplyToObjectDocumentWithValidReplacePatch(): void + { + $document = (object) ['simpleKey' => 'simpleValue']; + $patch = (object) ['op' => 'replace', 'path' => '/simpleKey', 'value' => 'changedValue']; + $this->Operation->apply($document, $patch); + $this->assertSame('changedValue', $document->simpleKey); + } + + public function testApplyWithInvalidPathThrowsException(): void + { + $this->expectException(UnknownPathException::class); + $document = [ + 'simpleKey' => 'simpleValue', + ]; + $patch = (object) ['op' => 'replace', 'path' => '/unknown/path', 'value' => 'valueToReplace']; + $this->Operation->apply($document, $patch); + } + + public function testGetRevertPatch(): void + { + $document = (object) ['simpleKey' => 'simpleValue']; + $patch = (object) ['op' => 'replace', 'path' => '/simpleKey', 'value' => 'changedValue']; + $this->Operation->apply($document, $patch); + $revertedPatch = $this->Operation->getRevertPatch($patch); + $this->assertSame(['op' => 'replace', 'path' => '/simpleKey', 'value' => 'simpleValue'], $revertedPatch); + } + + public function testGetRevertPatchWithNullPreviousValue(): void + { + $document = (object) ['simpleKey' => null]; + $patch = (object) ['op' => 'replace', 'path' => '/simpleKey', 'value' => 'changedValue']; + $this->Operation->apply($document, $patch); + $revertedPatch = $this->Operation->getRevertPatch($patch); + $this->assertSame(['op' => 'replace', 'path' => '/simpleKey', 'value' => null], $revertedPatch); + } +} diff --git a/tests/operations/TestTest.php b/tests/operations/TestTest.php new file mode 100644 index 0000000..f3cc433 --- /dev/null +++ b/tests/operations/TestTest.php @@ -0,0 +1,146 @@ +Operation = new Test(); + $this->Operation->setJsonHandler(new BasicJsonHandler); + } + + public function testGetOperation(): void + { + $this->assertSame('test', $this->Operation->getOperation()); + } + + public function testValidateSuccess(): void + { + $this->expectNotToPerformAssertions(); + $patch = (object) ['op' => 'test', 'path' => '/path/to/test', 'value' => 'test_value']; + $this->Operation->validate($patch); + } + + public function testValidateFailure(): void + { + $this->expectException(InvalidPatchValueException::class); + /** @var object{op:string, path: string, value: mixed} $patch */ + $patch = (object) [ + 'op' => 'test', + 'path' => '/path/to/test', /* no value */ + ]; + $this->Operation->validate($patch); + } + + public function testApplySuccessOnAssociativeDocument(): void + { + $this->expectNotToPerformAssertions(); + $document = ['path' => ['to' => ['test' => 'test_value']]]; + $patch = (object) ['op' => 'test', 'path' => '/path/to/test', 'value' => 'test_value']; + $this->Operation->apply($document, $patch); + } + + public function testApplySuccessOnObjectDocument(): void + { + $this->expectNotToPerformAssertions(); + $document = (object) ['path' => (object) ['to' => (object) ['test' => 'test_value']]]; + $patch = (object) ['op' => 'test', 'path' => '/path/to/test', 'value' => 'test_value']; + $this->Operation->apply($document, $patch); + } + + public function testApplySuccessWithNullValue(): void + { + $this->expectNotToPerformAssertions(); + $document = ['path' => ['to' => ['test' => null]]]; + $patch = (object) ['op' => 'test', 'path' => '/path/to/test', 'value' => null]; + $this->Operation->apply($document, $patch); + } + + public function testApplySuccessWithFalseValue(): void + { + $this->expectNotToPerformAssertions(); + $document = ['path' => ['to' => ['test' => false]]]; + $patch = (object) ['op' => 'test', 'path' => '/path/to/test', 'value' => false]; + $this->Operation->apply($document, $patch); + } + + public function testApplySuccessWithArrayValue(): void + { + $this->expectNotToPerformAssertions(); + $document = ['path' => ['to' => ['test' => 'value']]]; + $patch = (object) ['op' => 'test', 'path' => '/path', 'value' => ['to' => ['test' => 'value']]]; + $this->Operation->apply($document, $patch); + } + + public function testApplySuccessWithObjectValue(): void + { + $this->expectNotToPerformAssertions(); + $document = (object) ['path' => (object) ['to' => (object) ['test' => 'value']]]; + $patch = (object) ['op' => 'test', 'path' => '/path', 'value' => (object) ['to' => (object) ['test' => 'value']]]; + $this->Operation->apply($document, $patch); + } + + public function testApplyFailureDueToInvalidPath(): void + { + $this->expectException(UnknownPathException::class); + $document = 'wrong_test_value'; + $patch = (object) ['op' => 'test', 'path' => '/path/to/test', 'value' => 'test_value']; + $this->Operation->apply($document, $patch); + } + + public function testApplyFailureDueToUnexpectedValue(): void + { + $this->expectException(FailedTestException::class); + $document = ['path' => ['to' => ['test' => null]]]; + $patch = (object) ['op' => 'test', 'path' => '/path/to/test', 'value' => 'test_value']; + $this->Operation->apply($document, $patch); + } + + public function testGetRevertPatch(): void + { + $patch = (object) ['op' => 'test', 'path' => '/path/to/test', 'value' => 'test_value']; + $this->assertNull($this->Operation->getRevertPatch($patch)); + } +}