@phase2 @uko @coverage
Feature: UKO Loader coverage boost
  Exercises uncovered code paths in uko_loader.py to improve branch/line coverage.

  # ---------------------------------------------------------------------------
  # _detect_layer: full-IRI path (lines 87-90)
  # ---------------------------------------------------------------------------

  @uko_detect_layer
  Scenario: _detect_layer resolves layer from full IRI namespace
    Given a full IRI "https://cleveragents.ai/ontology/uko/code#Module"
    When I detect the layer for that URI
    Then the detected layer should be 1

  @uko_detect_layer
  Scenario: _detect_layer returns 0 for unknown URI
    Given a full IRI "https://example.com/unknown#Thing"
    When I detect the layer for that URI
    Then the detected layer should be 0

  @uko_detect_layer
  Scenario: _detect_layer resolves layer 2 from full IRI
    Given a full IRI "https://cleveragents.ai/ontology/uko/oo#Class"
    When I detect the layer for that URI
    Then the detected layer should be 2

  @uko_detect_layer
  Scenario: _detect_layer resolves layer 3 from full IRI
    Given a full IRI "https://cleveragents.ai/ontology/uko/py#Decorator"
    When I detect the layer for that URI
    Then the detected layer should be 3

  # ---------------------------------------------------------------------------
  # _extract_iri: called with and without angle-bracket IRI (lines 101-102)
  # ---------------------------------------------------------------------------

  @uko_extract_iri
  Scenario: _extract_iri extracts IRI from angle brackets
    Given a value string "<https://example.com/test>"
    When I extract the IRI from that value
    Then the extracted IRI should be "https://example.com/test"

  @uko_extract_iri
  Scenario: _extract_iri returns stripped value when no angle brackets
    Given a value string "plain-value"
    When I extract the IRI from that value
    Then the extracted IRI should be "plain-value"

  # ---------------------------------------------------------------------------
  # Non-resolvable property value else branch (line 181)
  # ---------------------------------------------------------------------------

  @uko_property_resolve
  Scenario: Property with HTTP value is kept as-is during resolution
    Given a TTL string with a property whose value starts with http:
      """
      @prefix uko: <https://cleveragents.ai/ontology/uko#> .
      @prefix owl: <http://www.w3.org/2002/07/owl#> .
      @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
      @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

      uko: a owl:Ontology ;
          owl:versionIRI <https://cleveragents.ai/ontology/uko/0.1.0> ;
          rdfs:label "Test" ;
          rdfs:comment "Test" .

      uko:myProp a owl:DatatypeProperty ;
          rdfs:label "myProp" ;
          rdfs:domain uko:InformationUnit ;
          rdfs:range <http://www.w3.org/2001/XMLSchema#string> .

      uko:InformationUnit a owl:Class ;
          rdfs:label "InformationUnit" .
      """
    When I parse the TTL coverage string
    Then the parsed ontology should contain a node labeled "myProp"
    And node "myProp" property "rdfs:range" should equal "http://www.w3.org/2001/XMLSchema#string"

  # ---------------------------------------------------------------------------
  # Validation: prefixed parent URI with undefined prefix (lines 249-254)
  # ---------------------------------------------------------------------------

  @uko_validation_prefixed
  Scenario: Validate detects undefined prefix in prefixed parent URI
    Given a UKO ontology with a prefixed parent referencing an undefined prefix
    When I run validation on the ontology
    Then the validation result should mention "undefined prefix"

  # ---------------------------------------------------------------------------
  # Validation: prefixed parent URI referencing non-existent node (lines 256-259)
  # ---------------------------------------------------------------------------

  @uko_validation_prefixed
  Scenario: Validate detects non-existent prefixed parent URI
    Given a UKO ontology with a prefixed parent referencing a non-existent node
    When I run validation on the ontology
    Then the validation result should mention "non-existent parent"

  # ---------------------------------------------------------------------------
  # resolve_inheritance: parent not in uri_map (line 310)
  # ---------------------------------------------------------------------------

  @uko_inheritance_coverage
  Scenario: resolve_inheritance skips unknown parent URIs gracefully
    Given a UKO ontology where a node has an external parent URI
    When I resolve the inheritance chain for the node with external parent
    Then the chain should contain the starting node only

  # ---------------------------------------------------------------------------
  # _detect_cycle_dfs: already-explored node (line 361)
  # ---------------------------------------------------------------------------

  @uko_cycle_dfs
  Scenario: DFS cycle detection handles diamond inheritance without error
    Given a UKO ontology with diamond inheritance shape
    When I resolve the inheritance chain for the diamond leaf
    Then the chain should include each ancestor at most once

  # ---------------------------------------------------------------------------
  # _detect_cycle_dfs: gray node popped from stack (line 363)
  # ---------------------------------------------------------------------------

  @uko_cycle_dfs
  Scenario: DFS detects self-referencing cycle
    Given a UKO ontology where a node is its own parent
    When I attempt to resolve inheritance for the self-referencing node
    Then a cycle error should be raised for that node

  # ---------------------------------------------------------------------------
  # _detect_cycle_dfs: node is None (line 370)
  # ---------------------------------------------------------------------------

  @uko_cycle_dfs
  Scenario: DFS cycle check handles start URI not in uri_map
    Given a UKO ontology with some nodes
    When I resolve the inheritance chain for a URI not in the ontology
    Then the chain should be empty

  # ---------------------------------------------------------------------------
  # _split_blocks: dot inside bare token is not a terminator (line 443)
  # ---------------------------------------------------------------------------

  @uko_parser
  Scenario: Parser treats dots in bare tokens as non-terminators
    Given a TTL string with dots in bare subject names:
      """
      @prefix uko: <https://cleveragents.ai/ontology/uko#> .
      @prefix owl: <http://www.w3.org/2002/07/owl#> .
      @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

      uko: a owl:Ontology ;
          owl:versionIRI <https://cleveragents.ai/ontology/uko/0.1.0> ;
          rdfs:label "Test" ;
          rdfs:comment "Test" .

      uko:v0.1 a owl:Class ;
          rdfs:label "Dotted" .

      uko:Thing a owl:Class ;
          rdfs:label "Thing" .
      """
    When I parse the TTL coverage string
    Then the parsed ontology should contain a node labeled "Thing"
    And the parsed ontology should contain a node labeled "Dotted"

  # ---------------------------------------------------------------------------
  # _split_blocks: unterminated statement remainder (line 451)
  # ---------------------------------------------------------------------------

  @uko_parser
  Scenario: Parser handles TTL block without trailing period
    Given a TTL string without trailing period:
      """
      @prefix uko: <https://cleveragents.ai/ontology/uko#> .
      @prefix owl: <http://www.w3.org/2002/07/owl#> .
      @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

      uko: a owl:Ontology ;
          owl:versionIRI <https://cleveragents.ai/ontology/uko/0.1.0> ;
          rdfs:label "Test" ;
          rdfs:comment "Test" .

      uko:Leftover a owl:Class ;
          rdfs:label "Leftover"
      """
    When I parse the TTL coverage string
    Then the parsed ontology should contain a node labeled "Leftover"

  # ---------------------------------------------------------------------------
  # _split_blocks: single-token statement (line 457)
  # ---------------------------------------------------------------------------

  @uko_parser
  Scenario: Parser skips single-token statements
    Given a TTL string with a stray single token:
      """
      @prefix uko: <https://cleveragents.ai/ontology/uko#> .
      @prefix owl: <http://www.w3.org/2002/07/owl#> .
      @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

      uko: a owl:Ontology ;
          owl:versionIRI <https://cleveragents.ai/ontology/uko/0.1.0> ;
          rdfs:label "Test" ;
          rdfs:comment "Test" .

      uko:Lone a owl:Class ;
          rdfs:label "Lone" .

      stray-token .

      uko:Valid a owl:Class ;
          rdfs:label "Valid" .
      """
    When I parse the TTL coverage string
    Then the parsed ontology should contain a node labeled "Valid"

  # ---------------------------------------------------------------------------
  # _parse_predicates: empty and single-part pairs (lines 469, 472)
  # ---------------------------------------------------------------------------

  @uko_parser
  Scenario: Parser handles predicates with empty and bare keyword pairs
    Given a TTL string with trailing semicolons and bare keywords:
      """
      @prefix uko: <https://cleveragents.ai/ontology/uko#> .
      @prefix owl: <http://www.w3.org/2002/07/owl#> .
      @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

      uko: a owl:Ontology ;
          owl:versionIRI <https://cleveragents.ai/ontology/uko/0.1.0> ;
          rdfs:label "Test" ;
          rdfs:comment "Test" .

      uko:Node1 a owl:Class ;
          rdfs:label "Node1" ; ;
      """
    When I parse the TTL coverage string
    Then the parsed ontology should contain a node labeled "Node1"

  # ---------------------------------------------------------------------------
  # _resolve_uri: angle-bracket IRI (line 517)
  # ---------------------------------------------------------------------------

  @uko_resolve_uri
  Scenario: _resolve_uri strips angle brackets from well-formed IRI
    Given a UKO loader instance
    When I resolve the prefixed URI "<https://example.com/thing>" with an empty prefix map
    Then the resolved URI should be "https://example.com/thing"

  # ---------------------------------------------------------------------------
  # _resolve_uri: prefix not in map (line 522)
  # ---------------------------------------------------------------------------

  @uko_resolve_uri
  Scenario: _resolve_uri returns prefixed name when prefix is unknown
    Given a UKO loader instance
    When I resolve the prefixed URI "unknown:Foo" with an empty prefix map
    Then the resolved URI should be "unknown:Foo"

  # ---------------------------------------------------------------------------
  # _extract_version_string: empty version IRI (line 531)
  # ---------------------------------------------------------------------------

  @uko_version_extract
  Scenario: _extract_version_string returns empty for empty IRI
    Given a UKO loader instance
    When I extract version string from an empty IRI
    Then the extracted version should be ""

  @uko_version_extract
  Scenario: _extract_version_string returns empty for non-semver segment
    Given a UKO loader instance
    When I extract version string from "https://example.com/ontology/latest"
    Then the extracted version should be ""

  # ---------------------------------------------------------------------------
  # load() via Path (line 117-118) — file-based loading
  # ---------------------------------------------------------------------------

  @uko_load_file
  Scenario: load() reads TTL from a file Path
    Given a temporary TTL file with valid content
    When I load the ontology from the temporary file
    Then the loaded ontology should have version "0.1.0"

  # ---------------------------------------------------------------------------
  # Ontology declaration via rdf:type instead of 'a' (line 136)
  # ---------------------------------------------------------------------------

  @uko_parser
  Scenario: Parser recognises ontology declaration via rdf:type
    Given a TTL string using rdf:type for ontology declaration:
      """
      @prefix uko: <https://cleveragents.ai/ontology/uko#> .
      @prefix owl: <http://www.w3.org/2002/07/owl#> .
      @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
      @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

      uko: rdf:type owl:Ontology ;
          owl:versionIRI <https://cleveragents.ai/ontology/uko/0.1.0> ;
          rdfs:label "Alt" ;
          rdfs:comment "Alt test" .

      uko:Thing a owl:Class ;
          rdfs:label "Thing" .
      """
    When I parse the TTL coverage string
    Then the parsed ontology version label should be "Alt"
    And the parsed ontology should contain a node labeled "Thing"
