[ONOS-7042] Value validation as per defined datatype restriction and pattern
Change-Id: I479e515e74bf59178bc56a8c94de25d14af17933
diff --git a/compiler/base/datamodel/src/main/java/org/onosproject/yang/compiler/datamodel/YangType.java b/compiler/base/datamodel/src/main/java/org/onosproject/yang/compiler/datamodel/YangType.java
index 9d6b22e..b9dcc42 100644
--- a/compiler/base/datamodel/src/main/java/org/onosproject/yang/compiler/datamodel/YangType.java
+++ b/compiler/base/datamodel/src/main/java/org/onosproject/yang/compiler/datamodel/YangType.java
@@ -296,7 +296,7 @@
* @param value input data value
* @throws DataModelException a violation of data model rules
*/
- void isValidValue(String value)
+ public void isValidValue(String value)
throws DataModelException {
switch (getDataType()) {
case INT8:
@@ -384,7 +384,9 @@
break;
}
case EMPTY: {
- if (value.length() > 0) {
+ // In case of xml empty value can come as null but in case of
+ // json and all it will come as ""
+ if (value != null && value.length() > 0) {
throw new DataTypeException("YANG file error : Input value \"" + value
+ "\" is not allowed for a data type " + getDataType());
}
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