Spaces:
Runtime error
Runtime error
| """Tests for the family registry. | |
| Covers: | |
| - Loading registry from YAML | |
| - Filtering by tag | |
| - Filtering by difficulty range | |
| - Looking up families by name (valid and invalid) | |
| - Verifying all registered manifests exist and validate | |
| """ | |
| from __future__ import annotations | |
| from pathlib import Path | |
| import pytest | |
| from open_range.registry import FamilyInfo, Registry | |
| ROOT = Path(__file__).parent.parent | |
| MANIFESTS_DIR = ROOT / "manifests" | |
| REGISTRY_PATH = MANIFESTS_DIR / "registry.yaml" | |
| # =================================================================== | |
| # Loading | |
| # =================================================================== | |
| class TestRegistryLoading: | |
| """Registry loads correctly from YAML.""" | |
| def test_load_default_registry(self): | |
| reg = Registry.load(REGISTRY_PATH) | |
| assert len(reg) > 0 | |
| def test_load_returns_registry_instance(self): | |
| reg = Registry.load(REGISTRY_PATH) | |
| assert isinstance(reg, Registry) | |
| def test_file_not_found_raises(self, tmp_path): | |
| with pytest.raises(FileNotFoundError): | |
| Registry.load(tmp_path / "nonexistent.yaml") | |
| def test_malformed_yaml_raises(self, tmp_path): | |
| bad = tmp_path / "bad.yaml" | |
| bad.write_text("not_families: {}") | |
| with pytest.raises(ValueError, match="families"): | |
| Registry.load(bad) | |
| def test_repr(self): | |
| reg = Registry.load(REGISTRY_PATH) | |
| r = repr(reg) | |
| assert "Registry(" in r | |
| assert "families" in r | |
| # =================================================================== | |
| # list_families | |
| # =================================================================== | |
| class TestListFamilies: | |
| """list_families returns all families sorted by difficulty.""" | |
| def test_returns_list(self): | |
| reg = Registry.load(REGISTRY_PATH) | |
| families = reg.list_families() | |
| assert isinstance(families, list) | |
| assert all(isinstance(f, FamilyInfo) for f in families) | |
| def test_sorted_by_difficulty(self): | |
| reg = Registry.load(REGISTRY_PATH) | |
| families = reg.list_families() | |
| difficulties = [f.difficulty for f in families] | |
| assert difficulties == sorted(difficulties) | |
| def test_all_families_have_required_fields(self): | |
| reg = Registry.load(REGISTRY_PATH) | |
| for fam in reg.list_families(): | |
| assert fam.name | |
| assert fam.display_name | |
| assert fam.manifest | |
| assert fam.difficulty >= 1 | |
| # =================================================================== | |
| # get_family | |
| # =================================================================== | |
| class TestGetFamily: | |
| """get_family looks up by registry key.""" | |
| def test_valid_name(self): | |
| reg = Registry.load(REGISTRY_PATH) | |
| fam = reg.get_family("tier1_basic_enterprise") | |
| assert fam.name == "tier1_basic_enterprise" | |
| assert fam.manifest == "tier1_basic.yaml" | |
| def test_invalid_name_raises_key_error(self): | |
| reg = Registry.load(REGISTRY_PATH) | |
| with pytest.raises(KeyError, match="nonexistent"): | |
| reg.get_family("nonexistent") | |
| def test_contains_operator(self): | |
| reg = Registry.load(REGISTRY_PATH) | |
| assert "tier1_basic_enterprise" in reg | |
| assert "nonexistent" not in reg | |
| # =================================================================== | |
| # filter_by_tag | |
| # =================================================================== | |
| class TestFilterByTag: | |
| """filter_by_tag returns families matching a tag.""" | |
| def test_healthcare_tag(self): | |
| reg = Registry.load(REGISTRY_PATH) | |
| results = reg.filter_by_tag("healthcare") | |
| assert len(results) >= 1 | |
| for fam in results: | |
| assert "healthcare" in [t.lower() for t in fam.tags] | |
| def test_case_insensitive(self): | |
| reg = Registry.load(REGISTRY_PATH) | |
| lower = reg.filter_by_tag("healthcare") | |
| upper = reg.filter_by_tag("Healthcare") | |
| assert len(lower) == len(upper) | |
| def test_nonexistent_tag_returns_empty(self): | |
| reg = Registry.load(REGISTRY_PATH) | |
| results = reg.filter_by_tag("zzz_nonexistent_tag") | |
| assert results == [] | |
| def test_hard_tag(self): | |
| reg = Registry.load(REGISTRY_PATH) | |
| results = reg.filter_by_tag("hard") | |
| assert len(results) >= 2 | |
| for fam in results: | |
| assert "hard" in [t.lower() for t in fam.tags] | |
| def test_tier_1_tag(self): | |
| reg = Registry.load(REGISTRY_PATH) | |
| results = reg.filter_by_tag("tier-1") | |
| assert len(results) >= 1 | |
| # =================================================================== | |
| # filter_by_difficulty | |
| # =================================================================== | |
| class TestFilterByDifficulty: | |
| """filter_by_difficulty returns families in a difficulty range.""" | |
| def test_difficulty_1(self): | |
| reg = Registry.load(REGISTRY_PATH) | |
| results = reg.filter_by_difficulty(1, 1) | |
| assert len(results) >= 1 | |
| for fam in results: | |
| assert fam.difficulty == 1 | |
| def test_difficulty_range(self): | |
| reg = Registry.load(REGISTRY_PATH) | |
| results = reg.filter_by_difficulty(1, 3) | |
| assert len(results) >= 3 # at least tier1, tier2, tier3 | |
| for fam in results: | |
| assert 1 <= fam.difficulty <= 3 | |
| def test_wide_range_returns_all(self): | |
| reg = Registry.load(REGISTRY_PATH) | |
| all_fam = reg.list_families() | |
| wide = reg.filter_by_difficulty(1, 5) | |
| assert len(wide) == len(all_fam) | |
| def test_empty_range(self): | |
| reg = Registry.load(REGISTRY_PATH) | |
| results = reg.filter_by_difficulty(5, 5) | |
| # May be empty if no difficulty-5 families exist | |
| for fam in results: | |
| assert fam.difficulty == 5 | |
| # =================================================================== | |
| # Manifest existence and validation | |
| # =================================================================== | |
| class TestManifestIntegrity: | |
| """All registered manifests exist on disk and validate.""" | |
| def test_all_manifest_files_exist(self): | |
| reg = Registry.load(REGISTRY_PATH) | |
| for fam in reg.list_families(): | |
| manifest_path = MANIFESTS_DIR / fam.manifest | |
| assert manifest_path.exists(), ( | |
| f"Family '{fam.name}' references '{fam.manifest}' " | |
| f"but {manifest_path} does not exist" | |
| ) | |
| def test_all_manifests_validate(self): | |
| from manifests.schema import load_manifest | |
| reg = Registry.load(REGISTRY_PATH) | |
| for fam in reg.list_families(): | |
| manifest_path = MANIFESTS_DIR / fam.manifest | |
| m = load_manifest(manifest_path) | |
| assert m.name, f"Manifest {fam.manifest} loaded but has empty name" | |
| assert m.tier >= 1 | |
| assert len(m.topology.hosts) >= 1 | |
| assert len(m.bug_families) >= 1 | |
| def test_learning_goals_non_empty(self): | |
| reg = Registry.load(REGISTRY_PATH) | |
| for fam in reg.list_families(): | |
| assert len(fam.learning_goals) >= 1, ( | |
| f"Family '{fam.name}' has no learning_goals" | |
| ) | |
| def test_tags_non_empty(self): | |
| reg = Registry.load(REGISTRY_PATH) | |
| for fam in reg.list_families(): | |
| assert len(fam.tags) >= 1, ( | |
| f"Family '{fam.name}' has no tags" | |
| ) | |