Add SchemaInferenceStack.effectiveStatus() 32/104132/5
authorRobert Varga <robert.varga@pantheon.tech>
Wed, 25 Jan 2023 04:32:22 +0000 (05:32 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Thu, 26 Oct 2023 20:28:12 +0000 (22:28 +0200)
EffectiveStatements are lacking the equivalent of
DocumentedNode.WithStatus.getStatus().

This patch introduces a utility method in SchemaInferenceStack, which
acts as a replacement producing results well-defined in
EffectiveStatement world.

JIRA: YANGTOOLS-1272
Change-Id: I1b07d4ab2eb43c62090d526326ac10df901e8bfb
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
model/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/SchemaInferenceStack.java
model/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/SchemaInferenceStackTest.java
model/yang-model-util/src/test/resources/schema-context-util/my-module.yang

index c5cde35a9dc8b109c27fff8818ca6e1b63da50ce..5ad2966934abf818d2af54c15ea1c03fa5c36bae 100644 (file)
@@ -44,6 +44,7 @@ import org.opendaylight.yangtools.yang.model.api.PathExpression.DerefSteps;
 import org.opendaylight.yangtools.yang.model.api.PathExpression.LocationPathSteps;
 import org.opendaylight.yangtools.yang.model.api.PathExpression.Steps;
 import org.opendaylight.yangtools.yang.model.api.SchemaTreeInference;
+import org.opendaylight.yangtools.yang.model.api.Status;
 import org.opendaylight.yangtools.yang.model.api.TypeAware;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode;
@@ -58,6 +59,7 @@ import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.StatusEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.TypedefAwareEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
@@ -367,6 +369,48 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex
         return groupingDepth != 0;
     }
 
+    /**
+     * Return the effective {@code status} of the {@link #currentStatement()}, if present. This method operates on
+     * the effective view of the model and therefore does not reflect status the declaration hierarchy. Most notably
+     * this YANG snippet:
+     * <pre>
+     * {@code
+     *   module foo {
+     *     grouping foo {
+     *       status obsolete;
+     *       leaf bar { type string; }
+     *     }
+     *
+     *     container foo {
+     *       status deprecated;
+     *       uses bar;
+     *     }
+     *
+     *     uses foo;
+     *   }
+     * }
+     * </pre>
+     * will cause this method to report the status of {@code leaf bar} as:
+     * <ul>
+     *   <li>{@link Status#OBSOLETE} at its original declaration site in {@code grouping foo}</li>
+     *   <li>{@link Status#DEPRECATED} at its instantiation in {@code container foo}</li>
+     *   <li>{@link Status#CURRENT} at its instantiation in {@code module foo}</li>
+     * </ul>
+     *
+     * @return {@link Status#CURRENT} if {@link #isEmpty()}, or the status of current statement as implied by its direct
+     *         and its ancestors' substaments.
+     */
+    public @NonNull Status effectiveStatus() {
+        final var it = reconstructDeque().descendingIterator();
+        while (it.hasNext()) {
+            final var optStatus = it.next().findFirstEffectiveSubstatementArgument(StatusEffectiveStatement.class);
+            if (optStatus.isPresent()) {
+                return optStatus.orElseThrow();
+            }
+        }
+        return Status.CURRENT;
+    }
+
     /**
      * Reset this stack to empty state.
      */
