diff --git a/src/SDK/Language/Python.php b/src/SDK/Language/Python.php index c8d19e639..2e1b63acd 100644 --- a/src/SDK/Language/Python.php +++ b/src/SDK/Language/Python.php @@ -124,6 +124,11 @@ public function getFiles(): array 'destination' => '{{ spec.title | caseSnake}}/__init__.py', 'template' => 'python/package/__init__.py.twig', ], + [ + 'scope' => 'default', + 'destination' => 'test/__init__.py', + 'template' => 'python/test/__init__.py.twig', + ], [ 'scope' => 'default', 'destination' => '{{ spec.title | caseSnake}}/client.py', @@ -134,21 +139,41 @@ public function getFiles(): array 'destination' => '{{ spec.title | caseSnake}}/permission.py', 'template' => 'python/package/permission.py.twig', ], + [ + 'scope' => 'default', + 'destination' => 'test/test_permission.py', + 'template' => 'python/test/test_permission.py.twig', + ], [ 'scope' => 'default', 'destination' => '{{ spec.title | caseSnake}}/role.py', 'template' => 'python/package/role.py.twig', ], + [ + 'scope' => 'default', + 'destination' => 'test/test_role.py', + 'template' => 'python/test/test_role.py.twig', + ], [ 'scope' => 'default', 'destination' => '{{ spec.title | caseSnake}}/id.py', 'template' => 'python/package/id.py.twig', ], + [ + 'scope' => 'default', + 'destination' => 'test/test_id.py', + 'template' => 'python/test/test_id.py.twig', + ], [ 'scope' => 'default', 'destination' => '{{ spec.title | caseSnake}}/query.py', 'template' => 'python/package/query.py.twig', ], + [ + 'scope' => 'default', + 'destination' => 'test/test_query.py', + 'template' => 'python/test/test_query.py.twig', + ], [ 'scope' => 'default', 'destination' => '{{ spec.title | caseSnake}}/exception.py', @@ -169,11 +194,21 @@ public function getFiles(): array 'destination' => '{{ spec.title | caseSnake}}/services/__init__.py', 'template' => 'python/package/services/__init__.py.twig', ], + [ + 'scope' => 'default', + 'destination' => 'test/services/__init__.py', + 'template' => 'python/test/services/__init__.py.twig', + ], [ 'scope' => 'service', 'destination' => '{{ spec.title | caseSnake}}/services/{{service.name | caseSnake}}.py', 'template' => 'python/package/services/service.py.twig', ], + [ + 'scope' => 'service', + 'destination' => 'test/services/test_{{service.name | caseSnake}}.py', + 'template' => 'python/test/services/test_service.py.twig', + ], [ 'scope' => 'method', 'destination' => 'docs/examples/{{service.name | caseLower}}/{{method.name | caseDash}}.md', diff --git a/templates/python/requirements.txt.twig b/templates/python/requirements.txt.twig index 2c24336eb..4e6362d89 100644 --- a/templates/python/requirements.txt.twig +++ b/templates/python/requirements.txt.twig @@ -1 +1,2 @@ requests==2.31.0 +requests_mock==1.11.0 diff --git a/templates/python/test/__init__.py.twig b/templates/python/test/__init__.py.twig new file mode 100644 index 000000000..e69de29bb diff --git a/templates/python/test/services/__init__.py.twig b/templates/python/test/services/__init__.py.twig new file mode 100644 index 000000000..e69de29bb diff --git a/templates/python/test/services/test_service.py.twig b/templates/python/test/services/test_service.py.twig new file mode 100644 index 000000000..174a3e4e3 --- /dev/null +++ b/templates/python/test/services/test_service.py.twig @@ -0,0 +1,43 @@ +import json +import requests_mock +import unittest + +from appwrite.client import Client +from appwrite.input_file import InputFile +from appwrite.services.{{ service.name | caseSnake }} import {{ service.name | caseUcfirst }} + + +class {{ service.name | caseUcfirst }}ServiceTest(unittest.TestCase): + + def setUp(self): + self.client = Client() + self.{{ service.name | caseSnake }} = {{ service.name | caseUcfirst }}(self.client) + +{% for method in service.methods %} + @requests_mock.Mocker() + def test_{{ method.name | caseSnake }}(self, m): + {%~ if method.type == 'webAuth' %} + data = '' + {%~ elseif method.type == 'location' %} + data = bytearray() + {%~ else %} + {%~ if method.responseModel and method.responseModel != 'any' %} + data = { + {%- for definition in spec.definitions ~%}{%~ if definition.name == method.responseModel -%}{%~ for property in definition.properties | filter((param) => param.required) ~%} + '{{property.name}}': {% if property.type == 'object' %}{}{% elseif property.type == '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 ~%} + } + {%~ else %} + data = '' + {%~ endif %} + {%~ endif %} + headers = {'Content-Type': {% if method.type == 'location' %}'application/octet-stream'{% else %}'application/json'{% endif %}} + m.request(requests_mock.ANY, requests_mock.ANY, {% if method.type == 'location' %}body=data{% else %}text=json.dumps(data){% endif %}, headers=headers) + + response = self.{{ service.name | caseSnake }}.{{ method.name | caseSnake }}({%~ for parameter in method.parameters.all | filter((param) => param.required) ~%} + {% if parameter.type == 'object' %}{}{% elseif parameter.type == 'array' %}[]{% elseif parameter.type == 'file' %}InputFile.from_bytes(bytearray()){% 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 ~%} + ) + + self.assertEqual(response, data) + +{% endfor %} diff --git a/templates/python/test/test_id.py.twig b/templates/python/test/test_id.py.twig new file mode 100644 index 000000000..33cc818b5 --- /dev/null +++ b/templates/python/test/test_id.py.twig @@ -0,0 +1,12 @@ +import unittest + +from appwrite.id import ID + + +class TestIDMethods(unittest.TestCase): + + def test_unique(self): + self.assertEqual(ID.unique(), 'unique()') + + def test_custom(self): + self.assertEqual(ID.custom('custom'), 'custom') diff --git a/templates/python/test/test_permission.py.twig b/templates/python/test/test_permission.py.twig new file mode 100644 index 000000000..ca5ed83a7 --- /dev/null +++ b/templates/python/test/test_permission.py.twig @@ -0,0 +1,22 @@ +import unittest + +from appwrite.permission import Permission +from appwrite.role import Role + + +class TestPermissionMethods(unittest.TestCase): + + def test_read(self): + self.assertEqual(Permission.read(Role.any()), 'read("any")') + + def test_write(self): + self.assertEqual(Permission.write(Role.any()), 'write("any")') + + def test_create(self): + self.assertEqual(Permission.create(Role.any()), 'create("any")') + + def test_update(self): + self.assertEqual(Permission.update(Role.any()), 'update("any")') + + def test_delete(self): + self.assertEqual(Permission.delete(Role.any()), 'delete("any")') diff --git a/templates/python/test/test_query.py.twig b/templates/python/test/test_query.py.twig new file mode 100644 index 000000000..b558fa059 --- /dev/null +++ b/templates/python/test/test_query.py.twig @@ -0,0 +1,110 @@ +import unittest + +from appwrite.query import Query + + +class BasicFilterQueryTest: + def __init__(self, description: str, value, expected_values: str): + self.description = description + self.value = value + self.expected_values = expected_values + + +tests = [ + BasicFilterQueryTest('with a string', 's', '["s"]'), + BasicFilterQueryTest('with an integer', 1, '[1]'), + BasicFilterQueryTest('with a double', 1.2, '[1.2]'), + BasicFilterQueryTest('with a whole number double', 1.0, '[1.0]'), + BasicFilterQueryTest('with a bool', False, '[false]'), + BasicFilterQueryTest('with a list', ['a', 'b', 'c'], '["a","b","c"]'), +] + + +class TestQueryMethods(unittest.TestCase): + + def test_equal(self): + for t in tests: + self.assertEqual( + Query.equal('attr', t.value), + f'equal("attr", {t.expected_values})', + t.description + ) + + def test_not_equal(self): + for t in tests: + self.assertEqual( + Query.not_equal('attr', t.value), + f'notEqual("attr", {t.expected_values})', + t.description + ) + + def test_less_than(self): + for t in tests: + self.assertEqual( + Query.less_than('attr', t.value), + f'lessThan("attr", {t.expected_values})', + t.description + ) + + def test_less_than_equal(self): + for t in tests: + self.assertEqual( + Query.less_than_equal('attr', t.value), + f'lessThanEqual("attr", {t.expected_values})', + t.description + ) + + def test_greater_than(self): + for t in tests: + self.assertEqual( + Query.greater_than('attr', t.value), + f'greaterThan("attr", {t.expected_values})', + t.description + ) + + def test_greater_than_equal(self): + for t in tests: + self.assertEqual( + Query.greater_than_equal('attr', t.value), + f'greaterThanEqual("attr", {t.expected_values})', + t.description + ) + + def test_search(self): + self.assertEqual(Query.search('attr', 'keyword1 keyword2'), 'search("attr", ["keyword1 keyword2"])') + + def test_is_null(self): + self.assertEqual(Query.is_null('attr'), 'isNull("attr")') + + def test_is_not_null(self): + self.assertEqual(Query.is_not_null('attr'), 'isNotNull("attr")') + + def test_between_with_integers(self): + self.assertEqual(Query.between('attr', 1, 2), 'between("attr", 1, 2)') + + def test_between_with_doubles(self): + self.assertEqual(Query.between('attr', 1.0, 2.0), 'between("attr", 1.0, 2.0)') + + def test_between_with_strings(self): + self.assertEqual(Query.between('attr', 'a', 'z'), 'between("attr", "a" "z")') + + def test_select(self): + self.assertEqual(Query.select(['attr1', 'attr2']), 'select(["attr1","attr2"])') + + def test_order_asc(self): + self.assertEqual(Query.order_asc('attr'), 'orderAsc("attr")') + + def test_order_desc(self): + self.assertEqual(Query.order_desc('attr'), 'orderDesc("attr")') + + def test_cursor_before(self): + self.assertEqual(Query.cursor_before('custom'), 'cursorBefore("custom")') + + def test_cursor_after(self): + self.assertEqual(Query.cursor_after('custom'), 'cursorAfter("custom")') + + def test_limit(self): + self.assertEqual(Query.limit(1), 'limit(1)') + + def test_offset(self): + self.assertEqual(Query.offset(1), 'offset(1)') diff --git a/templates/python/test/test_role.py.twig b/templates/python/test/test_role.py.twig new file mode 100644 index 000000000..f78a9ebc4 --- /dev/null +++ b/templates/python/test/test_role.py.twig @@ -0,0 +1,36 @@ +import unittest + +from appwrite.role import Role + + +class TestRoleMethods(unittest.TestCase): + + def test_any(self): + self.assertEqual(Role.any(), 'any') + + def test_user_without_status(self): + self.assertEqual(Role.user('custom'), 'user:custom') + + def test_user_with_status(self): + self.assertEqual(Role.user('custom', 'verified'), 'user:custom/verified') + + def test_users_without_status(self): + self.assertEqual(Role.users(), 'users') + + def test_users_with_status(self): + self.assertEqual(Role.users('verified'), 'users/verified') + + def test_guests(self): + self.assertEqual(Role.guests(), 'guests') + + def test_team_without_role(self): + self.assertEqual(Role.team('custom'), 'team:custom') + + def test_team_with_role(self): + self.assertEqual(Role.team('custom', 'owner'), 'team:custom/owner') + + def test_member(self): + self.assertEqual(Role.member('custom'), 'member:custom') + + def test_label(self): + self.assertEqual(Role.label('admin'), 'label:admin')