Skip to content

Commit 9047cda

Browse files
committed
ci: unit: add model tests
1 parent 8b5b6b0 commit 9047cda

File tree

3 files changed

+187
-0
lines changed

3 files changed

+187
-0
lines changed

tests/unit/models/__init__.py

Whitespace-only changes.
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
"""Unit tests for artifact-related domain models."""
2+
3+
from pathlib import Path
4+
5+
import pytest
6+
7+
from solc_select.models.artifacts import SolcArtifact
8+
from solc_select.models.platforms import Platform
9+
from solc_select.models.versions import SolcVersion
10+
11+
12+
def create_artifact(
13+
version: str = "0.8.19",
14+
platform: Platform | None = None,
15+
checksum_sha256: str = "abc123",
16+
checksum_keccak256: str | None = None,
17+
download_url: str = "https://example.com/solc",
18+
) -> SolcArtifact:
19+
"""Helper to create SolcArtifact with sensible defaults."""
20+
if platform is None:
21+
platform = Platform("linux", "amd64")
22+
return SolcArtifact(
23+
version=SolcVersion(version),
24+
platform=platform,
25+
file_path=Path(f"/tmp/solc-{version}"),
26+
download_url=download_url,
27+
checksum_sha256=checksum_sha256,
28+
checksum_keccak256=checksum_keccak256,
29+
)
30+
31+
32+
class TestSolcArtifact:
33+
"""Tests for SolcArtifact domain model."""
34+
35+
@pytest.mark.parametrize(
36+
"version,expected",
37+
[
38+
("0.6.12", True), # Old Windows version - should be ZIP
39+
("0.7.1", True), # Boundary - still ZIP
40+
("0.7.2", False), # First non-ZIP version
41+
("0.8.19", False), # Modern version
42+
],
43+
)
44+
def test_is_zip_archive_windows(self, version: str, expected: bool) -> None:
45+
"""Windows ZIP archive detection based on version boundary (0.7.1)."""
46+
artifact = create_artifact(version=version, platform=Platform("windows", "amd64"))
47+
assert artifact.is_zip_archive == expected
48+
49+
@pytest.mark.parametrize("os_type", ["linux", "darwin"])
50+
def test_is_zip_archive_non_windows(self, os_type: str) -> None:
51+
"""Non-Windows platforms should never have ZIP archives."""
52+
artifact = create_artifact(version="0.6.12", platform=Platform(os_type, "amd64"))
53+
assert not artifact.is_zip_archive
54+
55+
def test_checksum_prefix_removal(self) -> None:
56+
"""Checksums with 0x prefix should be stripped in __post_init__."""
57+
artifact = create_artifact(
58+
checksum_sha256="0xabc123def456",
59+
checksum_keccak256="0x789xyz",
60+
)
61+
assert artifact.checksum_sha256 == "abc123def456"
62+
assert artifact.checksum_keccak256 == "789xyz"
63+
64+
def test_get_binary_name_in_zip(self) -> None:
65+
"""Binary name inside ZIP archives should be solc.exe."""
66+
artifact = create_artifact(version="0.6.12", platform=Platform("windows", "amd64"))
67+
assert artifact.get_binary_name_in_zip() == "solc.exe"
68+
69+
def test_get_binary_name_in_zip_raises_for_non_zip(self) -> None:
70+
"""Calling get_binary_name_in_zip on non-ZIP should raise ValueError."""
71+
artifact = create_artifact(version="0.8.19", platform=Platform("windows", "amd64"))
72+
with pytest.raises(ValueError, match="Not a ZIP archive"):
73+
artifact.get_binary_name_in_zip()
74+
75+
@pytest.mark.parametrize(
76+
"download_url,checksum,error_msg",
77+
[
78+
("", "abc123", "Download URL cannot be empty"),
79+
("https://example.com", "", "SHA256 checksum cannot be empty"),
80+
],
81+
)
82+
def test_validation_errors(self, download_url: str, checksum: str, error_msg: str) -> None:
83+
"""Empty URL or checksum should raise ValueError."""
84+
with pytest.raises(ValueError, match=error_msg):
85+
SolcArtifact(
86+
version=SolcVersion("0.8.19"),
87+
platform=Platform("linux", "amd64"),
88+
file_path=Path("/tmp/solc-0.8.19"),
89+
download_url=download_url,
90+
checksum_sha256=checksum,
91+
checksum_keccak256=None,
92+
)

