Implement Supercharged Glyph Registry (LedoGlyph600)
New modules: - glyphs/super_registry.py: Registry for 600 supercharged glyphs - tests/test_supercharged_registry.py: Comprehensive test suite Features: - load_all_supercharged(): Lazy-load 600 glyphs from LedoGlyph600.json - get_super(): Retrieve glyph by ID with all supercharged fields - list_super_ids(): List all 600 glyph IDs (sorted) - search_super(): Search by query across specified fields - super_stats(): Registry metadata and statistics - get_super_field(): Nested field access via dot-notation - list_super_by_category(): Filter by category - get_super_by_band(): Filter by frequency band - get_glyphs_by_score_range(): Filter by score range Data source: /mnt/d/users/dave/Downloads/LEDONOVA/LedoGlyph600.json Supercharged fields: - Symbolic anatomy (originalMetrics: power, complexity, resonance, stability, connectivity, affinity) - Frequency signatures (praw: P, R, A, W) - Contributor inheritance (lineage: predecessors, siblings, descendants, signature) - Activation envelopes (activation: vector, score, signature, modes) - Resonance profiles (activation modes: dormant, present, resonant, overdrive) - Routing & governance metadata All 12 tests passing.
This commit is contained in:
@@ -0,0 +1,315 @@
|
||||
"""Supercharged Glyph Registry (LedoGlyph600)
|
||||
|
||||
Registry for 600-glyph supercharged dataset with:
|
||||
- 112 superpowers per glyph
|
||||
- frequency signatures (praw: P, R, A, W)
|
||||
- contributor inheritance (lineage)
|
||||
- symbolic anatomy (originalMetrics)
|
||||
- activation envelopes (activation modes)
|
||||
- resonance profiles (activation signatures)
|
||||
- extended metadata (governance, routing, storage)
|
||||
|
||||
Data source: /mnt/d/users/dave/Downloads/LEDONOVA/LedoGlyph600.json
|
||||
"""
|
||||
|
||||
from typing import Optional, List, Dict, Any
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
# Module-level cache
|
||||
_glyphs: Optional[Dict[str, dict]] = None
|
||||
_glyph_ids: Optional[List[str]] = None
|
||||
_loaded = False
|
||||
_load_path: Optional[Path] = None
|
||||
|
||||
|
||||
def load_all_supercharged(path: Optional[str] = None) -> None:
|
||||
"""Load all 600 supercharged glyphs from JSON file.
|
||||
|
||||
Lazy-loads and caches glyphs in module-level variables.
|
||||
Validates that exactly 600 glyphs are present.
|
||||
|
||||
Args:
|
||||
path: Optional path to LedoGlyph600.json file.
|
||||
Defaults to /mnt/d/users/dave/Downloads/LEDONOVA/LedoGlyph600.json
|
||||
|
||||
Raises:
|
||||
FileNotFoundError: If file doesn't exist
|
||||
ValueError: If glyph count != 600
|
||||
json.JSONDecodeError: If JSON is malformed
|
||||
"""
|
||||
global _glyphs, _glyph_ids, _loaded, _load_path
|
||||
|
||||
if _loaded:
|
||||
return
|
||||
|
||||
# Resolve path
|
||||
if path is None:
|
||||
path = "/mnt/d/users/dave/Downloads/LEDONOVA/LedoGlyph600.json"
|
||||
|
||||
filepath = Path(path)
|
||||
if not filepath.exists():
|
||||
raise FileNotFoundError(f"Supercharged glyph file not found: {filepath}")
|
||||
|
||||
_load_path = filepath
|
||||
|
||||
# Load JSON
|
||||
with open(filepath) as f:
|
||||
data = json.load(f)
|
||||
|
||||
# Extract glyphs
|
||||
if isinstance(data, dict) and "glyphs" in data:
|
||||
glyph_list = data["glyphs"]
|
||||
elif isinstance(data, list):
|
||||
glyph_list = data
|
||||
else:
|
||||
raise ValueError("Invalid glyph data structure")
|
||||
|
||||
# Validate count
|
||||
if len(glyph_list) != 600:
|
||||
raise ValueError(f"Expected 600 glyphs, got {len(glyph_list)}")
|
||||
|
||||
# Build cache dict by ID
|
||||
_glyphs = {}
|
||||
for glyph in glyph_list:
|
||||
glyph_id = glyph.get("id")
|
||||
if glyph_id:
|
||||
_glyphs[glyph_id] = glyph
|
||||
|
||||
# Build ID list
|
||||
_glyph_ids = sorted(list(_glyphs.keys()))
|
||||
|
||||
_loaded = True
|
||||
|
||||
|
||||
def get_super(glyph_id: str) -> Optional[dict]:
|
||||
"""Get a single supercharged glyph by ID.
|
||||
|
||||
Returns all fields: id, name, category, period, band, originalMetrics,
|
||||
praw, score, lineage, activation, routing, storage, governance.
|
||||
|
||||
Args:
|
||||
glyph_id: Glyph ID (e.g. "G001")
|
||||
|
||||
Returns:
|
||||
Glyph dict with all supercharged fields, or None if not found
|
||||
"""
|
||||
if not _loaded:
|
||||
load_all_supercharged()
|
||||
|
||||
return _glyphs.get(glyph_id) if _glyphs else None
|
||||
|
||||
|
||||
def list_super_ids() -> List[str]:
|
||||
"""List all supercharged glyph IDs (sorted).
|
||||
|
||||
Returns:
|
||||
List of 600 glyph IDs
|
||||
"""
|
||||
if not _loaded:
|
||||
load_all_supercharged()
|
||||
|
||||
return _glyph_ids[:] if _glyph_ids else []
|
||||
|
||||
|
||||
def search_super(
|
||||
query: str,
|
||||
*,
|
||||
fields: Optional[List[str]] = None,
|
||||
limit: int = 20
|
||||
) -> List[dict]:
|
||||
"""Search supercharged glyphs by query across specified fields.
|
||||
|
||||
Performs case-insensitive substring matching on string fields and
|
||||
numeric fields converted to strings.
|
||||
|
||||
Args:
|
||||
query: Search string (case-insensitive substring match)
|
||||
fields: List of field names to search.
|
||||
Defaults to ['id', 'name', 'category']
|
||||
limit: Maximum results to return (default 20)
|
||||
|
||||
Returns:
|
||||
List of matching glyph dicts (up to limit)
|
||||
"""
|
||||
if not _loaded:
|
||||
load_all_supercharged()
|
||||
|
||||
if not _glyphs:
|
||||
return []
|
||||
|
||||
if fields is None:
|
||||
fields = ["id", "name", "category"]
|
||||
|
||||
query_lower = query.lower()
|
||||
results = []
|
||||
|
||||
for glyph_id in _glyph_ids:
|
||||
glyph = _glyphs[glyph_id]
|
||||
|
||||
# Search in specified fields
|
||||
for field in fields:
|
||||
value = glyph.get(field)
|
||||
if value is None:
|
||||
continue
|
||||
|
||||
# Convert to string for matching
|
||||
if isinstance(value, str):
|
||||
if query_lower in value.lower():
|
||||
results.append(glyph)
|
||||
break
|
||||
elif isinstance(value, (int, float)):
|
||||
if query_lower in str(value).lower():
|
||||
results.append(glyph)
|
||||
break
|
||||
|
||||
# Stop if we've hit limit
|
||||
if len(results) >= limit:
|
||||
break
|
||||
|
||||
return results[:limit]
|
||||
|
||||
|
||||
def super_stats() -> dict:
|
||||
"""Get statistics about the supercharged glyph registry.
|
||||
|
||||
Validates registry integrity and returns metadata.
|
||||
|
||||
Returns:
|
||||
Dict with keys:
|
||||
- total_glyphs: Count of glyphs (should be 600)
|
||||
- fields_present: List of all field names found across glyphs
|
||||
- sample_ids: First 5 glyph IDs
|
||||
- categories: List of all unique categories
|
||||
- loaded: Whether registry is loaded
|
||||
- load_path: Path to data file
|
||||
"""
|
||||
if not _loaded:
|
||||
load_all_supercharged()
|
||||
|
||||
if not _glyphs:
|
||||
return {
|
||||
"total_glyphs": 0,
|
||||
"fields_present": [],
|
||||
"sample_ids": [],
|
||||
"categories": [],
|
||||
"loaded": False,
|
||||
"load_path": None,
|
||||
}
|
||||
|
||||
# Collect all field names
|
||||
all_fields = set()
|
||||
all_categories = set()
|
||||
|
||||
for glyph in _glyphs.values():
|
||||
all_fields.update(glyph.keys())
|
||||
category = glyph.get("category")
|
||||
if category:
|
||||
all_categories.add(category)
|
||||
|
||||
return {
|
||||
"total_glyphs": len(_glyphs),
|
||||
"fields_present": sorted(list(all_fields)),
|
||||
"sample_ids": _glyph_ids[:5] if _glyph_ids else [],
|
||||
"categories": sorted(list(all_categories)),
|
||||
"loaded": _loaded,
|
||||
"load_path": str(_load_path) if _load_path else None,
|
||||
}
|
||||
|
||||
|
||||
def get_super_field(glyph_id: str, field_path: str, default: Any = None) -> Any:
|
||||
"""Get a nested field from a supercharged glyph.
|
||||
|
||||
Supports dot-notation for nested fields (e.g. "activation.score",
|
||||
"praw.P", "lineage.signature").
|
||||
|
||||
Args:
|
||||
glyph_id: Glyph ID
|
||||
field_path: Field path (supports dots for nesting)
|
||||
default: Default value if not found
|
||||
|
||||
Returns:
|
||||
Field value or default
|
||||
"""
|
||||
glyph = get_super(glyph_id)
|
||||
if glyph is None:
|
||||
return default
|
||||
|
||||
# Handle nested paths
|
||||
parts = field_path.split(".")
|
||||
value = glyph
|
||||
|
||||
for part in parts:
|
||||
if isinstance(value, dict):
|
||||
value = value.get(part)
|
||||
if value is None:
|
||||
return default
|
||||
else:
|
||||
return default
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def list_super_by_category(category: str) -> List[dict]:
|
||||
"""List all supercharged glyphs in a category.
|
||||
|
||||
Args:
|
||||
category: Category name (e.g. "neural", "harmonic")
|
||||
|
||||
Returns:
|
||||
List of matching glyphs
|
||||
"""
|
||||
if not _loaded:
|
||||
load_all_supercharged()
|
||||
|
||||
if not _glyphs:
|
||||
return []
|
||||
|
||||
return [g for g in _glyphs.values() if g.get("category") == category]
|
||||
|
||||
|
||||
def get_super_by_band(band: int) -> List[dict]:
|
||||
"""List all supercharged glyphs in a frequency band.
|
||||
|
||||
Args:
|
||||
band: Band number
|
||||
|
||||
Returns:
|
||||
List of matching glyphs sorted by band
|
||||
"""
|
||||
if not _loaded:
|
||||
load_all_supercharged()
|
||||
|
||||
if not _glyphs:
|
||||
return []
|
||||
|
||||
return sorted(
|
||||
[g for g in _glyphs.values() if g.get("band") == band],
|
||||
key=lambda g: g.get("id", "")
|
||||
)
|
||||
|
||||
|
||||
def get_glyphs_by_score_range(min_score: int, max_score: int) -> List[dict]:
|
||||
"""List glyphs with scores in the given range.
|
||||
|
||||
Args:
|
||||
min_score: Minimum score (inclusive)
|
||||
max_score: Maximum score (inclusive)
|
||||
|
||||
Returns:
|
||||
List of glyphs sorted by score descending
|
||||
"""
|
||||
if not _loaded:
|
||||
load_all_superchattracted()
|
||||
|
||||
if not _glyphs:
|
||||
return []
|
||||
|
||||
return sorted(
|
||||
[
|
||||
g for g in _glyphs.values()
|
||||
if min_score <= g.get("score", 0) <= max_score
|
||||
],
|
||||
key=lambda g: g.get("score", 0),
|
||||
reverse=True
|
||||
)
|
||||
@@ -0,0 +1,400 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Tests for Supercharged Glyph Registry (LedoGlyph600)
|
||||
|
||||
Tests verify:
|
||||
- load_all_supercharged loads exactly 600 glyphs
|
||||
- get_super returns correct glyph data
|
||||
- list_super_ids returns all glyph IDs
|
||||
- search_super works across supercharged fields
|
||||
- super_stats reports correct metadata
|
||||
- Helper functions work correctly
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path.cwd()))
|
||||
|
||||
from glyphs.super_registry import (
|
||||
load_all_supercharged,
|
||||
get_super,
|
||||
list_super_ids,
|
||||
search_super,
|
||||
super_stats,
|
||||
get_super_field,
|
||||
list_super_by_category,
|
||||
get_super_by_band,
|
||||
get_glyphs_by_score_range,
|
||||
)
|
||||
|
||||
|
||||
def test_load_all_supercharged():
|
||||
"""Test loading all 600 supercharged glyphs."""
|
||||
load_all_supercharged()
|
||||
stats = super_stats()
|
||||
|
||||
if stats["total_glyphs"] != 600:
|
||||
print(f"FAIL: Expected 600 glyphs, got {stats['total_glyphs']}")
|
||||
return False
|
||||
|
||||
if not stats["loaded"]:
|
||||
print("FAIL: Registry not marked as loaded")
|
||||
return False
|
||||
|
||||
print(f"PASS: Loaded 600 glyphs")
|
||||
return True
|
||||
|
||||
|
||||
def test_get_super():
|
||||
"""Test retrieving individual glyphs by ID."""
|
||||
load_all_supercharged()
|
||||
ids = list_super_ids()
|
||||
|
||||
if not ids:
|
||||
print("FAIL: No glyph IDs available")
|
||||
return False
|
||||
|
||||
# Test first glyph
|
||||
first_id = ids[0]
|
||||
glyph = get_super(first_id)
|
||||
|
||||
if glyph is None:
|
||||
print(f"FAIL: Could not get glyph {first_id}")
|
||||
return False
|
||||
|
||||
# Check required fields
|
||||
required_fields = ["id", "name", "category", "band", "score"]
|
||||
for field in required_fields:
|
||||
if field not in glyph:
|
||||
print(f"FAIL: Glyph missing field: {field}")
|
||||
return False
|
||||
|
||||
if glyph["id"] != first_id:
|
||||
print(f"FAIL: Glyph ID mismatch: {glyph['id']} != {first_id}")
|
||||
return False
|
||||
|
||||
print(f"PASS: Retrieved glyph {first_id} with all required fields")
|
||||
return True
|
||||
|
||||
|
||||
def test_get_super_nonexistent():
|
||||
"""Test retrieving non-existent glyph returns None."""
|
||||
load_all_supercharged()
|
||||
glyph = get_super("NONEXISTENT")
|
||||
|
||||
if glyph is not None:
|
||||
print("FAIL: Should return None for nonexistent glyph")
|
||||
return False
|
||||
|
||||
print("PASS: Returns None for nonexistent glyph")
|
||||
return True
|
||||
|
||||
|
||||
def test_list_super_ids():
|
||||
"""Test listing all glyph IDs."""
|
||||
load_all_supercharged()
|
||||
ids = list_super_ids()
|
||||
|
||||
if len(ids) != 600:
|
||||
print(f"FAIL: Expected 600 IDs, got {len(ids)}")
|
||||
return False
|
||||
|
||||
if ids != sorted(ids):
|
||||
print("FAIL: IDs are not sorted")
|
||||
return False
|
||||
|
||||
if not all(isinstance(id, str) for id in ids):
|
||||
print("FAIL: Not all IDs are strings")
|
||||
return False
|
||||
|
||||
print(f"PASS: Listed 600 sorted glyph IDs")
|
||||
return True
|
||||
|
||||
|
||||
def test_search_super_basic():
|
||||
"""Test basic search functionality."""
|
||||
load_all_supercharged()
|
||||
|
||||
# Search by ID
|
||||
results = search_super("G001", fields=["id"])
|
||||
if len(results) == 0:
|
||||
print("FAIL: Could not find G001")
|
||||
return False
|
||||
|
||||
if results[0]["id"] != "G001":
|
||||
print("FAIL: First result is not G001")
|
||||
return False
|
||||
|
||||
print(f"PASS: Found G001 by ID search")
|
||||
return True
|
||||
|
||||
|
||||
def test_search_super_case_insensitive():
|
||||
"""Test case-insensitive search."""
|
||||
load_all_supercharged()
|
||||
|
||||
# Get a known glyph
|
||||
first_glyph = get_super("G001")
|
||||
if first_glyph is None:
|
||||
print("FAIL: Could not load reference glyph")
|
||||
return False
|
||||
|
||||
name = first_glyph.get("name", "").lower()
|
||||
if not name:
|
||||
print("FAIL: Reference glyph has no name")
|
||||
return False
|
||||
|
||||
# Search with uppercase
|
||||
results = search_super(name.upper(), fields=["name"])
|
||||
if len(results) == 0:
|
||||
print(f"FAIL: Case-insensitive search failed for {name.upper()}")
|
||||
return False
|
||||
|
||||
print(f"PASS: Case-insensitive search works")
|
||||
return True
|
||||
|
||||
|
||||
def test_search_super_limit():
|
||||
"""Test search limit parameter."""
|
||||
load_all_supercharged()
|
||||
|
||||
# Search for common category
|
||||
results = search_super("", fields=["category"], limit=5)
|
||||
|
||||
# Note: empty query won't match, but we can test limit on real results
|
||||
ids = list_super_ids()
|
||||
|
||||
# Search for first 10 IDs with limit
|
||||
for test_id in ids[:10]:
|
||||
results = search_super(test_id, limit=3)
|
||||
if len(results) > 3:
|
||||
print(f"FAIL: Got {len(results)} results, limit was 3")
|
||||
return False
|
||||
|
||||
print("PASS: Search limit respected")
|
||||
return True
|
||||
|
||||
|
||||
def test_super_stats():
|
||||
"""Test statistics reporting."""
|
||||
load_all_supercharged()
|
||||
stats = super_stats()
|
||||
|
||||
# Verify stats keys
|
||||
required_keys = [
|
||||
"total_glyphs",
|
||||
"fields_present",
|
||||
"sample_ids",
|
||||
"categories",
|
||||
"loaded",
|
||||
"load_path",
|
||||
]
|
||||
|
||||
for key in required_keys:
|
||||
if key not in stats:
|
||||
print(f"FAIL: Missing stats key: {key}")
|
||||
return False
|
||||
|
||||
# Verify values
|
||||
if stats["total_glyphs"] != 600:
|
||||
print(f"FAIL: total_glyphs != 600")
|
||||
return False
|
||||
|
||||
if not isinstance(stats["fields_present"], list):
|
||||
print("FAIL: fields_present is not a list")
|
||||
return False
|
||||
|
||||
if not isinstance(stats["sample_ids"], list):
|
||||
print("FAIL: sample_ids is not a list")
|
||||
return False
|
||||
|
||||
# Check supercharged fields are present
|
||||
supercharged_fields = [
|
||||
"id",
|
||||
"name",
|
||||
"activation",
|
||||
"lineage",
|
||||
"praw",
|
||||
"originalMetrics",
|
||||
]
|
||||
|
||||
missing = [f for f in supercharged_fields if f not in stats["fields_present"]]
|
||||
if missing:
|
||||
print(f"FAIL: Missing supercharged fields: {missing}")
|
||||
return False
|
||||
|
||||
if stats["loaded"] != True:
|
||||
print("FAIL: loaded should be True")
|
||||
return False
|
||||
|
||||
if stats["sample_ids"] != list_super_ids()[:5]:
|
||||
print("FAIL: sample_ids mismatch")
|
||||
return False
|
||||
|
||||
print(f"PASS: Stats complete with {len(stats['categories'])} categories")
|
||||
return True
|
||||
|
||||
|
||||
def test_get_super_field():
|
||||
"""Test nested field retrieval."""
|
||||
load_all_supercharged()
|
||||
|
||||
glyph = get_super("G001")
|
||||
if glyph is None:
|
||||
print("FAIL: Could not load G001")
|
||||
return False
|
||||
|
||||
# Test direct field
|
||||
name = get_super_field("G001", "name")
|
||||
if name != glyph["name"]:
|
||||
print(f"FAIL: Direct field mismatch")
|
||||
return False
|
||||
|
||||
# Test nested field (if present)
|
||||
if "activation" in glyph:
|
||||
score = get_super_field("G001", "activation.score")
|
||||
if score != glyph.get("activation", {}).get("score"):
|
||||
print(f"FAIL: Nested field mismatch")
|
||||
return False
|
||||
|
||||
# Test default value
|
||||
missing = get_super_field("G001", "nonexistent.field", default="DEFAULT")
|
||||
if missing != "DEFAULT":
|
||||
print(f"FAIL: Default value not returned")
|
||||
return False
|
||||
|
||||
print("PASS: Nested field retrieval works")
|
||||
return True
|
||||
|
||||
|
||||
def test_list_super_by_category():
|
||||
"""Test filtering by category."""
|
||||
load_all_supercharged()
|
||||
|
||||
stats = super_stats()
|
||||
categories = stats.get("categories", [])
|
||||
|
||||
if not categories:
|
||||
print("SKIP: No categories found")
|
||||
return True
|
||||
|
||||
# Test first category
|
||||
category = categories[0]
|
||||
glyphs = list_super_by_category(category)
|
||||
|
||||
if len(glyphs) == 0:
|
||||
print(f"FAIL: No glyphs found in category {category}")
|
||||
return False
|
||||
|
||||
# Verify all returned glyphs are in that category
|
||||
for glyph in glyphs:
|
||||
if glyph.get("category") != category:
|
||||
print(f"FAIL: Glyph in wrong category")
|
||||
return False
|
||||
|
||||
print(f"PASS: Found {len(glyphs)} glyphs in category '{category}'")
|
||||
return True
|
||||
|
||||
|
||||
def test_get_super_by_band():
|
||||
"""Test filtering by frequency band."""
|
||||
load_all_supercharged()
|
||||
|
||||
# Get first glyph to find a band
|
||||
first = get_super(list_super_ids()[0])
|
||||
if first is None:
|
||||
print("FAIL: Could not load first glyph")
|
||||
return False
|
||||
|
||||
band = first.get("band")
|
||||
glyphs = get_super_by_band(band)
|
||||
|
||||
if len(glyphs) == 0:
|
||||
print(f"FAIL: No glyphs found in band {band}")
|
||||
return False
|
||||
|
||||
# Verify all are in same band
|
||||
for glyph in glyphs:
|
||||
if glyph.get("band") != band:
|
||||
print(f"FAIL: Glyph in wrong band")
|
||||
return False
|
||||
|
||||
print(f"PASS: Found {len(glyphs)} glyphs in band {band}")
|
||||
return True
|
||||
|
||||
|
||||
def test_get_glyphs_by_score_range():
|
||||
"""Test filtering by score range."""
|
||||
load_all_supercharged()
|
||||
|
||||
glyphs = get_glyphs_by_score_range(100, 200)
|
||||
|
||||
if len(glyphs) == 0:
|
||||
print("SKIP: No glyphs in score range 100-200")
|
||||
return True
|
||||
|
||||
# Verify all are in range and sorted
|
||||
prev_score = float('inf')
|
||||
for glyph in glyphs:
|
||||
score = glyph.get("score", 0)
|
||||
if not (100 <= score <= 200):
|
||||
print(f"FAIL: Glyph score {score} out of range")
|
||||
return False
|
||||
|
||||
if score > prev_score:
|
||||
print(f"FAIL: Results not sorted descending")
|
||||
return False
|
||||
|
||||
prev_score = score
|
||||
|
||||
print(f"PASS: Found {len(glyphs)} glyphs in score range [100-200]")
|
||||
return True
|
||||
|
||||
|
||||
def main_test():
|
||||
print("[TEST SUITE] test_supercharged_registry.py")
|
||||
print()
|
||||
|
||||
tests = [
|
||||
("Load all supercharged", test_load_all_supercharged),
|
||||
("Get single glyph", test_get_super),
|
||||
("Get nonexistent glyph", test_get_super_nonexistent),
|
||||
("List all glyph IDs", test_list_super_ids),
|
||||
("Search by ID", test_search_super_basic),
|
||||
("Case-insensitive search", test_search_super_case_insensitive),
|
||||
("Search limit", test_search_super_limit),
|
||||
("Statistics reporting", test_super_stats),
|
||||
("Get nested field", test_get_super_field),
|
||||
("Filter by category", test_list_super_by_category),
|
||||
("Filter by band", test_get_super_by_band),
|
||||
("Filter by score range", test_get_glyphs_by_score_range),
|
||||
]
|
||||
|
||||
passed = 0
|
||||
failed = 0
|
||||
skipped = 0
|
||||
|
||||
for name, test_func in tests:
|
||||
print(f"Running: {name}...", end=" ")
|
||||
try:
|
||||
result = test_func()
|
||||
if result is True:
|
||||
passed += 1
|
||||
elif result is None:
|
||||
skipped += 1
|
||||
print("SKIP")
|
||||
continue
|
||||
else:
|
||||
failed += 1
|
||||
except Exception as e:
|
||||
print(f"FAIL: {e}")
|
||||
failed += 1
|
||||
|
||||
print()
|
||||
print(f"Results: {passed} passed, {failed} failed, {skipped} skipped")
|
||||
|
||||
return 0 if failed == 0 else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main_test())
|
||||
Reference in New Issue
Block a user