@@ -694,12 +738,15 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex
      */
     public @NonNull SchemaTreeInference toSchemaTreeInference() {
         checkState(inInstantiatedContext(), "Cannot convert uninstantiated context %s", this);
-        final var cleanDeque = clean ? deque : reconstructSchemaInferenceStack().deque;
-        return DefaultSchemaTreeInference.unsafeOf(getEffectiveModelContext(), cleanDeque.stream()
+        return DefaultSchemaTreeInference.unsafeOf(getEffectiveModelContext(), reconstructDeque().stream()
             .map(stmt -> (SchemaTreeEffectiveStatement<?>) stmt)
             .collect(ImmutableList.toImmutableList()));
     }
 
+    private ArrayDeque<EffectiveStatement<?, ?>> reconstructDeque() {
+        return clean ? deque : reconstructSchemaInferenceStack().deque;
+    }
+
     /**
      * Convert current state into an absolute schema node identifier.
      *
index 76284ebbae245855400268bbc2a6fbd6a63b7c39..ccf51e90f843442e181427f8ef06922e1a778d28 100644 (file)
@@ -28,6 +28,7 @@ import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.PathExpression;
 import org.opendaylight.yangtools.yang.model.api.PathExpression.LocationPathSteps;
+import org.opendaylight.yangtools.yang.model.api.Status;
 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath;
 import org.opendaylight.yangtools.yang.xpath.api.YangXPathAxis;
@@ -99,6 +100,46 @@ class SchemaInferenceStackTest {
         assertNotExistentTypedef(stack, "schema parent (uri:my-module?revision=2014-10-07)my-container");
     }
 
+    @Test
+    void rootIsCurrent() {
+        final var stack = SchemaInferenceStack.of(context);
+        assertEquals(Status.CURRENT, stack.effectiveStatus());
+    }
+
+    @Test
+    void myGroupingIsCurrent() {
+        final var stack = SchemaInferenceStack.of(context);
+        stack.enterGrouping(QName.create(myModule.getQNameModule(), "my-grouping"));
+        assertEquals(Status.CURRENT, stack.effectiveStatus());
+    }
+
+    @Test
+    void myLeafInContainerIsDeprecated() {
+        final var stack = SchemaInferenceStack.of(context);
+        stack.enterDataTree(QName.create(myModule.getQNameModule(), "my-container"));
+        stack.enterDataTree(QName.create(myModule.getQNameModule(), "my-leaf-in-container"));
+        assertEquals(Status.DEPRECATED, stack.effectiveStatus());
+    }
+
+    @Test
+    void twoInGroupingIsObsolete() {
+        final var stack = SchemaInferenceStack.of(context);
+        stack.enterGrouping(QName.create(myModule.getQNameModule(), "my-name"));
+        stack.enterDataTree(QName.create(myModule.getQNameModule(), "two"));
+        assertEquals(Status.OBSOLETE, stack.effectiveStatus());
+    }
+
+    @Test
+    void twoInMyNameInputIsObsolete() {
+        final var stack = SchemaInferenceStack.of(context);
+        stack.enterSchemaTree(QName.create(myModule.getQNameModule(), "my-name"));
+        stack.enterSchemaTree(QName.create(myModule.getQNameModule(), "input"));
+        stack.enterSchemaTree(QName.create(myModule.getQNameModule(), "my-choice"));
+        stack.enterSchemaTree(QName.create(myModule.getQNameModule(), "case-two"));
+        stack.enterSchemaTree(QName.create(myModule.getQNameModule(), "two"));
+        assertEquals(Status.OBSOLETE, stack.effectiveStatus());
+    }
+
     private static void assertNotExistentGrouping(final SchemaInferenceStack stack, final String parentDesc) {
         final QName nonExistent = QName.create(myModule.getQNameModule(), "non-existent");
         assertEquals("Grouping (uri:my-module?revision=2014-10-07)non-existent not present in " + parentDesc,
index f4b1d99f4178b765b75665ec47df4d854442b1d7..c99930324e3c6e15f540aac2924e89946ae3affd 100644 (file)
@@ -29,6 +29,7 @@ module my-module {
     container my-container {
         leaf my-leaf-in-container {
             type int32;
+            status deprecated;
         }
         uses my-grouping;
         list my-list {
@@ -118,14 +119,11 @@ module my-module {
     grouping my-name {
         choice my-choice {
             case case-one {
-                container one {
-                    //empty
-                }
+                container one;
             }
             case case-two {
-                container two {
-                    //empty
-                }
+                container two;
+                status obsolete;
             }
         }
     }