Phase 4 구현 완료: Neo4j 벡터 검색 + 그래프 저장소
This commit is contained in:
214
test_phase3_validation.py
Normal file
214
test_phase3_validation.py
Normal file
@@ -0,0 +1,214 @@
|
||||
#!/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)
|
||||
Reference in New Issue
Block a user