Compare commits

..

No commits in common. "fe73b03bf3f3fef8776fb22072cb5ac946ee336c" and "de1122442b5e7cbb1fffe809c419e60be5be79e6" have entirely different histories.

7 changed files with 27 additions and 72 deletions

View file

@ -1,11 +0,0 @@
from pytest import Config
def pytest_configure(config: Config):
"""
Registers a new mark 'final' that can be applied to tests.
I did not want to add these in pyproject.toml.
"""
config.addinivalue_line("markers", "final: the final test")

View file

@ -41,9 +41,6 @@ update-deps:
# Run tests, ARGS are passed-through to pytest # Run tests, ARGS are passed-through to pytest
test *ARGS: test *ARGS:
uv run pytest tests.py -m "not final" {{ ARGS }}
alltests *ARGS:
uv run pytest tests.py {{ ARGS }} uv run pytest tests.py {{ ARGS }}
# run tests and create coverage reports # run tests and create coverage reports

View file

@ -3,7 +3,6 @@
DATABASE_URL = "sqlite:///database.db" DATABASE_URL = "sqlite:///database.db"
[tools] [tools]
difftastic = "latest"
markdownlint-cli2 = "latest" markdownlint-cli2 = "latest"
prek = "latest" prek = "latest"
python = "3.14" python = "3.14"

View file

@ -64,7 +64,6 @@ omit = ["tests.py"]
source_dirs = ["src/"] source_dirs = ["src/"]
[tool.pytest] [tool.pytest]
# custom marks are created in conftest.py
asyncio_mode = "auto" asyncio_mode = "auto"
[tool.ruff] [tool.ruff]

View file

@ -21,7 +21,7 @@ class TeilchenCreate(SQLModel):
class Teilchen(TeilchenCreate, table=True): class Teilchen(TeilchenCreate, table=True):
id: uuid.UUID = Field(default_factory=uuid.uuid7, primary_key=True) id: uuid.UUID = Field(default_factory=uuid.uuid7, primary_key=True) # ty:ignore[unresolved-attribute]
async def make_teilchen_input(text: str) -> TeilchenCreate | None: async def make_teilchen_input(text: str) -> TeilchenCreate | None:
@ -59,7 +59,7 @@ async def make_teilchen_input(text: str) -> TeilchenCreate | None:
description_start = text.find('"', name_end + 1) description_start = text.find('"', name_end + 1)
description_end = text.find('"', description_start + 1) description_end = text.find('"', description_start + 1)
if description_end > description_start: if description_end > description_start:
description = text[description_start + 1 : description_end] description = text[description_start:description_end]
else: else:
description = "" description = ""

View file

