mirror of
https://github.com/Second-Hand-Friends/kleinanzeigen-bot.git
synced 2026-03-12 10:31:50 +01:00
feat: Add descriptive comments and examples to create-config output (#805)
This commit is contained in:
@@ -7,7 +7,7 @@ from kleinanzeigen_bot.model.config_model import AdDefaults, Config, TimeoutConf
|
||||
|
||||
|
||||
def test_migrate_legacy_description_prefix() -> None:
|
||||
assert AdDefaults.model_validate({}).description_prefix is None
|
||||
assert AdDefaults.model_validate({}).description_prefix == "" # noqa: PLC1901 explicit empty check is clearer
|
||||
|
||||
assert AdDefaults.model_validate({"description_prefix": "Prefix"}).description_prefix == "Prefix"
|
||||
|
||||
@@ -19,7 +19,7 @@ def test_migrate_legacy_description_prefix() -> None:
|
||||
|
||||
|
||||
def test_migrate_legacy_description_suffix() -> None:
|
||||
assert AdDefaults.model_validate({}).description_suffix is None
|
||||
assert AdDefaults.model_validate({}).description_suffix == "" # noqa: PLC1901 explicit empty check is clearer
|
||||
|
||||
assert AdDefaults.model_validate({"description_suffix": "Suffix"}).description_suffix == "Suffix"
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
import unicodedata
|
||||
from pathlib import Path
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
def test_save_dict_normalizes_unicode_paths(tmp_path:Path) -> None:
|
||||
"""Test that save_dict normalizes paths to NFC for cross-platform consistency (issue #728).
|
||||
@@ -38,3 +40,166 @@ def test_save_dict_normalizes_unicode_paths(tmp_path:Path) -> None:
|
||||
# Either way, we should have exactly one YAML file total (no duplicates)
|
||||
all_yaml_files = list(tmp_path.rglob("*.yaml"))
|
||||
assert len(all_yaml_files) == 1, f"Expected exactly 1 YAML file total, found {len(all_yaml_files)}: {all_yaml_files}"
|
||||
|
||||
|
||||
def test_safe_get_with_type_error() -> None:
|
||||
"""Test safe_get returns None when accessing a non-dict value (TypeError)."""
|
||||
from kleinanzeigen_bot.utils import dicts # noqa: PLC0415
|
||||
|
||||
# Accessing a key on a string causes TypeError
|
||||
result = dicts.safe_get({"foo": "bar"}, "foo", "baz")
|
||||
assert result is None
|
||||
|
||||
|
||||
def test_safe_get_with_empty_dict() -> None:
|
||||
"""Test safe_get returns empty dict when given empty dict."""
|
||||
from kleinanzeigen_bot.utils import dicts # noqa: PLC0415
|
||||
|
||||
# Empty dict should return the dict itself (falsy but valid)
|
||||
result = dicts.safe_get({})
|
||||
assert result == {}
|
||||
|
||||
|
||||
def test_model_to_commented_yaml_with_dict_exclude() -> None:
|
||||
"""Test model_to_commented_yaml with dict exclude where field is not in exclude dict."""
|
||||
from kleinanzeigen_bot.utils.dicts import model_to_commented_yaml # noqa: PLC0415
|
||||
|
||||
class TestModel(BaseModel):
|
||||
included_field:str = Field(default = "value", description = "This field")
|
||||
excluded_field:str = Field(default = "excluded", description = "Excluded field")
|
||||
|
||||
model = TestModel()
|
||||
# Exclude only excluded_field, included_field should remain
|
||||
result = model_to_commented_yaml(model, exclude = {"excluded_field": None})
|
||||
|
||||
assert "included_field" in result
|
||||
assert "excluded_field" not in result
|
||||
|
||||
|
||||
def test_model_to_commented_yaml_with_list() -> None:
|
||||
"""Test model_to_commented_yaml handles list fields correctly."""
|
||||
from kleinanzeigen_bot.utils.dicts import model_to_commented_yaml # noqa: PLC0415
|
||||
|
||||
class TestModel(BaseModel):
|
||||
items:list[str] = Field(default_factory = lambda: ["item1", "item2"], description = "List of items")
|
||||
|
||||
model = TestModel()
|
||||
result = model_to_commented_yaml(model)
|
||||
|
||||
assert "items" in result
|
||||
assert isinstance(result["items"], list)
|
||||
assert result["items"] == ["item1", "item2"]
|
||||
|
||||
|
||||
def test_model_to_commented_yaml_with_multiple_scalar_examples() -> None:
|
||||
"""Test model_to_commented_yaml formats multiple scalar examples with bullets."""
|
||||
from kleinanzeigen_bot.utils.dicts import model_to_commented_yaml # noqa: PLC0415
|
||||
|
||||
class TestModel(BaseModel):
|
||||
choice:str = Field(default = "A", description = "Choose one", examples = ["A", "B", "C"])
|
||||
|
||||
model = TestModel()
|
||||
result = model_to_commented_yaml(model)
|
||||
|
||||
# Verify the field exists
|
||||
assert "choice" in result
|
||||
# Verify comment was added (check via the yaml_set_comment_before_after_key mechanism)
|
||||
assert result.ca is not None
|
||||
|
||||
|
||||
def test_model_to_commented_yaml_with_set_exclude() -> None:
|
||||
"""Test model_to_commented_yaml with set exclude (covers line 170 branch)."""
|
||||
from kleinanzeigen_bot.utils.dicts import model_to_commented_yaml # noqa: PLC0415
|
||||
|
||||
class TestModel(BaseModel):
|
||||
field1:str = Field(default = "value1", description = "First field")
|
||||
field2:str = Field(default = "value2", description = "Second field")
|
||||
|
||||
model = TestModel()
|
||||
# Use set for exclude (not dict)
|
||||
result = model_to_commented_yaml(model, exclude = {"field2"})
|
||||
|
||||
assert "field1" in result
|
||||
assert "field2" not in result
|
||||
|
||||
|
||||
def test_model_to_commented_yaml_with_nested_dict_exclude() -> None:
|
||||
"""Test model_to_commented_yaml with nested dict exclude (covers lines 186-187)."""
|
||||
from kleinanzeigen_bot.utils.dicts import model_to_commented_yaml # noqa: PLC0415
|
||||
|
||||
class NestedModel(BaseModel):
|
||||
nested_field:str = Field(default = "nested", description = "Nested")
|
||||
|
||||
class TestModel(BaseModel):
|
||||
parent:NestedModel = Field(default_factory = NestedModel, description = "Parent")
|
||||
|
||||
model = TestModel()
|
||||
# Nested exclude with None value
|
||||
result = model_to_commented_yaml(model, exclude = {"parent": None})
|
||||
|
||||
assert "parent" not in result
|
||||
|
||||
|
||||
def test_model_to_commented_yaml_with_plain_dict() -> None:
|
||||
"""Test model_to_commented_yaml with plain dict (covers lines 238-241)."""
|
||||
from kleinanzeigen_bot.utils.dicts import model_to_commented_yaml # noqa: PLC0415
|
||||
|
||||
# Plain dict (not a Pydantic model)
|
||||
plain_dict = {"key1": "value1", "key2": "value2"}
|
||||
result = model_to_commented_yaml(plain_dict)
|
||||
|
||||
assert "key1" in result
|
||||
assert "key2" in result
|
||||
assert result["key1"] == "value1"
|
||||
|
||||
|
||||
def test_model_to_commented_yaml_fallback() -> None:
|
||||
"""Test model_to_commented_yaml fallback for unsupported types (covers line 318)."""
|
||||
from kleinanzeigen_bot.utils.dicts import model_to_commented_yaml # noqa: PLC0415
|
||||
|
||||
# Custom object that's not a BaseModel, dict, list, or primitive
|
||||
class CustomObject:
|
||||
pass
|
||||
|
||||
obj = CustomObject()
|
||||
result = model_to_commented_yaml(obj)
|
||||
|
||||
# Should return as-is
|
||||
assert result is obj
|
||||
|
||||
|
||||
def test_save_commented_model_without_header(tmp_path:Path) -> None:
|
||||
"""Test save_commented_model without header (covers line 358)."""
|
||||
from kleinanzeigen_bot.utils.dicts import save_commented_model # noqa: PLC0415
|
||||
|
||||
class TestModel(BaseModel):
|
||||
field:str = Field(default = "value", description = "A field")
|
||||
|
||||
model = TestModel()
|
||||
filepath = tmp_path / "test.yaml"
|
||||
|
||||
# Save without header (header=None)
|
||||
save_commented_model(filepath, model, header = None)
|
||||
|
||||
assert filepath.exists()
|
||||
content = filepath.read_text()
|
||||
# Should not have a blank line at the start
|
||||
assert not content.startswith("\n")
|
||||
|
||||
|
||||
def test_model_to_commented_yaml_with_empty_list() -> None:
|
||||
"""Test model_to_commented_yaml correctly detects empty list fields via type annotation."""
|
||||
from kleinanzeigen_bot.utils.dicts import model_to_commented_yaml # noqa: PLC0415
|
||||
|
||||
class TestModel(BaseModel):
|
||||
items:list[str] = Field(default_factory = list, description = "List of items", examples = ["item1", "item2"])
|
||||
|
||||
model = TestModel()
|
||||
# Model has empty list, but should still be detected as list field via annotation
|
||||
result = model_to_commented_yaml(model)
|
||||
|
||||
assert "items" in result
|
||||
assert isinstance(result["items"], list)
|
||||
assert len(result["items"]) == 0
|
||||
# Verify comment includes "Example usage:" (list field format) not "Examples:" (scalar format)
|
||||
assert result.ca is not None
|
||||
|
||||
Reference in New Issue
Block a user