Files
wehub-resource-sync 7a0da7932b
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
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:08:55 +08:00

386 lines
12 KiB
Python

"""
Behavioral tests for base_candidate module.
Tests Candidate dataclass with evidence management and scoring logic.
"""
import pytest
class TestCandidateInit:
"""Tests for Candidate dataclass initialization."""
def test_basic_construction(self):
from local_deep_research.advanced_search_system.candidates.base_candidate import (
Candidate,
)
c = Candidate(name="Lake X")
assert c.name == "Lake X"
def test_evidence_defaults_empty_dict(self):
from local_deep_research.advanced_search_system.candidates.base_candidate import (
Candidate,
)
c = Candidate(name="Lake X")
assert c.evidence == {}
def test_score_defaults_zero(self):
from local_deep_research.advanced_search_system.candidates.base_candidate import (
Candidate,
)
c = Candidate(name="Lake X")
assert c.score == 0.0
def test_metadata_defaults_empty_dict(self):
from local_deep_research.advanced_search_system.candidates.base_candidate import (
Candidate,
)
c = Candidate(name="Lake X")
assert c.metadata == {}
class TestCandidateAddEvidence:
"""Tests for Candidate.add_evidence() method."""
def test_add_single_evidence(self):
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,
)
c = Candidate(name="Lake X")
e = Evidence(
claim="formed in ice age",
type=EvidenceType.RESEARCH_FINDING,
source="wiki",
)
c.add_evidence("c1", e)
assert "c1" in c.evidence
assert c.evidence["c1"] is e
def test_add_multiple_evidence(self):
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,
)
c = Candidate(name="Lake X")
e1 = Evidence(
claim="claim1", type=EvidenceType.DIRECT_STATEMENT, source="s1"
)
e2 = Evidence(
claim="claim2", type=EvidenceType.NEWS_REPORT, source="s2"
)
c.add_evidence("c1", e1)
c.add_evidence("c2", e2)
assert len(c.evidence) == 2
def test_overwrite_existing_evidence(self):
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,
)
c = Candidate(name="Lake X")
e1 = Evidence(claim="old", type=EvidenceType.INFERENCE, source="s1")
e2 = Evidence(
claim="new", type=EvidenceType.DIRECT_STATEMENT, source="s2"
)
c.add_evidence("c1", e1)
c.add_evidence("c1", e2)
assert c.evidence["c1"].claim == "new"
class TestCandidateCalculateScore:
"""Tests for Candidate.calculate_score() method."""
def test_empty_constraints_returns_zero(self):
from local_deep_research.advanced_search_system.candidates.base_candidate import (
Candidate,
)
c = Candidate(name="Lake X")
assert c.calculate_score([]) == 0.0
def test_single_constraint_with_evidence(self):
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,
)
c = Candidate(name="Lake X")
constraint = Constraint(
id="c1",
type=ConstraintType.PROPERTY,
description="d",
value="v",
weight=1.0,
)
evidence = Evidence(
claim="supports",
type=EvidenceType.DIRECT_STATEMENT,
source="s",
confidence=0.8,
)
c.add_evidence("c1", evidence)
score = c.calculate_score([constraint])
assert score == pytest.approx(0.8)
def test_score_considers_weight(self):
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,
)
c = Candidate(name="Lake X")
c1 = Constraint(
id="c1",
type=ConstraintType.PROPERTY,
description="d",
value="v",
weight=2.0,
)
c2 = Constraint(
id="c2",
type=ConstraintType.EVENT,
description="d",
value="v",
weight=1.0,
)
e1 = Evidence(
claim="e1",
type=EvidenceType.DIRECT_STATEMENT,
source="s",
confidence=0.9,
)
e2 = Evidence(
claim="e2",
type=EvidenceType.NEWS_REPORT,
source="s",
confidence=0.3,
)
c.add_evidence("c1", e1)
c.add_evidence("c2", e2)
score = c.calculate_score([c1, c2])
# (0.9*2.0 + 0.3*1.0) / (2.0 + 1.0) = 2.1 / 3.0 = 0.7
assert score == pytest.approx(0.7)
def test_missing_evidence_contributes_zero(self):
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,
)
c = Candidate(name="Lake X")
constraint = Constraint(
id="c1",
type=ConstraintType.PROPERTY,
description="d",
value="v",
weight=1.0,
)
score = c.calculate_score([constraint])
assert score == 0.0
def test_score_stored_on_candidate(self):
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,
)
c = Candidate(name="Lake X")
constraint = Constraint(
id="c1", type=ConstraintType.PROPERTY, description="d", value="v"
)
evidence = Evidence(
claim="c",
type=EvidenceType.DIRECT_STATEMENT,
source="s",
confidence=0.7,
)
c.add_evidence("c1", evidence)
c.calculate_score([constraint])
assert c.score == pytest.approx(0.7)
class TestCandidateGetUnverifiedConstraints:
"""Tests for Candidate.get_unverified_constraints() method."""
def test_all_unverified_when_no_evidence(self):
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,
)
c = Candidate(name="Lake X")
constraints = [
Constraint(
id="c1",
type=ConstraintType.PROPERTY,
description="d",
value="v",
),
Constraint(
id="c2", type=ConstraintType.EVENT, description="d", value="v"
),
]
unverified = c.get_unverified_constraints(constraints)
assert len(unverified) == 2
def test_none_unverified_when_all_have_evidence(self):
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,
)
c = Candidate(name="Lake X")
constraint = Constraint(
id="c1", type=ConstraintType.PROPERTY, description="d", value="v"
)
c.add_evidence(
"c1", Evidence(claim="c", type=EvidenceType.INFERENCE, source="s")
)
assert len(c.get_unverified_constraints([constraint])) == 0
def test_partial_evidence_returns_missing(self):
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,
)
c = Candidate(name="Lake X")
c1 = Constraint(
id="c1", type=ConstraintType.PROPERTY, description="d", value="v"
)
c2 = Constraint(
id="c2", type=ConstraintType.EVENT, description="d", value="v"
)
c.add_evidence(
"c1", Evidence(claim="c", type=EvidenceType.INFERENCE, source="s")
)
unverified = c.get_unverified_constraints([c1, c2])
assert len(unverified) == 1
assert unverified[0].id == "c2"
class TestCandidateGetWeakEvidence:
"""Tests for Candidate.get_weak_evidence() method."""
def test_empty_evidence_returns_empty(self):
from local_deep_research.advanced_search_system.candidates.base_candidate import (
Candidate,
)
c = Candidate(name="Lake X")
assert c.get_weak_evidence() == []
def test_returns_low_confidence_ids(self):
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,
)
c = Candidate(name="Lake X")
c.add_evidence(
"c1",
Evidence(
claim="weak",
type=EvidenceType.SPECULATION,
source="s",
confidence=0.1,
),
)
c.add_evidence(
"c2",
Evidence(
claim="strong",
type=EvidenceType.DIRECT_STATEMENT,
source="s",
confidence=0.9,
),
)
weak = c.get_weak_evidence(threshold=0.5)
assert "c1" in weak
assert "c2" not in weak
def test_custom_threshold(self):
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,
)
c = Candidate(name="Lake X")
c.add_evidence(
"c1",
Evidence(
claim="c",
type=EvidenceType.NEWS_REPORT,
source="s",
confidence=0.75,
),
)
# Default threshold is 0.5 - should not be weak
assert "c1" not in c.get_weak_evidence(threshold=0.5)
# Higher threshold - should be weak
assert "c1" in c.get_weak_evidence(threshold=0.8)