@ -1,3 +1,4 @@
from typing import TypedDict
import pytest import pytest
import logging import logging
@ -6,14 +7,23 @@ from teilchensammler_cli.models import TeilchenCreate, make_teilchen_input
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@pytest.mark.final # don't run while we are fiddling with the app
def test_initial_layout(snap_compare): def test_initial_layout(snap_compare):
from teilchensammler_cli.main import app from teilchensammler_cli.main import app
assert snap_compare(app, terminal_size=(130, 40)) assert snap_compare(app, terminal_size=(130, 40))
empty_teilchen = { class Teilchen(TypedDict):
"""The things I do for my LSP..."""
name: str
description: str
tags: str
text: str
number: int
empty_teilchen: Teilchen = {
"name": "", "name": "",
"description": "", "description": "",
"tags": "", "tags": "",
@ -22,62 +32,23 @@ empty_teilchen = {
} }
def TC(**kwargs) -> TeilchenCreate | None:
"""TC = TeilchenCreate
Create Teilchen with desired attributes.
Args:
input: mapping that must be well-formed enough to actually create a Teilchen
Returns:
- `None` on empty input
- an instance of `TeilchenCreate`
"""
if kwargs:
arguments = empty_teilchen | kwargs
return TeilchenCreate(**arguments) # ty:ignore[invalid-argument-type]
@pytest.mark.parametrize( @pytest.mark.parametrize(
"example_input,expected", "example_input,expected",
[ [
# Not enough data ("", None),
("", TC()), ("a", None),
(".", TC()), ("a.", {"name": "a", "text": "a."}),
("..", TC()), ("aa", None),
(".a.", TC()), ("aa.", {"name": "aa", "text": "aa."}),
("a", TC()),
("aa", TC()),
# Just enough for "name"
("a.", TC(name="a", text="a.")),
("aa.", TC(name="aa", text="aa.")),
("a..", TC(name="a", text="a..")),
("a.b.", TC(name="a", text="a.b.")),
# Just enough for "name" and "description"
('a."b"', TC(name="a", description="b", text='a."b"')),
('a. "b"', TC(name="a", description="b", text='a. "b"')),
('a. ""', TC(name="a", description="", text='a. ""')),
('. ""', TC()),
('. "b"', TC()),
# Just enough for "name" and "description" and "tags"
('a. "b" #c', TC(name="a", description="b", tags="#c", text='a. "b" #c')),
('a. "b #d" #c', TC(name="a", description="b #d", tags="#c #d", text='a. "b #d" #c')),
# swap order in input, tag result is stable
('a. "b #c" #d', TC(name="a", description="b #c", tags="#c #d", text='a. "b #c" #d')),
# Just enough for "name" and "tags"
("a. #d", TC(name="a", description="", tags="#d", text="a. #d")),
("a. #d#b", TC(name="a", description="", tags="#b #d", text="a. #d#b")),
("a. ##b", TC(name="a", description="", tags="#b", text="a. ##b")),
("a. #", TC(name="a", description="", tags="", text="a. #")),
("a. ##", TC(name="a", description="", tags="", text="a. ##")),
# do we care about "number"?
], ],
) )
async def test_maketeilcheninput_can_create_desired_teilchen( async def test_teilchendata_must_include_period(
example_input: str, expected: dict[str, str | int] | None example_input: str, expected: dict[str, str | int] | None
) -> None: ) -> None:
actual = await make_teilchen_input(example_input) thing = expected
if expected:
arguments = empty_teilchen | expected
thing = TeilchenCreate(**arguments) # ty:ignore[invalid-argument-type]
assert expected == actual assert await make_teilchen_input(example_input) == thing

4
uv.lock generated
View file

@ -1161,6 +1161,7 @@ dependencies = [
{ name = "orjson" }, { name = "orjson" },
{ name = "sqlmodel" }, { name = "sqlmodel" },
{ name = "textual" }, { name = "textual" },
{ name = "textual-dev" },
] ]
[package.dev-dependencies] [package.dev-dependencies]
@ -1170,7 +1171,6 @@ dev = [
{ name = "pytest-asyncio" }, { name = "pytest-asyncio" },
{ name = "pytest-cov" }, { name = "pytest-cov" },
{ name = "pytest-textual-snapshot" }, { name = "pytest-textual-snapshot" },
{ name = "textual-dev" },
{ name = "twine" }, { name = "twine" },
] ]
@ -1181,6 +1181,7 @@ requires-dist = [
{ name = "orjson", specifier = ">=3.11.4" }, { name = "orjson", specifier = ">=3.11.4" },
{ name = "sqlmodel", specifier = ">=0.0.27" }, { name = "sqlmodel", specifier = ">=0.0.27" },
{ name = "textual", specifier = ">=6.7.1" }, { name = "textual", specifier = ">=6.7.1" },
{ name = "textual-dev", specifier = ">=1.8.0" },
] ]
[package.metadata.requires-dev] [package.metadata.requires-dev]
@ -1190,7 +1191,6 @@ dev = [
{ name = "pytest-asyncio", specifier = ">=1.3.0" }, { name = "pytest-asyncio", specifier = ">=1.3.0" },
{ name = "pytest-cov", specifier = ">=7.0.0" }, { name = "pytest-cov", specifier = ">=7.0.0" },
{ name = "pytest-textual-snapshot", specifier = ">=1.0.0" }, { name = "pytest-textual-snapshot", specifier = ">=1.0.0" },
{ name = "textual-dev", specifier = ">=1.8.0" },
{ name = "twine", specifier = ">=6.2.0" }, { name = "twine", specifier = ">=6.2.0" },
] ]