Add collection payload to include each resource information separately 70/61070/2 accepted/tizen/common/20160316.160042 accepted/tizen/ivi/20160314.104637 accepted/tizen/mobile/20160314.104545 accepted/tizen/tv/20160314.104604 accepted/tizen/wearable/20160314.104619 submit/tizen/20160314.020248
authorHabib Virji <habib.virji@samsung.com>
Tue, 23 Feb 2016 00:45:29 +0000 (00:45 +0000)
committeryoungman <yman.jung@samsung.com>
Sun, 6 Mar 2016 23:46:36 +0000 (08:46 +0900)
Change-Id: I0692018c13d295d6a28d289819835c525dc08cf5

- Each resource information is stored separately.
[{"href":"", "rt": "", "if":"", <property>}, .. ]
- Compared to previous approach where all resource where stored together.
- It fixes issue related to checking map before finding value, duplicated information in the payload of rt and if.
- Adds unit test when empty array is passed as a parameter.
- Adds unit test for checking values not containing rt and itf.

Jira-Issue: 923, 950, 962
Change-Id: I0692018c13d295d6a28d289819835c525dc08cf5
Signed-off-by: Habib Virji <habib.virji@samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/5121
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: Jihun Ha <jihun.ha@samsung.com>
Reviewed-by: Jon A. Cruz <jonc@osg.samsung.com>
Reviewed-by: Mushfiqul Islam <i.mushfiq@samsung.com>
Signed-off-by: youngman <yman.jung@samsung.com>
resource/csdk/stack/src/ocpayloadconvert.c
resource/csdk/stack/src/ocpayloadparse.c
resource/unittests/OCRepresentationEncodingTest.cpp

index 85a36ce..a2035cf 100644 (file)
@@ -704,51 +704,76 @@ static int64_t OCConvertRepPayload(OCRepPayload* payload, uint8_t* outPayload, s
     int64_t err = 0;
 
     cbor_encoder_init(&encoder, outPayload, *size, 0);
-    CborEncoder rootMap;
-    err = err | cbor_encoder_create_map(&encoder, &rootMap, CborIndefiniteLength);
+    CborEncoder rootMap ;
 
-    if (payload->types)
+    size_t arrayCount = 0;
+    for (OCRepPayload *temp = payload; temp; temp = temp->next)
     {
-        OC_LOG(INFO, TAG, "Payload has types or interfaces");
-        char* joinedTypes = OCStringLLJoin(payload->types);
-        if (joinedTypes)
-        {
-            err = err | cbor_encode_text_string(&rootMap, OC_RSRVD_RESOURCE_TYPE,
-                    sizeof(OC_RSRVD_RESOURCE_TYPE) - 1);
-            err = err | cbor_encode_text_string(&rootMap, joinedTypes,
-                    strlen(joinedTypes));
-            OICFree(joinedTypes);
-        }
-        else
-        {
-            return OC_STACK_NO_MEMORY;
-        }
+        arrayCount++;
+    }
+    CborEncoder rootArray;
+    if (arrayCount > 1)
+    {
+        err = err | cbor_encoder_create_array(&encoder, &rootArray, arrayCount);
     }
-    if (payload->interfaces)
+
+    while (payload != NULL && (err == CborNoError))
     {
-        char* joinedInterfaces = OCStringLLJoin(payload->interfaces);
-        if (joinedInterfaces)
+        err = err | cbor_encoder_create_map(((arrayCount == 1)? &encoder: &rootArray),
+                                            &rootMap, CborIndefiniteLength);
+        // Only in case of collection href is included.
+        if (arrayCount > 1 && payload->uri && strlen(payload->uri) > 0)
         {
-            err = err | cbor_encode_text_string(&rootMap, OC_RSRVD_INTERFACE,
-                    sizeof(OC_RSRVD_INTERFACE) - 1);
-            err = err | cbor_encode_text_string(&rootMap, joinedInterfaces,
-                    strlen(joinedInterfaces));
-            OICFree(joinedInterfaces);
+            OC_LOG(INFO, TAG, "Payload has uri");
+            err = err | cbor_encode_text_string(&rootMap, OC_RSRVD_HREF,
+                    strlen(OC_RSRVD_HREF));
+            err = err | cbor_encode_text_string(&rootMap, payload->uri,
+                    strlen(payload->uri));
         }
-        else
+        if (payload->types)
         {
-            return OC_STACK_NO_MEMORY;
+            OC_LOG(INFO, TAG, "Payload has types");
+            char* joinedTypes = OCStringLLJoin(payload->types);
+            if (joinedTypes)
+            {
+                err = err | cbor_encode_text_string(&rootMap, OC_RSRVD_RESOURCE_TYPE,
+                        strlen(OC_RSRVD_RESOURCE_TYPE));
+                err = err | cbor_encode_text_string(&rootMap, joinedTypes,
+                        strlen(joinedTypes));
+                OICFree(joinedTypes);
+            }
+            else
+            {
+                return OC_STACK_NO_MEMORY;
+            }
+        }
+        if (payload->interfaces)
+        {
+            OC_LOG(INFO, TAG, "Payload has interfaces");
+            char* joinedInterfaces = OCStringLLJoin(payload->interfaces);
+            if (joinedInterfaces)
+            {
+                err = err | cbor_encode_text_string(&rootMap, OC_RSRVD_INTERFACE,
+                        strlen(OC_RSRVD_INTERFACE));
+                err = err | cbor_encode_text_string(&rootMap, joinedInterfaces,
+                        strlen(joinedInterfaces));
+                OICFree(joinedInterfaces);
+            }
+            else
+            {
+                return OC_STACK_NO_MEMORY;
+            }
         }
-    }
 
-    while(payload != NULL && (err == 0 || err == CborErrorOutOfMemory))
-    {
         err = err | OCConvertSingleRepPayload(&rootMap, payload);
+        err = err | cbor_encoder_close_container(((arrayCount == 1) ? &encoder: &rootArray),
+                                                &rootMap);
         payload = payload->next;
     }
-
-    // Close main array
-    err = err | cbor_encoder_close_container(&encoder, &rootMap);
+    if (arrayCount > 1)
+    {
+        err = err | cbor_encoder_close_container(&encoder, &rootArray);
+    }
 
     return checkError(err, &encoder, outPayload, size);
 }
