diff --git a/tests/api/conftest.py b/tests/api/conftest.py index c15b58fc6ee34fe384a2e0135272420eaff7eaf5..ce4f0d78fb444982a5c87a93b492bb52fcb120cc 100644 --- a/tests/api/conftest.py +++ b/tests/api/conftest.py @@ -20,8 +20,7 @@ from collections.abc import Generator import pytest import pytest_asyncio -from blacksheep import Application -from blacksheep import Request +from blacksheep import Application, Request from blacksheep.testing import TestClient from vigenere_api.api import application diff --git a/tests/api/helpers/__init__.py b/tests/api/helpers/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..bf8de0773dc8411127d6bbaa8262a9194c6fc4c0 --- /dev/null +++ b/tests/api/helpers/__init__.py @@ -0,0 +1,15 @@ +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# Vigenere-API + +# Copyright (C) 2023 Axel DAVID + +# + +# This program is free software: you can redistribute it and/or modify it under + +# the terms of the GNU General Public License as published by the Free Software + +# Foundation, either version 3 of the License, or (at your option) any later version. + +# + +# This program is distributed in the hope that it will be useful, but WITHOUT ANY + +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +# + +# You should have received a copy of the GNU General Public License along with + +# this program. If not, see <https://www.gnu.org/licenses/>. + +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/tests/api/helpers/test_controller.py b/tests/api/helpers/test_controller.py new file mode 100644 index 0000000000000000000000000000000000000000..0cb7857275817abc4279381b0dfa96b66ee84e62 --- /dev/null +++ b/tests/api/helpers/test_controller.py @@ -0,0 +1,93 @@ +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# Vigenere-API + +# Copyright (C) 2023 Axel DAVID + +# + +# This program is free software: you can redistribute it and/or modify it under + +# the terms of the GNU General Public License as published by the Free Software + +# Foundation, either version 3 of the License, or (at your option) any later version. + +# + +# This program is distributed in the hope that it will be useful, but WITHOUT ANY + +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +# + +# You should have received a copy of the GNU General Public License along with + +# this program. If not, see <https://www.gnu.org/licenses/>. + +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +import pytest +from blacksheep.server.controllers import APIController + +from vigenere_api.api.helpers.controller import _camel_to_kebab, Controller +from vigenere_api.api.helpers.errors import NameTypeError + + +class CamelCaseToKebabCaseSuite: + @staticmethod + def test_camelcase() -> None: + converted = _camel_to_kebab("Camel") + assert converted == "camel" + + converted = _camel_to_kebab("CamelCase") + assert converted == "camel-case" + + @staticmethod + def test_kebab() -> None: + converted = _camel_to_kebab("camel-case") + assert converted == "camel-case" + + @staticmethod + def test_snake_case() -> None: + converted = _camel_to_kebab("tedede_test") + assert converted == "tedede_test" + + @staticmethod + @pytest.mark.raises(excpetion=NameTypeError) + def test_bad_type_name() -> None: + _ignored = _camel_to_kebab(b"tedede") + + +class ControllerSuite: + @staticmethod + def test_instantiate() -> None: + controller = Controller() + assert controller is not None + assert isinstance(controller, Controller) + assert isinstance(controller, APIController) + + @staticmethod + def test_class_name() -> None: + assert Controller.__name__ == "Controller" + + assert Controller.class_name() == "" + + @staticmethod + def test_inheritance_with_basic_name() -> None: + class Test(Controller): + pass + + test = Test() + + assert isinstance(test, Controller) + assert isinstance(test, APIController) + assert test.class_name() == "test" + + @staticmethod + def test_inheritance_with_controller_name() -> None: + class TestController(Controller): + pass + + test = TestController() + + assert isinstance(test, Controller) + assert isinstance(test, APIController) + assert test.class_name() == "test" + + @staticmethod + def test_inheritance_with_complex_controller_name() -> None: + class ComplexTestController(Controller): + pass + + test = ComplexTestController() + + assert isinstance(test, Controller) + assert isinstance(test, APIController) + assert test.class_name() == "complex-test" diff --git a/tests/api/test_open_api_handler.py b/tests/api/helpers/test_open_api_handler.py similarity index 64% rename from tests/api/test_open_api_handler.py rename to tests/api/helpers/test_open_api_handler.py index f86b2de80a8c04fb07ef111729c65eedc32bebb1..d9437ce6ccf37d630125822cc18077d586d2555f 100644 --- a/tests/api/test_open_api_handler.py +++ b/tests/api/helpers/test_open_api_handler.py @@ -14,54 +14,38 @@ # this program. If not, see <https://www.gnu.org/licenses/>. + # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +import pytest + from openapidocs.common import Format -from openapidocs.v3 import Contact -from openapidocs.v3 import ExternalDocs -from openapidocs.v3 import Info -from openapidocs.v3 import License -from openapidocs.v3 import Tag +from openapidocs.v3 import ExternalDocs, Tag from vigenere_api.api import application -from vigenere_api.api.utils import VigenereAPIOpenAPIHandler +from vigenere_api.api.helpers import VigenereAPIOpenAPIHandler +from vigenere_api.api.helpers.errors import VersionTypeError +from vigenere_api.version import Version def basic_test() -> None: - docs = VigenereAPIOpenAPIHandler( - info=Info( - title="Vigenere-API", - version="1.0.0", - description=""" - An API to use cipher, decipher and decrypt method with the Vigenere algorithm. - The Caesar algorithm is provided for the cipher method and decipher method. + docs = VigenereAPIOpenAPIHandler(Version(major=1, minor=0, patch=0)) - It's a JSON-RPC API. - Powered by BlackSheep framework: https://www.neoteroi.dev/blacksheep/ - """, - contact=Contact(name="Axel DAVID", email="axel.david@etu.univ-amu.fr"), - license=License(name="GPL-3.0", url="TEST/LICENSE.md"), - ), - ui_path="/api/v1", - preferred_format=Format.YAML, - ) + assert docs.version == Version(major=1, minor=0, patch=0) info = docs.info assert info.title == "Vigenere-API" assert info.version == "1.0.0" - assert info.description == ( - "\n" - " An API to use cipher, decipher and decrypt method with the " - "Vigenere algorithm.\n" - " The Caesar algorithm is provided for the cipher method and " - "decipher method.\n" - "\n" - " It's a JSON-RPC API.\n" - " Powered by BlackSheep framework: " - "https://www.neoteroi.dev/blacksheep/\n" - " " + assert ( + info.description + == """ + An API to use cipher, decipher and decrypt method with the Vigenere algorithm. + The Caesar algorithm is provided for the cipher method and decipher method. + + It's a JSON-RPC API. + Powered by BlackSheep framework: https://www.neoteroi.dev/blacksheep/ + """ ) assert info.contact.name == "Axel DAVID" assert info.contact.email == "axel.david@etu.univ-amu.fr" assert info.license.name == "GPL-3.0" - assert info.license.url == "TEST/LICENSE.md" + assert info.license.url == "http://localhost:8080/LICENSE.md" assert docs.ui_providers[0].ui_path == "/api/v1" @@ -88,3 +72,8 @@ def basic_test() -> None: ), ), ] + + +@pytest.mark.raises(exception=VersionTypeError) +def test_bad_type_version() -> None: + _ignored = VigenereAPIOpenAPIHandler(b"toto") diff --git a/tests/api/helpers/test_open_api_route_filter.py b/tests/api/helpers/test_open_api_route_filter.py new file mode 100644 index 0000000000000000000000000000000000000000..398875c96f9eb2c678a0addcc1a39629e766d1d6 --- /dev/null +++ b/tests/api/helpers/test_open_api_route_filter.py @@ -0,0 +1,75 @@ +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# Vigenere-API + +# Copyright (C) 2023 Axel DAVID + +# + +# This program is free software: you can redistribute it and/or modify it under + +# the terms of the GNU General Public License as published by the Free Software + +# Foundation, either version 3 of the License, or (at your option) any later version. + +# + +# This program is distributed in the hope that it will be useful, but WITHOUT ANY + +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +# + +# You should have received a copy of the GNU General Public License along with + +# this program. If not, see <https://www.gnu.org/licenses/>. + +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +from inspect import signature + +import pytest +from blacksheep import Route + +from vigenere_api.api.helpers.errors import ( + ExcludedPathsTypeError, + ExcludedPathTypeError, + PathTypeError, +) +from vigenere_api.api.helpers.open_api_route_filter import get_route_filter + + +def test_get_filter() -> None: + excluded = [] + filter = get_route_filter(excluded) + + assert callable(filter) + s = signature(filter) + + assert s.return_annotation == bool + + parameters_type = list(s.parameters.values()) + + assert len(parameters_type) == 2 + assert parameters_type[0].annotation == str + assert parameters_type[1].annotation == Route + + +@pytest.mark.raises(exception=ExcludedPathsTypeError) +def test_bad_type_excluded() -> None: + excluded = 10 + _ignored = get_route_filter(excluded) + + +@pytest.mark.raises(exception=ExcludedPathTypeError) +def test_bad_type_path_in_excluded() -> None: + excluded = [b"test"] + _ignored = get_route_filter(excluded) + + +@pytest.mark.raises(exception=PathTypeError) +def test_filter_bad_type_path() -> None: + route_filter = get_route_filter(["/api"]) + _ignored = route_filter(b"/http", Route("http", {})) + + +def test_filter_bad_type_route() -> None: + route_filter = get_route_filter(["/api"]) + assert route_filter("/http", {}) + + +def test_filter_route_excluded() -> None: + route_filter = get_route_filter(["/api"]) + assert not route_filter("/api", Route("http", {})) + + +def test_filter_route_not_excluded() -> None: + route_filter = get_route_filter(["/api"]) + assert route_filter("/http", Route("http", {})) diff --git a/tests/api/test_index.py b/tests/api/test_index.py index 90ccf12180aa6885904dc9969ecd738f900db872..74f4522cbd7fe5a1921724e455a46dc9b723a0f7 100644 --- a/tests/api/test_index.py +++ b/tests/api/test_index.py @@ -31,3 +31,16 @@ async def test_get_index(test_client: TestClient) -> None: first_header = response.headers.values[0] assert first_header[0] == b"Location" assert first_header[1] == b"/api/v1" + + +@pytest.mark.asyncio() +async def test_bad_path(test_client: TestClient) -> None: + response = await test_client.get("/zzzzzzzzzz") + + assert response is not None + + assert response.status == 200 + assert response.content is not None + assert response.reason.upper() == "OK" + + assert await response.text() == "OOPS! Nothing was found here!" diff --git a/tests/api/v1/docs/test_caesar.py b/tests/api/v1/docs/test_caesar.py index b99670f46df7d768dfa925cb96e59d98f6c1ad72..da998664ffbffc7c74b9765501c7a6f23cc8ff1d 100644 --- a/tests/api/v1/docs/test_caesar.py +++ b/tests/api/v1/docs/test_caesar.py @@ -16,15 +16,19 @@ from http import HTTPStatus -from blacksheep.server.openapi.common import ContentInfo -from blacksheep.server.openapi.common import RequestBodyInfo -from blacksheep.server.openapi.common import ResponseExample -from blacksheep.server.openapi.common import ResponseInfo +from blacksheep.server.openapi.common import ( + ContentInfo, + RequestBodyInfo, + ResponseExample, + ResponseInfo, +) -from vigenere_api.api.v1.controllers.docs.caesar import CAESAR_DATA1 -from vigenere_api.api.v1.controllers.docs.caesar import CAESAR_DATA2 -from vigenere_api.api.v1.controllers.docs.caesar import CaesarControllerDocs -from vigenere_api.api.v1.controllers.docs.caesar import CaesarOperation +from vigenere_api.api.v1.controllers.caesar.docs import ( + CAESAR_DATA1, + CAESAR_DATA2, + CaesarControllerDocs, + CaesarOperation, +) from vigenere_api.models import CaesarData diff --git a/tests/api/v1/test_api.py b/tests/api/v1/test_api.py index 151c9561bc8d4210a110306a1077adccf12b8954..686fcf4dafd6dcde578bfaa93877a4677634d1a4 100644 --- a/tests/api/v1/test_api.py +++ b/tests/api/v1/test_api.py @@ -25,10 +25,6 @@ async def test_get_api_docs(test_client: TestClient) -> None: assert response.status == 200 assert response.content is not None - assert ( - response.content.body - == b'<!DOCTYPE html>\n<html>\n<head>\n <title>Vigenere-API</title>\n <link rel="icon" href="/favicon.png"/>\n <link type="text/css" rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@3.30.0/swagger-ui.css">\n</head>\n<body>\n <div id="swagger-ui"></div>\n <script src="https://cdn.jsdelivr.net/npm/swagger-ui-dist@3.30.0/swagger-ui-bundle.js"></script>\n <script>\n const ui = SwaggerUIBundle({\n url: \'/openapi.yaml\',\n oauth2RedirectUrl: window.location.origin + \'/docs/oauth2-redirect\',\n dom_id: \'#swagger-ui\',\n presets: [\n SwaggerUIBundle.presets.apis,\n SwaggerUIBundle.SwaggerUIStandalonePreset\n ],\n layout: "BaseLayout",\n deepLinking: true,\n showExtensions: true,\n showCommonExtensions: true\n })\n </script>\n</body>\n</html>\n' - ) assert response.reason.upper() == "OK" @@ -40,8 +36,4 @@ async def test_get_api_redocs(test_client: TestClient) -> None: assert response.status == 200 assert response.content is not None - assert ( - response.content.body - == b'<!DOCTYPE html>\n<html>\n <head>\n <title>Vigenere-API</title>\n <meta charset="utf-8"/>\n <meta name="viewport" content="width=device-width, initial-scale=1">\n <link rel="icon" href="/favicon.png"/>\n <link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">\n <style>\n body {\n margin: 0;\n padding: 0;\n }\n </style>\n </head>\n <body>\n <redoc spec-url="/openapi.yaml"></redoc>\n <script src="https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js"> </script>\n </body>\n</html>\n' - ) assert response.reason.upper() == "OK" diff --git a/tests/helpers/__init__.py b/tests/helpers/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..bf8de0773dc8411127d6bbaa8262a9194c6fc4c0 --- /dev/null +++ b/tests/helpers/__init__.py @@ -0,0 +1,15 @@ +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# Vigenere-API + +# Copyright (C) 2023 Axel DAVID + +# + +# This program is free software: you can redistribute it and/or modify it under + +# the terms of the GNU General Public License as published by the Free Software + +# Foundation, either version 3 of the License, or (at your option) any later version. + +# + +# This program is distributed in the hope that it will be useful, but WITHOUT ANY + +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +# + +# You should have received a copy of the GNU General Public License along with + +# this program. If not, see <https://www.gnu.org/licenses/>. + +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/tests/helpers/test_errors.py b/tests/helpers/test_errors.py new file mode 100644 index 0000000000000000000000000000000000000000..6fc5348e214eee69c180d2b1ccd592608e5d66bd --- /dev/null +++ b/tests/helpers/test_errors.py @@ -0,0 +1,26 @@ +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# Vigenere-API + +# Copyright (C) 2023 Axel DAVID + +# + +# This program is free software: you can redistribute it and/or modify it under + +# the terms of the GNU General Public License as published by the Free Software + +# Foundation, either version 3 of the License, or (at your option) any later version. + +# + +# This program is distributed in the hope that it will be useful, but WITHOUT ANY + +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +# + +# You should have received a copy of the GNU General Public License along with + +# this program. If not, see <https://www.gnu.org/licenses/>. + +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +import pytest + +from vigenere_api.helpers import VigenereAPITypeError + + +@pytest.mark.raises( + exception=VigenereAPITypeError, message="The text is 'str'. Please give a bytes." +) +def test_throws_VigenereAPITypeError() -> None: + raise VigenereAPITypeError("test", "text", "a bytes") diff --git a/tests/helpers/test_model.py b/tests/helpers/test_model.py new file mode 100644 index 0000000000000000000000000000000000000000..aacd8bd9b44f98024b46fe671269a73ff4c7608c --- /dev/null +++ b/tests/helpers/test_model.py @@ -0,0 +1,44 @@ +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# Vigenere-API + +# Copyright (C) 2023 Axel DAVID + +# + +# This program is free software: you can redistribute it and/or modify it under + +# the terms of the GNU General Public License as published by the Free Software + +# Foundation, either version 3 of the License, or (at your option) any later version. + +# + +# This program is distributed in the hope that it will be useful, but WITHOUT ANY + +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +# + +# You should have received a copy of the GNU General Public License along with + +# this program. If not, see <https://www.gnu.org/licenses/>. + +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +from vigenere_api.helpers import Model + + +def test_instantiate() -> None: + obj = Model() + + assert obj is not None + + +class InheritanceSuite: + @staticmethod + def test_basic() -> None: + class Test(Model): + pass + + obj = Test() + + assert obj is not None + assert obj == Model() + + @staticmethod + def test_with_new_field() -> None: + class Test(Model): + test: str + + obj = Test(test="TEST") + + assert obj is not None + assert obj.test == "TEST" diff --git a/tests/integration/api/test_index.py b/tests/integration/api/test_index.py index 6ffebf9d5dfcb074a2db8dc3eed00207a98f182f..3a2f38ddb4fe89231aca5ea32cf2a1ab1676f478 100644 --- a/tests/integration/api/test_index.py +++ b/tests/integration/api/test_index.py @@ -34,3 +34,20 @@ def test_get_index(server: str) -> None: assert response.next is not None assert response.next.path_url == "/api/v1" + + +@pytest.mark.integration_test() +def test_bad_path(server: str) -> None: + response = requests.get( + url=f"{server}/zzzzzzzzzz", + timeout=1, + allow_redirects=False, + ) + + assert response is not None + + assert response.status == 200 + assert response.content is not None + assert response.reason.upper() == "OK" + + assert response.text == "OOPS! Nothing was found here!" diff --git a/tests/models/test_caesar.py b/tests/models/test_caesar.py index 637311ee55323d7b191c707116ffa11525bb5915..1ae2967ded88306f42225637395d415522f69805 100644 --- a/tests/models/test_caesar.py +++ b/tests/models/test_caesar.py @@ -20,8 +20,7 @@ import pytest from pydantic import ValidationError from vigenere_api.models.caesar import CaesarData -from vigenere_api.models.errors import AlgorithmKeyTypeError -from vigenere_api.models.errors import AlgorithmTextTypeError +from vigenere_api.models.errors import AlgorithmKeyTypeError, AlgorithmTextTypeError class CtorSuite: diff --git a/tests/models/test_helper.py b/tests/models/test_helper.py index bc48b2c99d36fdedd90eb1f2ead605d43d2f6129..d1f30f7de7b4733a305a4a74fdb819eab2917e85 100644 --- a/tests/models/test_helper.py +++ b/tests/models/test_helper.py @@ -18,13 +18,15 @@ import pytest -from vigenere_api.models.helper import move_char -from vigenere_api.models.helper.errors import HelperBadCharValueError -from vigenere_api.models.helper.errors import HelperBadFirstLetterValueError -from vigenere_api.models.helper.errors import HelperBadLengthCharValueError -from vigenere_api.models.helper.errors import HelperCharTypeError -from vigenere_api.models.helper.errors import HelperFirstLetterTypeError -from vigenere_api.models.helper.errors import HelperKeyTypeError +from vigenere_api.models.helpers import move_char +from vigenere_api.models.helpers.errors import ( + HelperBadCharValueError, + HelperBadFirstLetterValueError, + HelperBadLengthCharValueError, + HelperCharTypeError, + HelperFirstLetterTypeError, + HelperKeyTypeError, +) def test_move_lower_letter() -> None: diff --git a/tests/version/__init__.py b/tests/version/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..bf8de0773dc8411127d6bbaa8262a9194c6fc4c0 --- /dev/null +++ b/tests/version/__init__.py @@ -0,0 +1,15 @@ +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# Vigenere-API + +# Copyright (C) 2023 Axel DAVID + +# + +# This program is free software: you can redistribute it and/or modify it under + +# the terms of the GNU General Public License as published by the Free Software + +# Foundation, either version 3 of the License, or (at your option) any later version. + +# + +# This program is distributed in the hope that it will be useful, but WITHOUT ANY + +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +# + +# You should have received a copy of the GNU General Public License along with + +# this program. If not, see <https://www.gnu.org/licenses/>. + +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/tests/version/test_version.py b/tests/version/test_version.py new file mode 100644 index 0000000000000000000000000000000000000000..35bafec88b3ce74ed5bf41fe43eabaf1dfd2b7a7 --- /dev/null +++ b/tests/version/test_version.py @@ -0,0 +1,129 @@ +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# Vigenere-API + +# Copyright (C) 2023 Axel DAVID + +# + +# This program is free software: you can redistribute it and/or modify it under + +# the terms of the GNU General Public License as published by the Free Software + +# Foundation, either version 3 of the License, or (at your option) any later version. + +# + +# This program is distributed in the hope that it will be useful, but WITHOUT ANY + +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +# + +# You should have received a copy of the GNU General Public License along with + +# this program. If not, see <https://www.gnu.org/licenses/>. + +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +import pytest +from pydantic import ValidationError + +from vigenere_api.version import get_version, Version + + +class CtorSuite: + @staticmethod + def test_ctor() -> None: + v = Version(major=1, minor=0, patch=0) + + assert v.major == 1 + assert v.minor == 0 + assert v.patch == 0 + + class MissingFieldsSuite: + @staticmethod + @pytest.mark.raises(exception=ValidationError, message="major") + def test_without_major() -> None: + _ignored = Version(minor=0, patch=0) + + @staticmethod + @pytest.mark.raises(exception=ValidationError, message="minor") + def test_without_minor() -> None: + _ignored = Version(major=0, patch=0) + + @staticmethod + @pytest.mark.raises(exception=ValidationError, message="patch") + def test_without_patch() -> None: + _ignored = Version(minor=0, major=0) + + @staticmethod + def test_with_only_patch() -> None: + with pytest.raises(ValidationError) as error: + _ignored = Version(patch=0) + + error_msg = str(error) + assert "minor" in error_msg + assert "major" in error_msg + + @staticmethod + def test_with_only_minor() -> None: + with pytest.raises(ValidationError) as error: + _ignored = Version(minor=0) + + error_msg = str(error) + assert "patch" in error_msg + assert "major" in error_msg + + @staticmethod + def test_with_only_manor() -> None: + with pytest.raises(ValidationError) as error: + _ignored = Version(major=0) + + error_msg = str(error) + assert "minor" in error_msg + assert "patch" in error_msg + + @staticmethod + def test_with_nothing() -> None: + with pytest.raises(ValidationError) as error: + _ignored = Version() + + error = error.value.args[0] + assert "major" in error[0]._loc + assert "minor" in error[1]._loc + assert "patch" in error[2]._loc + + class BadTypeSuite: + @staticmethod + @pytest.mark.raises(exception=ValidationError, message="major") + def test_major() -> None: + _ignored = Version(major=1.0, minor=0, patch=0) + + @staticmethod + @pytest.mark.raises(exception=ValidationError, message="minor") + def test_minor() -> None: + _ignored = Version(major=1, minor=0.0, patch=0) + + @staticmethod + @pytest.mark.raises(exception=ValidationError, message="patch") + def test_patch() -> None: + _ignored = Version(major=1, minor=0, patch=0.0) + + class BadValueSuite: + @staticmethod + @pytest.mark.raises(exception=ValidationError, message="major") + def test_major() -> None: + _ignored = Version(major=-10, minor=0, patch=0) + + @staticmethod + @pytest.mark.raises(exception=ValidationError, message="minor") + def test_minor() -> None: + _ignored = Version(major=1, minor=-8, patch=0) + + @staticmethod + @pytest.mark.raises(exception=ValidationError, message="patch") + def test_patch() -> None: + _ignored = Version(major=1, minor=0, patch=-9) + + +class OperationSuite: + @staticmethod + def test_str() -> None: + v = Version(major=1, minor=0, patch=0) + + assert str(v) == "1.0.0" + + +def test_get_version() -> None: + v = get_version() + + assert isinstance(v, Version) + assert v == Version(major=1, minor=0, patch=0)