mirror of
https://github.com/researchobjectschema/ro-crate-interoperability-profile.git
synced 2026-03-09 10:17:45 +01:00
* Update quickstart examples * Implementation dump: Pydantic decorators but still java api compatible * Cleanup for publishing
272 lines
11 KiB
Python
272 lines
11 KiB
Python
import unittest
|
|
import sys
|
|
from pathlib import Path
|
|
from datetime import datetime
|
|
|
|
# Add source to path
|
|
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
|
|
|
|
from lib_ro_crate_schema.crate.metadata_entry import MetadataEntry
|
|
from rdflib import URIRef, RDF, Literal
|
|
|
|
|
|
class TestMetadataEntry(unittest.TestCase):
|
|
"""Test cases for the MetadataEntry class"""
|
|
|
|
def setUp(self):
|
|
"""Set up test fixtures"""
|
|
self.basic_entry = MetadataEntry(
|
|
id="basic_entry",
|
|
class_id="BasicClass"
|
|
)
|
|
|
|
self.complete_entry = MetadataEntry(
|
|
id="person1",
|
|
class_id="Person",
|
|
properties={
|
|
"name": "John Doe",
|
|
"age": 30,
|
|
"active": True
|
|
},
|
|
references={
|
|
"knows": ["person2", "person3"],
|
|
"worksFor": ["organization1"]
|
|
}
|
|
)
|
|
|
|
self.datetime_entry = MetadataEntry(
|
|
id="event1",
|
|
class_id="Event",
|
|
properties={
|
|
"title": "Important Meeting",
|
|
"startTime": datetime(2023, 12, 25, 14, 30, 0)
|
|
}
|
|
)
|
|
|
|
def test_metadata_entry_creation(self):
|
|
"""Test basic MetadataEntry object creation"""
|
|
self.assertEqual(self.basic_entry.id, "basic_entry")
|
|
self.assertEqual(self.basic_entry.class_id, "BasicClass")
|
|
self.assertEqual(self.basic_entry.properties, {})
|
|
self.assertEqual(self.basic_entry.references, {})
|
|
|
|
def test_complete_entry_properties(self):
|
|
"""Test entry with complete properties and references"""
|
|
self.assertEqual(self.complete_entry.id, "person1")
|
|
self.assertEqual(self.complete_entry.class_id, "Person")
|
|
|
|
# Check properties
|
|
self.assertEqual(self.complete_entry.properties["name"], "John Doe")
|
|
self.assertEqual(self.complete_entry.properties["age"], 30)
|
|
self.assertEqual(self.complete_entry.properties["active"], True)
|
|
|
|
# Check references
|
|
self.assertEqual(self.complete_entry.references["knows"], ["person2", "person3"])
|
|
self.assertEqual(self.complete_entry.references["worksFor"], ["organization1"])
|
|
|
|
def test_java_api_compatibility(self):
|
|
"""Test Java API compatibility methods"""
|
|
self.assertEqual(self.complete_entry.getId(), "person1")
|
|
self.assertEqual(self.complete_entry.getClassId(), "Person")
|
|
|
|
values = self.complete_entry.getValues()
|
|
self.assertEqual(values["name"], "John Doe")
|
|
self.assertEqual(values["age"], 30)
|
|
|
|
references = self.complete_entry.getReferences()
|
|
self.assertEqual(references["knows"], ["person2", "person3"])
|
|
|
|
# Test alias method
|
|
self.assertEqual(self.complete_entry.get_values(), self.complete_entry.properties)
|
|
|
|
def test_to_triples(self):
|
|
"""Test RDF triple generation"""
|
|
triples = list(self.complete_entry.to_triples())
|
|
|
|
# Should generate multiple triples
|
|
self.assertGreater(len(triples), 0)
|
|
|
|
# Convert to string representation for easier testing
|
|
triple_strs = [(str(s), str(p), str(o)) for s, p, o in triples]
|
|
|
|
# Check for type declaration
|
|
type_triple_found = any("Person" in triple[2] for triple in triple_strs)
|
|
self.assertTrue(type_triple_found, "Should generate class type triple")
|
|
|
|
# Check for properties
|
|
name_triple_found = any("name" in triple[1] and "John Doe" in triple[2] for triple in triple_strs)
|
|
self.assertTrue(name_triple_found, "Should generate property triples")
|
|
|
|
age_triple_found = any("age" in triple[1] and "30" in triple[2] for triple in triple_strs)
|
|
self.assertTrue(age_triple_found, "Should generate age property triple")
|
|
|
|
def test_datetime_handling(self):
|
|
"""Test handling of datetime objects in properties"""
|
|
triples = list(self.datetime_entry.to_triples())
|
|
triple_strs = [(str(s), str(p), str(o)) for s, p, o in triples]
|
|
|
|
# Datetime should be converted to ISO format string
|
|
datetime_found = any("startTime" in triple[1] and "2023-12-25T14:30:00" in triple[2] for triple in triple_strs)
|
|
self.assertTrue(datetime_found, "Should convert datetime to ISO string")
|
|
|
|
def test_reference_triples(self):
|
|
"""Test reference generation in triples"""
|
|
triples = list(self.complete_entry.to_triples())
|
|
triple_strs = [(str(s), str(p), str(o)) for s, p, o in triples]
|
|
|
|
# Check for reference triples (no Literal wrapper for references)
|
|
knows_ref_found = any("knows" in triple[1] and "person2" in triple[2] for triple in triple_strs)
|
|
self.assertTrue(knows_ref_found, "Should generate reference triples")
|
|
|
|
works_for_ref_found = any("worksFor" in triple[1] and "organization1" in triple[2] for triple in triple_strs)
|
|
self.assertTrue(works_for_ref_found, "Should generate worksFor reference")
|
|
|
|
def test_empty_entry_triples(self):
|
|
"""Test triple generation for entry with no properties or references"""
|
|
empty_entry = MetadataEntry(id="empty", class_id="EmptyClass")
|
|
triples = list(empty_entry.to_triples())
|
|
|
|
# Should at least generate the type declaration
|
|
self.assertGreater(len(triples), 0)
|
|
|
|
triple_strs = [(str(s), str(p), str(o)) for s, p, o in triples]
|
|
type_found = any("EmptyClass" in triple[2] for triple in triple_strs)
|
|
self.assertTrue(type_found, "Should generate type declaration even for empty entry")
|
|
|
|
def test_mixed_property_types(self):
|
|
"""Test entry with various property value types"""
|
|
mixed_entry = MetadataEntry(
|
|
id="mixed",
|
|
class_id="MixedType",
|
|
properties={
|
|
"string_prop": "text value",
|
|
"int_prop": 42,
|
|
"float_prop": 3.14,
|
|
"bool_prop": False,
|
|
"none_prop": None # Should be filtered out
|
|
}
|
|
)
|
|
|
|
triples = list(mixed_entry.to_triples())
|
|
triple_strs = [(str(s), str(p), str(o)) for s, p, o in triples]
|
|
|
|
# Check each type is properly handled
|
|
string_found = any("string_prop" in triple[1] and "text value" in triple[2] for triple in triple_strs)
|
|
int_found = any("int_prop" in triple[1] and "42" in triple[2] for triple in triple_strs)
|
|
float_found = any("float_prop" in triple[1] and "3.14" in triple[2] for triple in triple_strs)
|
|
bool_found = any("bool_prop" in triple[1] and "false" in triple[2] for triple in triple_strs)
|
|
|
|
self.assertTrue(string_found, "Should handle string properties")
|
|
self.assertTrue(int_found, "Should handle integer properties")
|
|
self.assertTrue(float_found, "Should handle float properties")
|
|
self.assertTrue(bool_found, "Should handle boolean properties")
|
|
|
|
# None properties should not generate triples (filtered out in actual implementation)
|
|
none_found = any("none_prop" in triple[1] for triple in triple_strs)
|
|
# Note: The current implementation might include None values,
|
|
# but ideally they should be filtered out
|
|
|
|
def test_multiple_references_same_property(self):
|
|
"""Test property with multiple reference values"""
|
|
multi_ref_entry = MetadataEntry(
|
|
id="multi_ref",
|
|
class_id="MultiRef",
|
|
references={
|
|
"collaborator": ["person1", "person2", "person3"]
|
|
}
|
|
)
|
|
|
|
triples = list(multi_ref_entry.to_triples())
|
|
triple_strs = [(str(s), str(p), str(o)) for s, p, o in triples]
|
|
|
|
# Should generate separate triples for each reference
|
|
collab1_found = any("collaborator" in triple[1] and "person1" in triple[2] for triple in triple_strs)
|
|
collab2_found = any("collaborator" in triple[1] and "person2" in triple[2] for triple in triple_strs)
|
|
collab3_found = any("collaborator" in triple[1] and "person3" in triple[2] for triple in triple_strs)
|
|
|
|
self.assertTrue(collab1_found, "Should generate triple for person1")
|
|
self.assertTrue(collab2_found, "Should generate triple for person2")
|
|
self.assertTrue(collab3_found, "Should generate triple for person3")
|
|
|
|
|
|
def test_id_and_class_id_validation(self):
|
|
"""Test that id and class_id are properly set and accessible"""
|
|
entry = MetadataEntry(id="test_id", class_id="TestClass")
|
|
|
|
# Direct access
|
|
self.assertEqual(entry.id, "test_id")
|
|
self.assertEqual(entry.class_id, "TestClass")
|
|
|
|
# Java API access
|
|
self.assertEqual(entry.getId(), "test_id")
|
|
self.assertEqual(entry.getClassId(), "TestClass")
|
|
|
|
|
|
def test_get_entry_as_compatibility(self):
|
|
"""Test the get_entry_as method for SchemaFacade compatibility"""
|
|
# This test verifies that MetadataEntry objects work with the new get_entry_as method
|
|
from lib_ro_crate_schema.crate.schema_facade import SchemaFacade
|
|
from pydantic import BaseModel
|
|
from typing import Optional
|
|
|
|
# Create a simple test model
|
|
class TestPerson(BaseModel):
|
|
name: str
|
|
age: Optional[int] = None
|
|
active: Optional[bool] = None
|
|
|
|
# Create a facade and add our test entry
|
|
facade = SchemaFacade()
|
|
facade.addEntry(self.complete_entry)
|
|
|
|
# Test conversion to our test model
|
|
person_instance = facade.get_entry_as("person1", TestPerson)
|
|
|
|
self.assertIsNotNone(person_instance)
|
|
self.assertIsInstance(person_instance, TestPerson)
|
|
self.assertEqual(person_instance.name, "John Doe")
|
|
self.assertEqual(person_instance.age, 30)
|
|
self.assertEqual(person_instance.active, True)
|
|
|
|
# Test with non-existent entry
|
|
none_result = facade.get_entry_as("nonexistent", TestPerson)
|
|
self.assertIsNone(none_result)
|
|
|
|
def test_get_entry_as_with_references(self):
|
|
"""Test get_entry_as handling of references"""
|
|
from lib_ro_crate_schema.crate.schema_facade import SchemaFacade
|
|
from pydantic import BaseModel
|
|
from typing import Optional, List
|
|
|
|
class TestOrganization(BaseModel):
|
|
name: str
|
|
|
|
class TestPersonWithRefs(BaseModel):
|
|
name: str
|
|
age: Optional[int] = None
|
|
knows: Optional[List[str]] = None # Keep as strings for this test
|
|
worksFor: Optional[str] = None # Single reference as string
|
|
|
|
# Create facade and add entries
|
|
facade = SchemaFacade()
|
|
facade.addEntry(self.complete_entry)
|
|
|
|
# Add a referenced organization entry
|
|
org_entry = MetadataEntry(
|
|
id="organization1",
|
|
class_id="Organization",
|
|
properties={"name": "Tech Corp"}
|
|
)
|
|
facade.addEntry(org_entry)
|
|
|
|
# Test conversion
|
|
person = facade.get_entry_as("person1", TestPersonWithRefs)
|
|
|
|
self.assertIsNotNone(person)
|
|
self.assertEqual(person.name, "John Doe")
|
|
self.assertEqual(person.age, 30)
|
|
self.assertEqual(person.knows, ["person2", "person3"]) # References as IDs
|
|
self.assertEqual(person.worksFor, "organization1") # Single reference as ID
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main() |