Files
ss-tools/backend/tests/services/dataset_review/test_semantic_resolver_edge.py
2026-06-16 12:01:03 +03:00

121 lines
4.8 KiB
Python

# #region Test.DatasetReview.SemanticResolverEdge [C:3] [TYPE Module] [SEMANTICS test,semantic,resolver,fuzzy,match,edge]
# @BRIEF Edge-case coverage for semantic_resolver.py uncovered lines (149, 343, 347).
# @RELATION BINDS_TO -> [SemanticResolver]
# @TEST_EDGE: missing_mapping -> Returns empty when no mapping found
# @TEST_EDGE: invalid_type -> Non-string input handled gracefully
# @TEST_EDGE: empty_input -> Empty string returns no matches
from pathlib import Path
import sys
sys.path.insert(0, str(Path(__file__).parent.parent.parent / "src"))
from unittest.mock import patch
import pytest
class TestSemanticSourceResolverEdge:
"""Cover fuzzy match and row processing edge cases."""
@pytest.fixture
def resolver(self):
from src.services.dataset_review.semantic_resolver import SemanticSourceResolver
return SemanticSourceResolver()
def test_find_fuzzy_matches_with_empty_key(self, resolver):
"""Row with empty field_key is skipped (line 343)."""
field_name = "region"
rows = [
{"field_key": "", "field_name": "Empty"},
{"field_key": "region", "field_name": "Region"},
]
result = resolver._find_fuzzy_matches(field_name, rows)
assert len(result) >= 1
# The empty key row should be skipped, only region matches
def test_find_fuzzy_matches_low_score_skipped(self, resolver):
"""Row with score below 0.72 is skipped (line 347)."""
field_name = "region"
rows = [
{"field_key": "completely_different_name", "field_name": "Different"},
]
result = resolver._find_fuzzy_matches(field_name, rows)
assert len(result) == 0
def test_find_fuzzy_matches_good_score(self, resolver):
"""Row with score above 0.72 is included."""
# Use strings close enough to exceed 0.72 threshold
field_name = "salesregion"
rows = [
{"field_key": "sales_region", "field_name": "Sales Region"},
]
result = resolver._find_fuzzy_matches(field_name, rows)
assert len(result) >= 1
assert result[0]["score"] >= 0.72
def test_find_fuzzy_matches_top_3(self, resolver):
"""Only top 3 fuzzy matches returned."""
field_name = "sales_amount_value"
rows = [
{"field_key": f"sales_amount_{i}" if i < 5 else "unrelated", "field_name": f"Sales {i}"}
for i in range(10)
]
result = resolver._find_fuzzy_matches(field_name, rows)
assert len(result) <= 3
def test_resolve_from_dictionary_no_matches(self, resolver):
"""Field with no dictionary match produces unresolved entry."""
source_payload = {
"source_ref": "test_dict",
"rows": [
{"field_name": "Region"},
{"field_name": "Country"},
],
}
fields = [{"field_name": "nonexistent_field"}]
result = resolver.resolve_from_dictionary(source_payload, fields)
assert result.unresolved_fields == ["nonexistent_field"]
assert len(result.resolved_fields) == 1
assert result.resolved_fields[0]["status"] == "unresolved"
def test_normalize_dictionary_row(self, resolver):
"""_normalize_dictionary_row produces expected keys."""
row = {"field_name": "My Field", "verbose_name": "My Field Label"}
result = resolver._normalize_dictionary_row(row)
assert result["field_key"] == "myfield" # normalized: lowercase, no spaces
assert result["field_name"] == "My Field"
def test_resolve_from_dictionary_fuzzy_match(self, resolver):
"""Fuzzy match produces ranked candidates (coverage for line 149)."""
source_payload = {
"source_ref": "test_dict",
"rows": [
{"field_name": "Sales Amount"},
{"field_name": "Revenue"},
],
}
# Use a field name close enough to "sales amount"
fields = [{"field_name": "sales_amount"}]
result = resolver.resolve_from_dictionary(source_payload, fields)
assert len(result.resolved_fields) == 1
assert result.resolved_fields[0]["field_name"] == "sales_amount"
candidates = result.resolved_fields[0].get("candidates", [])
# Should have at least one candidate (exact or fuzzy)
assert len(candidates) >= 1
def test_resolve_from_dictionary_locked_field(self, resolver):
"""Locked field is preserved."""
source_payload = {
"source_ref": "test_dict",
"rows": [
{"field_name": "Region"},
],
}
fields = [{"field_name": "region", "is_locked": True}]
result = resolver.resolve_from_dictionary(source_payload, fields)
assert result.resolved_fields[0].get("is_locked") is True
# #endregion Test.DatasetReview.SemanticResolverEdge