[ONOS-7042] Value validation as per defined datatype restriction and pattern

Change-Id: I479e515e74bf59178bc56a8c94de25d14af17933
diff --git a/runtime/src/main/java/org/onosproject/yang/runtime/SerializerHelper.java b/runtime/src/main/java/org/onosproject/yang/runtime/SerializerHelper.java
index 327308f..6c40db9 100644
--- a/runtime/src/main/java/org/onosproject/yang/runtime/SerializerHelper.java
+++ b/runtime/src/main/java/org/onosproject/yang/runtime/SerializerHelper.java
@@ -17,7 +17,9 @@
 package org.onosproject.yang.runtime;
 
 import org.onosproject.yang.compiler.datamodel.YangLeaf;
+import org.onosproject.yang.compiler.datamodel.YangLeafList;
 import org.onosproject.yang.compiler.datamodel.YangSchemaNode;
+import org.onosproject.yang.compiler.datamodel.exceptions.DataModelException;
 import org.onosproject.yang.model.DataNode;
 import org.onosproject.yang.model.InnerNode;
 import org.onosproject.yang.model.LeafNode;
@@ -323,14 +325,12 @@
                         if (((YangLeaf) childSchema).isKeyLeaf()) {
                             throw new IllegalArgumentException(E_RESID);
                         }
-                        valObject = ((LeafSchemaContext) childSchema)
-                                .fromString(value);
+                        valObject = getLeaf(value, childSchema);
                         builder = LeafNode.builder(name, namespace).type(nodeType)
                                 .value(valObject);
                         break;
                     case MULTI_INSTANCE_LEAF_VALUE_NODE:
-                        valObject = ((LeafSchemaContext) childSchema)
-                                .fromString(value);
+                        valObject = getLeafList(value, childSchema);
                         builder = LeafNode.builder(name, namespace).type(nodeType)
                                 .value(valObject);
                         builder = builder.addLeafListValue(valObject);
