from __future__ import annotations import hashlib import importlib.util import json from pathlib import Path import tempfile import unittest SCRIPT = Path(__file__).resolve().parents[1] / "scripts" / "citation_watermark.py" SPEC = importlib.util.spec_from_file_location("citation_watermark", SCRIPT) assert SPEC is not None and SPEC.loader is not None citation = importlib.util.module_from_spec(SPEC) SPEC.loader.exec_module(citation) class CitationWatermarkTests(unittest.TestCase): def setUp(self) -> None: self.temporary = tempfile.TemporaryDirectory() self.root = Path(self.temporary.name) self.manifest = self.root / "download-manifest.json" self.manifest.write_text( json.dumps( { "source": { "url": "https://www.jove.com/v/69844/a-protocol-for-harvesting-single-cell-suspension-from-mouse-corneas" } } ), encoding="utf-8", ) def tearDown(self) -> None: self.temporary.cleanup() def test_attaches_exact_normalized_citation_without_url_by_default(self) -> None: path = citation.attach_citation( self.manifest, "Huang, C., Jiang, N. A Protocol. J. Vis. Exp. doi:10.3791/69844 (2026).", ) self.assertEqual( path.read_text(encoding="utf-8"), "Huang, C., Jiang, N. A Protocol. J. Vis. Exp. doi:10.3791/69844 (2026).\n", ) manifest = json.loads(self.manifest.read_text(encoding="utf-8")) record = manifest["citation_watermark"] self.assertFalse(record["include_source_url"]) self.assertEqual(record["position"], "top-left") self.assertEqual(record["citation_sha256"], hashlib.sha256(path.read_bytes()).hexdigest()) def test_optional_source_url_uses_manifest_canonical_url(self) -> None: path = citation.attach_citation( self.manifest, "Formal citation.", include_source_url=True, ) self.assertIn("\nSource: https://www.jove.com/v/69844/", path.read_text(encoding="utf-8")) def test_structured_citation_and_internal_notice_preserve_four_line_layout(self) -> None: citation_text = ( "Huang, C., Jiang, N., Zheng, X., Gu, H., Zhang, L., Ou, S.\n" "A Protocol for Harvesting Single-cell Suspension from Mouse Corneas.\n" "J. Vis. Exp. (230), e69844, doi:10.3791/69844 (2026)." ) path = citation.attach_citation( self.manifest, citation_text, notice=citation.DEFAULT_INTERNAL_NOTICE, ) self.assertEqual( path.read_text(encoding="utf-8"), "内容引自网络,仅供内部交流\n\n" + citation_text + "\n", ) manifest = json.loads(self.manifest.read_text(encoding="utf-8")) record = manifest["citation_watermark"] self.assertEqual(record["layout"], "notice-plus-three-line-citation") self.assertEqual(record["notice"], citation.DEFAULT_INTERNAL_NOTICE) def test_cli_accepts_three_structured_fields_and_default_notice(self) -> None: result = citation.main( [ str(self.manifest), "--authors", "Authors", "--title", "Title", "--publication", "Journal. doi:test.", "--notice", ] ) self.assertEqual(result, 0) self.assertEqual( (self.root / "citation-watermark.txt").read_text(encoding="utf-8"), "内容引自网络,仅供内部交流\n\nAuthors\nTitle\nJournal. doi:test.\n", ) def test_refuses_signed_or_credential_like_source_url(self) -> None: self.manifest.write_text( json.dumps({"source": {"url": "https://cdn.example/video?token=secret"}}), encoding="utf-8", ) with self.assertRaisesRegex(citation.CitationError, "signed or credential"): citation.attach_citation( self.manifest, "Formal citation.", include_source_url=True, ) if __name__ == "__main__": unittest.main()