diff options
Diffstat (limited to 'tests/api/test_character.py')
-rw-r--r-- | tests/api/test_character.py | 285 |
1 files changed, 285 insertions, 0 deletions
diff --git a/tests/api/test_character.py b/tests/api/test_character.py new file mode 100644 index 0000000..567d2a4 --- /dev/null +++ b/tests/api/test_character.py @@ -0,0 +1,285 @@ +from datetime import datetime as dt +from datetime import timezone + +import pytest +from conftest import DB, Response +from hircine.db.models import Character + + +@pytest.fixture +def query_character(execute_id): + query = """ + query character($id: Int!) { + character(id: $id) { + __typename + ... on Character { + id + name + } + ... on Error { + message + } + ... on IDNotFoundError { + id + } + } + } + """ + + return execute_id(query) + + +@pytest.fixture +def query_characters(execute): + query = """ + query characters { + characters { + __typename + count + edges { + id + name + } + } + } + """ + + return execute(query) + + +@pytest.fixture +def add_character(execute_add): + mutation = """ + mutation addCharacter($input: AddCharacterInput!) { + addCharacter(input: $input) { + __typename + ... on AddSuccess { + id + } + ... on Error { + message + } + ... on InvalidParameterError { + parameter + } + } + } + """ + + return execute_add(mutation) + + +@pytest.fixture +def update_characters(execute_update): + mutation = """ + mutation updateCharacters($ids: [Int!]!, $input: UpdateCharacterInput!) { + updateCharacters(ids: $ids, input: $input) { + __typename + ... on Success { + message + } + ... on Error { + message + } + ... on IDNotFoundError { + id + } + ... on InvalidParameterError { + parameter + } + } + } + """ # noqa: E501 + + return execute_update(mutation) + + +@pytest.fixture +def delete_characters(execute_delete): + mutation = """ + mutation deleteCharacters($ids: [Int!]!) { + deleteCharacters(ids: $ids) { + __typename + ... on Success { + message + } + ... on Error { + message + } + ... on IDNotFoundError { + id + } + } + } + """ + + return execute_delete(mutation) + + +@pytest.mark.anyio +async def test_query_character(query_character, gen_character): + character = await DB.add(next(gen_character)) + + response = Response(await query_character(character.id)) + response.assert_is("Character") + + assert response.id == character.id + assert response.name == character.name + + +@pytest.mark.anyio +async def test_query_character_fails_not_found(query_character): + response = Response(await query_character(1)) + response.assert_is("IDNotFoundError") + assert response.id == 1 + assert response.message == "Character ID not found: '1'" + + +@pytest.mark.anyio +async def test_query_characters(query_characters, gen_character): + characters = await DB.add_all(*gen_character) + + response = Response(await query_characters()) + response.assert_is("CharacterFilterResult") + + assert response.count == len(characters) + assert isinstance((response.edges), list) + assert len(response.edges) == len(characters) + + edges = iter(response.edges) + for character in sorted(characters, key=lambda a: a.name): + edge = next(edges) + assert edge["id"] == character.id + assert edge["name"] == character.name + + +@pytest.mark.anyio +async def test_add_character(add_character): + response = Response(await add_character({"name": "added character"})) + response.assert_is("AddSuccess") + + character = await DB.get(Character, response.id) + assert character is not None + assert character.name == "added character" + + +@pytest.mark.anyio +async def test_add_character_fails_empty_parameter(add_character): + response = Response(await add_character({"name": ""})) + + response.assert_is("InvalidParameterError") + assert response.parameter == "name" + assert response.message == "Invalid parameter 'name': cannot be empty" + + +@pytest.mark.anyio +async def test_add_character_fails_exists(add_character, gen_character): + character = await DB.add(next(gen_character)) + + response = Response(await add_character({"name": character.name})) + response.assert_is("NameExistsError") + assert response.message == "Another Character with this name exists" + + +@pytest.mark.anyio +async def test_delete_character(delete_characters, gen_character): + character = await DB.add(next(gen_character)) + id = character.id + + response = Response(await delete_characters(id)) + response.assert_is("DeleteSuccess") + + character = await DB.get(Character, id) + assert character is None + + +@pytest.mark.anyio +async def test_delete_character_not_found(delete_characters): + response = Response(await delete_characters(1)) + + response.assert_is("IDNotFoundError") + assert response.id == 1 + assert response.message == "Character ID not found: '1'" + + +@pytest.mark.anyio +async def test_update_character(update_characters, gen_character): + character = await DB.add(next(gen_character)) + + input = {"name": "updated character"} + response = Response(await update_characters(character.id, input)) + response.assert_is("UpdateSuccess") + + character = await DB.get(Character, character.id) + assert character is not None + assert character.name == "updated character" + + +@pytest.mark.anyio +async def test_update_character_fails_exists(update_characters, gen_character): + first = await DB.add(next(gen_character)) + second = await DB.add(next(gen_character)) + + response = Response(await update_characters(second.id, {"name": first.name})) + response.assert_is("NameExistsError") + assert response.message == "Another Character with this name exists" + + +@pytest.mark.anyio +async def test_update_character_fails_not_found(update_characters): + response = Response(await update_characters(1, {"name": "updated_character"})) + + response.assert_is("IDNotFoundError") + assert response.id == 1 + assert response.message == "Character ID not found: '1'" + + +@pytest.mark.anyio +async def test_update_characters_cannot_bulk_edit_name( + update_characters, gen_character +): + first = await DB.add(next(gen_character)) + second = await DB.add(next(gen_character)) + + response = Response( + await update_characters([first.id, second.id], {"name": "unique"}) + ) + response.assert_is("InvalidParameterError") + + +@pytest.mark.parametrize( + "empty", + [ + None, + "", + ], + ids=[ + "none", + "empty string", + ], +) +@pytest.mark.anyio +async def test_update_character_fails_empty_parameter( + update_characters, gen_character, empty +): + character = await DB.add(next(gen_character)) + response = Response(await update_characters(character.id, {"name": empty})) + + response.assert_is("InvalidParameterError") + assert response.parameter == "name" + assert response.message == "Invalid parameter 'name': cannot be empty" + + +@pytest.mark.anyio +async def test_update_character_changes_updated_at(update_characters): + original_character = Character(name="character") + original_character.updated_at = dt(2023, 1, 1, tzinfo=timezone.utc) + original_character = await DB.add(original_character) + + response = Response( + await update_characters(original_character.id, {"name": "updated"}) + ) + response.assert_is("UpdateSuccess") + + character = await DB.get(Character, original_character.id) + assert character.updated_at > original_character.updated_at |