feat(domain): add domain layer foundation -- enums, value objects, TechniqueEntity, repository ports

This commit is contained in:
2026-02-18 19:10:31 +01:00
parent e651ef8a8c
commit 5c55e7c17f
14 changed files with 761 additions and 28 deletions

View File

@@ -0,0 +1,114 @@
"""Tests for domain value objects: MitreId and ScoringWeights."""
import sys
import os
backend_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
if backend_dir not in sys.path:
sys.path.insert(0, backend_dir)
import pytest
from app.domain.value_objects.mitre_id import MitreId
from app.domain.value_objects.scoring_weights import ScoringWeights
# ── MitreId ──────────────────────────────────────────────────────────
class TestMitreId:
def test_valid_technique(self):
mid = MitreId("T1059")
assert mid.value == "T1059"
assert str(mid) == "T1059"
assert not mid.is_subtechnique
assert mid.parent_id is None
def test_valid_subtechnique(self):
mid = MitreId("T1059.001")
assert mid.value == "T1059.001"
assert mid.is_subtechnique
assert mid.parent_id == "T1059"
def test_invalid_empty_string(self):
with pytest.raises(ValueError, match="Invalid MITRE"):
MitreId("")
def test_invalid_no_prefix(self):
with pytest.raises(ValueError, match="Invalid MITRE"):
MitreId("1059")
def test_invalid_wrong_prefix(self):
with pytest.raises(ValueError, match="Invalid MITRE"):
MitreId("A1059")
def test_invalid_too_few_digits(self):
with pytest.raises(ValueError, match="Invalid MITRE"):
MitreId("T105")
def test_invalid_subtechnique_format(self):
with pytest.raises(ValueError, match="Invalid MITRE"):
MitreId("T1059.01") # needs 3 digits after dot
def test_invalid_trailing_garbage(self):
with pytest.raises(ValueError, match="Invalid MITRE"):
MitreId("T1059.001.002")
def test_equality_with_same_mitre_id(self):
assert MitreId("T1059") == MitreId("T1059")
def test_equality_with_string(self):
assert MitreId("T1059") == "T1059"
def test_inequality(self):
assert MitreId("T1059") != MitreId("T1060")
def test_hashable(self):
s = {MitreId("T1059"), MitreId("T1059"), MitreId("T1060")}
assert len(s) == 2
def test_immutable(self):
mid = MitreId("T1059")
with pytest.raises(AttributeError):
mid.value = "T1060"
# ── ScoringWeights ───────────────────────────────────────────────────
class TestScoringWeights:
def test_valid_default(self):
w = ScoringWeights.default()
assert w.tests == 40.0
assert w.detection_rules == 25.0
assert w.d3fend == 15.0
assert w.freshness == 10.0
assert w.platform_diversity == 10.0
def test_valid_custom(self):
w = ScoringWeights(
tests=50, detection_rules=20, d3fend=10,
freshness=10, platform_diversity=10,
)
assert w.tests == 50
def test_invalid_sum_not_100(self):
with pytest.raises(ValueError, match="sum to 100"):
ScoringWeights(
tests=50, detection_rules=20, d3fend=10,
freshness=10, platform_diversity=5,
)
def test_invalid_negative_weight(self):
with pytest.raises(ValueError, match="non-negative"):
ScoringWeights(
tests=-10, detection_rules=40, d3fend=30,
freshness=20, platform_diversity=20,
)
def test_immutable(self):
w = ScoringWeights.default()
with pytest.raises(AttributeError):
w.tests = 50