tests/unit/models/test_versions.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
"""Unit tests for version-related domain models."""
2+
3+
import pytest
4+
5+
from solc_select.models.versions import SolcVersion, VersionRange
6+
7+
8+
class TestVersionRange:
9+
"""Tests for VersionRange domain model."""
10+
11+
@pytest.mark.parametrize(
12+
"version,expected",
13+
[
14+
("0.8.10", True), # Within bounds
15+
("0.8.0", True), # Exact minimum (inclusive)
16+
("0.8.20", True), # Exact maximum (inclusive)
17+
("0.7.6", False), # Below minimum
18+
("0.8.21", False), # Above maximum
19+
],
20+
)
21+
def test_contains_bounded_range(self, version: str, expected: bool) -> None:
22+
"""VersionRange with both bounds should be inclusive [min, max]."""
23+
version_range = VersionRange(
24+
min_version=SolcVersion("0.8.0"),
25+
max_version=SolcVersion("0.8.20"),
26+
)
27+
assert version_range.contains(SolcVersion(version)) == expected
28+
29+
def test_contains_unbounded_min(self) -> None:
30+
"""None as minimum means no lower bound."""
31+
version_range = VersionRange(min_version=None, max_version=SolcVersion("0.8.20"))
32+
assert version_range.contains(SolcVersion("0.4.0"))
33+
assert version_range.contains(SolcVersion("0.8.20"))
34+
assert not version_range.contains(SolcVersion("0.8.21"))
35+
36+
def test_contains_unbounded_max(self) -> None:
37+
"""None as maximum means no upper bound."""
38+
version_range = VersionRange(min_version=SolcVersion("0.8.0"), max_version=None)
39+
assert version_range.contains(SolcVersion("0.8.0"))
40+
assert version_range.contains(SolcVersion("0.9.0"))
41+
assert not version_range.contains(SolcVersion("0.7.6"))
42+
43+
def test_contains_unbounded_both(self) -> None:
44+
"""None for both means all versions are valid."""
45+
version_range = VersionRange(min_version=None, max_version=None)
46+
assert version_range.contains(SolcVersion("0.4.0"))
47+
assert version_range.contains(SolcVersion("0.9.0"))
48+
49+
def test_from_min_factory(self) -> None:
50+
"""Creates open-ended range [min, infinity)."""
51+
version_range = VersionRange.from_min("0.8.5")
52+
assert version_range.min_version == SolcVersion("0.8.5")
53+
assert version_range.max_version is None
54+
assert version_range.contains(SolcVersion("0.8.5"))
55+
assert not version_range.contains(SolcVersion("0.8.4"))
56+
57+
def test_exact_range_factory(self) -> None:
58+
"""Creates closed range [min, max]."""
59+
version_range = VersionRange.exact_range("0.8.5", "0.8.23")
60+
assert version_range.min_version == SolcVersion("0.8.5")
61+
assert version_range.max_version == SolcVersion("0.8.23")
62+
assert version_range.contains(SolcVersion("0.8.5"))
63+
assert version_range.contains(SolcVersion("0.8.23"))
64+
assert not version_range.contains(SolcVersion("0.8.4"))
65+
assert not version_range.contains(SolcVersion("0.8.24"))
66+
67+
68+
class TestSolcVersion:
69+
"""Tests for SolcVersion domain model."""
70+
71+
def test_parse_valid_version(self) -> None:
72+
"""Parse valid version string."""
73+
version = SolcVersion.parse("0.8.19")
74+
assert version == SolcVersion("0.8.19")
75+
assert isinstance(version, SolcVersion)
76+
77+
def test_parse_latest_raises_error(self) -> None:
78+
"""Parse 'latest' should raise ValueError with clear message."""
79+
with pytest.raises(ValueError) as exc_info:
80+
SolcVersion.parse("latest")
81+
assert "Cannot parse 'latest'" in str(exc_info.value)
82+
assert "resolve to actual version first" in str(exc_info.value)
83+
84+
def test_version_comparison(self) -> None:
85+
"""SolcVersion should support comparison operations."""
86+
v1 = SolcVersion("0.8.19")
87+
v2 = SolcVersion("0.8.20")
88+
v3 = SolcVersion("0.8.19")
89+
90+
assert v1 < v2
91+
assert v2 > v1
92+
assert v1 == v3
93+
assert v1 <= v3
94+
assert v1 >= v3
95+
assert v1 != v2

0 commit comments

Comments
 (0)