255 lines
8.5 KiB
Python
255 lines
8.5 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Test script for relationship domain/range constraint validation.
|
|
|
|
Tests the validate_relationship_constraints() function with various
|
|
valid and invalid relationship configurations.
|
|
"""
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# Add src to path
|
|
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
|
|
|
|
from glam_extractor.annotators.base import (
|
|
validate_relationship_constraints,
|
|
_type_matches_constraint,
|
|
RELATIONSHIP_CONSTRAINTS,
|
|
)
|
|
|
|
|
|
def test_type_matching():
|
|
"""Test the hierarchical type matching logic."""
|
|
print("\n" + "="*60)
|
|
print("Testing _type_matches_constraint()")
|
|
print("="*60)
|
|
|
|
# Test exact match
|
|
assert _type_matches_constraint("AGT.PER", ["AGT.PER"]) == True
|
|
print(" [PASS] Exact match: AGT.PER in [AGT.PER]")
|
|
|
|
# Test subtype match (AGT.PER matches parent AGT)
|
|
assert _type_matches_constraint("AGT.PER", ["AGT"]) == True
|
|
print(" [PASS] Subtype match: AGT.PER in [AGT]")
|
|
|
|
# Test GRP.HER matches GRP
|
|
assert _type_matches_constraint("GRP.HER", ["GRP"]) == True
|
|
print(" [PASS] Subtype match: GRP.HER in [GRP]")
|
|
|
|
# Test parent matches if child is allowed
|
|
assert _type_matches_constraint("AGT", ["AGT.PER"]) == True
|
|
print(" [PASS] Parent match: AGT in [AGT.PER]")
|
|
|
|
# Test mismatch
|
|
assert _type_matches_constraint("WRK.TXT", ["AGT"]) == False
|
|
print(" [PASS] Mismatch: WRK.TXT NOT in [AGT]")
|
|
|
|
# Test empty list (any type allowed)
|
|
assert _type_matches_constraint("WRK.VIS", []) == True
|
|
print(" [PASS] Empty list: WRK.VIS in []")
|
|
|
|
# Test None type
|
|
assert _type_matches_constraint(None, ["AGT"]) == False
|
|
print(" [PASS] None type: None NOT in [AGT]")
|
|
|
|
print("\n All type matching tests PASSED!")
|
|
|
|
|
|
def test_valid_relationships():
|
|
"""Test relationships that should pass validation."""
|
|
print("\n" + "="*60)
|
|
print("Testing VALID relationships")
|
|
print("="*60)
|
|
|
|
test_cases = [
|
|
# REL.CRE.AUT - Author relationship
|
|
("REL.CRE.AUT", "AGT.PER", "WRK.TXT", "Martin Luther authored 95 Theses"),
|
|
|
|
# REL.CRE.ART - Artist created artwork
|
|
("REL.CRE.ART", "AGT.PER", "WRK.VIS", "Rembrandt created The Night Watch"),
|
|
|
|
# REL.SOC.FAM.SPO - Spouse relationship
|
|
("REL.SOC.FAM.SPO", "AGT.PER", "AGT.PER", "Martin Luther married Katharina von Bora"),
|
|
|
|
# REL.CUS.KEP - Kept by heritage institution
|
|
("REL.CUS.KEP", "WRK.VIS", "GRP.HER", "The Night Watch kept by Rijksmuseum"),
|
|
|
|
# REL.SPA.LOC - Location relationship
|
|
("REL.SPA.LOC", "GRP.HER", "TOP.SET", "Rijksmuseum located in Amsterdam"),
|
|
|
|
# REL.ORG.FND - Founded by
|
|
("REL.ORG.FND", "AGT.PER", "GRP.HER", "Person founded museum"),
|
|
|
|
# REL.SOC.MEM - Membership
|
|
("REL.SOC.MEM", "AGT.PER", "GRP.HER", "Person member of organization"),
|
|
|
|
# REL.WRK.PRT - Part of work
|
|
("REL.WRK.PRT", "WRK.TXT", "WRK.SER", "Book part of series"),
|
|
]
|
|
|
|
all_passed = True
|
|
for rel_type, subject, obj, description in test_cases:
|
|
result = validate_relationship_constraints(rel_type, subject, obj)
|
|
if result.is_valid:
|
|
print(f" [PASS] {rel_type}: {description}")
|
|
else:
|
|
print(f" [FAIL] {rel_type}: {description}")
|
|
print(f" Warnings: {result.warnings}")
|
|
all_passed = False
|
|
|
|
if all_passed:
|
|
print(f"\n All {len(test_cases)} valid relationship tests PASSED!")
|
|
else:
|
|
print(f"\n Some valid relationship tests FAILED!")
|
|
|
|
|
|
def test_invalid_relationships():
|
|
"""Test relationships that should fail validation (generate warnings)."""
|
|
print("\n" + "="*60)
|
|
print("Testing INVALID relationships (should generate warnings)")
|
|
print("="*60)
|
|
|
|
test_cases = [
|
|
# Wrong domain - place cannot be author
|
|
("REL.CRE.AUT", "TOP.SET", "WRK.TXT", "Place as author (invalid)"),
|
|
|
|
# Wrong range - person cannot be authored
|
|
("REL.CRE.AUT", "AGT.PER", "AGT.PER", "Person authored person (invalid)"),
|
|
|
|
# Wrong domain - work cannot have spouse
|
|
("REL.SOC.FAM.SPO", "WRK.TXT", "AGT.PER", "Work as spouse (invalid)"),
|
|
|
|
# Wrong range - person as manifestation
|
|
("REL.WRK.MAN", "WRK.MAN", "AGT.PER", "Person as expression (invalid)"),
|
|
|
|
# Wrong domain for organizational
|
|
("REL.ORG.PAR", "AGT.PER", "GRP", "Person as parent org (invalid)"),
|
|
]
|
|
|
|
all_passed = True
|
|
for rel_type, subject, obj, description in test_cases:
|
|
result = validate_relationship_constraints(rel_type, subject, obj)
|
|
if not result.is_valid and result.warnings:
|
|
print(f" [PASS] {rel_type}: {description}")
|
|
print(f" Warning: {result.warnings[0][:60]}...")
|
|
else:
|
|
print(f" [FAIL] {rel_type}: Expected warnings but got none")
|
|
all_passed = False
|
|
|
|
if all_passed:
|
|
print(f"\n All {len(test_cases)} invalid relationship tests PASSED!")
|
|
else:
|
|
print(f"\n Some invalid relationship tests FAILED!")
|
|
|
|
|
|
def test_strict_mode():
|
|
"""Test that strict mode converts warnings to errors."""
|
|
print("\n" + "="*60)
|
|
print("Testing STRICT mode validation")
|
|
print("="*60)
|
|
|
|
# Invalid relationship
|
|
result_soft = validate_relationship_constraints(
|
|
"REL.CRE.AUT", "TOP.SET", "WRK.TXT", strict=False
|
|
)
|
|
result_strict = validate_relationship_constraints(
|
|
"REL.CRE.AUT", "TOP.SET", "WRK.TXT", strict=True
|
|
)
|
|
|
|
# Soft mode should have warnings
|
|
assert len(result_soft.warnings) > 0 and len(result_soft.errors) == 0
|
|
print(" [PASS] Soft mode: Generates warnings, no errors")
|
|
|
|
# Strict mode should have errors
|
|
assert len(result_strict.errors) > 0 and len(result_strict.warnings) == 0
|
|
print(" [PASS] Strict mode: Generates errors, no warnings")
|
|
|
|
print("\n All strict mode tests PASSED!")
|
|
|
|
|
|
def test_constraint_coverage():
|
|
"""Verify all relationship types have constraints defined."""
|
|
print("\n" + "="*60)
|
|
print("Testing constraint coverage")
|
|
print("="*60)
|
|
|
|
# Core relationship types that MUST have constraints
|
|
required_types = [
|
|
"REL.CRE", "REL.CRE.AUT", "REL.CRE.ART",
|
|
"REL.SOC", "REL.SOC.FAM", "REL.SOC.FAM.SPO",
|
|
"REL.CUS", "REL.CUS.KEP", "REL.CUS.OWN",
|
|
"REL.ORG", "REL.ORG.PAR",
|
|
"REL.WRK", "REL.WRK.EXP",
|
|
"REL.SPA", "REL.SPA.LOC",
|
|
"REL.EVT", "REL.EVT.PAR",
|
|
]
|
|
|
|
missing = []
|
|
for rel_type in required_types:
|
|
if rel_type not in RELATIONSHIP_CONSTRAINTS:
|
|
missing.append(rel_type)
|
|
|
|
if missing:
|
|
print(f" [FAIL] Missing constraints for: {missing}")
|
|
else:
|
|
print(f" [PASS] All {len(required_types)} required relationship types have constraints")
|
|
|
|
print(f"\n Total constraints defined: {len(RELATIONSHIP_CONSTRAINTS)}")
|
|
|
|
|
|
def test_validation_result_details():
|
|
"""Test that validation results contain expected details."""
|
|
print("\n" + "="*60)
|
|
print("Testing validation result details")
|
|
print("="*60)
|
|
|
|
result = validate_relationship_constraints(
|
|
"REL.CRE.AUT", "TOP.SET", "WRK.TXT"
|
|
)
|
|
|
|
# Check result fields
|
|
assert result.relationship_type == "REL.CRE.AUT"
|
|
print(f" [PASS] relationship_type: {result.relationship_type}")
|
|
|
|
assert result.subject_type == "TOP.SET"
|
|
print(f" [PASS] subject_type: {result.subject_type}")
|
|
|
|
assert result.object_type == "WRK.TXT"
|
|
print(f" [PASS] object_type: {result.object_type}")
|
|
|
|
assert len(result.expected_domains) > 0
|
|
print(f" [PASS] expected_domains: {result.expected_domains}")
|
|
|
|
assert len(result.expected_ranges) > 0
|
|
print(f" [PASS] expected_ranges: {result.expected_ranges}")
|
|
|
|
assert result.domain_valid == False
|
|
print(f" [PASS] domain_valid: {result.domain_valid}")
|
|
|
|
assert result.range_valid == True # WRK.TXT is valid
|
|
print(f" [PASS] range_valid: {result.range_valid}")
|
|
|
|
print("\n All validation result detail tests PASSED!")
|
|
|
|
|
|
def main():
|
|
"""Run all tests."""
|
|
print("\n" + "="*60)
|
|
print("RELATIONSHIP CONSTRAINT VALIDATION TESTS")
|
|
print("="*60)
|
|
|
|
test_type_matching()
|
|
test_valid_relationships()
|
|
test_invalid_relationships()
|
|
test_strict_mode()
|
|
test_constraint_coverage()
|
|
test_validation_result_details()
|
|
|
|
print("\n" + "="*60)
|
|
print("ALL TESTS COMPLETED SUCCESSFULLY!")
|
|
print("="*60 + "\n")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|