111 lines
4.7 KiB
Python
111 lines
4.7 KiB
Python
import json
|
|
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
from core.skills import SkillRegistry
|
|
from skills.literature.scripts.merge_publications import (
|
|
exact_key,
|
|
main,
|
|
merge_publications,
|
|
normalize_doi,
|
|
normalize_isbn,
|
|
normalize_record,
|
|
)
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
|
|
class LiteratureSkillTests(unittest.TestCase):
|
|
def test_literature_is_the_only_publication_search_skill(self) -> None:
|
|
registry = SkillRegistry(ROOT / "skills")
|
|
self.assertIn("literature", registry.skills)
|
|
self.assertNotIn("research", registry.skills)
|
|
self.assertNotIn("documents", registry.skills)
|
|
|
|
|
|
class LiteratureNormalizationTests(unittest.TestCase):
|
|
def test_normalizes_doi_and_isbn(self) -> None:
|
|
self.assertEqual(normalize_doi("https://doi.org/10.1000/ABC.1."), "10.1000/abc.1")
|
|
self.assertEqual(normalize_isbn("0-306-40615-2"), "9780306406157")
|
|
|
|
def test_preserves_unknown_raw_type(self) -> None:
|
|
record = normalize_record({"title": "A", "type": "future-object"}, "future")
|
|
self.assertEqual(record["type"], "other")
|
|
self.assertEqual(record["raw_type"], "future-object")
|
|
|
|
def test_different_book_editions_have_different_keys(self) -> None:
|
|
first = normalize_record(
|
|
{"title": "Materials", "type": "book", "isbn": "9780306406157", "edition": "1st"},
|
|
"books",
|
|
)
|
|
second = normalize_record(
|
|
{"title": "Materials", "type": "book", "isbn": "9780306406157", "edition": "2nd"},
|
|
"books",
|
|
)
|
|
self.assertNotEqual(exact_key(first), exact_key(second))
|
|
|
|
def test_preserves_date_and_relations(self) -> None:
|
|
record = normalize_record(
|
|
{
|
|
"title": "Chapter",
|
|
"type": "book-chapter",
|
|
"publication_date": "2025-03-09",
|
|
"is_part_of": "Book A",
|
|
},
|
|
"books",
|
|
)
|
|
self.assertEqual(record["issued"], {"year": 2025, "month": 3, "day": 9})
|
|
self.assertEqual(record["relations"]["is_part_of"], "Book A")
|
|
|
|
|
|
class LiteratureMergeTests(unittest.TestCase):
|
|
def test_merges_same_doi_and_preserves_sources(self) -> None:
|
|
result = merge_publications([
|
|
("paper_server", {"id": "p1", "doi": "10.1/ABC", "title": "Title", "abstract": "A"}),
|
|
("materials_library", {"id": "m1", "doi": "https://doi.org/10.1/abc", "title": "Title"}),
|
|
])
|
|
self.assertEqual(len(result["publications"]), 1)
|
|
self.assertEqual(
|
|
{source["backend"] for source in result["publications"][0]["sources"]},
|
|
{"paper_server", "materials_library"},
|
|
)
|
|
|
|
def test_does_not_merge_chapter_with_book(self) -> None:
|
|
result = merge_publications([
|
|
("source", {"title": "Hydration", "type": "book", "first_author": "Li", "year": 2024}),
|
|
("source", {"title": "Hydration", "type": "book_chapter", "first_author": "Li", "year": 2024}),
|
|
])
|
|
self.assertEqual(len(result["publications"]), 2)
|
|
|
|
def test_keeps_standard_revisions_and_patent_family_members(self) -> None:
|
|
result = merge_publications([
|
|
("standards", {"title": "Method", "type": "standard", "standard_number": "GB/T 1", "publisher": "SAC", "year": 2020}),
|
|
("standards", {"title": "Method", "type": "standard", "standard_number": "GB/T 1", "publisher": "SAC", "year": 2025}),
|
|
("patents", {"title": "Binder", "type": "patent", "patent_publication_number": "CN100A", "patent_family": "F1"}),
|
|
("patents", {"title": "Binder", "type": "patent", "patent_publication_number": "US100B", "patent_family": "F1"}),
|
|
])
|
|
self.assertEqual(len(result["publications"]), 4)
|
|
|
|
def test_marks_similar_titles_as_possible_duplicates(self) -> None:
|
|
result = merge_publications([
|
|
("a", {"title": "Hydration of low carbon cement systems", "type": "article", "year": 2024}),
|
|
("b", {"title": "Hydration of low-carbon cement system", "type": "article", "year": 2024}),
|
|
])
|
|
self.assertEqual(len(result["publications"]), 2)
|
|
self.assertEqual(len(result["possible_duplicates"]), 1)
|
|
|
|
def test_cli_writes_output(self) -> None:
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
root = Path(tmp)
|
|
source = root / "source.json"
|
|
output = root / "output.json"
|
|
source.write_text(json.dumps([{"title": "A", "doi": "10.1/a"}]), encoding="utf-8")
|
|
self.assertEqual(main(["--input", f"paper_server={source}", "--output", str(output)]), 0)
|
|
self.assertEqual(len(json.loads(output.read_text(encoding="utf-8"))["publications"]), 1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|