215 lines
5.9 KiB
Python
215 lines
5.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Phase 3 validation test."""
|
|
|
|
import asyncio
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).parent / "ontology_platform"))
|
|
|
|
from ont_platform.core.validation import (
|
|
OntologyGuard,
|
|
OntologyEntity,
|
|
OntologyRelation,
|
|
)
|
|
|
|
|
|
async def test_valid_extraction():
|
|
"""Test valid extraction result."""
|
|
print("\n[TEST 1] Valid extraction result")
|
|
|
|
guard = OntologyGuard(validator_type="lightweight", strict=False)
|
|
|
|
result = {
|
|
"entities": [
|
|
{
|
|
"id": "E_001",
|
|
"label": "Python",
|
|
"type": "concept",
|
|
"confidence": 0.9,
|
|
},
|
|
{
|
|
"id": "E_002",
|
|
"label": "Programming",
|
|
"type": "concept",
|
|
"confidence": 0.85,
|
|
},
|
|
],
|
|
"relations": [
|
|
{
|
|
"id": "R_001",
|
|
"source_id": "E_001",
|
|
"target_id": "E_002",
|
|
"predicate": "is_used_for",
|
|
"confidence": 0.8,
|
|
},
|
|
],
|
|
"warnings": [],
|
|
}
|
|
|
|
validated = await guard.validate(result)
|
|
print(f" Validation passed: {validated.validation_passed}")
|
|
print(f" Entities: {len(validated.entities)}")
|
|
print(f" Relations: {len(validated.relations)}")
|
|
assert validated.validation_passed
|
|
print(" [PASS]")
|
|
|
|
|
|
async def test_invalid_entity_id():
|
|
"""Test validation catches invalid entity ID."""
|
|
print("\n[TEST 2] Invalid entity ID format")
|
|
|
|
guard = OntologyGuard(validator_type="lightweight", strict=False)
|
|
|
|
result = {
|
|
"entities": [
|
|
{
|
|
"id": "INVALID_123", # Should start with E_
|
|
"label": "Test",
|
|
"type": "concept",
|
|
"confidence": 0.9,
|
|
},
|
|
],
|
|
"relations": [],
|
|
"warnings": [],
|
|
}
|
|
|
|
validated = await guard.validate(result)
|
|
print(f" Validation passed: {validated.validation_passed}")
|
|
print(f" Validation errors: {len(validated.validation_errors)}")
|
|
print(f" Warnings: {validated.warnings[:1]}")
|
|
assert not validated.validation_passed
|
|
assert len(validated.validation_errors) > 0
|
|
print(" [PASS]")
|
|
|
|
|
|
async def test_missing_relation_endpoint():
|
|
"""Test validation catches missing relation endpoints."""
|
|
print("\n[TEST 3] Missing relation endpoint")
|
|
|
|
guard = OntologyGuard(validator_type="lightweight", strict=False)
|
|
|
|
result = {
|
|
"entities": [
|
|
{
|
|
"id": "E_001",
|
|
"label": "Python",
|
|
"type": "concept",
|
|
"confidence": 0.9,
|
|
},
|
|
],
|
|
"relations": [
|
|
{
|
|
"id": "R_001",
|
|
"source_id": "E_001",
|
|
"target_id": "E_999", # Non-existent entity
|
|
"predicate": "uses",
|
|
"confidence": 0.8,
|
|
},
|
|
],
|
|
"warnings": [],
|
|
}
|
|
|
|
validated = await guard.validate(result)
|
|
print(f" Validation passed: {validated.validation_passed}")
|
|
print(f" Validation errors: {len(validated.validation_errors)}")
|
|
assert not validated.validation_passed
|
|
print(" [PASS]")
|
|
|
|
|
|
async def test_confidence_range():
|
|
"""Test validation checks confidence range."""
|
|
print("\n[TEST 4] Confidence range validation")
|
|
|
|
guard = OntologyGuard(validator_type="lightweight", strict=False)
|
|
|
|
result = {
|
|
"entities": [
|
|
{
|
|
"id": "E_001",
|
|
"label": "Test",
|
|
"type": "concept",
|
|
"confidence": 1.5, # Out of range [0.0, 1.0]
|
|
},
|
|
],
|
|
"relations": [],
|
|
"warnings": [],
|
|
}
|
|
|
|
validated = await guard.validate(result)
|
|
print(f" Validation passed: {validated.validation_passed}")
|
|
print(f" Validation errors: {len(validated.validation_errors)}")
|
|
assert not validated.validation_passed
|
|
print(" [PASS]")
|
|
|
|
|
|
async def test_self_relation():
|
|
"""Test validation rejects self-relations."""
|
|
print("\n[TEST 5] Self-relation validation")
|
|
|
|
guard = OntologyGuard(validator_type="lightweight", strict=False)
|
|
|
|
result = {
|
|
"entities": [
|
|
{
|
|
"id": "E_001",
|
|
"label": "Test",
|
|
"type": "concept",
|
|
"confidence": 0.9,
|
|
},
|
|
],
|
|
"relations": [
|
|
{
|
|
"id": "R_001",
|
|
"source_id": "E_001",
|
|
"target_id": "E_001", # Self-loop
|
|
"predicate": "relates_to",
|
|
"confidence": 0.8,
|
|
},
|
|
],
|
|
"warnings": [],
|
|
}
|
|
|
|
validated = await guard.validate(result)
|
|
print(f" Validation passed: {validated.validation_passed}")
|
|
print(f" Validation errors: {len(validated.validation_errors)}")
|
|
assert not validated.validation_passed
|
|
print(" [PASS]")
|
|
|
|
|
|
async def main():
|
|
"""Run all tests."""
|
|
print("=" * 60)
|
|
print("Phase 3: Validation Tests (Lightweight MVP)")
|
|
print("=" * 60)
|
|
|
|
try:
|
|
await test_valid_extraction()
|
|
await test_invalid_entity_id()
|
|
await test_missing_relation_endpoint()
|
|
await test_confidence_range()
|
|
await test_self_relation()
|
|
|
|
print("\n" + "=" * 60)
|
|
print("All tests passed!")
|
|
print("=" * 60)
|
|
print("\nValidation capabilities:")
|
|
print(" - Entity ID format (E_xxxxx)")
|
|
print(" - Confidence range [0.0, 1.0]")
|
|
print(" - Relation endpoint existence")
|
|
print(" - Self-relation prevention")
|
|
print(" - Field length constraints")
|
|
print("\nUpgrade path (Optional B):")
|
|
print(" - Guardrails: ValidatorFactory.create('guardrails')")
|
|
print(" - OntoCast: ValidatorFactory.create('ontocast')")
|
|
|
|
return True
|
|
except AssertionError as e:
|
|
print(f"\nTest failed: {e}")
|
|
return False
|
|
|
|
|
|
if __name__ == "__main__":
|
|
success = asyncio.run(main())
|
|
sys.exit(0 if success else 1)
|