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