Fixed decode of YANG presence container with YCH

Change-Id: I3bd323dcdc84771da310ebb19d1573f7cf5252ba
diff --git a/apps/yms/api/src/main/java/org/onosproject/yms/ydt/YdtBuilder.java b/apps/yms/api/src/main/java/org/onosproject/yms/ydt/YdtBuilder.java
index 2161366..b7ac2fd 100644
--- a/apps/yms/api/src/main/java/org/onosproject/yms/ydt/YdtBuilder.java
+++ b/apps/yms/api/src/main/java/org/onosproject/yms/ydt/YdtBuilder.java
@@ -199,6 +199,18 @@
             throws IllegalArgumentException;
 
     /**
+     * Adds a child node or leaf node based on schema.
+     *
+     * @param name      name of child/leaf to be added
+     * @param namespace namespace of child/leaf to be added, if it's null, parent's
+     *                  namespace will be applied to child
+     * @throws IllegalArgumentException when method has been passed an illegal
+     *                                  or inappropriate argument.
+     */
+    void addNode(String name, String namespace)
+            throws IllegalArgumentException;
+
+    /**
      * Adds an instance of a child list node, or adds a child leaf list with
      * multiple instance.
      * In case the name and namespace identifies the child list node, then
diff --git a/apps/yms/app/src/main/java/org/onosproject/yms/app/ych/defaultcodecs/xml/XmlCodecListener.java b/apps/yms/app/src/main/java/org/onosproject/yms/app/ych/defaultcodecs/xml/XmlCodecListener.java
index eefc60f..2cfef20 100644
--- a/apps/yms/app/src/main/java/org/onosproject/yms/app/ych/defaultcodecs/xml/XmlCodecListener.java
+++ b/apps/yms/app/src/main/java/org/onosproject/yms/app/ych/defaultcodecs/xml/XmlCodecListener.java
@@ -73,8 +73,8 @@
 
         /*
          * When new module has to be added, and if curnode has reference of
-         * previous module, then we need to traverse back to parent(logical root
-         * node).
+         * previous module, then we need to traverse back to parent(logical
+         * root node).
          */
         if (ydtExtBuilder.getRootNode() == ydtExtBuilder.getCurNode()
                 .getParent() && prevNodeNamespace != null &&
@@ -82,11 +82,15 @@
             ydtExtBuilder.traverseToParent();
         }
 
