Compare commits
7 commits
de1122442b
...
fe73b03bf3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe73b03bf3 | ||
|
|
19f01c56bb | ||
|
|
dbc46d4e03 | ||
|
|
00621a9859 | ||
|
|
3268de32ea | ||
|
|
736fd02b50 | ||
|
|
3a4137e706 |
7 changed files with 72 additions and 27 deletions
11
conftest.py
Normal file
11
conftest.py
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
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")
|
||||||
3
justfile
3
justfile
|
|
@ -41,6 +41,9 @@ 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
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
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"
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ 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]
|
||||||
|
|
|
||||||
|
|
@ -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) # ty:ignore[unresolved-attribute]
|
id: uuid.UUID = Field(default_factory=uuid.uuid7, primary_key=True)
|
||||||
|
|
||||||
|
|
||||||
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:description_end]
|
description = text[description_start + 1 : description_end]
|
||||||
else:
|
else:
|
||||||
description = ""
|
description = ""
|
||||||
|
|
||||||
|
|
|
||||||
75
tests.py
75
tests.py
|
|
@ -1,4 +1,3 @@
|
||||||
from typing import TypedDict
|
|
||||||
import pytest
|
import pytest
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
|
@ -7,23 +6,14 @@ 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))
|
||||||
|
|
||||||
|
|
||||||
class Teilchen(TypedDict):
|
empty_teilchen = {
|
||||||
"""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": "",
|
||||||
|
|
@ -32,23 +22,62 @@ empty_teilchen: 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",
|
||||||
[
|
[
|
||||||
("", None),
|
# Not enough data
|
||||||
("a", None),
|
("", TC()),
|
||||||
("a.", {"name": "a", "text": "a."}),
|
(".", TC()),
|
||||||
("aa", None),
|
("..", TC()),
|
||||||
("aa.", {"name": "aa", "text": "aa."}),
|
(".a.", TC()),
|
||||||
|
("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_teilchendata_must_include_period(
|
async def test_maketeilcheninput_can_create_desired_teilchen(
|
||||||
example_input: str, expected: dict[str, str | int] | None
|
example_input: str, expected: dict[str, str | int] | None
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
||||||
thing = expected
|
actual = await make_teilchen_input(example_input)
|
||||||
if expected:
|
|
||||||
arguments = empty_teilchen | expected
|
|
||||||
thing = TeilchenCreate(**arguments) # ty:ignore[invalid-argument-type]
|
|
||||||
|
|
||||||
assert await make_teilchen_input(example_input) == thing
|
assert expected == actual
|
||||||
|
|
|
||||||
4
uv.lock
generated
4
uv.lock
generated
|
|
@ -1161,7 +1161,6 @@ dependencies = [
|
||||||
{ name = "orjson" },
|
{ name = "orjson" },
|
||||||
{ name = "sqlmodel" },
|
{ name = "sqlmodel" },
|
||||||
{ name = "textual" },
|
{ name = "textual" },
|
||||||
{ name = "textual-dev" },
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dev-dependencies]
|
[package.dev-dependencies]
|
||||||
|
|
@ -1171,6 +1170,7 @@ 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,7 +1181,6 @@ 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]
|
||||||
|
|
@ -1191,6 +1190,7 @@ 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" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue