Merge "Fixed YANG model registry to remove the model during unregistration and to protect against NPE."
diff --git a/compiler/base/datamodel/src/test/java/org/onosproject/yang/compiler/datamodel/CheckValidationTest.java b/compiler/base/datamodel/src/test/java/org/onosproject/yang/compiler/datamodel/CheckValidationTest.java
new file mode 100644
index 0000000..1827aba
--- /dev/null
+++ b/compiler/base/datamodel/src/test/java/org/onosproject/yang/compiler/datamodel/CheckValidationTest.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2017-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.yang.compiler.datamodel;
+
+import org.onosproject.yang.compiler.datamodel.exceptions.DataModelException;
+import org.onosproject.yang.compiler.datamodel.utils.builtindatatype.DataTypeException;
+import org.onosproject.yang.compiler.datamodel.utils.builtindatatype.YangDataTypes;
+import org.onosproject.yang.compiler.datamodel.utils.builtindatatype.YangUint16;
+import org.onosproject.yang.compiler.datamodel.utils.builtindatatype.YangUint32;
+import org.onosproject.yang.compiler.datamodel.utils.builtindatatype.YangUint64;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import static org.junit.Assert.assertEquals;
+import static org.onosproject.yang.compiler.datamodel.utils.builtindatatype.YangInt8.MAX_VALUE;
+import static org.onosproject.yang.compiler.datamodel.utils.builtindatatype.YangInt8.MIN_VALUE;
+
+/**
+ * Utility class to check error messages.
+ */
+final class CheckValidationTest {
+    private static final String E_MESS = "Exception has not occurred for " +
+            "invalid value with type ";
+    private static boolean expOccurred;
+
+    private CheckValidationTest() {
+    }
+
+    /**
+     * Tests the value against the respective YANG node data type.
+     *
+     * @param node  associated with YANG node data type
+     * @param value associated with value of YANG node
+     */
+    static void dataValidation(YangType node, String value)
+            throws DataModelException {
+        YangDataTypes type = node.getDataType();
+        try {
+            node.isValidValue(value);
+        } catch (DataTypeException e) {
+            expOccurred = true;
+            assertEquals(e.getMessage(), getErrorString(value, type));
+        }
+        assertEquals(E_MESS + type, expOccurred, true);
+    }
+
+    /**
+     * Tests the range of the value against the respective YANG node data type.
+     *
+     * @param node  associated with YANG node data type
+     * @param value associated with value of YANG node
+     */
+    static void rangeCheck(YangType node, String value)
+            throws DataModelException {
+        YangDataTypes type = node.getDataType();
+        try {
+            node.isValidValue(value);
+        } catch (DataTypeException e) {
+            expOccurred = true;
+            assertEquals(e.getMessage(), getRangeError(value, type));
+        }
+        assertEquals(E_MESS + type, expOccurred, true);
+    }
+
+    /**
+     * Returns the error message for the corresponding range of value of the
+     * respective data type.
+     *
+     * @param value associated with value of YANG node
+     * @param type  of the YANG node
+     * @return the error message associated with the validation
+     */
+    private static String getRangeError(String value, YangDataTypes type) {
+        StringBuilder msg = new StringBuilder();
+        switch (type) {
+            case UINT8:
+                if (Integer.valueOf(value) < MIN_VALUE) {
+                    msg.append("YANG file error : ")
+                            .append(value)
+                            .append(" is lesser than minimum value ")
+                            .append(MIN_VALUE).append(".");
+                } else if (Integer.valueOf(value) > MAX_VALUE) {
+                    msg.append("YANG file error : ")
+                            .append(value)
+                            .append(" is greater than maximum value ")
+                            .append(MAX_VALUE).append(".");
+                }
+                break;
+            case UINT16:
+                if (Integer.valueOf(value) < YangUint16.MIN_VALUE) {
+                    msg.append("YANG file error : ")
+                            .append(value)
+                            .append(" is lesser than minimum value ")
+                            .append(YangUint16.MIN_VALUE).append(".");
+                } else if (Integer.valueOf(value) > YangUint16.MAX_VALUE) {
+                    msg.append("YANG file error : ")
+                            .append(value)
+                            .append(" is greater than maximum value ")
+                            .append(YangUint16.MAX_VALUE).append(".");
+                }
+                break;
+            case UINT32:
+                if (Long.parseLong(value) < YangUint32.MIN_VALUE) {
+                    msg.append("YANG file error : ")
+                            .append(value)
+                            .append(" is lesser than minimum value ")
+                            .append(YangUint32.MIN_VALUE).append(".");
+                } else if (Long.parseLong(value) > YangUint32.MAX_VALUE) {
+                    msg.append("YANG file error : ")
+                            .append(value)
+                            .append(" is greater than maximum value ")
+                            .append(YangUint32.MAX_VALUE).append(".");
+                }
+                break;
+            case UINT64:
+                BigInteger val = new BigInteger(value);
+                if (val.compareTo(YangUint64.MIN_VALUE) == -1) {
+                    msg.append("YANG file error : ")
+                            .append(value)
+                            .append(" is lesser than minimum value ")
+                            .append(YangUint64.MIN_VALUE).append(".");
+                } else if (val.compareTo(YangUint64.MAX_VALUE) == 1) {
+                    msg.append("YANG file error : ")
+                            .append(value)
+                            .append(" is greater than maximum value ")
+                            .append(YangUint64.MAX_VALUE).append(".");
+                }
+                break;
+            case DECIMAL64:
+                BigDecimal decVal = new BigDecimal(value);
+                BigDecimal min = new BigDecimal("-9.2233720368547763E+17");
+                BigDecimal max = new BigDecimal("9.2233720368547763E+17");
+
+                if (decVal.compareTo(min) == -1) {
+                    msg.append("YANG file error : ")
+                            .append(value)
+                            .append(" is less than minimum value ")
+                            .append(min).append(".");
+                } else if (decVal.compareTo(max) == 1) {
+                    msg.append("YANG file error : ")
+                            .append(value)
+                            .append(" is greater than maximum value ")
+                            .append(max).append(".");
+                }
+                break;
+            default:
+                return null;
+        }
+        return msg.toString();
+    }
+
+    /**
+     * Utility function to get the error string of the respective data type.
+     *
+     * @param value    is associated with value of the YANG node value
+     * @param dataType is associated with YANG data type
+     * @return the error string
+     */
+
+    private static String getErrorString(String value, YangDataTypes dataType) {
+        StringBuilder msg = new StringBuilder();
+        switch (dataType) {
+            case UINT8:
+            case UINT16:
+            case UINT32:
+            case UINT64:
+            case INT8:
+            case INT16:
+            case INT32:
+            case INT64:
+            case DECIMAL64:
+                msg.append("YANG file error : Input value ").append("\"")
+                        .append(value).append("\"")
+                        .append(" is not a valid ")
+                        .append(dataType.toString().toLowerCase())
+                        .append(".");
+                break;
+            case BITS:
+            case ENUMERATION:
+            case BINARY:
+            case STRING:
+            case BOOLEAN:
+                msg.append("YANG file error : Input value ").append("\"")
+                        .append(value).append("\"")
+                        .append(" is not a valid ").append(dataType);
+                break;
+            case EMPTY:
+                msg.append("YANG file error : Input value ").append("\"")
+                        .append(value).append("\"")
+                        .append(" is not allowed for a data type ")
+                        .append(dataType);
+                break;
+            default:
+                return null;
+        }
+        return msg.toString();
+    }
+}
\ No newline at end of file
diff --git a/compiler/base/datamodel/src/test/java/org/onosproject/yang/compiler/datamodel/DataValidator.java b/compiler/base/datamodel/src/test/java/org/onosproject/yang/compiler/datamodel/DataValidator.java
new file mode 100644
index 0000000..5d6ac49
--- /dev/null
+++ b/compiler/base/datamodel/src/test/java/org/onosproject/yang/compiler/datamodel/DataValidator.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2017-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.yang.compiler.datamodel;
+
+import org.junit.Test;
+import org.onosproject.yang.compiler.datamodel.exceptions.DataModelException;
+
+import static org.onosproject.yang.compiler.datamodel.CheckValidationTest.dataValidation;
+import static org.onosproject.yang.compiler.datamodel.CheckValidationTest.rangeCheck;
+import static org.onosproject.yang.compiler.datamodel.utils.builtindatatype.YangDataTypes.BINARY;
+import static org.onosproject.yang.compiler.datamodel.utils.builtindatatype.YangDataTypes.BITS;
+import static org.onosproject.yang.compiler.datamodel.utils.builtindatatype.YangDataTypes.BOOLEAN;
+import static org.onosproject.yang.compiler.datamodel.utils.builtindatatype.YangDataTypes.DECIMAL64;
+import static org.onosproject.yang.compiler.datamodel.utils.builtindatatype.YangDataTypes.EMPTY;
+import static org.onosproject.yang.compiler.datamodel.utils.builtindatatype.YangDataTypes.INT16;
+import static org.onosproject.yang.compiler.datamodel.utils.builtindatatype.YangDataTypes.INT32;
+import static org.onosproject.yang.compiler.datamodel.utils.builtindatatype.YangDataTypes.INT64;
+import static org.onosproject.yang.compiler.datamodel.utils.builtindatatype.YangDataTypes.INT8;
+import static org.onosproject.yang.compiler.datamodel.utils.builtindatatype.YangDataTypes.UINT16;
+import static org.onosproject.yang.compiler.datamodel.utils.builtindatatype.YangDataTypes.UINT32;
+import static org.onosproject.yang.compiler.datamodel.utils.builtindatatype.YangDataTypes.UINT64;
+import static org.onosproject.yang.compiler.datamodel.utils.builtindatatype.YangDataTypes.UINT8;
+
+/**
+ * Unit tests for data type validations.Creates and validates different data
+ * types against their data types covering different scenarios.
+ */
+public class DataValidator {
+
+    /*
+     * Creating nodes of type INT8 and testing the data validation.
+     */
+    @Test
+    public void negativeIntTest1() throws DataModelException {
+
+        YangType<?> newNode = new YangType<>();
+        newNode.setDataType(INT8);
+        dataValidation(newNode, "-129");
+        dataValidation(newNode, "128");
+        dataValidation(newNode, " ");
+    }
+
+    /*
+     * Creating nodes of type INT16 and testing the data validation.
+     */
+    @Test
+    public void negativeIntTest2() throws DataModelException {
+
+        YangType<?> newNode = new YangType<>();
+        newNode.setDataType(INT16);
+        dataValidation(newNode, "-32769");
+        dataValidation(newNode, "32768");
+        dataValidation(newNode, " ");
+    }
+
+    /*
+     * Creating nodes of type INT32 and testing the data validation.
+     */
+    @Test
+    public void negativeIntTest3() throws DataModelException {
+
+        YangType<?> newNode = new YangType<>();
+        newNode.setDataType(INT32);
+        dataValidation(newNode, "-2147483649");
+        dataValidation(newNode, "2147483648");
+        dataValidation(newNode, " ");
+    }
+
+    /**
+     * Creating nodes of type INT64 and testing the data validation.
+     */
+    @Test
+    public void negativeIntTest4() throws DataModelException {
+
+        YangType<?> newNode = new YangType<>();
+        newNode.setDataType(INT64);
+        dataValidation(newNode, "-9223372036854775809");
+        dataValidation(newNode, "9223372036854775808");
+        dataValidation(newNode, " ");
+    }
+
+    /**
+     * Creating nodes of type UINT8 and testing the data validation.
+     */
+    @Test
+    public void negativeUintTest1() throws DataModelException {
+
+        YangType<?> newNode = new YangType<>();
+        newNode.setDataType(UINT8);
+        rangeCheck(newNode, "-1");
+        rangeCheck(newNode, "256");
+        dataValidation(newNode, " ");
+    }
+
+    /**
+     * Creating nodes of type UINT16 and testing the data validation.
+     */
+    @Test
+    public void negativeUintTest2() throws DataModelException {
+
+        YangType<?> newNode = new YangType<>();
+        newNode.setDataType(UINT16);
+        rangeCheck(newNode, "-2");
+        rangeCheck(newNode, "65536");
+        dataValidation(newNode, " ");
+    }
+
+    /**
+     * Creating nodes of type UINT32 and testing the data validation.
+     */
+    @Test
+    public void negativeUintTest3() throws DataModelException {
+
+        YangType<?> newNode = new YangType<>();
+        newNode.setDataType(UINT32);
+        rangeCheck(newNode, "-3");
+        rangeCheck(newNode, "4294967298");
+        dataValidation(newNode, " ");
+    }
+
+    /**
+     * Creating nodes of type UINT64 and testing the data validation.
+     */
+    @Test
+    public void negativeUintTest4() throws DataModelException {
+
+        YangType<?> newNode = new YangType<>();
+        newNode.setDataType(UINT64);
+        rangeCheck(newNode, "-9223372036854775809");
+        rangeCheck(newNode, "18446744073709551616");
+        dataValidation(newNode, " ");
+    }
+
+    /**
+     * Creating nodes of type BOOLEAN and testing the data validation.
+     */
+    @Test
+    public void negativeBool() throws DataModelException {
+        YangType<?> newNode = new YangType<>();
+        newNode.setDataType(BOOLEAN);
+        dataValidation(newNode, " ");
+        dataValidation(newNode, "10");
+        dataValidation(newNode, "ABCD");
+    }
+
+    /**
+     * Creating nodes of type DECIMAL64 and testing the data validation.
+     */
+    @Test
+    public void negativeDec64() throws DataModelException {
+
+        YangType<YangDecimal64> newNode = new YangType<>();
+        newNode.setDataType(DECIMAL64);
+        YangDecimal64 decimal64Node = new YangDecimal64();
+        newNode.setDataTypeExtendedInfo(decimal64Node);
+        rangeCheck(newNode, "-932337203685477580.9");
+        rangeCheck(newNode, "932337203685477580.8");
+        dataValidation(newNode, " ");
+    }
+
+    /**
+     * Creating nodes of type BIT and testing the data validation.
+     */
+    @Test
+    public void negativeBits() throws DataModelException {
+
+        YangType<YangBits> newNode = new YangType<>();
+        newNode.setDataType(BITS);
+        YangBits bitNode = new YangBits();
+        newNode.setDataTypeExtendedInfo(bitNode);
+        dataValidation(newNode, " ");
+        dataValidation(newNode, "0");
+        dataValidation(newNode, "default");
+        dataValidation(newNode, "1");
+    }
+
+    /**
+     * Creating nodes of type EMPTY and testing the data validation.
+     */
+    @Test
+    public void negativeEmpty() throws DataModelException {
+
+        YangType<?> newNode = new YangType<>();
+        newNode.setDataType(EMPTY);
+        dataValidation(newNode, "0");
+        dataValidation(newNode, "ABCD");
+    }
+
+    /**
+     * Creating nodes of type BINARY and testing the data validation.
+     */
+    @Test
+    public void negativeBin() throws DataModelException {
+
+        YangType<?> newNode = new YangType<>();
+        newNode.setDataType(BINARY);
+        dataValidation(newNode, "  ");
+    }
+
+   /* TODO: need to verify .
+    @Test
+    public void negativeEnum() throws DataModelException {
+
+        YangType<YangEnumeration> newNode = new YangType<>();
+        newNode.setDataType(YangDataTypes.ENUMERATION);
+        YangEnum enum1 = new YangEnum();
+        enum1.setNamedValue("sample1");
+
+        YangEnum enum2 = new YangEnum();
+        enum2.setNamedValue("sample2");
+        enum2.setValue(20);
+
+        YangEnumeration YEnumeration = new YangEnumeration() {
+            @Override
+            public String getJavaPackage() {
+                return null;
+            }
+
+            @Override
+            public String getJavaClassNameOrBuiltInType() {
+                return null;
+            }
+
+            @Override
+            public String getJavaAttributeName() {
+                return null;
+            }
+        };
+        YEnumeration.addEnumInfo(enum1);
+        YEnumeration.addEnumInfo(enum2);
+        newNode.setDataTypeExtendedInfo(YEnumeration);
+        dataValidation(newNode," ");
+        dataValidation(newNode,"123");
+        dataValidation(newNode,"sample1");
+    }
+
+    @Test
+    public void negativeUnion() throws DataModelException {
+        YangType<?> newNode = new YangType<>();
+        newNode.setDataType(YangDataTypes.UNION);
+        List<YangType<?>> list = new LinkedList<>();
+        YangUnion union = new YangUnion() {
+            @Override
+            public String getJavaPackage() {
+                return null;
+            }
+
+            @Override
+            public String getJavaClassNameOrBuiltInType() {
+                return null;
+            }
+
+            @Override
+            public String getJavaAttributeName() {
+                return null;
+            }
+        };
+        YangUnion YUnion = union;
+        YangType<YangInt8> typeInt1 = new YangType<>();
+        YangType<YangDecimal64> typeInt2 = new YangType<>();
+        YUnion.addType(typeInt1);
+        YUnion.addType(typeInt2);
+        //  newNode.setDataTypeExtendedInfo(YUnion);
+        dataValidation(newNode,"INT8");
+    }
+    */
+}