#!/usr/bin/env python3
"""Phase 3 Option B: OntoCast GraphUpdate 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 OntoCastValidator, SPARQLValidator
async def test_valid_sparql():
"""Test valid SPARQL query validation."""
print("\n[TEST 1] Valid SPARQL INSERT operation")
validator = OntoCastValidator(strict=False)
update = {
"operations": [
{
"operation_type": "INSERT",
"query": """
PREFIX ex:
INSERT DATA {
ex:resource1 a ex:Class;
ex:property1 "value" .
}
""",
"description": "Insert new resource"
}
],
"namespaces": {
"ex": "http://example.org/"
}
}
result = await validator.validate(update)
print(f" Validation passed: {result.validation_passed}")
print(f" Errors: {len(result.validation_errors)}")
print(f" Warnings: {len(result.validation_warnings)}")
assert result.validation_passed
print(" [PASS]")
async def test_invalid_syntax():
"""Test invalid SPARQL syntax detection."""
print("\n[TEST 2] Invalid SPARQL syntax")
validator = OntoCastValidator(strict=False)
update = {
"operations": [
{
"operation_type": "INSERT",
"query": "INSERT { ex:s ex:p ex:o ", # Missing closing brace
"description": "Broken query"
}
],
"namespaces": {}
}
result = await validator.validate(update)
print(f" Validation passed: {result.validation_passed}")
print(f" Errors: {result.validation_errors[:1] if result.validation_errors else []}")
assert not result.validation_passed
assert len(result.validation_errors) > 0
print(" [PASS]")
async def test_operation_order():
"""Test SPARQL operation order validation."""
print("\n[TEST 3] Safe operation order (INSERT → UPDATE → DELETE)")
validator = OntoCastValidator(strict=False)
update = {
"operations": [
{
"operation_type": "INSERT",
"query": "INSERT DATA { }",
},
{
"operation_type": "UPDATE",
"query": "DELETE { } INSERT { }",
},
{
"operation_type": "DELETE",
"query": "DELETE DATA { }",
},
],
"namespaces": {}
}
result = await validator.validate(update)
print(f" Validation passed: {result.validation_passed}")
print(f" Errors: {len(result.validation_errors)}")
assert result.validation_passed
print(" [PASS]")
async def test_unsafe_order():
"""Test unsafe operation order detection."""
print("\n[TEST 4] Unsafe operation order (DELETE before INSERT)")
validator = OntoCastValidator(strict=False)
update = {
"operations": [
{
"operation_type": "DELETE",
"query": "DELETE DATA { }",
},
{
"operation_type": "INSERT",
"query": "INSERT DATA { }",
},
],
"namespaces": {}
}
result = await validator.validate(update)
print(f" Validation passed: {result.validation_passed}")
print(f" Errors: {result.validation_errors[:1] if result.validation_errors else []}")
assert not result.validation_passed
assert any("order" in e.lower() for e in result.validation_errors)
print(" [PASS]")
async def test_prefix_validation():
"""Test prefix declaration validation."""
print("\n[TEST 5] Undeclared prefix detection")
validator = OntoCastValidator(strict=False)
update = {
"operations": [
{
"operation_type": "INSERT",
"query": "INSERT DATA { foo:s foo:p foo:o }", # foo prefix not declared
}
],
"namespaces": {
"ex": "http://example.org/"
}
}
result = await validator.validate(update)
print(f" Validation passed: {result.validation_passed}")
print(f" Warnings: {result.validation_warnings[:1] if result.validation_warnings else []}")
assert len(result.validation_warnings) > 0
print(" [PASS]")
async def test_sparql_validator_directly():
"""Test SPARQLValidator utility functions."""
print("\n[TEST 6] SPARQLValidator utility functions")
# Test syntax validation
valid, errors = SPARQLValidator.validate_sparql_syntax(
"INSERT DATA { }"
)
assert valid
print(f" Valid syntax check: OK")
# Test empty query
valid, errors = SPARQLValidator.validate_sparql_syntax("")
assert not valid
assert any("empty" in e.lower() for e in errors)
print(f" Empty query detection: OK")
# Test unbalanced brackets
valid, errors = SPARQLValidator.validate_sparql_syntax("INSERT { ")
assert not valid
print(f" Unbalanced bracket detection: OK")
print(" [PASS]")
async def main():
"""Run all tests."""
print("=" * 60)
print("Phase 3 Option B: OntoCast GraphUpdate Validation Tests")
print("(Hybrid approach - SPARQL validation, Critic loop prepared)")
print("=" * 60)
try:
await test_valid_sparql()
await test_invalid_syntax()
await test_operation_order()
await test_unsafe_order()
await test_prefix_validation()
await test_sparql_validator_directly()
print("\n" + "=" * 60)
print("All tests passed!")
print("=" * 60)
print("\nPhase 3 Option B capabilities:")
print(" [OK] SPARQL syntax validation")
print(" [OK] Safe operation ordering (INSERT -> UPDATE -> DELETE)")
print(" [OK] Prefix declaration checking")
print(" [OK] Injection pattern detection")
print(" [OK] Balanced bracket validation")
print("\nFuture extensions:")
print(" [>>] Critic loop integration (Phase 4)")
print(" [>>] Full RDF consistency checks (when Fuseki available)")
print(" [>>] GraphUpdate tracing and audit log")
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)