|
|
@@ -6,6 +6,10 @@ and integration scenarios.
|
|
|
"""
|
|
|
|
|
|
import pytest
|
|
|
+from pathlib import Path
|
|
|
+import tempfile
|
|
|
+import json
|
|
|
+import os
|
|
|
|
|
|
from src.glossary.models import Glossary, GlossaryEntry, TermCategory
|
|
|
from src.glossary.matcher import GlossaryMatcher, TermMatch
|
|
|
@@ -68,6 +72,197 @@ class TestGlossary:
|
|
|
assert "林风" in glossary
|
|
|
assert "火球术" not in glossary
|
|
|
|
|
|
+ def test_save_to_file(self):
|
|
|
+ """Test saving glossary to a JSON file."""
|
|
|
+ glossary = Glossary()
|
|
|
+ glossary.add(GlossaryEntry("林风", "Lin Feng", TermCategory.CHARACTER))
|
|
|
+ glossary.add(GlossaryEntry("火球术", "Fireball", TermCategory.SKILL))
|
|
|
+
|
|
|
+ with tempfile.TemporaryDirectory() as tmpdir:
|
|
|
+ filepath = Path(tmpdir) / "glossary.json"
|
|
|
+ glossary.save_to_file(filepath)
|
|
|
+
|
|
|
+ # Verify file exists and contains correct data
|
|
|
+ assert filepath.exists()
|
|
|
+
|
|
|
+ with open(filepath, "r", encoding="utf-8") as f:
|
|
|
+ data = json.load(f)
|
|
|
+
|
|
|
+ assert len(data) == 2
|
|
|
+ assert data[0]["source"] == "林风"
|
|
|
+ assert data[0]["target"] == "Lin Feng"
|
|
|
+ assert data[0]["category"] == "character"
|
|
|
+
|
|
|
+ def test_load_from_file(self):
|
|
|
+ """Test loading glossary from a JSON file."""
|
|
|
+ with tempfile.TemporaryDirectory() as tmpdir:
|
|
|
+ filepath = Path(tmpdir) / "glossary.json"
|
|
|
+
|
|
|
+ # Create test JSON file
|
|
|
+ test_data = [
|
|
|
+ {
|
|
|
+ "source": "林风",
|
|
|
+ "target": "Lin Feng",
|
|
|
+ "category": "character",
|
|
|
+ "context": "Main protagonist"
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "source": "火球术",
|
|
|
+ "target": "Fireball",
|
|
|
+ "category": "skill",
|
|
|
+ "context": ""
|
|
|
+ }
|
|
|
+ ]
|
|
|
+
|
|
|
+ with open(filepath, "w", encoding="utf-8") as f:
|
|
|
+ json.dump(test_data, f, ensure_ascii=False)
|
|
|
+
|
|
|
+ # Load and verify
|
|
|
+ glossary = Glossary()
|
|
|
+ glossary.load_from_file(filepath)
|
|
|
+
|
|
|
+ assert len(glossary) == 2
|
|
|
+ assert "林风" in glossary
|
|
|
+ assert glossary.get("林风").target == "Lin Feng"
|
|
|
+ assert glossary.get("林风").context == "Main protagonist"
|
|
|
+ assert glossary.get("火球术").category == TermCategory.SKILL
|
|
|
+
|
|
|
+ def test_load_from_file_clears_existing_entries(self):
|
|
|
+ """Test that loading from file clears existing entries."""
|
|
|
+ glossary = Glossary()
|
|
|
+ glossary.add(GlossaryEntry("林风", "Lin Feng", TermCategory.CHARACTER))
|
|
|
+
|
|
|
+ with tempfile.TemporaryDirectory() as tmpdir:
|
|
|
+ filepath = Path(tmpdir) / "glossary.json"
|
|
|
+ test_data = [
|
|
|
+ {
|
|
|
+ "source": "火球术",
|
|
|
+ "target": "Fireball",
|
|
|
+ "category": "skill",
|
|
|
+ "context": ""
|
|
|
+ }
|
|
|
+ ]
|
|
|
+
|
|
|
+ with open(filepath, "w", encoding="utf-8") as f:
|
|
|
+ json.dump(test_data, f)
|
|
|
+
|
|
|
+ glossary.load_from_file(filepath)
|
|
|
+
|
|
|
+ # Old entry should be gone
|
|
|
+ assert "林风" not in glossary
|
|
|
+ # New entry should be present
|
|
|
+ assert "火球术" in glossary
|
|
|
+
|
|
|
+ def test_save_and_load_roundtrip(self):
|
|
|
+ """Test that save and load preserves all data."""
|
|
|
+ original = Glossary()
|
|
|
+ original.add(GlossaryEntry("林风", "Lin Feng", TermCategory.CHARACTER, "Protagonist"))
|
|
|
+ original.add(GlossaryEntry("火球术", "Fireball", TermCategory.SKILL))
|
|
|
+ original.add(GlossaryEntry("东方大陆", "Eastern Continent", TermCategory.LOCATION))
|
|
|
+
|
|
|
+ with tempfile.TemporaryDirectory() as tmpdir:
|
|
|
+ filepath = Path(tmpdir) / "glossary.json"
|
|
|
+ original.save_to_file(filepath)
|
|
|
+
|
|
|
+ loaded = Glossary()
|
|
|
+ loaded.load_from_file(filepath)
|
|
|
+
|
|
|
+ # Verify all entries preserved
|
|
|
+ assert len(loaded) == len(original)
|
|
|
+ assert loaded.get("林风").target == "Lin Feng"
|
|
|
+ assert loaded.get("林风").context == "Protagonist"
|
|
|
+ assert loaded.get("火球术").category == TermCategory.SKILL
|
|
|
+ assert loaded.get("东方大陆").target == "Eastern Continent"
|
|
|
+
|
|
|
+ def test_load_from_file_creates_parent_directories(self):
|
|
|
+ """Test that save_to_file creates parent directories."""
|
|
|
+ glossary = Glossary()
|
|
|
+ glossary.add(GlossaryEntry("林风", "Lin Feng", TermCategory.CHARACTER))
|
|
|
+
|
|
|
+ with tempfile.TemporaryDirectory() as tmpdir:
|
|
|
+ # Create a nested path that doesn't exist
|
|
|
+ filepath = Path(tmpdir) / "nested" / "dir" / "glossary.json"
|
|
|
+
|
|
|
+ glossary.save_to_file(filepath)
|
|
|
+
|
|
|
+ assert filepath.exists()
|
|
|
+
|
|
|
+ def test_load_from_file_not_found(self):
|
|
|
+ """Test loading from non-existent file raises error."""
|
|
|
+ glossary = Glossary()
|
|
|
+
|
|
|
+ with pytest.raises(FileNotFoundError):
|
|
|
+ glossary.load_from_file(Path("/nonexistent/path/glossary.json"))
|
|
|
+
|
|
|
+ def test_load_from_file_invalid_json(self):
|
|
|
+ """Test loading from file with invalid JSON raises error."""
|
|
|
+ with tempfile.TemporaryDirectory() as tmpdir:
|
|
|
+ filepath = Path(tmpdir) / "invalid.json"
|
|
|
+
|
|
|
+ with open(filepath, "w") as f:
|
|
|
+ f.write("not valid json {]")
|
|
|
+
|
|
|
+ glossary = Glossary()
|
|
|
+ with pytest.raises(json.JSONDecodeError):
|
|
|
+ glossary.load_from_file(filepath)
|
|
|
+
|
|
|
+ def test_load_from_file_invalid_category(self):
|
|
|
+ """Test that invalid category defaults to OTHER."""
|
|
|
+ with tempfile.TemporaryDirectory() as tmpdir:
|
|
|
+ filepath = Path(tmpdir) / "glossary.json"
|
|
|
+ test_data = [
|
|
|
+ {
|
|
|
+ "source": "林风",
|
|
|
+ "target": "Lin Feng",
|
|
|
+ "category": "invalid_category",
|
|
|
+ "context": ""
|
|
|
+ }
|
|
|
+ ]
|
|
|
+
|
|
|
+ with open(filepath, "w", encoding="utf-8") as f:
|
|
|
+ json.dump(test_data, f)
|
|
|
+
|
|
|
+ glossary = Glossary()
|
|
|
+ glossary.load_from_file(filepath)
|
|
|
+
|
|
|
+ # Should default to OTHER
|
|
|
+ assert glossary.get("林风").category == TermCategory.OTHER
|
|
|
+
|
|
|
+ def test_load_from_file_missing_optional_fields(self):
|
|
|
+ """Test loading entries with missing optional fields."""
|
|
|
+ with tempfile.TemporaryDirectory() as tmpdir:
|
|
|
+ filepath = Path(tmpdir) / "glossary.json"
|
|
|
+ test_data = [
|
|
|
+ {
|
|
|
+ "source": "林风",
|
|
|
+ "target": "Lin Feng"
|
|
|
+ # Missing category and context
|
|
|
+ }
|
|
|
+ ]
|
|
|
+
|
|
|
+ with open(filepath, "w", encoding="utf-8") as f:
|
|
|
+ json.dump(test_data, f)
|
|
|
+
|
|
|
+ glossary = Glossary()
|
|
|
+ glossary.load_from_file(filepath)
|
|
|
+
|
|
|
+ # Should use defaults
|
|
|
+ assert glossary.get("林风").category == TermCategory.OTHER
|
|
|
+ assert glossary.get("林风").context == ""
|
|
|
+
|
|
|
+ def test_save_to_file_empty_glossary(self):
|
|
|
+ """Test saving an empty glossary."""
|
|
|
+ glossary = Glossary()
|
|
|
+
|
|
|
+ with tempfile.TemporaryDirectory() as tmpdir:
|
|
|
+ filepath = Path(tmpdir) / "empty.json"
|
|
|
+ glossary.save_to_file(filepath)
|
|
|
+
|
|
|
+ with open(filepath, "r", encoding="utf-8") as f:
|
|
|
+ data = json.load(f)
|
|
|
+
|
|
|
+ assert data == []
|
|
|
+
|
|
|
|
|
|
class TestGlossaryMatcher:
|
|
|
"""Test cases for GlossaryMatcher."""
|