Merge "test for ModelObjectId & bugfix"
diff --git a/model/src/main/java/org/onosproject/yang/model/AtomicPath.java b/model/src/main/java/org/onosproject/yang/model/AtomicPath.java
index e6a0179..2baf83f 100644
--- a/model/src/main/java/org/onosproject/yang/model/AtomicPath.java
+++ b/model/src/main/java/org/onosproject/yang/model/AtomicPath.java
@@ -16,16 +16,13 @@
 
 package org.onosproject.yang.model;
 
-import java.util.Objects;
-
 import static com.google.common.base.MoreObjects.toStringHelper;
-import static java.util.Objects.hash;
 
 /**
  * Abstraction of an entity which identifies a generated class uniquely among
  * its siblings.
  */
-public class AtomicPath {
+public abstract class AtomicPath {
 
     private DataNode.Type type;
 
@@ -57,18 +54,10 @@
     }
 
     @Override
-    public int hashCode() {
-        return hash(type);
-    }
+    public abstract int hashCode();
 
     @Override
-    public boolean equals(Object obj) {
-        if (obj == null) {
-            return false;
-        }
-        AtomicPath that = (AtomicPath) obj;
-        return Objects.equals(type, that.type);
-    }
+    public abstract boolean equals(Object obj);
 
     @Override
     public String toString() {
diff --git a/model/src/main/java/org/onosproject/yang/model/ModelObjectId.java b/model/src/main/java/org/onosproject/yang/model/ModelObjectId.java
index c1048d9..451cc99 100644
--- a/model/src/main/java/org/onosproject/yang/model/ModelObjectId.java
+++ b/model/src/main/java/org/onosproject/yang/model/ModelObjectId.java
@@ -18,6 +18,7 @@
 
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Objects;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
 import static java.util.Objects.hash;
@@ -68,13 +69,14 @@
 
     @Override
     public boolean equals(Object obj) {
-        if (obj == null) {
-            return false;
+        if (obj == this) {
+            return true;
         }
-        ModelObjectId that = (ModelObjectId) obj;
-        List<AtomicPath> thatList = that.atomicPaths;
-        return atomicPaths.size() == thatList.size() &&
-                atomicPaths.containsAll(thatList);
+        if (obj instanceof ModelObjectId) {
+            ModelObjectId that = (ModelObjectId) obj;
+            return Objects.equals(this.atomicPaths, that.atomicPaths);
+        }
+        return false;
     }
 
     @Override
diff --git a/model/src/main/java/org/onosproject/yang/model/MultiInstanceLeaf.java b/model/src/main/java/org/onosproject/yang/model/MultiInstanceLeaf.java
index 56cf8dd..a11cf35 100644
--- a/model/src/main/java/org/onosproject/yang/model/MultiInstanceLeaf.java
+++ b/model/src/main/java/org/onosproject/yang/model/MultiInstanceLeaf.java
@@ -18,6 +18,10 @@
 
 import static org.onosproject.yang.model.DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE;
 
+import java.util.Objects;
+
+import com.google.common.base.MoreObjects;
+
 /**
  * Represents a leaf-list attribute in class.
  */
@@ -74,4 +78,31 @@
     public void value(Object v) {
         value = v;
     }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof MultiInstanceLeaf) {
+            MultiInstanceLeaf<?> that = (MultiInstanceLeaf<?>) obj;
+            // super.type is ensured to be equal
+            return Objects.equals(this.leafIdentifier, that.leafIdentifier) &&
+                   Objects.equals(this.value, that.value);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(type(), leafIdentifier, value);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("leafIdentifier", leafIdentifier)
+                .add("value", value)
+                .toString();
+    }
 }
diff --git a/model/src/main/java/org/onosproject/yang/model/MultiInstanceNode.java b/model/src/main/java/org/onosproject/yang/model/MultiInstanceNode.java
index 8bf66ac..b48b453 100644
--- a/model/src/main/java/org/onosproject/yang/model/MultiInstanceNode.java
+++ b/model/src/main/java/org/onosproject/yang/model/MultiInstanceNode.java
@@ -18,6 +18,10 @@
 
 import static org.onosproject.yang.model.DataNode.Type.MULTI_INSTANCE_NODE;
 
+import java.util.Objects;
+
+import com.google.common.base.MoreObjects;
+
 /**
  * Represents a multi instance object.
  */
@@ -74,4 +78,31 @@
     public void key(K k) {
         key = k;
     }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof MultiInstanceNode) {
+            MultiInstanceNode<?, ?> that = (MultiInstanceNode<?, ?>) obj;
+            // super.type is ensured to be equal
+            return Objects.equals(this.listClass, that.listClass) &&
+                   Objects.equals(this.key, that.key);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(type(), listClass, key);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("listClass", listClass)
+                .add("key", key)
+                .toString();
+    }
 }
