import hashlib import json from pathlib import Path import tempfile import unittest from unittest.mock import patch from paper_atlas.collectors import aamas, aamas2025 FIXTURE = Path(__file__).parent/'fixtures/aamas2025' class Aamas2025Tests(unittest.TestCase): def parse(self, html=None): return aamas2025.parse_contents(html or (FIXTURE/'contents.html').read_text(), {'observed_at': '2026-11-09T12:31:50+00:00', 'url': aamas2025.URLS['contents']}) def test_real_toc_preserves_every_title_author_and_affiliation(self): expected = json.loads((FIXTURE/'expected-authors.json').read_text()) self.assertEqual(hashlib.sha256((FIXTURE/'contents.html').read_bytes()).hexdigest(), expected['source_sha256']) rows, excluded = self.parse() self.assertEqual((len(rows), len(excluded)), (476, 3)) by_url = {r['paper_url']: r for r in expected['entries']} for row in rows: original = by_url[row['metadata']['paper_url']] self.assertEqual(row['title'], original['title']) self.assertEqual(row['authors'], [a['name'] for a in original['authors']]) self.assertEqual(row['metadata']['author_affiliations'], [a['affiliation'] for a in original['authors']]) self.assertIsNone(row['abstract']) self.assertEqual(row['identifiers'], {}) self.assertEqual(row['status'], 'accepted') self.assertNotIn('decision_date', row) self.assertTrue(all(t['namespace'] == 'aamas_proceedings:publication_format' for t in row['tags'])) def test_publication_format_and_track_are_separate(self): rows, excluded = self.parse() groups = {k: sum(r['track'] == k for r in rows) for k in {r['track'] for r in rows}} self.assertEqual(groups, {'proceedings_unspecified': 409, 'blue_sky': 12, 'doctoral': 25, 'demo': 21, 'jaamas': 9}) competition = next(r for r in rows if r['external_id'] == '2025/p3000') self.assertEqual(competition['year'], 2025) self.assertEqual(competition['metadata']['publication_format'], 'competition_report') self.assertEqual(competition['metadata']['section_heading'], 'Demo Track') self.assertEqual(competition['track'], 'proceedings_unspecified') self.assertEqual(len({r['external_id'] for r in rows}), 476) self.assertEqual([r['publisher_page'] for r in excluded], [1, 3, 4]) def test_refuses_changed_edition_inventory_or_author_markup(self): original = (FIXTURE/'contents.html').read_text() for html in [original.replace('AAMAS 2025:', 'AAMAS 2026:', 1), original.replace('../pdfs/p5.pdf', '../pdfs/p14.pdf', 1), original.replace('Paper Track', 'Workshop Track'), original.replace('Amir Abolfazli', '', 1), original.replace('[COMP24]', '[CHANGED]', 1)]: with self.subTest(change=html[:60]): with self.assertRaises(ValueError): self.parse(html) def test_frozen_collection_is_partial_and_never_fetches_pdfs(self): with tempfile.TemporaryDirectory() as tmp, patch.object(aamas2025, 'fetch', side_effect=AssertionError('No HTTP in frozen mode')): out = Path(tmp)/'out' report = aamas.collect(2025, out, snapshots=FIXTURE) self.assertEqual(report['records'], 476) self.assertFalse(report['database_written']) self.assertFalse(report['pdfs_downloaded']) self.assertEqual(len(report['files']), 5) for m in report['files']: self.assertEqual(m['status'], 'partial') self.assertEqual(m['missing_abstract_count'], m['count']) self.assertEqual(hashlib.sha256(Path(m['file']).read_bytes()).hexdigest(), m['file_sha256']) receipt = report['source_receipts'][0]['response_receipt'] self.assertEqual(receipt['at_precision'], 'filesystem_write_time_recovered') self.assertTrue((out/'aamas-proceedings-2025.json').is_file()) def test_rejects_tampered_or_unsafe_frozen_response(self): import shutil for mode in ['tamper', 'path', 'status']: with self.subTest(mode=mode), tempfile.TemporaryDirectory() as tmp: root = Path(tmp); source = root/'source'; shutil.copytree(FIXTURE, source) p = source/'receipts.json'; r = json.loads(p.read_text()) if mode == 'tamper': (source/'contents.html').write_text('bad') elif mode == 'path': r['receipts'][0]['file'] = '../index.html' else: r['receipts'][0]['http_status'] = 403 p.write_text(json.dumps(r)) with self.assertRaises(ValueError): aamas.collect(2025, root/'out', snapshots=source) self.assertFalse((root/'out/aamas-proceedings-2025.json').exists())