diff --git a/amanuensis/backend/article.py b/amanuensis/backend/article.py index 53e82af..973c123 100644 --- a/amanuensis/backend/article.py +++ b/amanuensis/backend/article.py @@ -2,13 +2,20 @@ Article query interface """ +from typing import Optional + from sqlalchemy import select from amanuensis.db import * from amanuensis.errors import ArgumentError -def create(db: DbContext, lexicon_id: int, user_id: int, character_id: int) -> Article: +def create( + db: DbContext, + lexicon_id: int, + user_id: int, + character_id: Optional[int], +) -> Article: """ Create a new article in a lexicon. """ diff --git a/amanuensis/backend/character.py b/amanuensis/backend/character.py index bedda1f..1b87b3b 100644 --- a/amanuensis/backend/character.py +++ b/amanuensis/backend/character.py @@ -2,6 +2,8 @@ Character query interface """ +from typing import Optional + from sqlalchemy import select, func from amanuensis.db import * @@ -9,7 +11,11 @@ from amanuensis.errors import ArgumentError def create( - db: DbContext, lexicon_id: int, user_id: int, name: str, signature: str + db: DbContext, + lexicon_id: int, + user_id: int, + name: str, + signature: Optional[str], ) -> Character: """ Create a new character for a user. diff --git a/amanuensis/backend/lexicon.py b/amanuensis/backend/lexicon.py index 925f5e9..18bbe84 100644 --- a/amanuensis/backend/lexicon.py +++ b/amanuensis/backend/lexicon.py @@ -13,7 +13,12 @@ from amanuensis.errors import ArgumentError RE_ALPHANUM_DASH_UNDER = re.compile(r"^[A-Za-z0-9-_]*$") -def create(db: DbContext, name: str, title: str, prompt: str) -> Lexicon: +def create( + db: DbContext, + name: str, + title: str, + prompt: str, +) -> Lexicon: """ Create a new lexicon. """ diff --git a/amanuensis/backend/membership.py b/amanuensis/backend/membership.py index 511b138..7440353 100644 --- a/amanuensis/backend/membership.py +++ b/amanuensis/backend/membership.py @@ -8,7 +8,12 @@ from amanuensis.db import DbContext, Membership from amanuensis.errors import ArgumentError -def create(db: DbContext, user_id: int, lexicon_id: int, is_editor: bool) -> Membership: +def create( + db: DbContext, + user_id: int, + lexicon_id: int, + is_editor: bool, +) -> Membership: """ Create a new user membership in a lexicon. """ diff --git a/amanuensis/backend/post.py b/amanuensis/backend/post.py index 53161b4..3544b90 100644 --- a/amanuensis/backend/post.py +++ b/amanuensis/backend/post.py @@ -10,7 +10,12 @@ from amanuensis.db import DbContext, Post from amanuensis.errors import ArgumentError -def create(db: DbContext, lexicon_id: int, user_id: int, body: str) -> Post: +def create( + db: DbContext, + lexicon_id: int, + user_id: int, + body: str, +) -> Post: """ Create a new post """ diff --git a/tests/conftest.py b/tests/conftest.py index 68c8f78..a93b93c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -11,7 +11,7 @@ import amanuensis.backend.user as userq @pytest.fixture -def db(): +def db() -> DbContext: """Provides an initialized database in memory.""" db = DbContext("sqlite:///:memory:", debug=False) db.create_all() diff --git a/tests/test_article.py b/tests/test_article.py index 8b7b6cf..b19a088 100644 --- a/tests/test_article.py +++ b/tests/test_article.py @@ -1,6 +1,7 @@ import pytest from amanuensis.db import DbContext +from amanuensis.db.models import Character, Lexicon, User import amanuensis.backend.article as artiq from amanuensis.errors import ArgumentError @@ -9,18 +10,18 @@ from amanuensis.errors import ArgumentError def test_create_article(db: DbContext, make): """Test new article creation""" # Create two users in a shared lexicon - user1 = make.user() - user2 = make.user() - lexicon1 = make.lexicon() + user1: User = make.user() + user2: User = make.user() + lexicon1: Lexicon = make.lexicon() make.membership(user_id=user1.id, lexicon_id=lexicon1.id) make.membership(user_id=user2.id, lexicon_id=lexicon1.id) - char1_1 = make.character(lexicon_id=lexicon1.id, user_id=user1.id) - char1_2 = make.character(lexicon_id=lexicon1.id, user_id=user2.id) + char1_1: Character = make.character(lexicon_id=lexicon1.id, user_id=user1.id) + char1_2: Character = make.character(lexicon_id=lexicon1.id, user_id=user2.id) # Create a lexicon that only one user is in - lexicon2 = make.lexicon() + lexicon2: Lexicon = make.lexicon() make.membership(user_id=user2.id, lexicon_id=lexicon2.id) - char2_2 = make.character(lexicon_id=lexicon2.id, user_id=user2.id) + char2_2: Character = make.character(lexicon_id=lexicon2.id, user_id=user2.id) # User cannot create article for another user's character with pytest.raises(ArgumentError): diff --git a/tests/test_character.py b/tests/test_character.py index 55f33b1..dc50302 100644 --- a/tests/test_character.py +++ b/tests/test_character.py @@ -7,35 +7,44 @@ from amanuensis.errors import ArgumentError def test_create_character(db: DbContext, lexicon_with_editor, make): """Test creating a character.""" + lexicon: Lexicon + user: User lexicon, user = lexicon_with_editor - kwargs = { + defaults: dict = { "db": db, "user_id": user.id, "lexicon_id": lexicon.id, "name": "Character Name", "signature": "Signature", } + kwargs: dict # Bad argument types with pytest.raises(ArgumentError): - charq.create(**{**kwargs, "name": b"bytestring"}) + kwargs = {**defaults, "name": b"bytestring"} + charq.create(**kwargs) with pytest.raises(ArgumentError): - charq.create(**{**kwargs, "name": None}) + kwargs = {**defaults, "name": None} + charq.create(**kwargs) with pytest.raises(ArgumentError): - charq.create(**{**kwargs, "signature": b"bytestring"}) + kwargs = {**defaults, "signature": b"bytestring"} + charq.create(**kwargs) # Bad character name with pytest.raises(ArgumentError): - charq.create(**{**kwargs, "name": " "}) + kwargs = {**defaults, "name": " "} + charq.create(**kwargs) # Signature is auto-populated - char = charq.create(**{**kwargs, "signature": None}) + kwargs = {**defaults, "signature": None} + char = charq.create(**kwargs) assert char.signature is not None # User must be in lexicon - new_user = make.user() + new_user: User = make.user() with pytest.raises(ArgumentError): - charq.create(**{**kwargs, "user_id": new_user.id}) + kwargs = {**defaults, "user_id": new_user.id} + charq.create(**kwargs) def test_character_limits(db: DbContext, lexicon_with_editor): @@ -47,12 +56,14 @@ def test_character_limits(db: DbContext, lexicon_with_editor): # Set character limit to one and create a character lexicon.character_limit = 1 db.session.commit() - char1 = charq.create(db, lexicon.id, user.id, "Test Character 1", signature=None) + char1: Character = charq.create( + db, lexicon.id, user.id, "Test Character 1", signature=None + ) assert char1.id, "Failed to create character 1" # Creating a second character should fail with pytest.raises(ArgumentError): - char2 = charq.create( + char2: Character = charq.create( db, lexicon.id, user.id, "Test Character 2", signature=None ) assert char2 @@ -65,7 +76,7 @@ def test_character_limits(db: DbContext, lexicon_with_editor): # Creating a third character should fail with pytest.raises(ArgumentError): - char3 = charq.create( + char3: Character = charq.create( db, lexicon.id, user.id, "Test Character 3", signature=None ) assert char3 diff --git a/tests/test_lexicon.py b/tests/test_lexicon.py index 0af9546..9e1c400 100644 --- a/tests/test_lexicon.py +++ b/tests/test_lexicon.py @@ -1,3 +1,4 @@ +from amanuensis.db.models import Lexicon import datetime import pytest @@ -9,24 +10,37 @@ from amanuensis.errors import ArgumentError def test_create_lexicon(db: DbContext): """Test new game creation.""" - kwargs = {"name": "Test", "title": None, "prompt": "A test Lexicon game"} + defaults: dict = { + "db": db, + "name": "Test", + "title": None, + "prompt": "A test Lexicon game", + } + kwargs: dict + # Test name constraints with pytest.raises(ArgumentError): - lexiq.create(db, **{**kwargs, "name": None}) + kwargs = {**defaults, "name": None} + lexiq.create(**kwargs) with pytest.raises(ArgumentError): - lexiq.create(db, **{**kwargs, "name": ""}) + kwargs = {**defaults, "name": ""} + lexiq.create(**kwargs) with pytest.raises(ArgumentError): - lexiq.create(db, **{**kwargs, "name": " "}) + kwargs = {**defaults, "name": " "} + lexiq.create(**kwargs) with pytest.raises(ArgumentError): - lexiq.create(db, **{**kwargs, "name": ".."}) + kwargs = {**defaults, "name": ".."} + lexiq.create(**kwargs) with pytest.raises(ArgumentError): - lexiq.create(db, **{**kwargs, "name": "\x00"}) + kwargs = {**defaults, "name": "\x00"} + lexiq.create(**kwargs) with pytest.raises(ArgumentError): - lexiq.create(db, **{**kwargs, "name": "space in name"}) + kwargs = {**defaults, "name": "space in name"} + lexiq.create(**kwargs) # Validate that creation populates fields, including timestamps before = datetime.datetime.utcnow() - datetime.timedelta(seconds=1) - new_lexicon = lexiq.create(db, **kwargs) + new_lexicon: Lexicon = lexiq.create(**defaults) after = datetime.datetime.utcnow() + datetime.timedelta(seconds=1) assert new_lexicon assert new_lexicon.id is not None @@ -36,5 +50,4 @@ def test_create_lexicon(db: DbContext): # No duplicate lexicon names with pytest.raises(ArgumentError): - duplicate = lexiq.create(db, **kwargs) - assert duplicate + lexiq.create(**defaults) diff --git a/tests/test_membership.py b/tests/test_membership.py index a86c79e..45e70a1 100644 --- a/tests/test_membership.py +++ b/tests/test_membership.py @@ -10,13 +10,13 @@ import amanuensis.backend.membership as memq def test_create_membership(db: DbContext, make): """Test joining a game.""" # Set up a user and a lexicon - new_user = make.user() + new_user: User = make.user() assert new_user.id, "Failed to create user" - new_lexicon = make.lexicon() + new_lexicon: Lexicon = make.lexicon() assert new_lexicon.id, "Failed to create lexicon" # Add the user to the lexicon as an editor - mem = memq.create(db, new_user.id, new_lexicon.id, True) + mem: Membership = memq.create(db, new_user.id, new_lexicon.id, True) assert mem, "Failed to create membership" # Check that the user and lexicon are mutually visible in the ORM relationships @@ -24,7 +24,7 @@ def test_create_membership(db: DbContext, make): assert any(map(lambda mem: mem.user == new_user, new_lexicon.memberships)) # Check that the editor flag was set properly - editor = db( + editor: User = db( select(User) .join(User.memberships) .join(Membership.lexicon) @@ -37,5 +37,4 @@ def test_create_membership(db: DbContext, make): # Check that joining twice is not allowed with pytest.raises(ArgumentError): - mem2 = memq.create(db, new_user.id, new_lexicon.id, False) - assert mem2 + memq.create(db, new_user.id, new_lexicon.id, False) diff --git a/tests/test_post.py b/tests/test_post.py index bb0b61d..773b705 100644 --- a/tests/test_post.py +++ b/tests/test_post.py @@ -11,34 +11,47 @@ def test_create_post(db: DbContext, lexicon_with_editor): lexicon, editor = lexicon_with_editor # argument dictionary for post object - kwargs = {"lexicon_id": lexicon.id, "user_id": editor.id, "body": "body"} + defaults: dict = { + "db": db, + "lexicon_id": lexicon.id, + "user_id": editor.id, + "body": "body", + } + kwargs: dict # ids are integers with pytest.raises(ArgumentError): - postq.create(db, **{**kwargs, "user_id": "zero"}) + kwargs = {**defaults, "user_id": "zero"} + postq.create(**kwargs) with pytest.raises(ArgumentError): - postq.create(db, **{**kwargs, "lexicon_id": "zero"}) + kwargs = {**defaults, "lexicon_id": "zero"} + postq.create(**kwargs) # empty arguments don't work with pytest.raises(ArgumentError): - postq.create(db, **{**kwargs, "lexicon_id": ""}) + kwargs = {**defaults, "lexicon_id": ""} + postq.create(**kwargs) with pytest.raises(ArgumentError): - postq.create(db, **{**kwargs, "user_id": ""}) + kwargs = {**defaults, "user_id": ""} + postq.create(**kwargs) with pytest.raises(ArgumentError): - postq.create(db, **{**kwargs, "body": ""}) + kwargs = {**defaults, "body": ""} + postq.create(**kwargs) # post with only whitespace doesn't work with pytest.raises(ArgumentError): - postq.create(db, **{**kwargs, "body": " "}) + kwargs = {**defaults, "body": " "} + postq.create(**kwargs) # post creation works and populates fields - new_post = postq.create(db, **kwargs) + new_post = postq.create(**defaults) assert new_post assert new_post.lexicon_id is not None assert new_post.user_id is not None assert new_post.body is not None # post creation works when user is None - new_post = postq.create(db, **{**kwargs, "user_id": None}) + kwargs = {**defaults, "user_id": None} + new_post = postq.create(**kwargs) assert new_post assert new_post.user_id is None diff --git a/tests/test_user.py b/tests/test_user.py index 71b483a..f1e8b76 100644 --- a/tests/test_user.py +++ b/tests/test_user.py @@ -1,3 +1,4 @@ +from amanuensis.db.models import User import pytest from amanuensis.db import DbContext @@ -7,39 +8,45 @@ from amanuensis.errors import ArgumentError def test_create_user(db: DbContext): """Test new user creation.""" - kwargs = { + defaults: dict = { + "db": db, "username": "username", "password": "password", "display_name": "User Name", "email": "user@example.com", "is_site_admin": False, } + kwargs: dict # Test length constraints with pytest.raises(ArgumentError): - userq.create(db, **{**kwargs, "username": "me"}) + kwargs = {**defaults, "username": "me"} + userq.create(**kwargs) with pytest.raises(ArgumentError): - userq.create( - db, **{**kwargs, "username": "the right honorable user-name, esquire"} - ) + kwargs = {**defaults, "username": "the right honorable user-name, esquire"} + userq.create(**kwargs) + # Test allowed characters with pytest.raises(ArgumentError): - userq.create(db, **{**kwargs, "username": "user name"}) + kwargs = {**defaults, "username": "user name"} + userq.create(**kwargs) + # No password with pytest.raises(ArgumentError): - userq.create(db, **{**kwargs, "password": None}) + kwargs = {**defaults, "password": None} + userq.create(**kwargs) # Valid creation works and populates fields - new_user = userq.create(db, **kwargs) + new_user = userq.create(**defaults) assert new_user assert new_user.id is not None assert new_user.created is not None # No duplicate usernames with pytest.raises(ArgumentError): - duplicate = userq.create(db, **kwargs) + userq.create(**defaults) # Missing display name populates with username - user2_kw = {**kwargs, "username": "user2", "display_name": None} - user2 = userq.create(db, **user2_kw) + user2_kw: dict = {**defaults, "username": "user2", "display_name": None} + user2: User = userq.create(**user2_kw) assert user2.display_name is not None