from datetime import datetime as dt from datetime import timezone import pytest from conftest import DB, Response from hircine.db.models import World @pytest.fixture def query_world(execute_id): query = """ query world($id: Int!) { world(id: $id) { __typename ... on World { id name } ... on Error { message } ... on IDNotFoundError { id } } } """ return execute_id(query) @pytest.fixture def query_worlds(execute): query = """ query worlds { worlds { __typename count edges { id name } } } """ return execute(query) @pytest.fixture def add_world(execute_add): mutation = """ mutation addWorld($input: AddWorldInput!) { addWorld(input: $input) { __typename ... on AddSuccess { id } ... on Error { message } ... on InvalidParameterError { parameter } } } """ return execute_add(mutation) @pytest.fixture def update_worlds(execute_update): mutation = """ mutation updateWorlds($ids: [Int!]!, $input: UpdateWorldInput!) { updateWorlds(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_worlds(execute_delete): mutation = """ mutation deleteWorlds($ids: [Int!]!) { deleteWorlds(ids: $ids) { __typename ... on Success { message } ... on Error { message } ... on IDNotFoundError { id } } } """ return execute_delete(mutation) @pytest.mark.anyio async def test_query_world(query_world, gen_world): world = await DB.add(next(gen_world)) response = Response(await query_world(world.id)) response.assert_is("World") assert response.id == world.id assert response.name == world.name @pytest.mark.anyio async def test_query_world_fails_not_found(query_world): response = Response(await query_world(1)) response.assert_is("IDNotFoundError") assert response.id == 1 assert response.message == "World ID not found: '1'" @pytest.mark.anyio async def test_query_worlds(query_worlds, gen_world): worlds = await DB.add_all(*gen_world) response = Response(await query_worlds()) response.assert_is("WorldFilterResult") assert response.count == len(worlds) assert isinstance((response.edges), list) assert len(response.edges) == len(worlds) edges = iter(response.edges) for world in sorted(worlds, key=lambda a: a.name): edge = next(edges) assert edge["id"] == world.id assert edge["name"] == world.name @pytest.mark.anyio async def test_add_world(add_world): response = Response(await add_world({"name": "added world"})) response.assert_is("AddSuccess") world = await DB.get(World, response.id) assert world is not None assert world.name == "added world" @pytest.mark.anyio async def test_add_world_fails_empty_parameter(add_world): response = Response(await add_world({"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_world_fails_exists(add_world, gen_world): world = await DB.add(next(gen_world)) response = Response(await add_world({"name": world.name})) response.assert_is("NameExistsError") assert response.message == "Another World with this name exists" @pytest.mark.anyio async def test_delete_world(delete_worlds, gen_world): world = await DB.add(next(gen_world)) id = world.id response = Response(await delete_worlds(id)) response.assert_is("DeleteSuccess") world = await DB.get(World, id) assert world is None @pytest.mark.anyio async def test_delete_world_not_found(delete_worlds): response = Response(await delete_worlds(1)) response.assert_is("IDNotFoundError") assert response.id == 1 assert response.message == "World ID not found: '1'" @pytest.mark.anyio async def test_update_world(update_worlds, gen_world): world = await DB.add(next(gen_world)) input = {"name": "updated world"} response = Response(await update_worlds(world.id, input)) response.assert_is("UpdateSuccess") world = await DB.get(World, world.id) assert world is not None assert world.name == "updated world" @pytest.mark.anyio async def test_update_world_fails_exists(update_worlds, gen_world): first = await DB.add(next(gen_world)) second = await DB.add(next(gen_world)) response = Response(await update_worlds(second.id, {"name": first.name})) response.assert_is("NameExistsError") assert response.message == "Another World with this name exists" @pytest.mark.anyio async def test_update_world_fails_not_found(update_worlds): response = Response(await update_worlds(1, {"name": "updated world"})) response.assert_is("IDNotFoundError") assert response.id == 1 assert response.message == "World ID not found: '1'" @pytest.mark.anyio async def test_update_worlds_cannot_bulk_edit_name(update_worlds, gen_world): first = await DB.add(next(gen_world)) second = await DB.add(next(gen_world)) response = Response(await update_worlds([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_world_fails_empty_parameter(update_worlds, gen_world, empty): world = await DB.add(next(gen_world)) response = Response(await update_worlds(world.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_world_changes_updated_at(update_worlds): original_world = World(name="world") original_world.updated_at = dt(2023, 1, 1, tzinfo=timezone.utc) original_world = await DB.add(original_world) response = Response(await update_worlds(original_world.id, {"name": "updated"})) response.assert_is("UpdateSuccess") world = await DB.get(World, original_world.id) assert world.updated_at > original_world.updated_at