refactor(tests): one definition each for the copied fixtures and fakes (#2825, milestone 296 area 1)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 8s
CI & Build / integration (push) Successful in 24s
CI & Build / TypeScript typecheck (push) Successful in 32s
CI & Build / Python tests (push) Successful in 54s
CI & Build / Build & push image (push) Successful in 18s
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 8s
CI & Build / integration (push) Successful in 24s
CI & Build / TypeScript typecheck (push) Successful in 32s
CI & Build / Python tests (push) Successful in 54s
CI & Build / Build & push image (push) Successful in 18s
The shape ledger showed the same test scaffolding defined over and over: _bind_user x12 (byte-identical), _dispose_engine x10 in three wordings, _no_supersession x3, _make_mock_session x7 in three subsets, a get-or-create User helper x2 (+3 inlined), and fifteen hand-rolled MagicMock note factories each re-explaining the same "an auto-MagicMock attribute is truthy" hazard (note 2109). Now: conftest.py carries _bind_user / _dispose_engine / _no_supersession as opt-in fixtures (pytestmark = usefixtures(...) per module, so unit tests pay nothing), and tests/helpers.py carries make_mock_session(), ensure_user() and fake_note(**attrs) — the hazard documented once, real values on every attribute the product reads. Call sites were rewritten by AST so titles with dashes and commas survived; the three SimpleNamespace _note stand-ins that only feed a single function stay local. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,7 @@ from scribe.services.dedup import (
|
||||
find_duplicate_note,
|
||||
find_duplicate_rule,
|
||||
)
|
||||
from tests.helpers import fake_note
|
||||
|
||||
|
||||
def _session_returning(note):
|
||||
@@ -22,15 +23,9 @@ def _session_returning(note):
|
||||
return s
|
||||
|
||||
|
||||
def _fake_note(id=1, title="T", note_type="note"):
|
||||
n = MagicMock()
|
||||
n.id, n.title, n.note_type = id, title, note_type
|
||||
return n
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_title_exact_match_returns_title_duplicate():
|
||||
note = _fake_note(id=10, title="Setup CI")
|
||||
note = fake_note(id=10, title="Setup CI")
|
||||
with patch("scribe.services.dedup.async_session",
|
||||
return_value=_session_returning(note)):
|
||||
# whitespace/case differences are normalized away
|
||||
@@ -54,7 +49,7 @@ async def test_short_body_skips_semantic_check():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_semantic_match_when_body_substantial():
|
||||
hit = _fake_note(id=20, title="Existing", note_type="note")
|
||||
hit = fake_note(id=20, title="Existing", note_type="note")
|
||||
sem = AsyncMock(return_value=[(0.93, hit)])
|
||||
with patch("scribe.services.dedup.async_session",
|
||||
return_value=_session_returning(None)), \
|
||||
@@ -82,7 +77,7 @@ async def test_gate_catches_a_duplicate_hiding_in_a_later_chunk():
|
||||
n_chunks = len(chunk_document("Title", body))
|
||||
assert n_chunks > 1, "test body must actually chunk"
|
||||
|
||||
hit = _fake_note(id=30, title="The existing decision", note_type="note")
|
||||
hit = fake_note(id=30, title="The existing decision", note_type="note")
|
||||
# Every chunk misses except the LAST one the gate will ask about.
|
||||
sem = AsyncMock(side_effect=[[] for _ in range(n_chunks - 1)] + [[(0.94, hit)]])
|
||||
with patch("scribe.services.dedup.async_session",
|
||||
@@ -97,7 +92,7 @@ async def test_gate_catches_a_duplicate_hiding_in_a_later_chunk():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_semantic_match_of_other_note_type_is_ignored():
|
||||
other = _fake_note(id=21, title="X", note_type="process")
|
||||
other = fake_note(id=21, title="X", note_type="process")
|
||||
sem = AsyncMock(return_value=[(0.97, other)])
|
||||
with patch("scribe.services.dedup.async_session",
|
||||
return_value=_session_returning(None)), \
|
||||
@@ -108,7 +103,7 @@ async def test_semantic_match_of_other_note_type_is_ignored():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_rule_title_match_in_topic():
|
||||
rule = _fake_note(id=47, title="Honor the multi-user sharing ACL")
|
||||
rule = fake_note(id=47, title="Honor the multi-user sharing ACL")
|
||||
with patch("scribe.services.dedup.async_session",
|
||||
return_value=_session_returning(rule)):
|
||||
dup = await find_duplicate_rule(
|
||||
@@ -171,8 +166,7 @@ def _session_sequence(results):
|
||||
async def test_same_location_is_a_duplicate_however_it_is_described():
|
||||
"""The measured false NEGATIVE: identical code at an identical
|
||||
repo·path·symbol was created because the prose around it differed."""
|
||||
existing = _fake_note(id=30, title=".btn-primary — a page's main action",
|
||||
note_type="snippet")
|
||||
existing = fake_note(id=30, title=".btn-primary — a page's main action", note_type="snippet")
|
||||
sem = AsyncMock()
|
||||
with patch("scribe.services.dedup.async_session",
|
||||
return_value=_session_sequence([None, existing])), \
|
||||
@@ -193,7 +187,7 @@ async def test_same_location_is_a_duplicate_however_it_is_described():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_identical_code_is_a_duplicate_at_a_different_location():
|
||||
existing = _fake_note(id=31, title="group_pairs", note_type="snippet")
|
||||
existing = fake_note(id=31, title="group_pairs", note_type="snippet")
|
||||
with patch("scribe.services.dedup.async_session",
|
||||
return_value=_session_sequence([None, None, existing])), \
|
||||
patch("scribe.services.dedup.embeddings_svc.semantic_search_notes",
|
||||
|
||||
Reference in New Issue
Block a user