Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Enterprise-grade research with multi-source synthesis, citation tracking, and verification. 8-phase pipeline with auto-continuation.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
tests/test_evidence_store.py
1#!/usr/bin/env python32"""Smoke tests for evidence_store.py CLI."""34import json5import os6import shutil7import subprocess8import sys9import tempfile10import unittest1112SCRIPT = os.path.join(os.path.dirname(__file__), '..', 'scripts', 'evidence_store.py')131415def run_es(*args: str) -> dict | list:16"""Run evidence_store.py with args, return parsed JSON from stdout."""17result = subprocess.run(18[sys.executable, SCRIPT, *args],19capture_output=True, text=True,20)21if result.returncode != 0:22raise RuntimeError(f'Exit {result.returncode}: {result.stderr}')23return json.loads(result.stdout)242526class TestInit(unittest.TestCase):27def test_creates_empty_file(self):28with tempfile.TemporaryDirectory() as d:29out = run_es('init', '--dir', d)30self.assertEqual(out['status'], 'ok')31path = os.path.join(d, 'evidence.jsonl')32self.assertTrue(os.path.exists(path))33self.assertEqual(os.path.getsize(path), 0)343536class TestAddEvidence(unittest.TestCase):37def setUp(self):38self.tmpdir = tempfile.mkdtemp()39run_es('init', '--dir', self.tmpdir)4041def tearDown(self):42shutil.rmtree(self.tmpdir, ignore_errors=True)4344def test_add_and_dedup(self):45ev = json.dumps({46'source_id': 'abcdef0123456789',47'quote': 'FActScore decomposes generation into atomic facts.',48'evidence_type': 'direct_quote',49'locator': 'page 3',50'retrieval_query': 'factuality evaluation methods',51})52out1 = run_es('add', '--json', ev, '--dir', self.tmpdir)53self.assertEqual(out1['status'], 'added')54self.assertEqual(len(out1['evidence_id']), 16)5556# Same quote -> duplicate57out2 = run_es('add', '--json', ev, '--dir', self.tmpdir)58self.assertEqual(out2['status'], 'duplicate')59self.assertEqual(out2['evidence_id'], out1['evidence_id'])6061def test_whitespace_normalization(self):62ev1 = json.dumps({63'source_id': 'abcdef0123456789',64'quote': ' FActScore decomposes generation into atomic facts. ',65'evidence_type': 'direct_quote',66})67ev2 = json.dumps({68'source_id': 'abcdef0123456789',69'quote': 'FActScore decomposes generation into atomic facts.',70'evidence_type': 'direct_quote',71})72out1 = run_es('add', '--json', ev1, '--dir', self.tmpdir)73out2 = run_es('add', '--json', ev2, '--dir', self.tmpdir)74# Should be same ID due to normalization75self.assertEqual(out1['evidence_id'], out2['evidence_id'])76self.assertEqual(out2['status'], 'duplicate')7778def test_different_sources_different_ids(self):79ev1 = json.dumps({80'source_id': 'aaaaaaaaaaaaaaaa',81'quote': 'Same quote text.',82'evidence_type': 'paraphrase',83})84ev2 = json.dumps({85'source_id': 'bbbbbbbbbbbbbbbb',86'quote': 'Same quote text.',87'evidence_type': 'paraphrase',88})89out1 = run_es('add', '--json', ev1, '--dir', self.tmpdir)90out2 = run_es('add', '--json', ev2, '--dir', self.tmpdir)91self.assertNotEqual(out1['evidence_id'], out2['evidence_id'])92self.assertEqual(out2['status'], 'added')939495class TestListAndExport(unittest.TestCase):96def setUp(self):97self.tmpdir = tempfile.mkdtemp()98run_es('init', '--dir', self.tmpdir)99# Add 3 evidence items from 2 sources100for src, quote in [101('src_aaa', 'First quote from source A.'),102('src_aaa', 'Second quote from source A.'),103('src_bbb', 'Quote from source B.'),104]:105run_es('add', '--json', json.dumps({106'source_id': src,107'quote': quote,108'evidence_type': 'direct_quote',109}), '--dir', self.tmpdir)110111def tearDown(self):112shutil.rmtree(self.tmpdir, ignore_errors=True)113114def test_list_all(self):115out = run_es('list', '--dir', self.tmpdir)116self.assertEqual(out['count'], 3)117118def test_list_filtered(self):119out = run_es('list', '--dir', self.tmpdir, '--source-id', 'src_aaa')120self.assertEqual(out['count'], 2)121122out = run_es('list', '--dir', self.tmpdir, '--source-id', 'src_bbb')123self.assertEqual(out['count'], 1)124125def test_export(self):126out = run_es('export', '--dir', self.tmpdir)127self.assertIsInstance(out, list)128self.assertEqual(len(out), 3)129# Each has required fields130for row in out:131self.assertIn('evidence_id', row)132self.assertIn('source_id', row)133self.assertIn('quote', row)134self.assertIn('evidence_type', row)135self.assertIn('captured_at', row)136137138class TestEvidenceID(unittest.TestCase):139"""Unit tests for compute_evidence_id."""140141@classmethod142def setUpClass(cls):143sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'scripts'))144from evidence_store import compute_evidence_id, normalize_quote145cls.compute_id = staticmethod(compute_evidence_id)146cls.normalize = staticmethod(normalize_quote)147148def test_deterministic(self):149id1 = self.compute_id('src_a', 'test quote', 'page 1')150id2 = self.compute_id('src_a', 'test quote', 'page 1')151self.assertEqual(id1, id2)152153def test_locator_matters(self):154id1 = self.compute_id('src_a', 'test quote', 'page 1')155id2 = self.compute_id('src_a', 'test quote', 'page 2')156self.assertNotEqual(id1, id2)157158def test_normalize_whitespace(self):159self.assertEqual(160self.normalize(' hello world '),161'hello world',162)163164165if __name__ == '__main__':166unittest.main()167