Merge changes Iaac9f7e2,I9c336a30
authorTony Tkacik <ttkacik@cisco.com>
Tue, 8 Apr 2014 11:44:55 +0000 (11:44 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Tue, 8 Apr 2014 11:44:55 +0000 (11:44 +0000)
* changes:
  Fix for Bug 364.
  Fix for Bug 394.

17 files changed:
yang/yang-parser-impl/src/main/antlr/YangParser.g4
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/api/DataSchemaNodeBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/AnyXmlBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/ChoiceBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/ChoiceCaseBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/ContainerSchemaNodeBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/GroupingBuilderImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/LeafListSchemaNodeBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/LeafSchemaNodeBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/ListSchemaNodeBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/ModuleBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserListenerImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/ParserListenerUtils.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/RefineUtils.java
yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/impl/Bug394Test.java [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/bugs/bug394/bug394-ext.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/bugs/bug394/bug394.yang [new file with mode: 0644]

index b237e073c31c5e4de81d4539a1b15a8b8a15be27..b9b77ad3bcdde00a826f70437129387aa37b0de9 100644 (file)
@@ -21,7 +21,7 @@ yang : module_stmt | submodule_stmt ;
 
 string : STRING (PLUS STRING)*;
 
-identifier_stmt : IDENTIFIER string? stmtend;
+identifier_stmt : IDENTIFIER string? (stmtend | (LEFT_BRACE unknown_statement* RIGHT_BRACE));
 unknown_statement : (YIN_ELEMENT_KEYWORD | YANG_VERSION_KEYWORD | WHEN_KEYWORD | VALUE_KEYWORD | USES_KEYWORD | UNITS_KEYWORD | UNIQUE_KEYWORD | 
                     TYPEDEF_KEYWORD | TYPE_KEYWORD | SUBMODULE_KEYWORD | RPC_KEYWORD | REVISION_DATE_KEYWORD | REVISION_KEYWORD | 
                     REQUIRE_INSTANCE_KEYWORD | REFINE_KEYWORD | RANGE_KEYWORD | PRESENCE_KEYWORD | PREFIX_KEYWORD | 
index 018610176407a65eab6da4ecdb6c1dddeb9dd24e..e816e8c282e0cc7ff4f0c66c8f22d138bd14eff6 100644 (file)
@@ -42,14 +42,14 @@ public interface DataSchemaNodeBuilder extends SchemaNodeBuilder, GroupingMember
      *
      * @return value of config statement
      */
-    Boolean isConfiguration();
+    boolean isConfiguration();
 
     /**
      * Set config statement.
      *
      * @param config
      */
-    void setConfiguration(Boolean config);
+    void setConfiguration(boolean config);
 
     /**
      * Get constraints of this builder.
index aefc94f030ad1089e9487f34a42e9b558447d0bd..171390676964d685a4e6c27541f40ae8b1352da2 100644 (file)
@@ -139,12 +139,12 @@ public final class AnyXmlBuilder extends AbstractSchemaNodeBuilder implements Da
     }
 
     @Override
-    public Boolean isConfiguration() {
+    public boolean isConfiguration() {
         return instance.configuration;
     }
 
     @Override
-    public void setConfiguration(final Boolean configuration) {
+    public void setConfiguration(final boolean configuration) {
         instance.configuration = configuration;
     }
 
index 9b68ec19ea36221f571cdc84d48ec0ae955936fa..d885a76ae1a7411e80a6e37918c3b2afca07fdc4 100644 (file)
@@ -236,12 +236,12 @@ public final class ChoiceBuilder extends AbstractSchemaNodeBuilder implements Da
     }
 
     @Override
-    public Boolean isConfiguration() {
+    public boolean isConfiguration() {
         return instance.configuration;
     }
 
     @Override
-    public void setConfiguration(Boolean configuration) {
+    public void setConfiguration(boolean configuration) {
         instance.configuration = configuration;
     }
 
index 58bc85a518c122dfdbd0b6aa48bb19bc54be7f75..59072615d3d17a29656025913b66de9348d0325e 100644 (file)
@@ -177,12 +177,12 @@ public final class ChoiceCaseBuilder extends AbstractDataNodeContainerBuilder im
     }
 
     @Override
-    public Boolean isConfiguration() {
+    public boolean isConfiguration() {
         return false;
     }
 
     @Override
-    public void setConfiguration(final Boolean configuration) {
+    public void setConfiguration(final boolean configuration) {
         throw new YangParseException(moduleName, line, "Can not add config statement to choice case.");
     }
 
index d0461705a2ad27941240253ea39cc3e99148122b..4e1aab1bfb29cdcb531456dd13f512118b60f1b7 100644 (file)
@@ -36,7 +36,6 @@ public final class ContainerSchemaNodeBuilder extends AbstractDataNodeContainerB
 
     private final SchemaPath path;
     // DataSchemaNode args
-    private Boolean configuration;
     private final ConstraintsBuilder constraints;
     // AugmentationTarget args
     private final List<AugmentationSchemaBuilder> augmentationBuilders = new ArrayList<>();
@@ -77,20 +76,12 @@ public final class ContainerSchemaNodeBuilder extends AbstractDataNodeContainerB
         instance.uses.addAll(base.getUses());
         instance.presence = base.isPresenceContainer();
         instance.configuration = base.isConfiguration();
-        this.configuration = base.isConfiguration();
+        instance.configuration = base.isConfiguration();
     }
 
     @Override
     public ContainerSchemaNode build() {
         if (!isBuilt) {
-
-            // if this builder represents rpc input or output, it can has
-            // configuration value set to null
-            if (configuration == null) {
-                configuration = false;
-            }
-            instance.setConfiguration(configuration);
-
             // USES
             for (UsesNodeBuilder builder : addedUsesNodes) {
                 usesNodes.add(builder.build());
@@ -227,12 +218,12 @@ public final class ContainerSchemaNodeBuilder extends AbstractDataNodeContainerB
     }
 
     @Override
-    public Boolean isConfiguration() {
+    public boolean isConfiguration() {
         return instance.configuration;
     }
 
     @Override
-    public void setConfiguration(Boolean configuration) {
+    public void setConfiguration(boolean configuration) {
         instance.configuration = configuration;
     }
 
@@ -354,10 +345,6 @@ public final class ContainerSchemaNodeBuilder extends AbstractDataNodeContainerB
             return configuration;
         }
 
-        private void setConfiguration(boolean configuration) {
-            this.configuration = configuration;
-        }
-
         @Override
         public ConstraintDefinition getConstraints() {
             return constraints;
index c8d698227255f63fbd2f93148afd4f5d45e49bc6..e2bf02ce186bdd1886a1fddbbe57ed868e4b9196 100644 (file)
@@ -114,9 +114,6 @@ public final class GroupingBuilderImpl extends AbstractDataNodeContainerBuilder
         for (DataSchemaNodeBuilder node : addedChildNodes) {
             DataSchemaNodeBuilder copy = CopyUtils.copy(node, newParent, true);
             ParserUtils.setNodeAddedByUses(copy);
-            if (newParent instanceof DataSchemaNodeBuilder) {
-                ParserUtils.setNodeConfig(copy, ((DataSchemaNodeBuilder)newParent).isConfiguration());
-            }
             nodes.add(copy);
         }
         return nodes;
index a7616796d56138cc7711ae782d7e947f3349df9b..3f9f7ae8ca45526290047e188c4ec59679b159d4 100644 (file)
@@ -141,12 +141,12 @@ public final class LeafListSchemaNodeBuilder extends AbstractTypeAwareBuilder im
     }
 
     @Override
-    public Boolean isConfiguration() {
+    public boolean isConfiguration() {
         return instance.configuration;
     }
 
     @Override
-    public void setConfiguration(Boolean configuration) {
+    public void setConfiguration(boolean configuration) {
         instance.configuration = configuration;
     }
 
index c6336c6d4b8a8bb05c4501c69375f4f424c09cc5..e0303dce26b86a90a0c978854fa9c99fbf283111 100644 (file)
@@ -154,12 +154,12 @@ public final class LeafSchemaNodeBuilder extends AbstractTypeAwareBuilder implem
     }
 
     @Override
-    public Boolean isConfiguration() {
+    public boolean isConfiguration() {
         return instance.configuration;
     }
 
     @Override
-    public void setConfiguration(final Boolean configuration) {
+    public void setConfiguration(final boolean configuration) {
         instance.configuration = configuration;
     }
 
index f9f1e27c5f21a067ce81226517f4148b4e443bc9..bba5c7c92a5799b0274f10abf0a7fd3d9d8c5f52 100644 (file)
@@ -235,12 +235,12 @@ public final class ListSchemaNodeBuilder extends AbstractDataNodeContainerBuilde
     }
 
     @Override
-    public Boolean isConfiguration() {
+    public boolean isConfiguration() {
         return instance.configuration;
     }
 
     @Override
-    public void setConfiguration(Boolean configuration) {
+    public void setConfiguration(boolean configuration) {
         instance.configuration = configuration;
     }
 
index 4350692632ef0eb2d159e6dd2ac253ba742581f3..3695ec5cf0e5d88cf9fc6978a443c68bfcbe9707 100644 (file)
@@ -280,17 +280,6 @@ public class ModuleBuilder extends AbstractDataNodeContainerBuilder {
         }
     }
 
-    public Builder getActualParent() {
-        if (actualPath.size() < 2) {
-            return null;
-        } else {
-            Builder builderChild = actualPath.removeFirst();
-            Builder builderParent = actualPath.peekFirst();
-            actualPath.addFirst(builderChild);
-            return builderParent;
-        }
-    }
-
     public Set<TypeAwareBuilder> getDirtyNodes() {
         return dirtyNodes;
     }
index 222e718650bfbbecb75906302b77b225069bf227..0990f0c95fa204c9e447c9f9454ce236d76c4d69 100644 (file)
@@ -493,7 +493,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
         ContainerSchemaNodeBuilder builder = moduleBuilder.addContainerNode(line, containerQName, path);
         parseSchemaNodeArgs(ctx, builder);
         parseConstraints(ctx, builder.getConstraints());
-        builder.setConfiguration(getConfig(ctx, moduleBuilder.getActualParent(), moduleName, line));
+        builder.setConfiguration(getConfig(ctx, builder, moduleName, line));
 
         for (int i = 0; i < ctx.getChildCount(); ++i) {
             final ParseTree childNode = ctx.getChild(i);
@@ -525,7 +525,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
         LeafSchemaNodeBuilder builder = moduleBuilder.addLeafNode(line, leafQName, path);
         parseSchemaNodeArgs(ctx, builder);
         parseConstraints(ctx, builder.getConstraints());
-        builder.setConfiguration(getConfig(ctx, moduleBuilder.getActualParent(), moduleName, line));
+        builder.setConfiguration(getConfig(ctx, builder, moduleName, line));
 
         String defaultStr = null;
         String unitsStr = null;
@@ -628,7 +628,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
 
         parseSchemaNodeArgs(ctx, builder);
         parseConstraints(ctx, builder.getConstraints());
-        builder.setConfiguration(getConfig(ctx, moduleBuilder.getActualParent(), moduleName, ctx.getStart().getLine()));
+        builder.setConfiguration(getConfig(ctx, builder, moduleName, ctx.getStart().getLine()));
 
         for (int i = 0; i < ctx.getChildCount(); ++i) {
             final ParseTree childNode = ctx.getChild(i);
@@ -662,7 +662,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
 
         parseSchemaNodeArgs(ctx, builder);
         parseConstraints(ctx, builder.getConstraints());
-        builder.setConfiguration(getConfig(ctx, moduleBuilder.getActualParent(), moduleName, line));
+        builder.setConfiguration(getConfig(ctx, builder, moduleName, line));
 
         for (int i = 0; i < ctx.getChildCount(); ++i) {
             ParseTree childNode = ctx.getChild(i);
@@ -698,7 +698,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
 
         parseSchemaNodeArgs(ctx, builder);
         parseConstraints(ctx, builder.getConstraints());
-        builder.setConfiguration(getConfig(ctx, moduleBuilder.getActualParent(), moduleName, line));
+        builder.setConfiguration(getConfig(ctx, builder, moduleName, line));
     }
 
     @Override
@@ -722,7 +722,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
 
         parseSchemaNodeArgs(ctx, builder);
         parseConstraints(ctx, builder.getConstraints());
-        builder.setConfiguration(getConfig(ctx, moduleBuilder.getActualParent(), moduleName, line));
+        builder.setConfiguration(getConfig(ctx, builder, moduleName, line));
 
         // set 'default' case
         for (int i = 0; i < ctx.getChildCount(); i++) {
@@ -789,49 +789,38 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
     // Unknown nodes
     @Override
     public void enterIdentifier_stmt(YangParser.Identifier_stmtContext ctx) {
-        final int line = ctx.getStart().getLine();
-        final String nodeParameter = stringFromNode(ctx);
-        enterLog("unknown-node", nodeParameter, line);
+        handleUnknownNode(ctx.getStart().getLine(), ctx);
+    }
 
-        QName nodeType;
-        final String nodeTypeStr = ctx.getChild(0).getText();
-        final String[] splittedElement = nodeTypeStr.split(":");
-        if (splittedElement.length == 1) {
-            nodeType = new QName(namespace, revision, yangModelPrefix, splittedElement[0]);
-        } else {
-            nodeType = new QName(namespace, revision, splittedElement[0], splittedElement[1]);
-        }
+    @Override
+    public void exitIdentifier_stmt(YangParser.Identifier_stmtContext ctx) {
+        moduleBuilder.exitNode();
+        exitLog("unknown-node", removeNodeFromPath());
+    }
 
-        QName qname = null;
-        try {
-            if (!Strings.isNullOrEmpty(nodeParameter)) {
-                String[] splittedName = nodeParameter.split(":");
-                if (splittedName.length == 2) {
-                    qname = new QName(null, null, splittedName[0], splittedName[1]);
-                } else {
-                    qname = new QName(namespace, revision, yangModelPrefix, splittedName[0]);
-                }
-            } else {
-                qname = nodeType;
-            }
-        } catch (IllegalArgumentException e) {
-            qname = nodeType;
-            
-        }
-        addNodeToPath(qname);
-        SchemaPath path = createActualSchemaPath(actualPath.peek());
+    @Override public void enterUnknown_statement(YangParser.Unknown_statementContext ctx) {
+        handleUnknownNode(ctx.getStart().getLine(), ctx);
+    }
 
-        UnknownSchemaNodeBuilder builder = moduleBuilder.addUnknownSchemaNode(line, qname, path);
-        builder.setNodeType(nodeType);
-        builder.setNodeParameter(nodeParameter);
+    @Override public void exitUnknown_statement(YangParser.Unknown_statementContext ctx) {
+        moduleBuilder.exitNode();
+        exitLog("unknown-node", removeNodeFromPath());
+    }
 
+    @Override public void enterUnknown_statement2(YangParser.Unknown_statement2Context ctx) {
+        handleUnknownNode(ctx.getStart().getLine(), ctx);
+    }
 
-        parseSchemaNodeArgs(ctx, builder);
-        moduleBuilder.enterNode(builder);
+    @Override public void exitUnknown_statement2(YangParser.Unknown_statement2Context ctx) {
+        moduleBuilder.exitNode();
+        exitLog("unknown-node", removeNodeFromPath());
     }
 
-    @Override
-    public void exitIdentifier_stmt(YangParser.Identifier_stmtContext ctx) {
+    @Override public void enterUnknown_statement3(YangParser.Unknown_statement3Context ctx) {
+        handleUnknownNode(ctx.getStart().getLine(), ctx);
+    }
+
+    @Override public void exitUnknown_statement3(YangParser.Unknown_statement3Context ctx) {
         moduleBuilder.exitNode();
         exitLog("unknown-node", removeNodeFromPath());
     }
@@ -871,6 +860,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
 
         ContainerSchemaNodeBuilder builder = moduleBuilder.addRpcInput(line, rpcQName, path);
         moduleBuilder.enterNode(builder);
+        builder.setConfiguration(true);
 
         parseSchemaNodeArgs(ctx, builder);
         parseConstraints(ctx, builder.getConstraints());
@@ -894,6 +884,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
 
         ContainerSchemaNodeBuilder builder = moduleBuilder.addRpcOutput(path, rpcQName, line);
         moduleBuilder.enterNode(builder);
+        builder.setConfiguration(true);
 
         parseSchemaNodeArgs(ctx, builder);
         parseConstraints(ctx, builder.getConstraints());
@@ -1013,4 +1004,45 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
         LOGGER.trace("setting {} {}", p1, p2);
     }
 
+    private void handleUnknownNode(final int line, final ParseTree ctx) {
+        final String nodeParameter = stringFromNode(ctx);
+        enterLog("unknown-node", nodeParameter, line);
+
+        QName nodeType;
+        final String nodeTypeStr = ctx.getChild(0).getText();
+        final String[] splittedElement = nodeTypeStr.split(":");
+        if (splittedElement.length == 1) {
+            nodeType = new QName(namespace, revision, yangModelPrefix, splittedElement[0]);
+        } else {
+            nodeType = new QName(namespace, revision, splittedElement[0], splittedElement[1]);
+        }
+
+        QName qname = null;
+        try {
+            if (!Strings.isNullOrEmpty(nodeParameter)) {
+                String[] splittedName = nodeParameter.split(":");
+                if (splittedName.length == 2) {
+                    qname = new QName(null, null, splittedName[0], splittedName[1]);
+                } else {
+                    qname = new QName(namespace, revision, yangModelPrefix, splittedName[0]);
+                }
+            } else {
+                qname = nodeType;
+            }
+        } catch (IllegalArgumentException e) {
+            qname = nodeType;
+
+        }
+        addNodeToPath(qname);
+        SchemaPath path = createActualSchemaPath(actualPath.peek());
+
+        UnknownSchemaNodeBuilder builder = moduleBuilder.addUnknownSchemaNode(line, qname, path);
+        builder.setNodeType(nodeType);
+        builder.setNodeParameter(nodeParameter);
+
+
+        parseSchemaNodeArgs(ctx, builder);
+        moduleBuilder.enterNode(builder);
+    }
+
 }
index ec26b4483a1f7e42b8f7b93989fe34fc40109a6e..059b368590f3ecc95100eac0d77b76d685d62d1c 100644 (file)
@@ -949,16 +949,16 @@ public final class ParserListenerUtils {
      *
      * @param ctx
      *            context to parse
-     * @param parent
-     *            parent node
+     * @param node
+     *            current node
      * @param moduleName
      *            name of current module
      * @param line
      *            line in current module
      * @return config statement parsed from given context
      */
-    public static Boolean getConfig(final ParseTree ctx, final Builder parent, final String moduleName, final int line) {
-        Boolean result;
+    public static boolean getConfig(final ParseTree ctx, final Builder node, final String moduleName, final int line) {
+        boolean result;
         // parse configuration statement
         Boolean config = null;
         for (int i = 0; i < ctx.getChildCount(); i++) {
@@ -971,24 +971,15 @@ public final class ParserListenerUtils {
 
         // If 'config' is not specified, the default is the same as the parent
         // schema node's 'config' value
+        boolean parentConfig = getParentConfig(node);
         if (config == null) {
-            if (parent instanceof DataSchemaNodeBuilder) {
-                Boolean parentConfig = ((DataSchemaNodeBuilder) parent).isConfiguration();
-                // If the parent node is a rpc input or output, it can has
-                // config set to null
-                result = parentConfig == null ? true : parentConfig;
-            } else {
-                result = true;
-            }
+            result = parentConfig;
         } else {
-            // Check first: if a node has 'config' set to 'false', no node
-            // underneath it can have 'config' set to 'true'
-            if (parent instanceof DataSchemaNodeBuilder && !(parent instanceof ChoiceCaseBuilder)) {
-                Boolean parentConfig = ((DataSchemaNodeBuilder) parent).isConfiguration();
-                if (!parentConfig && config) {
-                    throw new YangParseException(moduleName, line,
-                            "Can not set 'config' to 'true' if parent node has 'config' set to 'false'");
-                }
+            // Check: if a node has 'config' set to 'false', no node underneath
+            // it can have 'config' set to 'true'
+            if (!parentConfig && config) {
+                throw new YangParseException(moduleName, line,
+                        "Can not set 'config' to 'true' if parent node has 'config' set to 'false'");
             }
             result = config;
         }
@@ -996,6 +987,21 @@ public final class ParserListenerUtils {
         return result;
     }
 
+    private static boolean getParentConfig(Builder node) {
+        Builder parent = node.getParent();
+        boolean config = false;
+
+        if (parent instanceof ChoiceCaseBuilder) {
+            parent = parent.getParent();
+        }
+        if (parent instanceof DataSchemaNodeBuilder) {
+            config = ((DataSchemaNodeBuilder) parent).isConfiguration();
+        } else {
+            config = true;
+        }
+        return config;
+    }
+
     /**
      * Parse config statement.
      *
index e7c53023a6319db489b56558a606ab90d0d30fe7..00b95cb37292bcfd940b7eda03b7cbe9a85823df 100644 (file)
@@ -287,7 +287,7 @@ public final class RefineUtils {
         Boolean config = refine.isConfiguration();
         if (config != null) {
             try {
-                Method method = cls.getDeclaredMethod("setConfiguration", Boolean.class);
+                Method method = cls.getDeclaredMethod("setConfiguration", Boolean.TYPE);
                 method.invoke(node, config);
             } catch (Exception e) {
                 throw new YangParseException(moduleName, line, "Cannot refine config in " + cls.getName(), e);
diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/impl/Bug394Test.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/impl/Bug394Test.java
new file mode 100644 (file)
index 0000000..c91a579
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.parser.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+import java.util.Set;
+
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
+
+/**
+ * Test antlr grammar capability to parse nested unknown nodes.
+ */
+public class Bug394Test {
+
+    @Test
+    public void testParseList() throws Exception {
+        Set<Module> modules = TestUtils.loadModules(getClass().getResource("/bugs/bug394").toURI());
+        Module bug394 = TestUtils.findModule(modules, "bug394");
+        assertNotNull(bug394);
+        Module bug394_ext = TestUtils.findModule(modules, "bug394-ext");
+        assertNotNull(bug394_ext);
+
+        ContainerSchemaNode logrecords = (ContainerSchemaNode) bug394.getDataChildByName("logrecords");
+        assertNotNull(logrecords);
+
+        List<UnknownSchemaNode> nodes = logrecords.getUnknownSchemaNodes();
+        assertEquals(2, nodes.size());
+
+        List<ExtensionDefinition> extensions = bug394_ext.getExtensionSchemaNodes();
+        assertEquals(2, extensions.size());
+
+        assertTrue(extensions.contains(nodes.get(0).getExtensionDefinition()));
+        assertTrue(extensions.contains(nodes.get(1).getExtensionDefinition()));
+    }
+
+}
diff --git a/yang/yang-parser-impl/src/test/resources/bugs/bug394/bug394-ext.yang b/yang/yang-parser-impl/src/test/resources/bugs/bug394/bug394-ext.yang
new file mode 100644 (file)
index 0000000..9af32ad
--- /dev/null
@@ -0,0 +1,21 @@
+module bug394-ext {
+    yang-version 1;
+    namespace "urn:test:bug394-ext";
+    prefix "b394e";
+
+    revision "2014-03-04" {
+    }
+
+
+    extension info {
+        description "Takes string as argument. Provide short info message";
+    }
+
+    extension action {
+        description "Define new action.";
+        argument "show" {
+            yin-element "true";
+        }
+    }
+
+}
diff --git a/yang/yang-parser-impl/src/test/resources/bugs/bug394/bug394.yang b/yang/yang-parser-impl/src/test/resources/bugs/bug394/bug394.yang
new file mode 100644 (file)
index 0000000..470eba3
--- /dev/null
@@ -0,0 +1,44 @@
+module bug394 {
+    yang-version 1;
+    namespace "urn:test:bug394";
+    prefix "b394";
+
+    import bug394-ext {
+        prefix ext;
+        revision-date 2014-03-04;
+    }
+
+    revision "2014-03-04" {
+    }
+
+
+    container logrecords {
+        ext:info "Shows logrecords information";
+        ext:action show {
+
+            info "Shows the log records";
+            actionpoint logging-logrecord-show;
+
+            input {
+                leaf from {
+                    type yang:date-and-time;
+                    default 2000-01-01T00:00:00-00:00;
+                    description "Shows the log records from the given time";
+                }
+                leaf to {
+                    type yang:date-and-time;
+                    default 2099-01-01T00:00:00-00:00;
+                    description "Shows the log records up to the given time";
+                }
+            }
+            output {
+                leaf data {
+                    cli-drop-node-name;
+                    type string;
+                    description "Shows the log records according to the given input";
+                }
+            }
+        }
+    }
+
+}