@@ -347,8 +347,7 @@
             } else {
                 switch (nodeType) {
                     case SINGLE_INSTANCE_LEAF_VALUE_NODE:
-                        valObject = ((LeafSchemaContext) childSchema)
-                                .fromString(value);
+                        valObject = getLeaf(value, childSchema);
                         if (((YangLeaf) childSchema).isKeyLeaf()) {
                             builder = builder.addKeyLeaf(
                                     name, namespace, valObject);
@@ -357,8 +356,7 @@
                                 name, namespace, valObject).type(nodeType);
                         break;
                     case MULTI_INSTANCE_LEAF_VALUE_NODE:
-                        valObject = ((LeafSchemaContext) childSchema)
-                                .fromString(value);
+                        valObject = getLeafList(value, childSchema);
                         builder = builder.createChildBuilder(
                                 name, namespace, valObject).type(nodeType);
                         builder = builder.addLeafListValue(valObject);
@@ -378,6 +376,47 @@
     }
 
     /**
+     * Returns the corresponding datatype value object for given leaf-list
+     * value.
+     *
+     * @param val value in string
+     * @param ctx schema context
+     * @return object of value
+     * @throws IllegalArgumentException a violation of data type rules
+     */
+    private static Object getLeafList(String val, SchemaContext ctx)
+            throws IllegalArgumentException {
+        LeafSchemaContext schema;
+        try {
+            schema = (LeafSchemaContext) ctx;
+            ((YangLeafList) schema).getDataType().isValidValue(val);
+        } catch (DataModelException e) {
+            throw new IllegalArgumentException(e.getMessage());
+        }
+        return schema.fromString(val);
+    }
+
+    /**
+     * Returns the corresponding datatype value object for given leaf value.
+     *
+     * @param val value in string
+     * @param ctx schema context
+     * @return object of value
+     * @throws IllegalArgumentException a violation of data type rules
+     */
+    private static Object getLeaf(String val, SchemaContext ctx)
+            throws IllegalArgumentException {
+        LeafSchemaContext schema;
+        try {
+            schema = (LeafSchemaContext) ctx;
+            ((YangLeaf) schema).getDataType().isValidValue(val);
+        } catch (DataModelException e) {
+            throw new IllegalArgumentException(e.getMessage());
+        }
+        return schema.fromString(val);
+    }
+
+    /**
      * Returns resource identifier for a given data node. This API will
      * be used by serializer to obtain the resource identifier in the
      * scenario when an annotation is associated with a given data node.
diff --git a/runtime/src/test/java/org/onosproject/yang/runtime/impl/YobAugmentTest.java b/runtime/src/test/java/org/onosproject/yang/runtime/impl/YobAugmentTest.java
index d1bf76a..689f87c 100644
--- a/runtime/src/test/java/org/onosproject/yang/runtime/impl/YobAugmentTest.java
+++ b/runtime/src/test/java/org/onosproject/yang/runtime/impl/YobAugmentTest.java
@@ -305,7 +305,7 @@
         InnerModelObject obj = it.next().getValue();
         AugmentedEventStream es = (AugmentedEventStream) obj;
         DateAndTime replay = es.replayStartTime();
-        assertThat(replay.toString(), is("2000-06-12T06:23:21"));
+        assertThat(replay.toString(), is("2000-06-12T06:23:21.52Z"));
     }
 
     private ResourceData buildDnForInputUsesAug() {
@@ -318,7 +318,7 @@
         value = "stream";
         dBlr = addDataNode(dBlr, "stream", SUB_NAME_SPACE, value, null);
         dBlr = exitDataNode(dBlr);
-        value = "2000-06-12T06:23:21";
+        value = "2000-06-12T06:23:21.52Z";
         dBlr = addDataNode(dBlr, "replay-start-time", SUB_NAME_SPACE,
                            value, null);
         dBlr = exitDataNode(dBlr);
diff --git a/runtime/src/test/java/org/onosproject/yang/runtime/impl/YobGroupingUsesTest.java b/runtime/src/test/java/org/onosproject/yang/runtime/impl/YobGroupingUsesTest.java
index cb25bf4..fd9303e 100644
--- a/runtime/src/test/java/org/onosproject/yang/runtime/impl/YobGroupingUsesTest.java
+++ b/runtime/src/test/java/org/onosproject/yang/runtime/impl/YobGroupingUsesTest.java
@@ -55,6 +55,18 @@
     private static final String TE_NS = "urn:ietf:params:xml:ns:yang:yrt-ietf-te-topology";
     private static final String TE = "urn:ietf:params:xml:ns:yang:ietf-te";
     private static final String RPC_NS = "yms:test:ytb:ytb:rpc";
+    private static final String DURATION_TIME =
+            "P9243983843671636195325300973389215743Y441498414397233640755" +
+                    "748678783585602855222287242483601612720MT42429291980" +
+                    "9198503801168838636847720848117391695063559947287623" +
+                    "02419062212H5803675020235950787S";
+    private static final String REPEAT_INTERVAL =
+            "R006733702120616055381223229783008865740416144969234/P988414" +
+                    "1350640084815248711164804331178923236350109520293255" +
+                    "5007727609859241946405817769469072177M30614037188965" +
+                    "5752702322778693919891230979781747844670759083567190" +
+                    "85127201004965309450WT393H91819305489488863421529096" +
+                    "58695920717372841701557104867M992396486515481883800S";
     TestYangSerializerContext context = new TestYangSerializerContext();
     private DataNode.Builder dBlr;
     private String value;
@@ -79,13 +91,13 @@
         dBlr = addDataNode(dBlr, "schedule-id", TE_NS, value, null);
         dBlr = exitDataNode(dBlr);
         value = "start";
-        dBlr = addDataNode(dBlr, "start", TE_NS, value, null);
+        String time = "2000-06-12T06:23:21.52Z";
+        dBlr = addDataNode(dBlr, "start", TE_NS, time, null);
         dBlr = exitDataNode(dBlr);
-        value = "schedule-duration";
-        dBlr = addDataNode(dBlr, "schedule-duration", TE_NS, value, null);
+        dBlr = addDataNode(dBlr, "schedule-duration", TE_NS, DURATION_TIME, null);
         dBlr = exitDataNode(dBlr);
         value = "repeat-interval";
-        dBlr = addDataNode(dBlr, "repeat-interval", TE_NS, value, null);
+        dBlr = addDataNode(dBlr, "repeat-interval", TE_NS, REPEAT_INTERVAL, null);
         dBlr = exitDataNode(dBlr);
         dBlr = exitDataNode(dBlr); // schedule
         dBlr = exitDataNode(dBlr); // schedules
@@ -113,9 +125,9 @@
         assertThat(linkTmp.name().toString(), is("name"));
         Schedule sh = linkTmp.teLinkAttributes().schedules().schedule().get(0);
         assertThat(sh.scheduleId(), is(100L));
-        assertThat(sh.start().toString(), is("start"));
-        assertThat(sh.scheduleDuration(), is("schedule-duration"));
-        assertThat(sh.repeatInterval(), is("repeat-interval"));
+        assertThat(sh.start().toString(), is("2000-06-12T06:23:21.52Z"));
+        assertThat(sh.scheduleDuration(), is(DURATION_TIME));
+        assertThat(sh.repeatInterval(), is(REPEAT_INTERVAL));
     }
 
     private DataNode buildDataNodeWithIdentityRef() {
diff --git a/runtime/src/test/java/org/onosproject/yang/runtime/impl/YobSimpleDataTypeTest.java b/runtime/src/test/java/org/onosproject/yang/runtime/impl/YobSimpleDataTypeTest.java
index 7eedef0..39ee323 100644
--- a/runtime/src/test/java/org/onosproject/yang/runtime/impl/YobSimpleDataTypeTest.java
+++ b/runtime/src/test/java/org/onosproject/yang/runtime/impl/YobSimpleDataTypeTest.java
@@ -91,11 +91,11 @@
         dBlr = addDataNode(dBlr, "lfnint64Max", DATA_TYPE_NAME_SPACE, value, null);
         dBlr = exitDataNode(dBlr);
 
-        value = "32767";
+        value = "255";
         dBlr = addDataNode(dBlr, "lfnuint8Max", DATA_TYPE_NAME_SPACE, value, null);
         dBlr = exitDataNode(dBlr);
 
-        value = "2147483647";
+        value = "65535";
         dBlr = addDataNode(dBlr, "lfnuint16Max", DATA_TYPE_NAME_SPACE, value, null);
         dBlr = exitDataNode(dBlr);
 
@@ -481,11 +481,11 @@
         dBlr = addDataNode(dBlr, "lfnint64Max", null, value, null);
         dBlr = exitDataNode(dBlr);
 
-        value = "32767";
+        value = "255";
         dBlr = addDataNode(dBlr, "lfnuint8Max", null, value, null);
         dBlr = exitDataNode(dBlr);
 
-        value = "2147483647";
+        value = "65535";
         dBlr = addDataNode(dBlr, "lfnuint16Max", null, value, null);
         dBlr = exitDataNode(dBlr);
 
@@ -653,9 +653,9 @@
         assertThat(cont.lfnint64Min(), is(10090L));
         assertThat(cont.lfnint64Max(), is(100700L));
 
-        val = 32767;
+        val = 255;
         assertThat(cont.lfnuint8Max(), is(val));
-        assertThat(cont.lfnuint16Max(), is(2147483647));
+        assertThat(cont.lfnuint16Max(), is(65535));
         assertThat(cont.lfnuint32Max(), is(10000L));
         assertThat(cont.lfuint64Max().toString(), is("32656256558"));
         assertThat(cont.lfstr(), is("string1"));
@@ -811,9 +811,9 @@
         assertThat(cont.lfnint64Min().get(0), is(10090L));
         assertThat(cont.lfnint64Max().get(0), is(100700L));
 
-        val = 32767;
+        val = 255;
         assertThat(cont.lfnuint8Max().get(0), is(val));
-        assertThat(cont.lfnuint16Max().get(0), is(2147483647));
+        assertThat(cont.lfnuint16Max().get(0), is(65535));
         assertThat(cont.lfnuint32Max().get(0), is(10000L));
         assertThat(cont.lfuint64Max().get(0).toString(), is("32656256558"));
         assertThat(cont.lfstr().get(0), is("string1"));
diff --git a/runtime/src/test/java/org/onosproject/yang/runtime/impl/serializerhelper/CheckEnumKeyValidationTest.java b/runtime/src/test/java/org/onosproject/yang/runtime/impl/serializerhelper/CheckEnumKeyValidationTest.java
new file mode 100644
index 0000000..9f85ff7
--- /dev/null
+++ b/runtime/src/test/java/org/onosproject/yang/runtime/impl/serializerhelper/CheckEnumKeyValidationTest.java
@@ -0,0 +1,112 @@
+package org.onosproject.yang.runtime.impl.serializerhelper;
+
+import org.junit.Test;
+import org.onosproject.yang.model.DataNode;
+import org.onosproject.yang.model.InnerNode;
+import org.onosproject.yang.model.KeyLeaf;
+import org.onosproject.yang.model.ListKey;
+import org.onosproject.yang.model.NodeKey;
+import org.onosproject.yang.model.ResourceId;
+import org.onosproject.yang.runtime.HelperContext;
+import org.onosproject.yang.runtime.impl.TestYangSerializerContext;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import static org.onosproject.yang.model.DataNode.Type.MULTI_INSTANCE_NODE;
+import static org.onosproject.yang.model.DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE;
+import static org.onosproject.yang.runtime.SerializerHelper.addDataNode;
+import static org.onosproject.yang.runtime.SerializerHelper.exitDataNode;
+import static org.onosproject.yang.runtime.SerializerHelper.getResourceId;
+import static org.onosproject.yang.runtime.SerializerHelper.initializeDataNode;
+import static org.onosproject.yang.runtime.impl.TestUtils.validateDataNode;
+import static org.onosproject.yang.runtime.impl.TestUtils.validateLeafDataNode;
+import static org.onosproject.yang.runtime.impl.TestUtils.validateResourceId;
+import static org.onosproject.yang.runtime.impl.TestUtils.walkINTree;
+
+/**
+ * Tests the serializer helper data validation.
+ */
+public class CheckEnumKeyValidationTest {
+
+    public static final String LNS = "ydt.enumListKeyTest";
+    TestYangSerializerContext context = new TestYangSerializerContext();
+    /*
+     * Reference for data node info.
+     */
+    HelperContext info;
+
+    /*
+     * Reference for data node builder.
+     */
+    DataNode.Builder dBlr;
+
+    /*
+     * Reference for resource id.
+     */
+    ResourceId id;
+
+    /*
+     * Reference for the value.
+     */
+    String value;
+
+    /*
+     * Reference for string array to used for resource id testing.
+     */
+    String[] nA;
+    String[] nsA;
+    String[] valA;
+
+    private static final String[] EXPECTED = {
+            "Entry Node is /.",
+            "Entry Node is enumList.",
+            "Entry Node is enumleaf.",
+            "Exit Node is enumleaf.",
+            "Entry Node is enumleaf1.",
+            "Exit Node is enumleaf1.",
+            "Exit Node is enumList.",
+            "Exit Node is /."
+    };
+
+    @Test
+    public void addDataNodeToBuilder() {
+        dBlr = initializeDataNode(context);
+        dBlr = addDataNode(dBlr, "enumList", LNS, value, null);
+        value = "ten";
+        dBlr = addDataNode(dBlr, "enumleaf", LNS, value, null);
+        value = "hundred";
+        dBlr = exitDataNode(dBlr);
+        dBlr = addDataNode(dBlr, "enumleaf1", null, value, null);
+
+        // resource ID validation
+        id = getResourceId(dBlr);
+        nA = new String[]{"/", "enumList", "enumleaf", "enumleaf1"};
+        nsA = new String[]{null, LNS, LNS, LNS};
+        valA = new String[]{"ten", "hundred"};
+        validateResourceId(nA, nsA, valA, id);
+
+        dBlr = dBlr.exitNode();
+        dBlr = dBlr.exitNode();
+
+        // Validating the data node.
+        DataNode node = dBlr.build();
+        node = ((InnerNode) node).childNodes().entrySet().iterator().next()
+                .getValue();
+
+        validateDataNode(node, "enumList", LNS, MULTI_INSTANCE_NODE,
+                         true, null);
+        Iterator<KeyLeaf> keyIt = ((ListKey) node.key())
+                .keyLeafs().iterator();
+
+        validateLeafDataNode(keyIt.next(), "enumleaf", LNS, "ten");
+        Iterator<Map.Entry<NodeKey, DataNode>> it;
+        it = ((InnerNode) node).childNodes().entrySet().iterator();
+
+        validateDataNode(it.next().getValue(), "enumleaf", LNS,
+                         SINGLE_INSTANCE_LEAF_VALUE_NODE, true, "ten");
+        validateDataNode(it.next().getValue(), "enumleaf1", LNS,
+                         SINGLE_INSTANCE_LEAF_VALUE_NODE, true, "hundred");
+        walkINTree(dBlr.build(), EXPECTED);
+    }
+}
diff --git a/runtime/src/test/java/org/onosproject/yang/runtime/impl/serializerhelper/CheckEnumValidationTest.java b/runtime/src/test/java/org/onosproject/yang/runtime/impl/serializerhelper/CheckEnumValidationTest.java
new file mode 100644
index 0000000..0870025
--- /dev/null
+++ b/runtime/src/test/java/org/onosproject/yang/runtime/impl/serializerhelper/CheckEnumValidationTest.java
@@ -0,0 +1,94 @@
+package org.onosproject.yang.runtime.impl.serializerhelper;
+
+import org.junit.Test;
+import org.onosproject.yang.model.DataNode;
+import org.onosproject.yang.model.InnerNode;
+import org.onosproject.yang.model.ResourceId;
+import org.onosproject.yang.runtime.HelperContext;
+import org.onosproject.yang.runtime.impl.TestYangSerializerContext;
+
+import static org.onosproject.yang.model.DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE;
+import static org.onosproject.yang.model.DataNode.Type.SINGLE_INSTANCE_NODE;
+import static org.onosproject.yang.runtime.SerializerHelper.addDataNode;
+import static org.onosproject.yang.runtime.SerializerHelper.getResourceId;
+import static org.onosproject.yang.runtime.SerializerHelper.initializeDataNode;
+import static org.onosproject.yang.runtime.impl.TestUtils.validateDataNode;
+import static org.onosproject.yang.runtime.impl.TestUtils.validateResourceId;
+import static org.onosproject.yang.runtime.impl.TestUtils.walkINTree;
+
+/**
+ * Tests the serializer helper data validation.
+ */
+public class CheckEnumValidationTest {
+
+    public static final String LNS = "ydt.enumtest";
+    TestYangSerializerContext context = new TestYangSerializerContext();
+    /*
+     * Reference for data node info.
+     */
+    HelperContext info;
+
+    /*
+     * Reference for data node builder.
+     */
+    DataNode.Builder dBlr;
+
+    /*
+     * Reference for resource id.
+     */
+    ResourceId id;
+
+    /*
+     * Reference for the value.
+     */
+    String value;
+
+    /*
+ * Reference for string array to used for resource id testing.
+ */
+    String[] nA;
+    String[] nsA;
+    String[] valA;
+
+    private static final String[] EXPECTED = {
+            "Entry Node is /.",
+            "Entry Node is enumList.",
+            "Entry Node is enumleaf.",
+            "Exit Node is enumleaf.",
+            "Exit Node is enumList.",
+            "Exit Node is /."
+    };
+
+    @Test
+    public void addDataNodeToBuilder() {
+        dBlr = initializeDataNode(context);
+        dBlr = addDataNode(dBlr, "enumList", LNS, value, null);
+        value = "ten";
+        dBlr = addDataNode(dBlr, "enumleaf", LNS, value, null);
+
+        // resource ID validation
+        id = getResourceId(dBlr);
+        nA = new String[]{"/", "enumList", "enumleaf"};
+        nsA = new String[]{null, LNS, LNS};
+        valA = new String[]{"ten"};
+        validateResourceId(nA, nsA, valA, id);
+
+        dBlr = dBlr.exitNode();
+        dBlr = dBlr.exitNode();
+
+        // Validating the data node.
+        DataNode node = dBlr.build();
+        node = ((InnerNode) node).childNodes().entrySet().iterator().next()
+                .getValue();
+
+        validateDataNode(node, "enumList", LNS, SINGLE_INSTANCE_NODE,
+                         true, null);
+
+        node = ((InnerNode) node).childNodes().entrySet().iterator().next()
+                .getValue();
+
+        validateDataNode(node, "enumleaf", LNS,
+                         SINGLE_INSTANCE_LEAF_VALUE_NODE, true, "ten");
+        walkINTree(dBlr.build(), EXPECTED);
+    }
+}
diff --git a/runtime/src/test/resources/dataTypeValidation.yang b/runtime/src/test/resources/dataTypeValidation.yang
new file mode 100644
index 0000000..8ff874b
--- /dev/null
+++ b/runtime/src/test/resources/dataTypeValidation.yang
@@ -0,0 +1,22 @@
+module dataTypes {
+
+    yang-version 1;
+
+    namespace "ydt.dataTypes";
+
+    prefix "datatypes";
+
+    organization "ON-LAB";
+
+    description "This module defines all data types.";
+
+    revision "2016-05-24" {
+        description "Initial revision.";
+    }
+
+    container datatype{
+        leaf integer {
+            type int8;
+        }
+    }
+}
\ No newline at end of file
diff --git a/runtime/src/test/resources/enumListKeyTest.yang b/runtime/src/test/resources/enumListKeyTest.yang
new file mode 100644
index 0000000..e03964a
--- /dev/null
+++ b/runtime/src/test/resources/enumListKeyTest.yang
@@ -0,0 +1,34 @@
+module enumListKeyTest {
+
+    yang-version 1;
+
+    namespace "ydt.enumListKeyTest";
+
+    prefix "enumListKeyTest";
+
+    organization "ON-LAB";
+
+    description "This module defines for enumListKeyTest classifier.";
+
+    revision "2016-05-24" {
+        description "Initial revision.";
+    }
+
+    list enumList {
+        key enumleaf;
+            leaf enumleaf {
+                type enumeration {
+                  enum ten { value "10";}
+                  enum hundred { value "100";}
+                  enum thousand { value "1000"; }
+                }
+            }
+            leaf enumleaf1 {
+                type enumeration {
+                  enum ten { value "10";}
+                  enum hundred { value "100";}
+                  enum thousand { value "1000"; }
+                }
+            }
+    }
+}
\ No newline at end of file
diff --git a/runtime/src/test/resources/enumTest.yang b/runtime/src/test/resources/enumTest.yang
new file mode 100644
index 0000000..904691b
--- /dev/null
+++ b/runtime/src/test/resources/enumTest.yang
@@ -0,0 +1,26 @@
+module enumtest {
+
+    yang-version 1;
+
+    namespace "ydt.enumtest";
+
+    prefix "enumtest";
+
+    organization "ON-LAB";
+
+    description "This module defines for enumtest classifier.";
+
+    revision "2016-05-24" {
+        description "Initial revision.";
+    }
+
+    container enumList {
+        leaf enumleaf {
+            type enumeration {
+              enum ten { value "10";}
+              enum hundred { value "100";}
+              enum thousand { value "1000"; }
+            }
+        }
+    }
+}
\ No newline at end of file