index c045e14..1851d45 100644 (file)
@@ -961,18 +961,29 @@ static bool OCParseSingleRepPayload(OCRepPayload** outPayload, CborValue *objMap
         }
 
         OCRepPayload* curPayload = *outPayload;
-
-        size_t len;
-        CborValue repMap;
+        size_t len = 0;
+        CborValue repMap = *objMap;
         err = err || cbor_value_enter_container(objMap, &repMap);
-
-        while(!err && cbor_value_is_valid(&repMap))
+        while (!err && cbor_value_is_valid(&repMap))
         {
-            char* name;
-            err = err || cbor_value_dup_text_string(&repMap, &name, &len, NULL);
-            err = err || cbor_value_advance(&repMap);
+            char *name = NULL;
+            if (cbor_value_is_text_string(&repMap))
+            {
+                err = err || cbor_value_dup_text_string(&repMap, &name, &len, NULL);
+                err = err || cbor_value_advance(&repMap);
+                if (name &&
+                    ((0 == strcmp(OC_RSRVD_HREF, name)) ||
+                     (0 == strcmp(OC_RSRVD_RESOURCE_TYPE, name)) ||
+                    (0 == strcmp(OC_RSRVD_INTERFACE, name))))
+                {
+                    err = err || cbor_value_advance(&repMap);
+                    OICFree(name);
+                    continue;
+                }
 
+            }
             CborType type = cbor_value_get_type(&repMap);
+
             switch(type)
             {
                 case CborNullType:
@@ -1053,10 +1064,11 @@ static bool OCParseSingleRepPayload(OCRepPayload** outPayload, CborValue *objMap
             }
             OICFree(name);
         }
-
-        err = err || cbor_value_leave_container(objMap, &repMap);
-
-        if(err)
+        if (cbor_value_is_container(objMap))
+        {
+            err = err || cbor_value_leave_container(objMap, &repMap);
+        }
+        if (err)
         {
             OCRepPayloadDestroy(*outPayload);
             *outPayload = NULL;
@@ -1066,7 +1078,7 @@ static bool OCParseSingleRepPayload(OCRepPayload** outPayload, CborValue *objMap
     return err;
 }
 
-static OCStackResult OCParseRepPayload(OCPayload** outPayload, CborValue* rootMap)
+static OCStackResult OCParseRepPayload(OCPayload** outPayload, CborValue* root)
 {
     if (!outPayload)
     {
@@ -1075,64 +1087,83 @@ static OCStackResult OCParseRepPayload(OCPayload** outPayload, CborValue* rootMa
 
     OCRepPayload *rootPayload = NULL;
     OCRepPayload *curPayload = NULL;
-    OCRepPayload *temp = OCRepPayloadCreate();
-    if (!temp)
-    {
-        return OC_STACK_NO_MEMORY;
-    }
 
     CborValue curVal;
     bool err = false;
-    size_t len;
-    err = err || cbor_value_map_find_value(rootMap, OC_RSRVD_RESOURCE_TYPE, &curVal);
-    if(cbor_value_is_text_string(&curVal))
+    size_t len = 0;
+    CborValue rootMap = *root;
+    if (cbor_value_is_array(root))
+    {
+        cbor_value_enter_container(root, &rootMap);
+    }
+    while (!err && cbor_value_is_valid(&rootMap))
     {
-        char* allRt = NULL;
-        err = err || cbor_value_dup_text_string(&curVal, &allRt, &len, NULL);
-        if (allRt)
+        OCRepPayload *temp = OCRepPayloadCreate();
+        if (!temp)
         {
-            char* savePtr;
-            char* curPtr = strtok_r(allRt, " ", &savePtr);
-            while (curPtr)
+            return OC_STACK_NO_MEMORY;
+        }
+        if (!err && cbor_value_is_map(&rootMap))
+        {
+            err = err || cbor_value_map_find_value(&rootMap, OC_RSRVD_HREF, &curVal);
+            if (cbor_value_is_valid(&curVal))
             {
-                char* trimmed = InPlaceStringTrim(curPtr);
-                if (trimmed[0] != '\0')
+                err = err || cbor_value_dup_text_string(&curVal, &temp->uri, &len, NULL);
+            }
+        }
+        if (!err && cbor_value_is_map(&rootMap))
+        {
+            err = err || cbor_value_map_find_value(&rootMap, OC_RSRVD_RESOURCE_TYPE, &curVal);
+            if(cbor_value_is_text_string(&curVal))
+            {
+                char* allRt = NULL;
+                err = err || cbor_value_dup_text_string(&curVal, &allRt, &len, NULL);
+                if (allRt)
                 {
-                    OCRepPayloadAddResourceType(temp, curPtr);
+                    char* savePtr;
+                    char* curPtr = strtok_r(allRt, " ", &savePtr);
+                    while (curPtr)
+                    {
+                        char* trimmed = InPlaceStringTrim(curPtr);
+                        if (trimmed[0] != '\0')
+                        {
+                            OCRepPayloadAddResourceType(temp, curPtr);
+                        }
+                        curPtr = strtok_r(NULL, " ", &savePtr);
+                    }
                 }
-                curPtr = strtok_r(NULL, " ", &savePtr);
+                OICFree(allRt);
             }
         }
-        OICFree(allRt);
-    }
-
-    err = err || cbor_value_map_find_value(rootMap, OC_RSRVD_INTERFACE, &curVal);
-    if(cbor_value_is_text_string(&curVal))
-    {
-        char* allIf = NULL;
-        err = err || cbor_value_dup_text_string(&curVal, &allIf, &len, NULL);
-        if (allIf)
+        if (!err && cbor_value_is_map(&rootMap))
         {
-            char* savePtr;
-            char* curPtr = strtok_r(allIf, " ", &savePtr);
-            while (curPtr)
+            err = err || cbor_value_map_find_value(&rootMap, OC_RSRVD_INTERFACE, &curVal);
+            if(cbor_value_is_text_string(&curVal))
             {
-                char* trimmed = InPlaceStringTrim(curPtr);
-                if (trimmed[0] != '\0')
+                char* allIf = NULL;
+                err = err || cbor_value_dup_text_string(&curVal, &allIf, &len, NULL);
+                if (allIf)
                 {
-                    OCRepPayloadAddInterface(temp, curPtr);
+                    char* savePtr;
+                    char* curPtr = strtok_r(allIf, " ", &savePtr);
+                    while (curPtr)
+                    {
+                        char* trimmed = InPlaceStringTrim(curPtr);
+                        if (trimmed[0] != '\0')
+                        {
+                            OCRepPayloadAddInterface(temp, curPtr);
+                        }
+                        curPtr = strtok_r(NULL, " ", &savePtr);
+                    }
                 }
-                curPtr = strtok_r(NULL, " ", &savePtr);
+                OICFree(allIf);
             }
         }
-        OICFree(allIf);
-    }
-
-    while (!err && cbor_value_is_map(rootMap))
-    {
-        err = err || OCParseSingleRepPayload(&temp, rootMap);
-
-        if(rootPayload == NULL)
+        if (!err && cbor_value_is_map(&rootMap))
+        {
+             err = err || OCParseSingleRepPayload(&temp, &rootMap);
+        }
+        if (rootPayload == NULL)
         {
             rootPayload = temp;
             curPayload = temp;
@@ -1142,21 +1173,18 @@ static OCStackResult OCParseRepPayload(OCPayload** outPayload, CborValue* rootMa
             curPayload->next = temp;
             curPayload = curPayload->next;
         }
-
-        if (cbor_value_is_valid(rootMap))
-        {
-            err = err || cbor_value_advance(rootMap);
-        }
-
-        if(err)
+        if (err)
         {
             OCRepPayloadDestroy(rootPayload);
             OC_LOG(ERROR, TAG, "CBOR error in ParseRepPayload");
             return OC_STACK_MALFORMED_RESPONSE;
         }
+        if (cbor_value_is_array(&rootMap))
+        {
+            err = err || cbor_value_advance(&rootMap);
+        }
     }
-
-    *outPayload = (OCPayload*)rootPayload;
+    *outPayload = (OCPayload *)rootPayload;
 
     return OC_STACK_OK;
 }
index e1b0807..edf695f 100644 (file)
@@ -232,6 +232,38 @@ namespace OCRepresentationEncodingTest
         OCPayloadDestroy(cparsed);
     }
 
+    TEST(RepresentationEncoding, RepAttributeEmpty)
+    {
+        OC::OCRepresentation startRep;
+        std::vector<int> iarr {};
+        startRep["iarr"] = {};
+
+        OC::MessageContainer mc1;
+        mc1.addRepresentation(startRep);
+
+        OCRepPayload* cstart = mc1.getPayload();
+        EXPECT_EQ(PAYLOAD_TYPE_REPRESENTATION, cstart->base.type);
+
+        uint8_t *cborData = NULL;
+        size_t cborSize = 0;
+        OCPayload *cparsed = NULL;
+        EXPECT_EQ(OC_STACK_OK, OCConvertPayload((OCPayload*)cstart, &cborData, &cborSize));
+        EXPECT_EQ(OC_STACK_OK, OCParsePayload(&cparsed, PAYLOAD_TYPE_REPRESENTATION,
+                    cborData, cborSize));
+        OCPayloadDestroy((OCPayload*)cstart);
+        OICFree(cborData);
+
+        OC::MessageContainer mc2;
+        mc2.setPayload(cparsed);
+        EXPECT_EQ(1u, mc2.representations().size());
+        const OC::OCRepresentation& r = mc2.representations()[0];
+
+        std::vector<int> iarr2 = r["iarr"];
+
+        EXPECT_EQ(iarr, iarr2);
+        OCPayloadDestroy(cparsed);
+    }
+
     TEST(RepresentationEncoding, RepAttribute)
     {
         OC::OCRepresentation startRep;
@@ -1148,4 +1180,71 @@ namespace OCRepresentationEncodingTest
         OCRepPayloadDestroy(payload);
         OCPayloadDestroy(cparsed);
     }
+    TEST(RepresentationEncodingRTandIF, TestPayloadContents)
+    {
+        OC::OCRepresentation subRep1;
+        std::vector<std::string> types;
+        types.push_back("rt.firstitem");
+        std::vector<std::string> interfaces;
+        interfaces.push_back("if.firstitem");
+        subRep1.setResourceTypes(types);
+        subRep1.setResourceInterfaces(interfaces);
+        subRep1.setNULL("NullAttr");
+        subRep1.setValue("IntAttr", 77);
+        subRep1.setValue("DoubleAttr", 3.333);
+        subRep1.setValue("BoolAttr", true);
+        subRep1.setValue("StringAttr", std::string("String attr"));
+
+        OC::MessageContainer mc1;
+        mc1.addRepresentation(subRep1);
+
+        OCRepPayload *repPayload = mc1.getPayload();
+        EXPECT_EQ(PAYLOAD_TYPE_REPRESENTATION, repPayload->base.type);
+
+        uint8_t *cborData = NULL;
+        size_t cborSize = 0;
+        OCPayload *cparsed = NULL;
+
+        EXPECT_EQ(OC_STACK_OK, OCConvertPayload((OCPayload*)repPayload, &cborData, &cborSize));
+        EXPECT_EQ(OC_STACK_OK, OCParsePayload(&cparsed, PAYLOAD_TYPE_REPRESENTATION,
+                    cborData, cborSize));
+
+        OCRepPayload *parsedPayload = (OCRepPayload *)cparsed;
+        EXPECT_EQ(NULL, parsedPayload->uri);
+        EXPECT_STREQ("rt.firstitem", parsedPayload->types->value);
+        EXPECT_EQ(NULL, parsedPayload->types->next);
+        EXPECT_STREQ("if.firstitem", parsedPayload->interfaces->value);
+        EXPECT_EQ(NULL, parsedPayload->interfaces->next);
+
+        // To make sure rt and if are not duplicated.
+        EXPECT_STREQ("BoolAttr", parsedPayload->values->name);
+        EXPECT_EQ(true, parsedPayload->values->b);
+        EXPECT_EQ(OCREP_PROP_BOOL, parsedPayload->values->type);
+        parsedPayload->values = parsedPayload->values->next;
+
+        EXPECT_STREQ("DoubleAttr", parsedPayload->values->name);
+        EXPECT_EQ(OCREP_PROP_DOUBLE, parsedPayload->values->type);
+        EXPECT_EQ(3.3330000000000002, parsedPayload->values->d);
+        parsedPayload->values = parsedPayload->values->next;
+
+        EXPECT_STREQ("IntAttr", parsedPayload->values->name);
+        EXPECT_EQ(77, parsedPayload->values->i);
+        EXPECT_EQ(OCREP_PROP_INT, parsedPayload->values->type);
+        parsedPayload->values = parsedPayload->values->next;
+
+        EXPECT_STREQ("NullAttr", parsedPayload->values->name);
+        EXPECT_EQ(OCREP_PROP_NULL, parsedPayload->values->type);
+        parsedPayload->values = parsedPayload->values->next;
+
+        EXPECT_STREQ("StringAttr", parsedPayload->values->name);
+        EXPECT_STREQ("String attr", parsedPayload->values->str);
+        EXPECT_EQ(OCREP_PROP_STRING, parsedPayload->values->type);
+        parsedPayload->values = parsedPayload->values->next;
+
+        EXPECT_EQ(NULL, parsedPayload->values);
+
+        OICFree(cborData);
+        OCRepPayloadDestroy(repPayload);
+        OCPayloadDestroy(cparsed);
+    }
 }