diff --git a/model/src/main/java/org/onosproject/yang/model/SingleInstanceLeaf.java b/model/src/main/java/org/onosproject/yang/model/SingleInstanceLeaf.java
index a721845..6b3bc81 100644
--- a/model/src/main/java/org/onosproject/yang/model/SingleInstanceLeaf.java
+++ b/model/src/main/java/org/onosproject/yang/model/SingleInstanceLeaf.java
@@ -18,6 +18,10 @@
 
 import static org.onosproject.yang.model.DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE;
 
+import java.util.Objects;
+
+import com.google.common.base.MoreObjects;
+
 /**
  * Represents a leaf attribute in class.
  */
@@ -52,4 +56,29 @@
     public void leafIdentifier(E leaf) {
         this.leafIdentifier = leaf;
     }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof SingleInstanceLeaf) {
+            SingleInstanceLeaf<?> that = (SingleInstanceLeaf<?>) obj;
+            // super.type is ensured to be equal
+            return Objects.equals(this.leafIdentifier, that.leafIdentifier);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(type(), leafIdentifier);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("leafIdentifier", leafIdentifier)
+                .toString();
+    }
 }
diff --git a/model/src/main/java/org/onosproject/yang/model/SingleInstanceNode.java b/model/src/main/java/org/onosproject/yang/model/SingleInstanceNode.java
index fba0f63..83ebc60 100644
--- a/model/src/main/java/org/onosproject/yang/model/SingleInstanceNode.java
+++ b/model/src/main/java/org/onosproject/yang/model/SingleInstanceNode.java
@@ -18,6 +18,10 @@
 
 import static org.onosproject.yang.model.DataNode.Type.SINGLE_INSTANCE_NODE;
 
+import java.util.Objects;
+
+import com.google.common.base.MoreObjects;
+
 /**
  * Represents a single instance object.
  */
@@ -52,4 +56,29 @@
     public void container(Class<T> container) {
         containerClass = container;
     }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof SingleInstanceNode) {
+            SingleInstanceNode<?> that = (SingleInstanceNode<?>) obj;
+            // super.type is ensured to be equal
+            return Objects.equals(this.containerClass, that.containerClass);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(type(), containerClass);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("containerClass", containerClass)
+                .toString();
+    }
 }
diff --git a/model/src/test/java/org/onosproject/yang/model/ModelObjectIdTest.java b/model/src/test/java/org/onosproject/yang/model/ModelObjectIdTest.java
new file mode 100644
index 0000000..4c81f28
--- /dev/null
+++ b/model/src/test/java/org/onosproject/yang/model/ModelObjectIdTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.yang.model;
+
+import org.junit.Test;
+
+import com.google.common.testing.EqualsTester;
+
+public class ModelObjectIdTest {
+
+
+    @Test
+    public void testEquals() {
+        new EqualsTester()
+            .addEqualityGroup(ModelObjectId.builder().build())
+            .addEqualityGroup(ModelObjectId.builder()
+                              .addChild(TestInnerModelObject.class)
+                              .build())
+            .addEqualityGroup(ModelObjectId.builder()
+                              .addChild(TestInnerModelObject.class)
+                              .addChild(TestInnerModelObject.class)
+                              .build())
+            .addEqualityGroup(ModelObjectId.builder()
+                              .addChild(TestMultiInstanceObject.class, TestKeyInfo.KEY_A)
+                              .build())
+            .addEqualityGroup(ModelObjectId.builder()
+                              .addChild(TestMultiInstanceObject.class, TestKeyInfo.KEY_B)
+                              .build())
+            .addEqualityGroup(ModelObjectId.builder()
+                              .addChild(TestMultiInstanceObject.class, TestKeyInfo.KEY_A)
+                              .addChild(TestMultiInstanceObject.class, TestKeyInfo.KEY_B)
+                              .build())
+            .addEqualityGroup(ModelObjectId.builder()
+                              .addChild(TestLeafIdentifier.LEAF_A)
+                              .build())
+            .addEqualityGroup(ModelObjectId.builder()
+                              .addChild(TestLeafIdentifier.LEAF_B)
+                              .build())
+            .addEqualityGroup(ModelObjectId.builder()
+                              .addChild(TestLeafIdentifier.LEAF_A)
+                              .addChild(TestLeafIdentifier.LEAF_B)
+                              .build())
+            .addEqualityGroup(ModelObjectId.builder()
+                              .addChild(TestLeafIdentifier.LEAF_A, "A")
+                              .build())
+            .addEqualityGroup(ModelObjectId.builder()
+                              .addChild(TestLeafIdentifier.LEAF_A, "B")
+                              .build())
+            .testEquals();
+    }
+
+    static class TestInnerModelObject extends InnerModelObject {
+
+    }
+
+    static class TestMultiInstanceObject
+        extends InnerModelObject
+        implements MultiInstanceObject<TestKeyInfo> {
+
+    }
+
+    static enum TestKeyInfo implements KeyInfo<TestMultiInstanceObject> {
+        KEY_A,
+        KEY_B
+    }
+
+    static enum TestLeafIdentifier implements LeafIdentifier {
+        LEAF_A,
+        LEAF_B
+    }
+}