[ONOS-5483] Leafref with path-predicate linking.

Change-Id: Id1f95e7b82de9d0b9b1717b8a0f96fb8d03939b1
diff --git a/plugin/maven/src/test/java/org/onosproject/yangutils/plugin/manager/IntraFileLeafrefLinkingTest.java b/plugin/maven/src/test/java/org/onosproject/yangutils/plugin/manager/IntraFileLeafrefLinkingTest.java
index f02fe65..e128979 100644
--- a/plugin/maven/src/test/java/org/onosproject/yangutils/plugin/manager/IntraFileLeafrefLinkingTest.java
+++ b/plugin/maven/src/test/java/org/onosproject/yangutils/plugin/manager/IntraFileLeafrefLinkingTest.java
@@ -1552,11 +1552,11 @@
         List<YangPathPredicate> pathPredicateList = abspath.getPathPredicatesList();
         Iterator<YangPathPredicate> pathPredicate = pathPredicateList.listIterator();
         YangPathPredicate pathPredicate1 = pathPredicate.next();
-        assertThat(pathPredicate1.getNodeIdentifier().getName(), is("name"));
-        assertThat(pathPredicate1.getNodeIdentifier().getPrefix(), nullValue());
-        assertThat(pathPredicate1.getRightRelativePath().getAncestorNodeCount(), is(1));
-        assertThat(pathPredicate1.getPathOperator(), is(YangPathOperator.EQUALTO));
-        assertThat(pathPredicate1.getRightRelativePath().getAtomicPathList().listIterator().next().getNodeIdentifier()
+        assertThat(pathPredicate1.getNodeId().getName(), is("name"));
+        assertThat(pathPredicate1.getNodeId().getPrefix(), nullValue());
+        assertThat(pathPredicate1.getRelPath().getAncestorNodeCount(), is(1));
+        assertThat(pathPredicate1.getPathOp(), is(YangPathOperator.EQUALTO));
+        assertThat(pathPredicate1.getRelPath().getAtomicPathList().listIterator().next().getNodeIdentifier()
                 .getName(), is("ifname"));
         //TODO : Fill the path predicates
 //        assertThat(pathPredicate1.getLeftAxisNode(), is(leafNameInList));
diff --git a/plugin/maven/src/test/java/org/onosproject/yangutils/plugin/manager/PathPredicateLinkingTest.java b/plugin/maven/src/test/java/org/onosproject/yangutils/plugin/manager/PathPredicateLinkingTest.java
new file mode 100644
index 0000000..e7ae30d
--- /dev/null
+++ b/plugin/maven/src/test/java/org/onosproject/yangutils/plugin/manager/PathPredicateLinkingTest.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yangutils.plugin.manager;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.onosproject.yangutils.datamodel.YangAtomicPath;
+import org.onosproject.yangutils.datamodel.YangAugment;
+import org.onosproject.yangutils.datamodel.YangContainer;
+import org.onosproject.yangutils.datamodel.YangLeaf;
+import org.onosproject.yangutils.datamodel.YangLeafRef;
+import org.onosproject.yangutils.datamodel.YangList;
+import org.onosproject.yangutils.datamodel.YangModule;
+import org.onosproject.yangutils.datamodel.YangNode;
+import org.onosproject.yangutils.datamodel.YangPathPredicate;
+import org.onosproject.yangutils.linker.exceptions.LinkerException;
+import org.onosproject.yangutils.linker.impl.YangLinkerManager;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.ListIterator;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
+import static org.onosproject.yangutils.linker.impl.YangLinkerUtils.updateFilePriority;
+import static org.onosproject.yangutils.utils.io.impl.YangFileScanner.getYangFiles;
+
+/**
+ * Test cases for path predicate linking in leaf-ref.
+ */
+public class PathPredicateLinkingTest {
+
+    private static final String DIR = "src/test/resources/pathpredicate/";
+
+    private final YangUtilManager utilMgr = new YangUtilManager();
+    private final YangLinkerManager linkerMgr = new YangLinkerManager();
+
+    @Rule
+    public ExpectedException thrown = ExpectedException.none();
+
+    private ListIterator<YangLeaf> leafItr;
+    private YangLeaf ifName;
+    private YangLeaf address;
+    private YangLeaf name;
+    private Iterator<YangAtomicPath> pathItr;
+    private YangAtomicPath atomicPath;
+    private Iterator<YangPathPredicate> predicateItr;
+    private YangPathPredicate predicate;
+
+    /**
+     * Processes simple path predicate which gets linked within the same file
+     * using relative path.
+     *
+     * @throws IOException if violates IO operation
+     */
+    @Test
+    public void processSimplePathPredicate() throws IOException {
+
+        utilMgr.createYangFileInfoSet(getYangFiles(DIR + "simple"));
+        utilMgr.parseYangFileInfoSet();
+        utilMgr.createYangNodeSet();
+        YangNode selfNode;
+
+        linkerMgr.createYangNodeSet(utilMgr.getYangNodeSet());
+        linkerMgr.addRefToYangFilesImportList(utilMgr.getYangNodeSet());
+
+        updateFilePriority(utilMgr.getYangNodeSet());
+
+        linkerMgr.processInterFileLinking(utilMgr.getYangNodeSet());
+        Iterator<YangNode> nodeItr = utilMgr.getYangNodeSet().iterator();
+        selfNode = nodeItr.next();
+
+        // Gets the list node.
+        YangList yangList = (YangList) selfNode.getChild();
+        // Gets the container node.
+        YangContainer container = (YangContainer) yangList.getNextSibling();
+
+        leafItr = container.getListOfLeaf().listIterator();
+        ifName = leafItr.next();
+        address = leafItr.next();
+
+        // Gets the address leaf's leaf-ref type.
+        YangLeafRef<?> leafRef2 = (YangLeafRef) address.getDataType()
+                .getDataTypeExtendedInfo();
+        pathItr = leafRef2.getAtomicPath().listIterator();
+        atomicPath = pathItr.next();
+
+        // Gets the path-predicate.
+        predicateItr = atomicPath.getPathPredicatesList().listIterator();
+        predicate = predicateItr.next();
+
+        // Gets the left and right axis node in path-predicate.
+        YangLeaf yangLeftLeaf = (YangLeaf) predicate.getLeftAxisNode();
+        YangLeaf yangRightLeaf = (YangLeaf) predicate.getRightAxisNode();
+
+        leafItr = yangList.getListOfLeaf().listIterator();
+        name = leafItr.next();
+
+        // Checks that right and left path-predicates are correct.
+        assertThat(yangLeftLeaf, is(name));
+        assertThat(yangRightLeaf, is(ifName));
+    }
+
+    /**
+     * Processes simple inter file path predicate which gets linked to another
+     * file using absolute path.
+     *
+     * @throws IOException if violates IO operation
+     */
+    @Test
+    public void processSimpleInterFilePathPredicate() throws IOException {
+
+        utilMgr.createYangFileInfoSet(getYangFiles(DIR + "simpleinterfile"));
+        utilMgr.parseYangFileInfoSet();
+        utilMgr.createYangNodeSet();
+        YangModule selfNode;
+
+        linkerMgr.createYangNodeSet(utilMgr.getYangNodeSet());
+        linkerMgr.addRefToYangFilesImportList(utilMgr.getYangNodeSet());
+
+        updateFilePriority(utilMgr.getYangNodeSet());
+
+        linkerMgr.processInterFileLinking(utilMgr.getYangNodeSet());
+        Iterator<YangNode> nodeItr = utilMgr.getYangNodeSet().iterator();
+
+        YangNode rootNode = nodeItr.next();
+        YangModule refNode;
+        if (rootNode.getName().equals("ietf-network")) {
+            selfNode = (YangModule) rootNode;
+            refNode = (YangModule) nodeItr.next();
+        } else {
+            refNode = (YangModule) rootNode;
+            selfNode = (YangModule) nodeItr.next();
+        }
+
+        // Gets the container node.
+        YangContainer container = (YangContainer) selfNode.getChild();
+        // Gets the list node.
+        YangList yangList = (YangList) refNode.getChild();
+
+        leafItr = container.getListOfLeaf().listIterator();
+        ifName = leafItr.next();
+        address = leafItr.next();
+
+        // Gets the address leaf's leaf-ref type.
+        YangLeafRef<?> leafRef2 = (YangLeafRef) address.getDataType()
+                .getDataTypeExtendedInfo();
+        pathItr = leafRef2.getAtomicPath().listIterator();
+        atomicPath = pathItr.next();
+
+        // Gets the path-predicate.
+        predicateItr = atomicPath.getPathPredicatesList().listIterator();
+        predicate = predicateItr.next();
+
+        // Gets the left and right axis node in path-predicate.
+        YangLeaf yangLeftLeaf = (YangLeaf) predicate.getLeftAxisNode();
+        YangLeaf yangRightLeaf = (YangLeaf) predicate.getRightAxisNode();
+
+        leafItr = yangList.getListOfLeaf().listIterator();
+        name = leafItr.next();
+
+        // Checks that right and left path-predicates are correct.
+        assertThat(yangLeftLeaf, is(name));
+        assertThat(yangRightLeaf, is(ifName));
+    }
+
+    /**
+     * Processes inter file path predicate, where leaf-ref is present under
+     * YANG augment.
+     *
+     * @throws IOException if violates IO operation
+     */
+    @Test
+    public void processInterFilePathPredicateFromAugment() throws IOException {
+
+        utilMgr.createYangFileInfoSet(getYangFiles(DIR + "interfileaugment"));
+        utilMgr.parseYangFileInfoSet();
+        utilMgr.createYangNodeSet();
+        YangModule selfNode;
+
+        linkerMgr.createYangNodeSet(utilMgr.getYangNodeSet());
+        linkerMgr.addRefToYangFilesImportList(utilMgr.getYangNodeSet());
+
+        updateFilePriority(utilMgr.getYangNodeSet());
+
+        linkerMgr.processInterFileLinking(utilMgr.getYangNodeSet());
+        Iterator<YangNode> nodeItr = utilMgr.getYangNodeSet().iterator();
+
+        YangNode rootNode = nodeItr.next();
+        YangModule refNode;
+        if (rootNode.getName().equals("ietf-network")) {
+            selfNode = (YangModule) rootNode;
+            refNode = (YangModule) nodeItr.next();
+        } else {
+            refNode = (YangModule) rootNode;
+            selfNode = (YangModule) nodeItr.next();
+        }
+
+        // Gets the augment node.
+        YangList list = (YangList) selfNode.getChild().getChild();
+
+        // Gets the augment node.
+        YangAugment augment = (YangAugment) refNode.getChild();
+
+        YangLeaf test;
+        YangLeaf networkId;
+        YangLeaf networkRef;
+
+        leafItr = augment.getListOfLeaf().listIterator();
+        test = leafItr.next();
+
+        YangLeafRef<?> leafRef =
+                (YangLeafRef) test.getDataType().getDataTypeExtendedInfo();
+        pathItr = leafRef.getAtomicPath().listIterator();
+        pathItr.next();
+        atomicPath = pathItr.next();
+
+        // Gets the path-predicate.
+        predicateItr = atomicPath.getPathPredicatesList().listIterator();
+        predicate = predicateItr.next();
+
+        // Gets the left and right axis node in path-predicate.
+        YangLeaf yangLeftLeaf = (YangLeaf) predicate.getLeftAxisNode();
+        YangLeaf yangRightLeaf = (YangLeaf) predicate.getRightAxisNode();
+
+        leafItr = list.getListOfLeaf().listIterator();
+        networkId = leafItr.next();
+        YangContainer reference = (YangContainer) list.getChild();
+        leafItr = reference.getListOfLeaf().listIterator();
+        networkRef = leafItr.next();
+
+        // Checks that right and left path-predicates are correct.
+        assertThat(yangLeftLeaf, is(networkId));
+        assertThat(yangRightLeaf, is(networkRef));
+    }
+
+    /**
+     * Processes an invalid scenario where the target leaf/leaf-list in
+     * path-predicate is not found.
+     *
+     * @throws IOException if violates IO operation
+     */
+    @Test
+    public void processInvalidPathLink() throws IOException {
+        thrown.expect(LinkerException.class);
+        thrown.expectMessage(
+                "YANG file error: There is no leaf/leaf-list in YANG node as " +
+                        "mentioned in the path predicate of the leafref path " +
+                        "../../interface[ifname = current()/../../ifname]" +
+                        "/address/ip");
+
+        utilMgr.createYangFileInfoSet(getYangFiles(DIR + "invalidlinking"));
+        utilMgr.parseYangFileInfoSet();
+        utilMgr.createYangNodeSet();
+
+        linkerMgr.createYangNodeSet(utilMgr.getYangNodeSet());
+        linkerMgr.addRefToYangFilesImportList(utilMgr.getYangNodeSet());
+
+        updateFilePriority(utilMgr.getYangNodeSet());
+
+        linkerMgr.processInterFileLinking(utilMgr.getYangNodeSet());
+    }
+
+    /**
+     * Processes an invalid scenario where the right axis node doesn't come
+     * under YANG list node.
+     *
+     * @throws IOException if violates IO operation
+     */
+    @Test
+    public void processInvalidPathLinkForList() throws IOException {
+        thrown.expect(LinkerException.class);
+        thrown.expectMessage(
+                "YANG file error: Path predicates are only applicable for " +
+                        "YANG list. The leafref path has path predicate for" +
+                        " non-list node in the path ../../default-address" +
+                        "[ifname = current()/../ifname]/ifname");
+
+        utilMgr.createYangFileInfoSet(getYangFiles(DIR + "invalidlinking2"));
+        utilMgr.parseYangFileInfoSet();
+        utilMgr.createYangNodeSet();
+
+        linkerMgr.createYangNodeSet(utilMgr.getYangNodeSet());
+        linkerMgr.addRefToYangFilesImportList(utilMgr.getYangNodeSet());
+
+        updateFilePriority(utilMgr.getYangNodeSet());
+
+        linkerMgr.processInterFileLinking(utilMgr.getYangNodeSet());
+    }
+
+    /**
+     * Processes an invalid scenario where the node in path predicate is not
+     * present in the traversal.
+     *
+     * @throws IOException if violates IO operation
+     */
+    @Test
+    public void processInvalidPathLinkForInvalidNode()
+            throws IOException {
+        thrown.expect(LinkerException.class);
+        thrown.expectMessage(
+                "YANG file error: The path predicate of the leafref has an " +
+                        "invalid path in ../../interface[name = current()/" +
+                        "../../address/ifname]/address/ip");
+
+        utilMgr.createYangFileInfoSet(getYangFiles(DIR + "invalidlinking3"));
+        utilMgr.parseYangFileInfoSet();
+        utilMgr.createYangNodeSet();
+
+        linkerMgr.createYangNodeSet(utilMgr.getYangNodeSet());
+        linkerMgr.addRefToYangFilesImportList(utilMgr.getYangNodeSet());
+
+        updateFilePriority(utilMgr.getYangNodeSet());
+
+        linkerMgr.processInterFileLinking(utilMgr.getYangNodeSet());
+    }
+}
diff --git a/plugin/maven/src/test/resources/pathpredicate/interfileaugment/ietf-network.yang b/plugin/maven/src/test/resources/pathpredicate/interfileaugment/ietf-network.yang
new file mode 100644
index 0000000..8e650da
--- /dev/null
+++ b/plugin/maven/src/test/resources/pathpredicate/interfileaugment/ietf-network.yang
@@ -0,0 +1,21 @@
+module ietf-network {
+    yang-version 1;
+    namespace "urn:ietf:params:xml:ns:yang:ietf-network";
+    prefix nd;
+    container networks {
+        list network {
+            key "network-id";
+            leaf network-id {
+                type uint8;
+            }
+            container reference {
+                leaf network-ref {
+                    type string;
+                }
+            }
+            leaf node-id {
+                type int8;
+            }
+        }
+    }
+}
diff --git a/plugin/maven/src/test/resources/pathpredicate/interfileaugment/ietf-topology.yang b/plugin/maven/src/test/resources/pathpredicate/interfileaugment/ietf-topology.yang
new file mode 100644
index 0000000..93bfa80
--- /dev/null
+++ b/plugin/maven/src/test/resources/pathpredicate/interfileaugment/ietf-topology.yang
@@ -0,0 +1,18 @@
+module ietf-topology {
+    yang-version 1;
+    namespace "urn:ietf:params:xml:ns:yang:ietf-te-topology";
+    // replace with IANA namespace when assigned
+    prefix "tet";
+
+    import ietf-network {
+        prefix "nw";
+    }
+    augment "/nw:networks/nw:network" {
+        leaf test {
+            type leafref {
+                path "../../nw:network[nw:network-id = current()/../" +
+                "nw:reference/nw:network-ref]/nw:node-id";
+            }
+        }
+    }
+}
diff --git a/plugin/maven/src/test/resources/pathpredicate/invalidlinking/ietf-network.yang b/plugin/maven/src/test/resources/pathpredicate/invalidlinking/ietf-network.yang
new file mode 100644
index 0000000..13bcb3e
--- /dev/null
+++ b/plugin/maven/src/test/resources/pathpredicate/invalidlinking/ietf-network.yang
@@ -0,0 +1,33 @@
+module ietf-network {
+    yang-version 1;
+    namespace "urn:ietf:params:xml:ns:yang:ietf-network";
+    prefix nd;
+    list interface {
+        key "name";
+        leaf name {
+            type string;
+        }
+        leaf admin-status {
+            type uint8;
+        }
+        list address {
+            key "ip";
+            leaf ip {
+                type int8;
+            }
+        }
+    }
+    container default-address {
+        leaf ifname {
+            type leafref {
+                path "../../interface/name";
+            }
+        }
+        leaf address {
+            type leafref {
+                path "../../interface[ifname = current()/../../ifname]"
+                    + "/address/ip";
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/plugin/maven/src/test/resources/pathpredicate/invalidlinking2/ietf-network.yang b/plugin/maven/src/test/resources/pathpredicate/invalidlinking2/ietf-network.yang
new file mode 100644
index 0000000..7c1881b
--- /dev/null
+++ b/plugin/maven/src/test/resources/pathpredicate/invalidlinking2/ietf-network.yang
@@ -0,0 +1,33 @@
+module ietf-network {
+    yang-version 1;
+    namespace "urn:ietf:params:xml:ns:yang:ietf-network";
+    prefix nd;
+    list interface {
+        key "name";
+        leaf name {
+            type string;
+        }
+        leaf admin-status {
+            type uint8;
+        }
+        list address {
+            key "ip";
+            leaf ip {
+                type int8;
+            }
+        }
+    }
+    container default-address {
+        leaf ifname {
+            type leafref {
+                path "../../interface/name";
+            }
+        }
+        leaf address {
+            type leafref {
+                path "../../default-address[ifname = current()/../ifname]/" +
+                "ifname";
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/plugin/maven/src/test/resources/pathpredicate/invalidlinking3/ietf-network.yang b/plugin/maven/src/test/resources/pathpredicate/invalidlinking3/ietf-network.yang
new file mode 100644
index 0000000..9ebb2ce
--- /dev/null
+++ b/plugin/maven/src/test/resources/pathpredicate/invalidlinking3/ietf-network.yang
@@ -0,0 +1,33 @@
+module ietf-network {
+    yang-version 1;
+    namespace "urn:ietf:params:xml:ns:yang:ietf-network";
+    prefix nd;
+    list interface {
+        key "name";
+        leaf name {
+            type string;
+        }
+        leaf admin-status {
+            type uint8;
+        }
+        list address {
+            key "ip";
+            leaf ip {
+                type int8;
+            }
+        }
+    }
+    container default-address {
+        leaf ifname {
+            type leafref {
+                path "../../interface/name";
+            }
+        }
+        leaf address {
+            type leafref {
+                path "../../interface[name = current()/../../address/ifname]"
+                    + "/address/ip";
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/plugin/maven/src/test/resources/pathpredicate/simple/ietf-network.yang b/plugin/maven/src/test/resources/pathpredicate/simple/ietf-network.yang
new file mode 100644
index 0000000..5c1ecdd
--- /dev/null
+++ b/plugin/maven/src/test/resources/pathpredicate/simple/ietf-network.yang
@@ -0,0 +1,33 @@
+module ietf-network {
+    yang-version 1;
+    namespace "urn:ietf:params:xml:ns:yang:ietf-network";
+    prefix nd;
+    list interface {
+        key "name";
+        leaf name {
+            type string;
+        }
+        leaf admin-status {
+            type uint8;
+        }
+        list address {
+            key "ip";
+            leaf ip {
+                type int8;
+            }
+        }
+    }
+    container default-address {
+        leaf ifname {
+            type leafref {
+                path "../../interface/name";
+            }
+        }
+        leaf address {
+            type leafref {
+                path "../../interface[name = current()/../ifname]"
+                    + "/address/ip";
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/plugin/maven/src/test/resources/pathpredicate/simpleinterfile/ietf-network.yang b/plugin/maven/src/test/resources/pathpredicate/simpleinterfile/ietf-network.yang
new file mode 100644
index 0000000..33d77dd
--- /dev/null
+++ b/plugin/maven/src/test/resources/pathpredicate/simpleinterfile/ietf-network.yang
@@ -0,0 +1,22 @@
+module ietf-network {
+    yang-version 1;
+    namespace "urn:ietf:params:xml:ns:yang:ietf-network";
+    prefix nd;
+    import ietf-topology {
+        prefix tp;
+    }
+    container default-address {
+        leaf ifname {
+            type leafref {
+                path "/tp:interface/tp:name";
+            }
+        }
+        leaf address {
+            type leafref {
+                path "/tp:interface[tp:name = current()/../nd:ifname]"
+                + "/tp:address/ip";
+            }
+        }
+    }
+}
+
diff --git a/plugin/maven/src/test/resources/pathpredicate/simpleinterfile/ietf-topology.yang b/plugin/maven/src/test/resources/pathpredicate/simpleinterfile/ietf-topology.yang
new file mode 100644
index 0000000..63db761
--- /dev/null
+++ b/plugin/maven/src/test/resources/pathpredicate/simpleinterfile/ietf-topology.yang
@@ -0,0 +1,21 @@
+   module ietf-topology {
+     yang-version 1;
+     namespace "urn:ietf:params:xml:ns:yang:ietf-topology";
+     prefix tp;
+     list interface {
+         key "name";
+         leaf name {
+             type string;
+         }
+         leaf admin-status {
+             type uint8;
+         }
+         list address {
+             key "ip";
+             leaf ip {
+                 type int8;
+             }
+         }
+     }
+   }
+