147 lines
5.8 KiB
Python
147 lines
5.8 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Final
|
|
|
|
import pytest
|
|
|
|
from noteflow.infrastructure.ai.nodes.verification import (
|
|
INVALID_CITATIONS_PREFIX,
|
|
NO_SEGMENTS_REASON,
|
|
VerificationResult,
|
|
verify_citations,
|
|
)
|
|
|
|
SEGMENT_ID_ONE: Final[int] = 1
|
|
SEGMENT_ID_TWO: Final[int] = 2
|
|
SEGMENT_ID_THREE: Final[int] = 3
|
|
SEGMENT_ID_INVALID: Final[int] = 999
|
|
INVALID_INDEX_ZERO: Final[int] = 0
|
|
INVALID_INDEX_ONE: Final[int] = 1
|
|
|
|
|
|
class TestVerificationResult:
|
|
def test_valid_result_creation(self) -> None:
|
|
result = VerificationResult(
|
|
is_valid=True,
|
|
invalid_citation_indices=(),
|
|
reason=None,
|
|
)
|
|
assert result.is_valid is True, "should be valid"
|
|
|
|
def test_valid_result_has_empty_invalid_indices(self) -> None:
|
|
result = VerificationResult(
|
|
is_valid=True,
|
|
invalid_citation_indices=(),
|
|
reason=None,
|
|
)
|
|
assert result.invalid_citation_indices == (), "should have empty indices"
|
|
|
|
def test_valid_result_has_no_reason(self) -> None:
|
|
result = VerificationResult(
|
|
is_valid=True,
|
|
invalid_citation_indices=(),
|
|
reason=None,
|
|
)
|
|
assert result.reason is None, "should have no reason"
|
|
|
|
def test_invalid_result_creation(self) -> None:
|
|
result = VerificationResult(
|
|
is_valid=False,
|
|
invalid_citation_indices=(INVALID_INDEX_ZERO,),
|
|
reason="Test reason",
|
|
)
|
|
assert result.is_valid is False, "should be invalid"
|
|
|
|
def test_invalid_result_has_indices(self) -> None:
|
|
result = VerificationResult(
|
|
is_valid=False,
|
|
invalid_citation_indices=(INVALID_INDEX_ZERO,),
|
|
reason="Test reason",
|
|
)
|
|
assert INVALID_INDEX_ZERO in result.invalid_citation_indices, "should contain index"
|
|
|
|
def test_invalid_result_has_reason(self) -> None:
|
|
result = VerificationResult(
|
|
is_valid=False,
|
|
invalid_citation_indices=(INVALID_INDEX_ZERO,),
|
|
reason="Test reason",
|
|
)
|
|
assert result.reason == "Test reason", "should have reason"
|
|
|
|
def test_verification_result_is_frozen(self) -> None:
|
|
result = VerificationResult(is_valid=True, invalid_citation_indices=())
|
|
with pytest.raises(AttributeError, match="cannot assign"):
|
|
result.is_valid = False
|
|
|
|
|
|
class TestVerifyCitations:
|
|
def test_verify_all_citations_valid(self) -> None:
|
|
cited_ids = [SEGMENT_ID_ONE, SEGMENT_ID_TWO]
|
|
available_ids = {SEGMENT_ID_ONE, SEGMENT_ID_TWO, SEGMENT_ID_THREE}
|
|
result = verify_citations(cited_ids, available_ids)
|
|
assert result.is_valid is True, "should be valid"
|
|
|
|
def test_all_citations_valid_has_empty_invalid_indices(self) -> None:
|
|
cited_ids = [SEGMENT_ID_ONE, SEGMENT_ID_TWO]
|
|
available_ids = {SEGMENT_ID_ONE, SEGMENT_ID_TWO, SEGMENT_ID_THREE}
|
|
result = verify_citations(cited_ids, available_ids)
|
|
assert result.invalid_citation_indices == (), "should have empty indices"
|
|
|
|
def test_invalid_citation_returns_invalid(self) -> None:
|
|
cited_ids = [SEGMENT_ID_ONE, SEGMENT_ID_INVALID]
|
|
available_ids = {SEGMENT_ID_ONE, SEGMENT_ID_TWO}
|
|
result = verify_citations(cited_ids, available_ids)
|
|
assert result.is_valid is False, "should be invalid"
|
|
|
|
def test_invalid_citation_identifies_index(self) -> None:
|
|
cited_ids = [SEGMENT_ID_ONE, SEGMENT_ID_INVALID]
|
|
available_ids = {SEGMENT_ID_ONE, SEGMENT_ID_TWO}
|
|
result = verify_citations(cited_ids, available_ids)
|
|
assert INVALID_INDEX_ONE in result.invalid_citation_indices, "should identify index 1"
|
|
|
|
def test_invalid_citation_has_reason(self) -> None:
|
|
cited_ids = [SEGMENT_ID_ONE, SEGMENT_ID_INVALID]
|
|
available_ids = {SEGMENT_ID_ONE, SEGMENT_ID_TWO}
|
|
result = verify_citations(cited_ids, available_ids)
|
|
assert result.reason is not None, "should have reason"
|
|
|
|
def test_invalid_citation_reason_contains_prefix(self) -> None:
|
|
cited_ids = [SEGMENT_ID_ONE, SEGMENT_ID_INVALID]
|
|
available_ids = {SEGMENT_ID_ONE, SEGMENT_ID_TWO}
|
|
result = verify_citations(cited_ids, available_ids)
|
|
assert INVALID_CITATIONS_PREFIX in (result.reason or ""), "reason should contain prefix"
|
|
|
|
def test_empty_available_ids_returns_invalid(self) -> None:
|
|
cited_ids = [SEGMENT_ID_ONE]
|
|
available_ids: set[int] = set()
|
|
result = verify_citations(cited_ids, available_ids)
|
|
assert result.is_valid is False, "should be invalid"
|
|
|
|
def test_empty_available_ids_has_no_segments_reason(self) -> None:
|
|
cited_ids = [SEGMENT_ID_ONE]
|
|
available_ids: set[int] = set()
|
|
result = verify_citations(cited_ids, available_ids)
|
|
assert result.reason == NO_SEGMENTS_REASON, "should have no segments reason"
|
|
|
|
def test_empty_cited_ids_with_available_returns_valid(self) -> None:
|
|
cited_ids: list[int] = []
|
|
available_ids = {SEGMENT_ID_ONE, SEGMENT_ID_TWO}
|
|
result = verify_citations(cited_ids, available_ids)
|
|
assert result.is_valid is True, "empty citations should be valid"
|
|
|
|
def test_multiple_invalid_citations(self) -> None:
|
|
cited_ids = [SEGMENT_ID_INVALID, SEGMENT_ID_INVALID]
|
|
available_ids = {SEGMENT_ID_ONE}
|
|
result = verify_citations(cited_ids, available_ids)
|
|
assert len(result.invalid_citation_indices) > INVALID_INDEX_ONE, "should have multiple"
|
|
|
|
|
|
class TestVerificationConstants:
|
|
def test_no_segments_reason_value(self) -> None:
|
|
expected = "No segments retrieved for question"
|
|
assert expected == NO_SEGMENTS_REASON, "constant should match"
|
|
|
|
def test_invalid_citations_prefix_value(self) -> None:
|
|
expected = "Invalid citation indices: "
|
|
assert expected == INVALID_CITATIONS_PREFIX, "constant should match"
|