Files
wehub-resource-sync 7a0da7932b
Backwards Compatibility / Verify Encryption Constants (push) Waiting to run
Backwards Compatibility / PyPI Version Compatibility (push) Waiting to run
Backwards Compatibility / Database Migration Tests (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
CodeQL Advanced / Analyze (python) (push) Waiting to run
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Blocked by required conditions
Docker Tests (Consolidated) / detect-changes (push) Waiting to run
Docker Tests (Consolidated) / Build Test Image (push) Waiting to run
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Blocked by required conditions
Docker Tests (Consolidated) / Accessibility Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / LLM Unit Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / LLM Example Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / Production Image Smoke Test (push) Blocked by required conditions
Docker Tests (Consolidated) / Infrastructure Tests (push) Blocked by required conditions
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Waiting to run
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:08:55 +08:00

705 lines
22 KiB
Python

"""
Tests for advanced_search_system base classes.
Tests cover:
- Constraint and ConstraintType
- Candidate class
- Evidence and EvidenceType
- BaseFilter abstract class
"""
import pytest
from unittest.mock import Mock
class TestConstraintType:
"""Tests for ConstraintType enum."""
def test_constraint_type_values(self):
"""Test all constraint type enum values exist."""
from local_deep_research.advanced_search_system.constraints.base_constraint import (
ConstraintType,
)
assert ConstraintType.PROPERTY.value == "property"
assert ConstraintType.NAME_PATTERN.value == "name_pattern"
assert ConstraintType.EVENT.value == "event"
assert ConstraintType.STATISTIC.value == "statistic"
assert ConstraintType.TEMPORAL.value == "temporal"
assert ConstraintType.LOCATION.value == "location"
assert ConstraintType.COMPARISON.value == "comparison"
assert ConstraintType.EXISTENCE.value == "existence"
def test_constraint_type_count(self):
"""Test that all constraint types are defined."""
from local_deep_research.advanced_search_system.constraints.base_constraint import (
ConstraintType,
)
assert len(ConstraintType) == 8
class TestConstraint:
"""Tests for Constraint dataclass."""
def test_constraint_creation_minimal(self):
"""Test creating constraint with minimal required fields."""
from local_deep_research.advanced_search_system.constraints.base_constraint import (
Constraint,
ConstraintType,
)
constraint = Constraint(
id="c1",
type=ConstraintType.PROPERTY,
description="Test constraint",
value="test value",
)
assert constraint.id == "c1"
assert constraint.type == ConstraintType.PROPERTY
assert constraint.description == "Test constraint"
assert constraint.value == "test value"
assert constraint.weight == 1.0
assert constraint.metadata == {}
def test_constraint_creation_full(self):
"""Test creating constraint with all fields."""
from local_deep_research.advanced_search_system.constraints.base_constraint import (
Constraint,
ConstraintType,
)
metadata = {"source": "test"}
constraint = Constraint(
id="c2",
type=ConstraintType.TEMPORAL,
description="Time constraint",
value="2024",
weight=0.5,
metadata=metadata,
)
assert constraint.id == "c2"
assert constraint.weight == 0.5
assert constraint.metadata == metadata
def test_constraint_post_init_creates_metadata(self):
"""Test that __post_init__ creates empty metadata dict."""
from local_deep_research.advanced_search_system.constraints.base_constraint import (
Constraint,
ConstraintType,
)
constraint = Constraint(
id="c3",
type=ConstraintType.LOCATION,
description="Location",
value="Colorado",
)
assert constraint.metadata is not None
assert isinstance(constraint.metadata, dict)
def test_constraint_to_search_terms_property(self):
"""Test to_search_terms for PROPERTY type."""
from local_deep_research.advanced_search_system.constraints.base_constraint import (
Constraint,
ConstraintType,
)
constraint = Constraint(
id="c1",
type=ConstraintType.PROPERTY,
description="Test",
value="formed during ice age",
)
result = constraint.to_search_terms()
assert result == "formed during ice age"
def test_constraint_to_search_terms_name_pattern(self):
"""Test to_search_terms for NAME_PATTERN type."""
from local_deep_research.advanced_search_system.constraints.base_constraint import (
Constraint,
ConstraintType,
)
constraint = Constraint(
id="c1",
type=ConstraintType.NAME_PATTERN,
description="Test",
value="body part",
)
result = constraint.to_search_terms()
assert "body part" in result
assert "name" in result
assert "trail" in result
def test_constraint_to_search_terms_event(self):
"""Test to_search_terms for EVENT type."""
from local_deep_research.advanced_search_system.constraints.base_constraint import (
Constraint,
ConstraintType,
)
constraint = Constraint(
id="c1",
type=ConstraintType.EVENT,
description="Test",
value="rockslide 2020",
)
result = constraint.to_search_terms()
assert "rockslide 2020" in result
assert "accident" in result or "incident" in result
def test_constraint_to_search_terms_statistic(self):
"""Test to_search_terms for STATISTIC type."""
from local_deep_research.advanced_search_system.constraints.base_constraint import (
Constraint,
ConstraintType,
)
constraint = Constraint(
id="c1",
type=ConstraintType.STATISTIC,
description="Test",
value="84.5x ratio",
)
result = constraint.to_search_terms()
assert "84.5x ratio" in result
assert "statistics" in result or "data" in result
def test_constraint_to_search_terms_other(self):
"""Test to_search_terms for other types (e.g., TEMPORAL)."""
from local_deep_research.advanced_search_system.constraints.base_constraint import (
Constraint,
ConstraintType,
)
constraint = Constraint(
id="c1",
type=ConstraintType.TEMPORAL,
description="Test",
value="2024",
)
result = constraint.to_search_terms()
assert result == "2024"
def test_constraint_is_critical_name_pattern(self):
"""Test is_critical returns True for NAME_PATTERN type."""
from local_deep_research.advanced_search_system.constraints.base_constraint import (
Constraint,
ConstraintType,
)
constraint = Constraint(
id="c1",
type=ConstraintType.NAME_PATTERN,
description="Test",
value="test",
weight=0.5, # Low weight but still critical
)
assert constraint.is_critical() is True
def test_constraint_is_critical_high_weight(self):
"""Test is_critical returns True for high weight constraints."""
from local_deep_research.advanced_search_system.constraints.base_constraint import (
Constraint,
ConstraintType,
)
constraint = Constraint(
id="c1",
type=ConstraintType.PROPERTY,
description="Test",
value="test",
weight=0.9,
)
assert constraint.is_critical() is True
def test_constraint_is_critical_low_weight(self):
"""Test is_critical returns False for low weight non-NAME_PATTERN."""
from local_deep_research.advanced_search_system.constraints.base_constraint import (
Constraint,
ConstraintType,
)
constraint = Constraint(
id="c1",
type=ConstraintType.PROPERTY,
description="Test",
value="test",
weight=0.5,
)
assert constraint.is_critical() is False
class TestEvidenceType:
"""Tests for EvidenceType enum."""
def test_evidence_type_values(self):
"""Test all evidence type enum values exist."""
from local_deep_research.advanced_search_system.evidence.base_evidence import (
EvidenceType,
)
assert EvidenceType.DIRECT_STATEMENT.value == "direct_statement"
assert EvidenceType.OFFICIAL_RECORD.value == "official_record"
assert EvidenceType.RESEARCH_FINDING.value == "research_finding"
assert EvidenceType.NEWS_REPORT.value == "news_report"
assert EvidenceType.STATISTICAL_DATA.value == "statistical_data"
assert EvidenceType.INFERENCE.value == "inference"
assert EvidenceType.CORRELATION.value == "correlation"
assert EvidenceType.SPECULATION.value == "speculation"
def test_evidence_type_base_confidence(self):
"""Test base confidence values for evidence types."""
from local_deep_research.advanced_search_system.evidence.base_evidence import (
EvidenceType,
)
assert EvidenceType.DIRECT_STATEMENT.base_confidence == 0.95
assert EvidenceType.OFFICIAL_RECORD.base_confidence == 0.90
assert EvidenceType.RESEARCH_FINDING.base_confidence == 0.85
assert EvidenceType.STATISTICAL_DATA.base_confidence == 0.85
assert EvidenceType.NEWS_REPORT.base_confidence == 0.75
assert EvidenceType.INFERENCE.base_confidence == 0.50
assert EvidenceType.CORRELATION.base_confidence == 0.30
assert EvidenceType.SPECULATION.base_confidence == 0.10
class TestEvidence:
"""Tests for Evidence dataclass."""
def test_evidence_creation_minimal(self):
"""Test creating evidence with minimal fields."""
from local_deep_research.advanced_search_system.evidence.base_evidence import (
Evidence,
EvidenceType,
)
evidence = Evidence(
claim="Test claim",
type=EvidenceType.NEWS_REPORT,
source="https://example.com",
)
assert evidence.claim == "Test claim"
assert evidence.type == EvidenceType.NEWS_REPORT
assert evidence.source == "https://example.com"
# Post-init should set confidence based on type
assert evidence.confidence == 0.75
def test_evidence_creation_with_confidence(self):
"""Test creating evidence with explicit confidence."""
from local_deep_research.advanced_search_system.evidence.base_evidence import (
Evidence,
EvidenceType,
)
evidence = Evidence(
claim="Test claim",
type=EvidenceType.NEWS_REPORT,
source="https://example.com",
confidence=0.9,
)
# Should keep provided confidence, not override
assert evidence.confidence == 0.9
def test_evidence_creation_full(self):
"""Test creating evidence with all fields."""
from local_deep_research.advanced_search_system.evidence.base_evidence import (
Evidence,
EvidenceType,
)
evidence = Evidence(
claim="Test claim",
type=EvidenceType.OFFICIAL_RECORD,
source="https://official.gov",
confidence=0.95,
reasoning="Found in official database",
raw_text="The official record states...",
metadata={"page": 1},
)
assert evidence.claim == "Test claim"
assert evidence.reasoning == "Found in official database"
assert evidence.raw_text == "The official record states..."
assert evidence.metadata == {"page": 1}
def test_evidence_timestamp_auto_generated(self):
"""Test that timestamp is automatically generated."""
from local_deep_research.advanced_search_system.evidence.base_evidence import (
Evidence,
EvidenceType,
)
evidence = Evidence(
claim="Test",
type=EvidenceType.INFERENCE,
source="test",
)
assert evidence.timestamp is not None
assert len(evidence.timestamp) > 0
def test_evidence_post_init_sets_confidence(self):
"""Test __post_init__ sets confidence based on type when 0."""
from local_deep_research.advanced_search_system.evidence.base_evidence import (
Evidence,
EvidenceType,
)
evidence = Evidence(
claim="Test",
type=EvidenceType.DIRECT_STATEMENT,
source="test",
confidence=0.0, # Will be replaced
)
assert evidence.confidence == 0.95
class TestCandidate:
"""Tests for Candidate dataclass."""
def test_candidate_creation_minimal(self):
"""Test creating candidate with minimal fields."""
from local_deep_research.advanced_search_system.candidates.base_candidate import (
Candidate,
)
candidate = Candidate(name="Test Candidate")
assert candidate.name == "Test Candidate"
assert candidate.evidence == {}
assert candidate.score == 0.0
assert candidate.metadata == {}
def test_candidate_add_evidence(self):
"""Test adding evidence to a candidate."""
from local_deep_research.advanced_search_system.candidates.base_candidate import (
Candidate,
)
from local_deep_research.advanced_search_system.evidence.base_evidence import (
Evidence,
EvidenceType,
)
candidate = Candidate(name="Test")
evidence = Evidence(
claim="Test claim",
type=EvidenceType.NEWS_REPORT,
source="https://example.com",
)
candidate.add_evidence("constraint_1", evidence)
assert "constraint_1" in candidate.evidence
assert candidate.evidence["constraint_1"] == evidence
def test_candidate_calculate_score_empty(self):
"""Test score calculation with no constraints."""
from local_deep_research.advanced_search_system.candidates.base_candidate import (
Candidate,
)
candidate = Candidate(name="Test")
score = candidate.calculate_score([])
assert score == 0.0
def test_candidate_calculate_score_with_evidence(self):
"""Test score calculation with evidence."""
from local_deep_research.advanced_search_system.candidates.base_candidate import (
Candidate,
)
from local_deep_research.advanced_search_system.constraints.base_constraint import (
Constraint,
ConstraintType,
)
from local_deep_research.advanced_search_system.evidence.base_evidence import (
Evidence,
EvidenceType,
)
candidate = Candidate(name="Test")
# Create constraints
c1 = Constraint(
id="c1",
type=ConstraintType.PROPERTY,
description="Test 1",
value="test",
weight=1.0,
)
c2 = Constraint(
id="c2",
type=ConstraintType.PROPERTY,
description="Test 2",
value="test",
weight=1.0,
)
# Add evidence with 0.8 confidence
evidence = Evidence(
claim="Test",
type=EvidenceType.NEWS_REPORT,
source="test",
confidence=0.8,
)
candidate.add_evidence("c1", evidence)
score = candidate.calculate_score([c1, c2])
# Score = (0.8 * 1.0) / (1.0 + 1.0) = 0.4
assert score == 0.4
assert candidate.score == 0.4
def test_candidate_calculate_score_weighted(self):
"""Test score calculation with weighted constraints."""
from local_deep_research.advanced_search_system.candidates.base_candidate import (
Candidate,
)
from local_deep_research.advanced_search_system.constraints.base_constraint import (
Constraint,
ConstraintType,
)
from local_deep_research.advanced_search_system.evidence.base_evidence import (
Evidence,
EvidenceType,
)
candidate = Candidate(name="Test")
# Create constraints with different weights
c1 = Constraint(
id="c1",
type=ConstraintType.PROPERTY,
description="Critical",
value="test",
weight=2.0,
)
c2 = Constraint(
id="c2",
type=ConstraintType.PROPERTY,
description="Minor",
value="test",
weight=0.5,
)
# Add evidence for c1 only
evidence = Evidence(
claim="Test",
type=EvidenceType.DIRECT_STATEMENT,
source="test",
confidence=1.0,
)
candidate.add_evidence("c1", evidence)
score = candidate.calculate_score([c1, c2])
# Score = (1.0 * 2.0) / (2.0 + 0.5) = 2.0 / 2.5 = 0.8
assert score == 0.8
def test_candidate_get_unverified_constraints(self):
"""Test getting unverified constraints."""
from local_deep_research.advanced_search_system.candidates.base_candidate import (
Candidate,
)
from local_deep_research.advanced_search_system.constraints.base_constraint import (
Constraint,
ConstraintType,
)
from local_deep_research.advanced_search_system.evidence.base_evidence import (
Evidence,
EvidenceType,
)
candidate = Candidate(name="Test")
c1 = Constraint(
id="c1",
type=ConstraintType.PROPERTY,
description="Test 1",
value="test",
)
c2 = Constraint(
id="c2",
type=ConstraintType.PROPERTY,
description="Test 2",
value="test",
)
c3 = Constraint(
id="c3",
type=ConstraintType.PROPERTY,
description="Test 3",
value="test",
)
# Add evidence for c1 only
evidence = Evidence(
claim="Test",
type=EvidenceType.NEWS_REPORT,
source="test",
)
candidate.add_evidence("c1", evidence)
unverified = candidate.get_unverified_constraints([c1, c2, c3])
assert len(unverified) == 2
assert c2 in unverified
assert c3 in unverified
assert c1 not in unverified
def test_candidate_get_weak_evidence(self):
"""Test getting constraints with weak evidence."""
from local_deep_research.advanced_search_system.candidates.base_candidate import (
Candidate,
)
from local_deep_research.advanced_search_system.evidence.base_evidence import (
Evidence,
EvidenceType,
)
candidate = Candidate(name="Test")
# Add strong evidence
strong = Evidence(
claim="Strong",
type=EvidenceType.DIRECT_STATEMENT,
source="test",
confidence=0.9,
)
candidate.add_evidence("c1", strong)
# Add weak evidence
weak = Evidence(
claim="Weak",
type=EvidenceType.SPECULATION,
source="test",
confidence=0.3,
)
candidate.add_evidence("c2", weak)
weak_constraints = candidate.get_weak_evidence(threshold=0.5)
assert len(weak_constraints) == 1
assert "c2" in weak_constraints
assert "c1" not in weak_constraints
def test_candidate_get_weak_evidence_custom_threshold(self):
"""Test getting weak evidence with custom threshold."""
from local_deep_research.advanced_search_system.candidates.base_candidate import (
Candidate,
)
from local_deep_research.advanced_search_system.evidence.base_evidence import (
Evidence,
EvidenceType,
)
candidate = Candidate(name="Test")
evidence = Evidence(
claim="Medium",
type=EvidenceType.NEWS_REPORT,
source="test",
confidence=0.7,
)
candidate.add_evidence("c1", evidence)
# With default threshold of 0.5, should not be weak
weak_default = candidate.get_weak_evidence()
assert "c1" not in weak_default
# With higher threshold, should be weak
weak_high = candidate.get_weak_evidence(threshold=0.8)
assert "c1" in weak_high
class TestBaseFilter:
"""Tests for BaseFilter abstract class."""
def test_base_filter_is_abstract(self):
"""Test that BaseFilter is abstract and cannot be instantiated."""
from local_deep_research.advanced_search_system.filters.base_filter import (
BaseFilter,
)
with pytest.raises(TypeError):
BaseFilter()
def test_base_filter_with_model(self):
"""Test BaseFilter subclass with model."""
from local_deep_research.advanced_search_system.filters.base_filter import (
BaseFilter,
)
class ConcreteFilter(BaseFilter):
def filter_results(self, results, query, **kwargs):
return results
mock_model = Mock()
filter_instance = ConcreteFilter(model=mock_model)
assert filter_instance.model == mock_model
def test_base_filter_without_model(self):
"""Test BaseFilter subclass without model."""
from local_deep_research.advanced_search_system.filters.base_filter import (
BaseFilter,
)
class ConcreteFilter(BaseFilter):
def filter_results(self, results, query, **kwargs):
return results
filter_instance = ConcreteFilter()
assert filter_instance.model is None
def test_base_filter_filter_results_abstract(self):
"""Test that filter_results must be implemented."""
from local_deep_research.advanced_search_system.filters.base_filter import (
BaseFilter,
)
class IncompleteFilter(BaseFilter):
pass
with pytest.raises(TypeError):
IncompleteFilter()
def test_base_filter_concrete_implementation(self):
"""Test a concrete filter implementation."""
from local_deep_research.advanced_search_system.filters.base_filter import (
BaseFilter,
)
class RelevanceFilter(BaseFilter):
def filter_results(self, results, query, **kwargs):
threshold = kwargs.get("threshold", 0.5)
return [r for r in results if r.get("score", 0) >= threshold]
filter_instance = RelevanceFilter()
results = [
{"title": "A", "score": 0.9},
{"title": "B", "score": 0.3},
{"title": "C", "score": 0.7},
]
filtered = filter_instance.filter_results(results, "test query")
assert len(filtered) == 2
assert {"title": "A", "score": 0.9} in filtered
assert {"title": "C", "score": 0.7} in filtered