-        if (nodeType == OBJECT_NODE && element.content() == null || element
-                .content().isEmpty()) {
-            nodeType = TEXT_NODE;
-        }
-        if (nodeType == OBJECT_NODE) {
+        if (nodeType == OBJECT_NODE &&
+                (element.content() == null || element.content().isEmpty())) {
+            if (ydtExtBuilder != null) {
+                if (ydtExtBuilder.getCurNode() == ydtExtBuilder.getRootNode()) {
+                    ydtExtBuilder.addChild(null, nameSpace, opType);
+                }
+                ydtExtBuilder.addNode(element.getName(), nameSpace);
+            }
+        } else if (nodeType == OBJECT_NODE) {
             if (ydtExtBuilder != null) {
                 if (ydtExtBuilder.getCurNode() == ydtExtBuilder.getRootNode()) {
                     ydtExtBuilder.addChild(null, nameSpace, opType);
@@ -94,7 +98,6 @@
                 ydtExtBuilder.addChild(element.getName(), nameSpace, opType);
             }
         } else if (nodeType == TEXT_NODE) {
-
             if (ydtExtBuilder != null) {
                 if (ydtExtBuilder.getCurNode() == ydtExtBuilder.getRootNode()) {
                     ydtExtBuilder.addChild(null, nameSpace, opType);
diff --git a/apps/yms/app/src/main/java/org/onosproject/yms/app/ydt/RequestedCallType.java b/apps/yms/app/src/main/java/org/onosproject/yms/app/ydt/RequestedCallType.java
index 4c1a16c..cae9134 100644
--- a/apps/yms/app/src/main/java/org/onosproject/yms/app/ydt/RequestedCallType.java
+++ b/apps/yms/app/src/main/java/org/onosproject/yms/app/ydt/RequestedCallType.java
@@ -35,5 +35,9 @@
      * Requested Node is of type multi instance leaf/node.
      */
     MULTI_INSTANCE,
-}
 
+    /**
+     * Requested Node is of type container but is empty.
+     */
+    EMPTY_CONTAINER,
+}
diff --git a/apps/yms/app/src/main/java/org/onosproject/yms/app/ydt/YangRequestWorkBench.java b/apps/yms/app/src/main/java/org/onosproject/yms/app/ydt/YangRequestWorkBench.java
index e5e9f86..2164e5b 100644
--- a/apps/yms/app/src/main/java/org/onosproject/yms/app/ydt/YangRequestWorkBench.java
+++ b/apps/yms/app/src/main/java/org/onosproject/yms/app/ydt/YangRequestWorkBench.java
@@ -522,6 +522,14 @@
         addLeaf(name, namespace, null, valueSet, MULTI_INSTANCE_LEAF);
     }
 
+    @Override
+    public void addNode(String name, String namespace)
+            throws IllegalArgumentException {
+        addChild(name, namespace, RequestedCardinality.UNKNOWN,
+                null, RequestedCallType.EMPTY_CONTAINER);
+    }
+
+
     /**
      * Adds a last leaf with list of values/single value to YANG data tree.
      * This method is used by all protocols which knows the nature
diff --git a/apps/yms/app/src/main/java/org/onosproject/yms/app/ydt/YdtNodeFactory.java b/apps/yms/app/src/main/java/org/onosproject/yms/app/ydt/YdtNodeFactory.java
index aa84cea..7fe6f95 100644
--- a/apps/yms/app/src/main/java/org/onosproject/yms/app/ydt/YdtNodeFactory.java
+++ b/apps/yms/app/src/main/java/org/onosproject/yms/app/ydt/YdtNodeFactory.java
@@ -186,6 +186,19 @@
                         throw new YdtException(E_MULTI_INS);
                 }
 
+            case EMPTY_CONTAINER:
+                switch (nodeType) {
+
+                case YANG_SINGLE_INSTANCE_NODE:
+                    return new YdtSingleInstanceNode(node);
+
+                case YANG_SINGLE_INSTANCE_LEAF_NODE:
+                    return new YdtSingleInstanceLeafNode(node);
+
+                default:
+                    return null;
+            }
+
             default:
                 return null;
         }
diff --git a/apps/yms/ut/src/test/java/org/onosproject/yms/app/ych/DefaultYangCodecHandlerTest.java b/apps/yms/ut/src/test/java/org/onosproject/yms/app/ych/DefaultYangCodecHandlerTest.java
index 802d0bd..6aea83c 100644
--- a/apps/yms/ut/src/test/java/org/onosproject/yms/app/ych/DefaultYangCodecHandlerTest.java
+++ b/apps/yms/ut/src/test/java/org/onosproject/yms/app/ych/DefaultYangCodecHandlerTest.java
@@ -16,6 +16,23 @@
 
 package org.onosproject.yms.app.ych;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.onosproject.yms.ych.YangProtocolEncodingFormat.XML;
+import static org.onosproject.yms.ydt.YmsOperationType.QUERY_CONFIG_REQUEST;
+import static org.onosproject.yms.ydt.YmsOperationType.QUERY_REQUEST;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
 import org.junit.Test;
 import org.onosproject.yang.gen.v1.ych.combined.rev20160524.CombinedOpParam;
 import org.onosproject.yang.gen.v1.ych.combined.rev20160524.combined.AsNum;
@@ -45,10 +62,11 @@
 import org.onosproject.yang.gen.v1.ych.combined.rev20160524.combined.attributes.bgpparameters.optionalcapabilities.cparameters.DefaultAs4BytesCapability;
 import org.onosproject.yang.gen.v1.ych.empty.container.rev20160524.EmptyContainerOpParam;
 import org.onosproject.yang.gen.v1.ych.empty.container.rev20160524.emptycontainer.EmptyContainer;
+import org.onosproject.yang.gen.v1.ych.purchasing.supervisor.rev20160524.YchPurchasingsupervisor.OnosYangOpType;
 import org.onosproject.yang.gen.v1.ych.purchasing.supervisor.rev20160524.YchPurchasingsupervisorOpParam;
 import org.onosproject.yang.gen.v1.ych.purchasing.supervisor.rev20160524.ychpurchasingsupervisor.DefaultYchPurchasingSupervisor;
 import org.onosproject.yang.gen.v1.ych.purchasing.supervisor.rev20160524.ychpurchasingsupervisor.YchPurchasingSupervisor;
-import org.onosproject.yang.gen.v1.ych.purchasing.supervisor.rev20160524.YchPurchasingsupervisor.OnosYangOpType;
+import org.onosproject.yang.gen.v1.ych.purchasing.supervisor.rev20160524.ychpurchasingsupervisor.ychpurchasingsupervisor.DefaultYchIsManager;
 import org.onosproject.yang.gen.v1.ydt.customs.supervisor.rev20160524.CustomssupervisorOpParam;
 import org.onosproject.yang.gen.v1.ydt.material.supervisor.rev20160524.MaterialsupervisorOpParam;
 import org.onosproject.yang.gen.v1.ydt.material.supervisor.rev20160524.materialsupervisor.DefaultSupervisor;
@@ -61,21 +79,6 @@
 import org.onosproject.yms.app.ysr.TestYangSchemaNodeProvider;
 import org.onosproject.yms.ych.YangCompositeEncoding;
 
-import java.io.BufferedReader;
-import java.io.FileReader;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.onosproject.yms.ych.YangProtocolEncodingFormat.XML;
-import static org.onosproject.yms.ydt.YmsOperationType.QUERY_CONFIG_REQUEST;
-import static org.onosproject.yms.ydt.YmsOperationType.QUERY_REQUEST;
-
 /**
  * Unit test case for default codec handler.
  */
@@ -87,6 +90,7 @@
     private static final String EMPTY_CONTAINER = "EmptyContainerOpParam";
     private static final String LOGISTIC_MOD = "LogisticsManagerOpParam";
     private static final String MERCHA_MOD = "MerchandisersupervisorOpParam";
+    private static final String PURCH_MOD = "YchPurchasingsupervisorOpParam";
 
     /**
      * Returns the xml string for customssupervisor module.
@@ -101,6 +105,19 @@
     }
 
     /**
+     * Returns the xml string for purchasesupervisor with empty selection node.
+     *
+     * @return the xml string for purchasesupervisor with empty selection node
+     */
+    private static String purchaseXmlEmptySelectionNode() {
+        return "<filter xmlns=\"ydt.filter-type\" type=\"subtree\">" +
+                "<ych-purchasing-supervisor xmlns=\"ych.purchasing-supervisor\">" +
+                "<ych-purchasing-specialist/>" +
+                "</ych-purchasing-supervisor>" +
+                "</filter>";
+    }
+
+    /**
      * Returns the xml string for merchandisersupervisor module.
      *
      * @return the xml string for merchandisersupervisor module
@@ -242,11 +259,48 @@
                 "<ych-purchasing-specialist>purchasingSpecialist" +
                 "</ych-purchasing-specialist>" +
                 "<ych-purchasing-support>support</ych-purchasing-support>" +
+                "<ych-is-manager/>" +
                 "</ych-purchasing-supervisor>" +
                 "</config>";
     }
 
     /**
+     * Returns the xml string for ych-purchasingsupervisor module with BitSet options.
+     *
+     * @return the XML string for ych-purchasingsupervisor module
+     */
+    private static String purchaseXmlOptions(BitSet options) {
+        boolean isFirst = true;
+
+        StringBuffer sb = new StringBuffer();
+        sb.append("<config xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" ");
+        sb.append("xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">");
+        sb.append("<ych-purchasing-supervisor xmlns=\"ych.purchasing-supervisor\" " +
+                "nc:operation=\"create\">");
+        sb.append("<ych-purchasing-support>support</ych-purchasing-support>");
+        if (options == null || options.isEmpty()) {
+            sb.append("<ych-purchasing-options/>");
+        } else {
+            sb.append("<ych-purchasing-options>");
+            for (int i = 0; i < 4; i++) {
+                if (options.get(i)) {
+                    if (isFirst) {
+                        isFirst = false;
+                    } else {
+                        sb.append(' ');
+                    }
+                    sb.append("option" + i);
+                }
+            }
+            sb.append("</ych-purchasing-options>");
+        }
+        sb.append("</ych-purchasing-supervisor>");
+        sb.append("</config>");
+
+        return sb.toString();
+    }
+
+    /**
      * Returns the xml string for employeeid module.
      *
      * @return the xml string for employeeid module
@@ -815,6 +869,7 @@
                         .YchPurchasingSupervisorBuilder()
                         .ychPurchasingSpecialist("purchasingSpecialist")
                         .ychPurchasingSupport("support")
+                        .ychIsManager(DefaultYchIsManager.builder().build())
                         .yangYchPurchasingSupervisorOpType(OnosYangOpType.CREATE).build();
         Object object = YchPurchasingsupervisorOpParam.builder()
                 .ychPurchasingSupervisor(supervisor).build();
@@ -1420,4 +1475,130 @@
                                                                  XML, null);
         processMerchandiserObj(objectList);
     }
+
+    @Test
+    public void proceessCodecDecodeFunctionForPresenceContainer() {
+        testYangSchemaNodeProvider.processSchemaRegistry(null);
+        DefaultYangSchemaRegistry schemaRegistry =
+                testYangSchemaNodeProvider.getDefaultYangSchemaRegistry();
+
+        YangCodecRegistry.initializeDefaultCodec();
+        DefaultYangCodecHandler defaultYangCodecHandler =
+                new DefaultYangCodecHandler(schemaRegistry);
+
+        // Verify the received object list
+        List<Object> objectList = defaultYangCodecHandler.decode(purchaseXml(),
+                                                                 XML, null);
+        assertNotNull(objectList);
+        Iterator<Object> iterator = objectList.iterator();
+        while (iterator.hasNext()) {
+            Object object = iterator.next();
+            if (object.getClass().getSimpleName().equals(PURCH_MOD)) {
+                YchPurchasingsupervisorOpParam purchasingsupervisorOpParam =
+                        (YchPurchasingsupervisorOpParam) object;
+                assertEquals(AM_OBJ + "purchasing-specialist: leaf value", "purchasingSpecialist",
+                             purchasingsupervisorOpParam.ychPurchasingSupervisor().ychPurchasingSpecialist());
+                assertEquals(AM_OBJ + "purchasing-support: leaf value", "support",
+                        purchasingsupervisorOpParam.ychPurchasingSupervisor().ychPurchasingSupport());
+                assertNotNull(AM_OBJ + "purchasing-manager: leaf value",
+                        purchasingsupervisorOpParam.ychPurchasingSupervisor().ychIsManager());
+            } else {
+                assertEquals(AM_OBJ, PURCH_MOD, object.getClass().getSimpleName());
+            }
+        }
+    }
+
+    @Test
+    public void proceessCodecDecodeFunctionForSelectionNode() {
+        testYangSchemaNodeProvider.processSchemaRegistry(null);
+        DefaultYangSchemaRegistry schemaRegistry =
+                testYangSchemaNodeProvider.getDefaultYangSchemaRegistry();
+
+        YangCodecRegistry.initializeDefaultCodec();
+        DefaultYangCodecHandler defaultYangCodecHandler =
+                new DefaultYangCodecHandler(schemaRegistry);
+
+        // Verify the received object list
+        List<Object> objectList = defaultYangCodecHandler.decode(
+                purchaseXmlEmptySelectionNode(), XML, null);
+        assertNotNull(objectList);
+        Iterator<Object> iterator = objectList.iterator();
+        while (iterator.hasNext()) {
+            Object object = iterator.next();
+            if (object.getClass().getSimpleName().equals(PURCH_MOD)) {
+                YchPurchasingsupervisorOpParam purchasingsupervisorOpParam =
+                        (YchPurchasingsupervisorOpParam) object;
+                assertNull(AM_OBJ + "purchasing-specialist: leaf value not empty",
+                         purchasingsupervisorOpParam.
+                         ychPurchasingSupervisor().ychPurchasingSpecialist());
+            } else {
+                assertEquals(AM_OBJ, PURCH_MOD, object.getClass().getSimpleName());
+            }
+        }
+    }
+
+    @Test
+    public void proceessCodecDecodeFunctionForBitmaskContainer() {
+        testYangSchemaNodeProvider.processSchemaRegistry(null);
+        DefaultYangSchemaRegistry schemaRegistry =
+                testYangSchemaNodeProvider.getDefaultYangSchemaRegistry();
+
+        YangCodecRegistry.initializeDefaultCodec();
+        DefaultYangCodecHandler defaultYangCodecHandler =
+                new DefaultYangCodecHandler(schemaRegistry);
+
+        BitSet purchaseOptions = new BitSet(4);
+        purchaseOptions.set(1); //option1
+        purchaseOptions.set(3); //option3
+
+        // Verify the received object list
+        List<Object> objectList = defaultYangCodecHandler.decode(
+                purchaseXmlOptions(purchaseOptions), XML, null);
+        assertNotNull(objectList);
+        Iterator<Object> iterator = objectList.iterator();
+        while (iterator.hasNext()) {
+            Object object = iterator.next();
+            if (object.getClass().getSimpleName().equals(PURCH_MOD)) {
+                YchPurchasingsupervisorOpParam purchasingsupervisorOpParam =
+                        (YchPurchasingsupervisorOpParam) object;
+                assertEquals(AM_OBJ + "purchasing-support: leaf value", "support",
+                        purchasingsupervisorOpParam.ychPurchasingSupervisor().ychPurchasingSupport());
+                assertEquals(AM_OBJ + "ych-puchasing-options: leaf value",
+                        purchaseOptions,
+                        purchasingsupervisorOpParam.ychPurchasingSupervisor().ychPurchasingOptions());
+            } else {
+                assertEquals(AM_OBJ, PURCH_MOD, object.getClass().getSimpleName());
+            }
+        }
+    }
+
+    @Test
+    public void proceessCodecDecodeFunctionForEmptyBitmask() {
+        testYangSchemaNodeProvider.processSchemaRegistry(null);
+        DefaultYangSchemaRegistry schemaRegistry =
+                testYangSchemaNodeProvider.getDefaultYangSchemaRegistry();
+
+        YangCodecRegistry.initializeDefaultCodec();
+        DefaultYangCodecHandler defaultYangCodecHandler =
+                new DefaultYangCodecHandler(schemaRegistry);
+
+        // Verify the received object list
+        List<Object> objectList = defaultYangCodecHandler.decode(
+                purchaseXmlOptions(null), XML, null);
+        assertNotNull(objectList);
+        Iterator<Object> iterator = objectList.iterator();
+        while (iterator.hasNext()) {
+            Object object = iterator.next();
+            if (object.getClass().getSimpleName().equals(PURCH_MOD)) {
+                YchPurchasingsupervisorOpParam purchasingsupervisorOpParam =
+                        (YchPurchasingsupervisorOpParam) object;
+                assertEquals(AM_OBJ + "purchasing-support: leaf value", "support",
+                        purchasingsupervisorOpParam.ychPurchasingSupervisor().ychPurchasingSupport());
+                assertNull(AM_OBJ + "ych-puchasing-options: leaf value empty",
+                        purchasingsupervisorOpParam.ychPurchasingSupervisor().ychPurchasingOptions());
+            } else {
+                assertEquals(AM_OBJ, PURCH_MOD, object.getClass().getSimpleName());
+            }
+        }
+    }
 }
\ No newline at end of file
diff --git a/apps/yms/ut/src/test/java/org/onosproject/yms/app/ydt/FoodArenaTest.java b/apps/yms/ut/src/test/java/org/onosproject/yms/app/ydt/FoodArenaTest.java
index 9754192..9efbc77 100644
--- a/apps/yms/ut/src/test/java/org/onosproject/yms/app/ydt/FoodArenaTest.java
+++ b/apps/yms/ut/src/test/java/org/onosproject/yms/app/ydt/FoodArenaTest.java
@@ -70,7 +70,7 @@
         ydtBuilder = getYdtBuilder("foodarena", "food", "ydt.food", NONE);
         ydtBuilder.addChild("food", "ydt.food", DELETE);
         YdtAppContext appRootNode = ydtBuilder.getAppRootNode();
-        assertEquals(appRootNode.getFirstChild().getOperationType(), DELETE_ONLY);
+        assertEquals(DELETE_ONLY, appRootNode.getFirstChild().getOperationType());
     }
 
     /**
diff --git a/apps/yms/ut/src/test/resources/ychTestResourceFiles/purchasingsupervisor.yang b/apps/yms/ut/src/test/resources/ychTestResourceFiles/purchasingsupervisor.yang
index 507c64e..29123a8 100644
--- a/apps/yms/ut/src/test/resources/ychTestResourceFiles/purchasingsupervisor.yang
+++ b/apps/yms/ut/src/test/resources/ychTestResourceFiles/purchasingsupervisor.yang
@@ -24,5 +24,20 @@
             type string;
             description "name of the support person";
         }
+
+        leaf ych-purchasing-options {
+            type bits {
+                bit "option0";
+                bit "option1";
+                bit "option2";
+                bit "option3";
+            }
+            description
+            "A bit mask that may have 0, 1, many or all options present";
+        }
+
+        container ych-is-manager {
+            presence "If node is present denotes that supervisor is a manager";
+        }
     }
 }
\ No newline at end of file
diff --git a/protocols/restconf/server/utils/src/test/java/org/onosproject/protocol/restconf/server/utils/parser/api/TestYdtBuilder.java b/protocols/restconf/server/utils/src/test/java/org/onosproject/protocol/restconf/server/utils/parser/api/TestYdtBuilder.java
index 97c7fe3..03cddba 100644
--- a/protocols/restconf/server/utils/src/test/java/org/onosproject/protocol/restconf/server/utils/parser/api/TestYdtBuilder.java
+++ b/protocols/restconf/server/utils/src/test/java/org/onosproject/protocol/restconf/server/utils/parser/api/TestYdtBuilder.java
@@ -182,4 +182,9 @@
     public YdtContextOperationType getYdtDefaultOpType() {
         return ydtDefaultOpType;
     }
+
+    @Override
+    public void addNode(String name, String namespace) throws IllegalArgumentException {
+        addChild(name, namespace, SINGLE_INSTANCE_NODE, null);
+    }
 }