From eb848a783af304011e8ea9a2e28655e340e2f4b5 Mon Sep 17 00:00:00 2001 From: geisterfurz007 Date: Sun, 29 Oct 2023 17:00:41 +0100 Subject: [PATCH 1/3] feat: php unit tests --- src/SDK/Language/PHP.php | 25 +++ templates/php/composer.json.twig | 3 +- templates/php/tests/IDTest.php.twig | 15 ++ templates/php/tests/PermissionTest.php.twig | 27 ++++ templates/php/tests/QueryTest.php.twig | 149 ++++++++++++++++++ templates/php/tests/RoleTest.php.twig | 47 ++++++ .../php/tests/Services/ServiceTest.php.twig | 44 ++++++ 7 files changed, 309 insertions(+), 1 deletion(-) create mode 100644 templates/php/tests/IDTest.php.twig create mode 100644 templates/php/tests/PermissionTest.php.twig create mode 100644 templates/php/tests/QueryTest.php.twig create mode 100644 templates/php/tests/RoleTest.php.twig create mode 100644 templates/php/tests/Services/ServiceTest.php.twig diff --git a/src/SDK/Language/PHP.php b/src/SDK/Language/PHP.php index 99ad8740e..035621534 100644 --- a/src/SDK/Language/PHP.php +++ b/src/SDK/Language/PHP.php @@ -177,21 +177,41 @@ public function getFiles(): array 'destination' => 'src/{{ spec.title | caseUcfirst}}/Permission.php', 'template' => 'php/src/Permission.php.twig', ], + [ + 'scope' => 'default', + 'destination' => 'tests/{{ spec.title | caseUcfirst}}/PermissionTest.php', + 'template' => 'php/tests/PermissionTest.php.twig', + ], [ 'scope' => 'default', 'destination' => 'src/{{ spec.title | caseUcfirst}}/Role.php', 'template' => 'php/src/Role.php.twig', ], + [ + 'scope' => 'default', + 'destination' => 'tests/{{ spec.title | caseUcfirst}}/RoleTest.php', + 'template' => 'php/tests/RoleTest.php.twig', + ], [ 'scope' => 'default', 'destination' => 'src/{{ spec.title | caseUcfirst}}/ID.php', 'template' => 'php/src/ID.php.twig', ], + [ + 'scope' => 'default', + 'destination' => 'tests/{{ spec.title | caseUcfirst}}/IDTest.php', + 'template' => 'php/tests/IDTest.php.twig', + ], [ 'scope' => 'default', 'destination' => 'src/{{ spec.title | caseUcfirst}}/Query.php', 'template' => 'php/src/Query.php.twig', ], + [ + 'scope' => 'default', + 'destination' => 'tests/{{ spec.title | caseUcfirst}}/QueryTest.php', + 'template' => 'php/tests/QueryTest.php.twig', + ], [ 'scope' => 'default', 'destination' => 'src/{{ spec.title | caseUcfirst}}/InputFile.php', @@ -212,6 +232,11 @@ public function getFiles(): array 'destination' => '/src/{{ spec.title | caseUcfirst}}/Services/{{service.name | caseUcfirst}}.php', 'template' => 'php/src/Services/Service.php.twig', ], + [ + 'scope' => 'service', + 'destination' => '/tests/{{ spec.title | caseUcfirst}}/Services/{{service.name | caseUcfirst}}Test.php', + 'template' => 'php/tests/Services/ServiceTest.php.twig', + ], ]; } diff --git a/templates/php/composer.json.twig b/templates/php/composer.json.twig index bf7288abe..d02b22973 100644 --- a/templates/php/composer.json.twig +++ b/templates/php/composer.json.twig @@ -18,7 +18,8 @@ "ext-json": "*" }, "require-dev": { - "phpunit/phpunit": "3.7.35" + "phpunit/phpunit": "^10", + "mockery/mockery": "^1.6.6" }, "minimum-stability": "dev" } \ No newline at end of file diff --git a/templates/php/tests/IDTest.php.twig b/templates/php/tests/IDTest.php.twig new file mode 100644 index 000000000..a48a6b5d8 --- /dev/null +++ b/templates/php/tests/IDTest.php.twig @@ -0,0 +1,15 @@ +assertSame('unique()', ID::unique()); + } + + public function testCustom(): void { + $this->assertSame('custom', ID::custom('custom')); + } +} diff --git a/templates/php/tests/PermissionTest.php.twig b/templates/php/tests/PermissionTest.php.twig new file mode 100644 index 000000000..cf4078407 --- /dev/null +++ b/templates/php/tests/PermissionTest.php.twig @@ -0,0 +1,27 @@ +assertSame('read("any")', Permission::read(Role::any())); + } + + public function testWrite(): void { + $this->assertSame('write("any")', Permission::write(Role::any())); + } + + public function testCreate(): void { + $this->assertSame('create("any")', Permission::create(Role::any())); + } + + public function testUpdate(): void { + $this->assertSame('update("any")', Permission::update(Role::any())); + } + + public function testDelete(): void { + $this->assertSame('delete("any")', Permission::delete(Role::any())); + } +} diff --git a/templates/php/tests/QueryTest.php.twig b/templates/php/tests/QueryTest.php.twig new file mode 100644 index 000000000..17e7c7195 --- /dev/null +++ b/templates/php/tests/QueryTest.php.twig @@ -0,0 +1,149 @@ +description = $description; + $this->value = $value; + $this->expectedValues = $expectedValues; + } +} + +final class QueryTest extends TestCase { + /** + * @var BasicFilterQueryTest[] $tests + */ + private array $tests; + + function __construct(string $name) + { + parent::__construct($name); + $this->tests = array( + new BasicFilterQueryTest('with a string', 's', '["s"]'), + new BasicFilterQueryTest('with a integer', 1, '[1]'), + new BasicFilterQueryTest('with a double', 1.2, '[1.2]'), + new BasicFilterQueryTest('with a whole number double', 1.0, '[1]'), + new BasicFilterQueryTest('with a bool', false, '[false]'), + new BasicFilterQueryTest('with a list', ['a', 'b', 'c'], '["a","b","c"]'), + ); + } + + public function testBasicFilterEqual(): void { + foreach($this->tests as $test) { + $this->assertSame( + "equal(\"attr\", $test->expectedValues)", + Query::equal('attr', $test->value), + $test->description, + ); + } + } + + public function testBasicFilterNotEqual(): void { + foreach($this->tests as $test) { + $this->assertSame( + "notEqual(\"attr\", $test->expectedValues)", + Query::notEqual('attr', $test->value), + $test->description, + ); + } + } + + public function testBasicFilterLessThan(): void { + foreach($this->tests as $test) { + $this->assertSame( + "lessThan(\"attr\", $test->expectedValues)", + Query::lessThan('attr', $test->value), + $test->description, + ); + } + } + + public function testBasicFilterLessThanEqual(): void { + foreach($this->tests as $test) { + $this->assertSame( + "lessThanEqual(\"attr\", $test->expectedValues)", + Query::lessThanEqual('attr', $test->value), + $test->description, + ); + } + } + + public function testBasicFilterGreaterThan(): void { + foreach($this->tests as $test) { + $this->assertSame( + "greaterThan(\"attr\", $test->expectedValues)", + Query::greaterThan('attr', $test->value), + $test->description, + ); + } + } + + public function testBasicFilterGreaterThanEqual(): void { + foreach($this->tests as $test) { + $this->assertSame( + "greaterThanEqual(\"attr\", $test->expectedValues)", + Query::greaterThanEqual('attr', $test->value), + $test->description, + ); + } + } + + public function testSearch(): void { + $this->assertSame('search("attr", ["keyword1 keyword2"])', Query::search('attr', 'keyword1 keyword2')); + } + + public function testIsNull(): void { + $this->assertSame('isNull("attr")', Query::isNull('attr')); + } + + public function testIsNotNull(): void { + $this->assertSame('isNotNull("attr")', Query::isNotNull('attr')); + } + + public function testBetweenWithIntegers(): void { + $this->assertSame('between("attr", [1,2])', Query::between('attr', 1, 2)); + } + + public function testBetweenWithDoubles(): void { + $this->assertSame('between("attr", [1,2])', Query::between('attr', 1.0, 2.0)); + } + + public function testBetweenWithStrings(): void { + $this->assertSame('between("attr", ["a","z"])', Query::between('attr', 'a', 'z')); + } + + public function testSelect(): void { + $this->assertSame('select(["attr1","attr2"])', Query::select(['attr1', 'attr2'])); + } + + public function testOrderAsc(): void { + $this->assertSame('orderAsc("attr")', Query::orderAsc('attr')); + } + + public function testOrderDesc(): void { + $this->assertSame('orderDesc("attr")', Query::orderDesc('attr')); + } + + public function testCursorBefore(): void { + $this->assertSame('cursorBefore("attr")', Query::cursorBefore('attr')); + } + + public function testCursorAfter(): void { + $this->assertSame('cursorAfter("attr")', Query::cursorAfter('attr')); + } + + public function testLimit(): void { + $this->assertSame('limit(1)', Query::limit(1)); + } + + public function testOffset(): void { + $this->assertSame('offset(1)', Query::offset(1)); + } +} diff --git a/templates/php/tests/RoleTest.php.twig b/templates/php/tests/RoleTest.php.twig new file mode 100644 index 000000000..9a800d54d --- /dev/null +++ b/templates/php/tests/RoleTest.php.twig @@ -0,0 +1,47 @@ +assertSame('any', Role::any()); + } + + public function testUserWithoutStatus(): void { + $this->assertSame('user:custom', Role::user('custom')); + } + + public function testUserWithStatus(): void { + $this->assertSame('user:custom/verified', Role::user('custom', 'verified')); + } + + public function testUsersWithoutStatus(): void { + $this->assertSame('users', Role::users()); + } + + public function testUsersWithStatus(): void { + $this->assertSame('users/verified', Role::users('verified')); + } + + public function testGuests(): void { + $this->assertSame('guests', Role::guests()); + } + + public function testTeamWithoutRole(): void { + $this->assertSame('team:custom', Role::team('custom')); + } + + public function testTeamWithRole(): void { + $this->assertSame('team:custom/owner', Role::team('custom', 'owner')); + } + + public function testMember(): void { + $this->assertSame('member:custom', Role::member('custom')); + } + + public function testLabel(): void { + $this->assertSame('label:admin', Role::label('admin')); + } +} diff --git a/templates/php/tests/Services/ServiceTest.php.twig b/templates/php/tests/Services/ServiceTest.php.twig new file mode 100644 index 000000000..04270d943 --- /dev/null +++ b/templates/php/tests/Services/ServiceTest.php.twig @@ -0,0 +1,44 @@ +client = Mockery::mock(Client::class); + $this->{{ service.name | caseCamel }} = new {{ service.name | caseUcfirst }}($this->client); + } + +{% for method in service.methods %} + public function testMethod{{method.name | caseUcfirst}}(): void { + {%~ if method.responseModel and method.responseModel != 'any' ~%} + $data = array( + {%- for definition in spec.definitions ~%}{%~ if definition.name == method.responseModel -%}{%~ for property in definition.properties | filter((param) => param.required) ~%} + "{{property.name | escapeDollarSign}}" => {% if property.type == 'object' %}array(){% elseif property.type == 'array' %}array(){% elseif property.type == 'string' %}"{{property.example | escapeDollarSign}}"{% elseif property.type == 'boolean' %}true{% else %}{{property.example}}{% endif %},{%~ endfor ~%}{% set break = true %}{%- else -%}{% set continue = true %}{%- endif -%}{%~ endfor -%} + ); + {%~ elseif (method.responseModel and method.responseModel == 'any') or method.type == 'webAuth' ~%} + $data = array(); + {%~ else ~%} + $data = ''; + {%~ endif ~%} + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + + $response = $this->{{service.name | caseCamel}}->{{method.name | caseCamel}}({%~ for parameter in method.parameters.all | filter((param) => param.required) ~%} + {{parameter.name | escapeKeyword | caseCamel}}: {% if parameter.type == 'object' %}array(){% elseif parameter.type == 'array' %}array(){% elseif parameter.type == 'file' %}InputFile::withData('', "image/png"){% elseif parameter.type == 'boolean' %}true{% elseif parameter.type == 'string' %}"{% if parameter.example is not empty %}{{parameter.example | escapeDollarSign}}{% endif %}"{% elseif parameter.type == 'integer' and parameter['x-example'] is empty %}1{% elseif parameter.type == 'number' and parameter['x-example'] is empty %}1.0{% else %}{{parameter.example}}{%~ endif ~%},{%~ endfor ~%} + ); + + $this->assertSame($data, $response); + } + +{% endfor %} +} From 99ee96ad415372ba5f0edfe4716fbf2095d6d15f Mon Sep 17 00:00:00 2001 From: geisterfurz007 Date: Tue, 31 Oct 2023 11:33:32 +0100 Subject: [PATCH 2/3] chore: align unit tests with PHP 7.1 --- templates/php/tests/QueryTest.php.twig | 8 ++++---- templates/php/tests/Services/ServiceTest.php.twig | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/templates/php/tests/QueryTest.php.twig b/templates/php/tests/QueryTest.php.twig index 17e7c7195..329a9412d 100644 --- a/templates/php/tests/QueryTest.php.twig +++ b/templates/php/tests/QueryTest.php.twig @@ -5,9 +5,9 @@ namespace Appwrite; use PHPUnit\Framework\TestCase; final class BasicFilterQueryTest { - public string $description; - public mixed $value; - public string $expectedValues; + public $description; + public $value; + public $expectedValues; public function __construct(string $description, mixed $value, string $expectedValues) { $this->description = $description; @@ -20,7 +20,7 @@ final class QueryTest extends TestCase { /** * @var BasicFilterQueryTest[] $tests */ - private array $tests; + private $tests; function __construct(string $name) { diff --git a/templates/php/tests/Services/ServiceTest.php.twig b/templates/php/tests/Services/ServiceTest.php.twig index 04270d943..6e31e9bf3 100644 --- a/templates/php/tests/Services/ServiceTest.php.twig +++ b/templates/php/tests/Services/ServiceTest.php.twig @@ -8,8 +8,8 @@ use Mockery; use PHPUnit\Framework\TestCase; final class {{service.name | caseUcfirst}}Test extends TestCase { - private Client $client; - private {{service.name | caseUcfirst}} ${{service.name | caseCamel}}; + private $client; + private ${{service.name | caseCamel}}; protected function setUp(): void { $this->client = Mockery::mock(Client::class); @@ -34,7 +34,7 @@ final class {{service.name | caseUcfirst}}Test extends TestCase { ->andReturn($data); $response = $this->{{service.name | caseCamel}}->{{method.name | caseCamel}}({%~ for parameter in method.parameters.all | filter((param) => param.required) ~%} - {{parameter.name | escapeKeyword | caseCamel}}: {% if parameter.type == 'object' %}array(){% elseif parameter.type == 'array' %}array(){% elseif parameter.type == 'file' %}InputFile::withData('', "image/png"){% elseif parameter.type == 'boolean' %}true{% elseif parameter.type == 'string' %}"{% if parameter.example is not empty %}{{parameter.example | escapeDollarSign}}{% endif %}"{% elseif parameter.type == 'integer' and parameter['x-example'] is empty %}1{% elseif parameter.type == 'number' and parameter['x-example'] is empty %}1.0{% else %}{{parameter.example}}{%~ endif ~%},{%~ endfor ~%} + {% if parameter.type == 'object' %}array(){% elseif parameter.type == 'array' %}array(){% elseif parameter.type == 'file' %}InputFile::withData('', "image/png"){% elseif parameter.type == 'boolean' %}true{% elseif parameter.type == 'string' %}"{% if parameter.example is not empty %}{{parameter.example | escapeDollarSign}}{% endif %}"{% elseif parameter.type == 'integer' and parameter['x-example'] is empty %}1{% elseif parameter.type == 'number' and parameter['x-example'] is empty %}1.0{% else %}{{parameter.example}}{%~ endif ~%}{% if not loop.last %},{% endif %}{%~ endfor ~%} ); $this->assertSame($data, $response); From b10525c40b76ad14df45aec83e20c57e5f2d1140 Mon Sep 17 00:00:00 2001 From: geisterfurz007 Date: Sun, 19 Nov 2023 16:39:08 +0100 Subject: [PATCH 3/3] fix: updated between serialization --- templates/php/tests/QueryTest.php.twig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/php/tests/QueryTest.php.twig b/templates/php/tests/QueryTest.php.twig index 329a9412d..900c7e429 100644 --- a/templates/php/tests/QueryTest.php.twig +++ b/templates/php/tests/QueryTest.php.twig @@ -108,15 +108,15 @@ final class QueryTest extends TestCase { } public function testBetweenWithIntegers(): void { - $this->assertSame('between("attr", [1,2])', Query::between('attr', 1, 2)); + $this->assertSame('between("attr", 1, 2)', Query::between('attr', 1, 2)); } public function testBetweenWithDoubles(): void { - $this->assertSame('between("attr", [1,2])', Query::between('attr', 1.0, 2.0)); + $this->assertSame('between("attr", 1, 2)', Query::between('attr', 1.0, 2.0)); } public function testBetweenWithStrings(): void { - $this->assertSame('between("attr", ["a","z"])', Query::between('attr', 'a', 'z')); + $this->assertSame('between("attr", "a", "z")', Query::between('attr', 'a', 'z')); } public function testSelect(): void {