Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ jobs:
python-version: ["3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

Expand All @@ -26,7 +26,7 @@ jobs:
pip install -e ".[dev]"

- name: Lint with ruff
run: pip install ruff && ruff check src/ --target-version py310
run: ruff check src/
- name: Run tests
run: |
python -m pytest tests/ -v --cov=src --cov-report=term-missing
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ jobs:
id-token: write

steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4

- name: Set up Python 3.11
uses: actions/setup-python@v6
uses: actions/setup-python@v5
with:
python-version: "3.11"

Expand Down
18 changes: 18 additions & 0 deletions tests/test_diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,24 @@ def test_three_envs(self):
assert results["prod"].count == 1


class TestChangeStr:
"""Tests for Change.__str__()."""

def test_str_added(self):
c = Change(key="port", change_type=ChangeType.ADDED, new_value=8080, env="prod")
expected = "[+] port = 8080 (env: prod)"
assert str(c) == expected

def test_str_removed(self):
c = Change(key="port", change_type=ChangeType.REMOVED, old_value=8080, env="dev")
expected = "[-] port (was 8080) (env: dev)"
assert str(c) == expected

def test_str_changed(self):
c = Change(key="host", change_type=ChangeType.CHANGED, old_value="localhost", new_value="prod.example.com", env="prod")
assert str(c) == "[~] host: 'localhost' \u2192 'prod.example.com' (env: prod)"


class TestDiffResultHelpers:
def test_by_type(self):
changes = [
Expand Down
54 changes: 54 additions & 0 deletions tests/test_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,60 @@ def test_ignores_comments(self):
assert "This is a comment" not in result


class TestLoadUnsupported:
"""Tests for fallback behaviour with unknown file extensions."""

def test_fallback_yaml_content_in_cfg(self):
"""Files with .cfg containing valid YAML should be parsed via fallback."""
content = yaml.dump({"key": "value", "nested": {"inner": 42}})
with tempfile.NamedTemporaryFile(suffix=".cfg", mode="w", delete=False) as f:
f.write(content)
f.flush()
result = load_file(f.name)
os.unlink(f.name)
assert result["key"] == "value"
assert result["nested.inner"] == 42

def test_fallback_yaml_as_json(self):
"""Files with unknown ext containing valid JSON should be parsed via fallback."""
content = json.dumps({"host": "localhost", "port": 8080})
with tempfile.NamedTemporaryFile(suffix=".cnf", mode="w", delete=False) as f:
f.write(content)
f.flush()
result = load_file(f.name)
os.unlink(f.name)
assert result["host"] == "localhost"
assert result["port"] == 8080

def test_unsupported_format_fallback_to_dotenv(self):
"""Files with unknown extension and no structured content fall through to .env parser and returns a dict."""
with tempfile.NamedTemporaryFile(suffix=".xyz", mode="w", delete=False) as f:
f.write("not a config")
f.flush()
result = load_file(f.name)
os.unlink(f.name)
assert isinstance(result, dict)

def test_unsupported_format_empty_result(self):
"""Garbage content with unknown extension returns empty dict via .env fallback."""
with tempfile.NamedTemporaryFile(suffix=".xyz", mode="w", delete=False) as f:
f.write("!!!garbage!!!")
f.flush()
result = load_file(f.name)
os.unlink(f.name)
assert result == {}

def test_yaml_non_dict_raises(self):
"""YAML containing a list (not a mapping) should raise ValueError."""
content = yaml.dump(["item1", "item2"])
with tempfile.NamedTemporaryFile(suffix=".yaml", mode="w", delete=False) as f:
f.write(content)
f.flush()
with pytest.raises(ValueError, match="YAML file must contain a mapping"):
load_file(f.name)
os.unlink(f.name)


class TestFlattenNested:
def test_flatten(self):
data = {"a": {"b": {"c": 1}, "d": 2}, "e": 3}
Expand Down
Loading