Files
CleverRDFlib/features/steps/loading_result_steps.py
CoreRasurae e828acf175
CI / lint (push) Successful in 1m32s
CI / typecheck (push) Successful in 1m38s
CI / lint (pull_request) Successful in 1m30s
CI / typecheck (pull_request) Successful in 1m30s
CI / behave (3.11) (pull_request) Successful in 1m39s
CI / behave (3.12) (pull_request) Successful in 1m39s
CI / build (pull_request) Successful in 1m29s
CI / behave (3.13) (pull_request) Successful in 1m39s
CI / behave (3.11) (push) Successful in 1m39s
CI / behave (3.12) (push) Successful in 1m41s
CI / behave (3.13) (push) Successful in 1m37s
CI / build (push) Successful in 1m30s
feat: Initial version of CleverRDFLib
ISSUES CLOSED: #1
2025-12-19 22:26:14 +00:00

691 lines
24 KiB
Python

"""
Step definitions for loading result feature tests.
This module implements tests for LoadingResult properties and methods.
"""
from __future__ import annotations
from typing import Any
from behave import given, then, when
from rdflib import Graph, Namespace, URIRef
from rdflib.namespace import OWL, RDF
from cleverrdf_lib.core.loading_result import LoadingResult
from cleverrdf_lib.observers.base_hierarchy_oberver import BaseClassHierarchyBuildObserver
TEST_NS = Namespace("http://example.org/test#")
def _assert_loading_result_exists(context: Any) -> None:
"""
Assert that loading_result exists in the context.
This helper function provides clear error messages when loading_result is missing.
Args:
context: The behave context object
Raises:
AssertionError: If loading_result is missing or None
"""
assert hasattr(context, "loading_result"), (
"loading_result must exist. Use 'I have a LoadingResult instance' or 'I have a loaded ontology' step first."
)
assert context.loading_result is not None, "loading_result must not be None"
def _assert_build_observer_exists(context: Any) -> None:
"""
Assert that build_observer exists in the context.
This helper function provides clear error messages when build_observer is missing.
Args:
context: The behave context object
Raises:
AssertionError: If build_observer is missing or None
"""
assert hasattr(context, "build_observer"), (
"build_observer must exist. Use 'I have a ClassHierarchyBuildObserver' step first."
)
assert context.build_observer is not None, "build_observer must not be None"
def _assert_multiple_observers_exist(context: Any) -> None:
"""
Assert that multiple_observers exists in the context.
This helper function provides clear error messages when multiple_observers is missing.
Args:
context: The behave context object
Raises:
AssertionError: If multiple_observers is missing or None
"""
assert hasattr(context, "multiple_observers"), (
"multiple_observers must exist. "
"Use 'I have multiple ClassHierarchyBuildObserver instances for result' step first."
)
assert context.multiple_observers is not None, "multiple_observers must not be None"
@given("I have a loaded ontology with classes for result")
def step_have_loaded_ontology_with_classes_result(context: Any) -> None:
"""
Create a LoadingResult with classes.
This creates a test loading result with a graph containing classes.
"""
from features.steps.common_steps import step_have_test_data_directory
from features.steps.ontology_loading_steps import step_have_valid_ontology_file
from cleverrdf_lib.core.ontology_loader import OntologyLoader
if not hasattr(context, "test_data_dir"):
step_have_test_data_directory(context)
step_have_valid_ontology_file(context, "test_data/result_test.owl")
loader = OntologyLoader()
context.loading_result = loader.load_ontology(context.ontology_file_path)
@given("I have a loaded ontology with metadata")
def step_have_loaded_ontology_with_metadata(context: Any) -> None:
"""
Create a LoadingResult with metadata.
This creates a test loading result with metadata.
"""
from features.steps.common_steps import step_have_test_data_directory
from features.steps.ontology_loading_steps import step_have_valid_ontology_file
from cleverrdf_lib.core.ontology_loader import OntologyLoader
if not hasattr(context, "test_data_dir"):
step_have_test_data_directory(context)
step_have_valid_ontology_file(context, "test_data/metadata_result.owl")
loader = OntologyLoader()
context.loading_result = loader.load_ontology(context.ontology_file_path)
@given("I have a loaded ontology")
def step_have_loaded_ontology_result(context: Any) -> None:
"""
Create a LoadingResult.
This creates a test loading result.
"""
from features.steps.common_steps import step_have_test_data_directory
from features.steps.ontology_loading_steps import step_have_valid_ontology_file
from cleverrdf_lib.core.ontology_loader import OntologyLoader
if not hasattr(context, "test_data_dir"):
step_have_test_data_directory(context)
step_have_valid_ontology_file(context, "test_data/result_test.owl")
loader = OntologyLoader()
context.loading_result = loader.load_ontology(context.ontology_file_path)
@given("I have a LoadingResult instance")
def step_have_loading_result_instance(context: Any) -> None:
"""
Create a LoadingResult instance.
This creates a test loading result directly.
"""
graph = Graph()
graph.bind("test", TEST_NS)
graph.bind("owl", OWL)
graph.bind("rdf", RDF)
ontology_uri = URIRef("http://example.org/test")
graph.add((ontology_uri, RDF.type, OWL.Ontology))
context.loading_result = LoadingResult(graph, {"http://example.org/test"}, [], [], None)
@given("I have a ClassHierarchyBuildObserver")
def step_have_build_observer_for_result(context: Any) -> None:
"""
Create a ClassHierarchyBuildObserver.
This creates a test build observer.
"""
context.build_events = []
class TestBuildObserver(BaseClassHierarchyBuildObserver):
def on_build_started(self, iri: str) -> None:
context.build_events.append(("started", iri))
def on_build_completed(self, iri: str) -> None:
context.build_events.append(("completed", iri))
context.build_observer = TestBuildObserver()
@given("I have multiple ClassHierarchyBuildObserver instances for result")
def step_have_multiple_build_observers_for_result(context: Any) -> None:
"""
Create multiple ClassHierarchyBuildObserver instances.
This creates multiple test build observers.
"""
context.observer1_events = []
context.observer2_events = []
class Observer1(BaseClassHierarchyBuildObserver):
def on_build_started(self, iri: str) -> None:
context.observer1_events.append(("started", iri))
class Observer2(BaseClassHierarchyBuildObserver):
def on_build_started(self, iri: str) -> None:
context.observer2_events.append(("started", iri))
context.observer1 = Observer1()
context.observer2 = Observer2()
context.multiple_observers = [context.observer1, context.observer2]
@given("I have a LoadingResult with no errors")
def step_have_loading_result_no_errors(context: Any) -> None:
"""
Create a LoadingResult with no errors.
This creates a successful loading result.
"""
graph = Graph()
graph.bind("test", TEST_NS)
graph.bind("owl", OWL)
graph.bind("rdf", RDF)
ontology_uri = URIRef("http://example.org/test")
graph.add((ontology_uri, RDF.type, OWL.Ontology))
context.loading_result = LoadingResult(graph, {"http://example.org/test"}, [], [], None)
@given("I have a LoadingResult with errors")
def step_have_loading_result_with_errors(context: Any) -> None:
"""
Create a LoadingResult with errors.
This creates a loading result with errors.
"""
graph = Graph()
graph.bind("test", TEST_NS)
graph.bind("owl", OWL)
graph.bind("rdf", RDF)
ontology_uri = URIRef("http://example.org/test")
graph.add((ontology_uri, RDF.type, OWL.Ontology))
errors = [{"uri": "http://example.org/failed", "message": "Failed to load", "exception": Exception("Test error")}]
context.loading_result = LoadingResult(graph, {"http://example.org/test"}, errors, [], None)
@given("I have a LoadingResult with loaded ontologies")
def step_have_loading_result_with_loaded(context: Any) -> None:
"""
Create a LoadingResult with loaded ontologies.
This creates a loading result with multiple loaded URIs.
"""
graph = Graph()
graph.bind("test", TEST_NS)
graph.bind("owl", OWL)
graph.bind("rdf", RDF)
ontology_uri = URIRef("http://example.org/test")
graph.add((ontology_uri, RDF.type, OWL.Ontology))
loaded_uris = {"http://example.org/test", "http://example.org/import1", "http://example.org/import2"}
context.loading_result = LoadingResult(graph, loaded_uris, [], [], None)
@given("I have a LoadingResult with loaded URIs")
def step_have_loading_result_with_uris(context: Any) -> None:
"""
Create a LoadingResult with loaded URIs.
This creates a loading result with specific URIs.
"""
graph = Graph()
graph.bind("test", TEST_NS)
graph.bind("owl", OWL)
graph.bind("rdf", RDF)
ontology_uri = URIRef("http://example.org/test")
graph.add((ontology_uri, RDF.type, OWL.Ontology))
loaded_uris = {"http://example.org/test", "http://example.org/import1"}
context.loading_result = LoadingResult(graph, loaded_uris, [], [], None)
@when("I access the class hierarchy property")
def step_access_class_hierarchy(context: Any) -> None:
"""
Access the class hierarchy property.
This accesses the class_hierarchy property.
"""
_assert_loading_result_exists(context)
context.accessed_hierarchy = context.loading_result.class_hierarchy
@when("I access the OWL metadata property")
def step_access_owl_metadata(context: Any) -> None:
"""
Access the OWL metadata property.
This accesses the owl_metadata property.
"""
_assert_loading_result_exists(context)
context.accessed_metadata = context.loading_result.owl_metadata
@when("I access the OWL validation result property")
def step_access_owl_validation(context: Any) -> None:
"""
Access the OWL validation result property.
This accesses the owl_validation_result property.
"""
_assert_loading_result_exists(context)
context.accessed_validation = context.loading_result.owl_validation_result
@when("I access the OWL consistency result property")
def step_access_owl_consistency(context: Any) -> None:
"""
Access the OWL consistency result property.
This accesses the owl_consistency_result property.
"""
_assert_loading_result_exists(context)
context.accessed_consistency = context.loading_result.owl_consistency_result
@when("I access the OWL version manager property")
def step_access_owl_version_manager(context: Any) -> None:
"""
Access the OWL version manager property.
This accesses the owl_version_manager property.
"""
_assert_loading_result_exists(context)
context.accessed_version_manager = context.loading_result.owl_version_manager
@when("I set the class hierarchy build observer")
def step_set_build_observer(context: Any) -> None:
"""
Set the class hierarchy build observer.
This calls set_class_hierarchy_build_observer.
"""
_assert_loading_result_exists(context)
_assert_build_observer_exists(context)
context.loading_result.set_class_hierarchy_build_observer(context.build_observer)
@when("I set the class hierarchy build observers")
def step_set_build_observers(context: Any) -> None:
"""
Set multiple class hierarchy build observers.
This calls set_class_hierarchy_build_observers.
"""
_assert_loading_result_exists(context)
_assert_multiple_observers_exist(context)
context.loading_result.set_class_hierarchy_build_observers(context.multiple_observers)
@when("I check if loading was successful")
def step_check_loading_success(context: Any) -> None:
"""
Check if loading was successful.
This accesses the is_successful property.
"""
_assert_loading_result_exists(context)
context.is_successful_for_all_ontologies = context.loading_result.is_successful_for_all_ontologies
@when("I get the loaded count")
def step_get_loaded_count(context: Any) -> None:
"""
Get the loaded count.
This accesses the loaded_count property.
"""
_assert_loading_result_exists(context)
context.loaded_count = context.loading_result.loaded_count
@when("I get the loaded URIs")
def step_get_loaded_uris(context: Any) -> None:
"""
Get the loaded URIs.
This accesses the loaded_uris property.
"""
_assert_loading_result_exists(context)
context.loaded_uris_set = context.loading_result.loaded_uris
@then("I should receive a ClassHierarchy instance")
def step_receive_class_hierarchy(context: Any) -> None:
"""
Verify that a ClassHierarchy instance was returned.
This checks return type correctness.
"""
from cleverrdf_lib.core.class_hierarchy import ClassHierarchy
assert context.accessed_hierarchy is not None, "Hierarchy should not be None"
assert isinstance(context.accessed_hierarchy, ClassHierarchy), "Should be ClassHierarchy instance"
@then("the hierarchy should be built")
def step_hierarchy_should_be_built(context: Any) -> None:
"""
Verify that the hierarchy is built.
This checks that hierarchy was built successfully.
"""
# Access get_all_classes to verify hierarchy works
_ = context.accessed_hierarchy.get_all_classes()
assert context.accessed_hierarchy is not None, "Hierarchy should exist"
@then("I should receive a dictionary of metadata from result")
def step_receive_metadata_dict(context: Any) -> None:
"""
Verify that a dictionary of metadata was returned.
This checks return type correctness.
"""
assert context.accessed_metadata is not None, "Metadata should not be None"
assert isinstance(context.accessed_metadata, dict), "Should be a dictionary"
@then("the metadata should contain ontology information")
def step_metadata_contains_info(context: Any) -> None:
"""
Verify that metadata contains ontology information.
This checks metadata content.
"""
# Metadata may or may not have specific keys depending on the graph
assert isinstance(context.accessed_metadata, dict), "Metadata should be a dictionary"
@then("I should receive a validation result")
def step_receive_validation_result(context: Any) -> None:
"""
Verify that a validation result was returned.
This checks return type correctness.
"""
assert context.accessed_validation is not None, "Validation result should not be None"
# Check that it has expected attributes
assert hasattr(context.accessed_validation, "errors"), "Should have errors attribute"
assert hasattr(context.accessed_validation, "warnings"), "Should have warnings attribute"
@then("the result should contain validation errors and warnings")
def step_validation_contains_errors_warnings(context: Any) -> None:
"""
Verify that validation result contains errors and warnings.
This checks validation result content.
"""
assert hasattr(context.accessed_validation, "errors"), "Should have errors"
assert hasattr(context.accessed_validation, "warnings"), "Should have warnings"
@then("I should receive a consistency result")
def step_receive_consistency_result(context: Any) -> None:
"""
Verify that a consistency result was returned.
This checks return type correctness.
"""
assert context.accessed_consistency is not None, "Consistency result should not be None"
# Check that it has expected attributes
assert hasattr(context.accessed_consistency, "is_consistent"), "Should have is_consistent attribute"
@then("the result should indicate consistency status")
def step_consistency_indicates_status(context: Any) -> None:
"""
Verify that consistency result indicates status.
This checks consistency result content.
"""
assert hasattr(context.accessed_consistency, "is_consistent"), "Should have is_consistent"
@then("I should receive a VersionManager instance")
def step_receive_version_manager(context: Any) -> None:
"""
Verify that a VersionManager instance was returned.
This checks return type correctness.
"""
from cleverrdf_lib.owl.version_manager import VersionManager
assert context.accessed_version_manager is not None, "Version manager should not be None"
assert isinstance(context.accessed_version_manager, VersionManager), "Should be VersionManager instance"
@then("I should be able to extract version information")
def step_can_extract_version_info(context: Any) -> None:
"""
Verify that version information can be extracted.
This checks version manager functionality.
"""
assert hasattr(context, "accessed_version_manager"), (
"accessed_version_manager must exist. Use 'I access the OWL version manager property' step first."
)
assert context.accessed_version_manager is not None, "accessed_version_manager must not be None"
version = context.accessed_version_manager.extract_version_info()
assert version is not None, "Should be able to extract version info"
@then("the observer should be registered")
def step_observer_registered(context: Any) -> None:
"""
Verify that the observer is registered.
This checks observer registration.
"""
_assert_loading_result_exists(context)
assert hasattr(context, "build_events"), (
"build_events must exist. Use 'I have a ClassHierarchyBuildObserver' step first."
)
# Access hierarchy to trigger build and verify observer receives events
_ = context.loading_result.class_hierarchy
assert len(context.build_events) > 0, "Observer should receive build events"
@then("the observer should receive build events when hierarchy is accessed")
def step_observer_receives_events(context: Any) -> None:
"""
Verify that observer receives build events.
This checks observer event reception.
"""
_assert_loading_result_exists(context)
assert hasattr(context, "build_events"), (
"build_events must exist. Use 'I have a ClassHierarchyBuildObserver' step first."
)
# Access hierarchy to trigger build
_ = context.loading_result.class_hierarchy
assert len(context.build_events) > 0, "Observer should receive build events"
@then("all observers should be registered")
def step_all_observers_registered(context: Any) -> None:
"""
Verify that all observers are registered.
This checks multiple observer registration.
"""
_assert_loading_result_exists(context)
assert hasattr(context, "observer1_events") and hasattr(context, "observer2_events"), (
"observer1_events and observer2_events must exist. "
"Use 'I have multiple ClassHierarchyBuildObserver instances for result' step first."
)
# Access hierarchy to trigger build and verify observers receive events
_ = context.loading_result.class_hierarchy
assert len(context.observer1_events) > 0 or len(context.observer2_events) > 0, "Observers should receive events"
@then("all observers should receive build events when hierarchy is accessed")
def step_all_observers_receive_events(context: Any) -> None:
"""
Verify that all observers receive build events.
This checks multiple observer event reception.
"""
_assert_loading_result_exists(context)
assert hasattr(context, "observer1_events") and hasattr(context, "observer2_events"), (
"observer1_events and observer2_events must exist. "
"Use 'I have multiple ClassHierarchyBuildObserver instances for result' step first."
)
# Access hierarchy to trigger build
_ = context.loading_result.class_hierarchy
assert len(context.observer1_events) > 0 or len(context.observer2_events) > 0, "Observers should receive events"
@given("I have a non-BaseClassHierarchyBuildObserver")
def step_have_non_base_build_observer(context: Any) -> None:
"""
Create a non-BaseClassHierarchyBuildObserver observer.
This creates an observer that is not a BaseClassHierarchyBuildObserver.
"""
class NonBaseObserver:
"""A simple observer that is not a BaseClassHierarchyBuildObserver."""
def on_build_started(self, iri: str) -> None:
pass
def on_build_completed(self, iri: str) -> None:
pass
context.non_base_observer = NonBaseObserver()
@when("I set the class hierarchy build observer on the result")
def step_set_build_observer_on_result(context: Any) -> None:
"""
Set the class hierarchy build observer on LoadingResult.
This calls set_class_hierarchy_build_observer.
"""
_assert_loading_result_exists(context)
_assert_build_observer_exists(context)
context.loading_result.set_class_hierarchy_build_observer(context.build_observer)
@when("I set the class hierarchy build observers on the result")
def step_set_build_observers_on_result(context: Any) -> None:
"""
Set multiple class hierarchy build observers on LoadingResult.
This calls set_class_hierarchy_build_observers.
"""
_assert_loading_result_exists(context)
_assert_multiple_observers_exist(context)
context.loading_result.set_class_hierarchy_build_observers(context.multiple_observers)
@when("I set the non-BaseClassHierarchyBuildObserver on the result")
def step_set_non_base_observer_on_result(context: Any) -> None:
"""
Set a non-BaseClassHierarchyBuildObserver on LoadingResult.
This tests the else branch in set_class_hierarchy_build_observer.
"""
_assert_loading_result_exists(context)
assert hasattr(context, "non_base_observer"), (
"non_base_observer must exist. Use 'I have a non-BaseClassHierarchyBuildObserver' step first."
)
assert context.non_base_observer is not None, "non_base_observer must not be None"
context.loading_result.set_class_hierarchy_build_observer(context.non_base_observer) # type: ignore[arg-type]
@then("the observer should be registered on the result")
def step_observer_registered_on_result(context: Any) -> None:
"""
Verify that the observer is registered on LoadingResult.
This checks observer registration by verifying that the observer receives build events.
"""
_assert_loading_result_exists(context)
assert hasattr(context, "build_events"), (
"build_events must exist. Use 'I have a ClassHierarchyBuildObserver' step first."
)
# Ensure hierarchy is accessed to trigger build (if not already accessed)
if not hasattr(context, "accessed_hierarchy"):
_ = context.loading_result.class_hierarchy
# Verify observer received build events
assert len(context.build_events) > 0, (
f"Observer should receive build events, but got {len(context.build_events)} events. "
"Make sure the hierarchy was accessed after setting the observer."
)
@then("all observers should be registered on the result")
def step_all_observers_registered_on_result(context: Any) -> None:
"""
Verify that all observers are registered on LoadingResult.
This checks multiple observer registration by verifying that all observers receive build events.
"""
_assert_loading_result_exists(context)
assert hasattr(context, "observer1_events") and hasattr(context, "observer2_events"), (
"observer1_events and observer2_events must exist. "
"Use 'I have multiple ClassHierarchyBuildObserver instances for result' step first."
)
# Ensure hierarchy is accessed to trigger build (if not already accessed)
if not hasattr(context, "accessed_hierarchy"):
_ = context.loading_result.class_hierarchy
# Verify all observers received build events
observer1_count = len(context.observer1_events)
observer2_count = len(context.observer2_events)
assert observer1_count > 0, (
f"Observer1 should receive build events, but got {observer1_count} events. "
"Make sure the hierarchy was accessed after setting the observers."
)
assert observer2_count > 0, (
f"Observer2 should receive build events, but got {observer2_count} events. "
"Make sure the hierarchy was accessed after setting the observers."
)
@then("the observer should be set even if not BaseClassHierarchyBuildObserver")
def step_observer_set_even_if_not_base(context: Any) -> None:
"""
Verify that observer is set even if not BaseClassHierarchyBuildObserver.
This checks the else branch in set_class_hierarchy_build_observer.
"""
assert hasattr(context, "accessed_hierarchy"), (
"accessed_hierarchy must exist. Use 'I access the class hierarchy property' step first."
)
# The observer should be set (even if not BaseClassHierarchyBuildObserver)
# This is verified by the hierarchy being built successfully
assert context.accessed_hierarchy is not None, "Hierarchy should be built"