180 lines
5.7 KiB
Python
180 lines
5.7 KiB
Python
from pathlib import Path
|
|
import json
|
|
|
|
import pytest
|
|
|
|
from scripts.prepare_string_species_snapshot import prepare_snapshot
|
|
|
|
|
|
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
|
FIXTURE_SOURCE = PROJECT_ROOT / "tests" / "fixtures" / "string_species" / "v12.0"
|
|
FULL_SNAPSHOT = PROJECT_ROOT / "data" / "string" / "v12.0"
|
|
|
|
|
|
@pytest.fixture()
|
|
def snapshot(tmp_path: Path):
|
|
from gfa_core.string_species_registry import load_string_snapshot
|
|
|
|
destination = tmp_path / "snapshot"
|
|
prepare_snapshot(destination, source_directory=FIXTURE_SOURCE)
|
|
return load_string_snapshot(destination)
|
|
|
|
|
|
def test_exact_string_uses_explicit_target_taxon(snapshot) -> None:
|
|
from gfa_core.string_species_registry import resolve_ppi_string_species
|
|
|
|
result = resolve_ppi_string_species(
|
|
snapshot,
|
|
"Os",
|
|
ppi_target_tree_taxon_id="39947",
|
|
)
|
|
|
|
assert result["selection_mode"] == "exact_string"
|
|
assert result["target_tree_taxon_id"] == "39947"
|
|
assert result["selected_string_taxon_id"] == "39947"
|
|
assert result["requires_user_confirmation"] is False
|
|
|
|
|
|
def test_os_alias_uses_string_japonica_taxon(snapshot) -> None:
|
|
from gfa_core.string_species_registry import resolve_ppi_string_species
|
|
|
|
result = resolve_ppi_string_species(snapshot, "Os")
|
|
|
|
assert result["target_tree_taxon_id"] == "39947"
|
|
assert result["selected_string_taxon_id"] == "39947"
|
|
assert result["resolution_source"] == "project_alias"
|
|
|
|
|
|
def test_explicit_taxon_overrides_project_alias(snapshot) -> None:
|
|
from gfa_core.string_species_registry import resolve_ppi_string_species
|
|
|
|
result = resolve_ppi_string_species(
|
|
snapshot,
|
|
"Os",
|
|
ppi_target_tree_taxon_id="39946",
|
|
)
|
|
|
|
assert result["target_tree_taxon_id"] == "39946"
|
|
assert result["selected_string_taxon_id"] == "39946"
|
|
assert result["resolution_source"] == "explicit_tree_taxon_id"
|
|
|
|
|
|
def test_registry_species_outside_legacy_map_is_exact_string(snapshot) -> None:
|
|
from gfa_core.string_species_registry import resolve_ppi_string_species
|
|
|
|
result = resolve_ppi_string_species(
|
|
snapshot,
|
|
"",
|
|
target_scientific_name="Brassica napus",
|
|
)
|
|
|
|
assert result["selection_mode"] == "exact_string"
|
|
assert result["selected_string_taxon_id"] == "3708"
|
|
|
|
|
|
def test_ambiguous_name_is_unresolved_not_at(snapshot) -> None:
|
|
from gfa_core.string_species_registry import resolve_ppi_string_species
|
|
|
|
result = resolve_ppi_string_species(
|
|
snapshot,
|
|
"At",
|
|
target_scientific_name="Ambiguous plant",
|
|
)
|
|
|
|
assert result["selection_mode"] == "unresolved"
|
|
assert result["selected_string_taxon_id"] == ""
|
|
assert result["issue_code"] == "target_string_tree_unresolved"
|
|
|
|
|
|
def test_tree_nearest_is_stable_top_three(snapshot) -> None:
|
|
from gfa_core.string_species_registry import resolve_ppi_string_species
|
|
|
|
first = resolve_ppi_string_species(snapshot, "Ft")
|
|
second = resolve_ppi_string_species(snapshot, "Ft")
|
|
|
|
assert first["selection_mode"] == "tree_nearest"
|
|
assert [row["selected_string_taxon_id"] for row in first["candidates"]] == [
|
|
"3562",
|
|
"3702",
|
|
"3708",
|
|
]
|
|
assert first["candidates"] == second["candidates"]
|
|
assert first["requires_user_confirmation"] is True
|
|
|
|
|
|
def test_unresolved_requires_explicit_model_fallback_choice(snapshot) -> None:
|
|
from gfa_core.string_species_registry import resolve_ppi_string_species
|
|
|
|
unresolved = resolve_ppi_string_species(snapshot, "Unknown")
|
|
fallback = resolve_ppi_string_species(
|
|
snapshot,
|
|
"Unknown",
|
|
allow_model_fallback=True,
|
|
)
|
|
|
|
assert unresolved["selection_mode"] == "unresolved"
|
|
assert unresolved["selected_string_taxon_id"] == ""
|
|
assert fallback["selection_mode"] == "model_fallback"
|
|
assert fallback["selected_string_taxon_id"] == "3702"
|
|
assert fallback["requires_user_confirmation"] is True
|
|
|
|
|
|
def test_corrupt_snapshot_is_resource_error(tmp_path: Path) -> None:
|
|
from gfa_core.string_species_registry import StringSnapshotError, load_string_snapshot
|
|
|
|
with pytest.raises(StringSnapshotError) as error:
|
|
load_string_snapshot(tmp_path)
|
|
|
|
assert error.value.code in {
|
|
"string_registry_unavailable",
|
|
"string_registry_integrity_failed",
|
|
}
|
|
|
|
|
|
def test_malformed_manifest_file_metadata_is_integrity_error(tmp_path: Path) -> None:
|
|
from gfa_core.string_species_registry import StringSnapshotError, load_string_snapshot
|
|
|
|
(tmp_path / "source_manifest.json").write_text(
|
|
json.dumps(
|
|
{
|
|
"snapshot_id": "invalid",
|
|
"string_version": "12.0",
|
|
"files": {
|
|
"species.v12.0.txt": "not-an-object",
|
|
"species.tree.v12.0.txt": {},
|
|
},
|
|
}
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
|
|
with pytest.raises(StringSnapshotError) as error:
|
|
load_string_snapshot(tmp_path)
|
|
|
|
assert error.value.code == "string_registry_integrity_failed"
|
|
|
|
|
|
def test_full_snapshot_supports_registry_only_species_and_second_non_ft_target() -> None:
|
|
from gfa_core.string_species_registry import (
|
|
load_string_snapshot,
|
|
resolve_ppi_string_species,
|
|
)
|
|
|
|
full = load_string_snapshot(FULL_SNAPSHOT)
|
|
brassica = resolve_ppi_string_species(
|
|
full,
|
|
"",
|
|
target_scientific_name="Brassica napus",
|
|
)
|
|
camellia = resolve_ppi_string_species(
|
|
full,
|
|
"",
|
|
ppi_target_tree_taxon_id="4442",
|
|
)
|
|
|
|
assert brassica["selection_mode"] == "exact_string"
|
|
assert brassica["selected_string_taxon_id"] == "3708"
|
|
assert camellia["selection_mode"] == "tree_nearest"
|
|
assert len(camellia["candidates"]) == 3
|
|
assert camellia["candidate_source"] == "string_species_tree"
|