From 970f4d4aa24fe9519366dfbb9346d37cf03ce0e8 Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Fri, 11 Sep 2015 09:30:09 -0700 Subject: [PATCH] Added unit tests for OCRepresentation to CBOR and back These unit tests validate the conversion of OCRepresentation objects through OCRepPayload and into CBOR, then brings them back. This validates all data types, including jagged arrays. Change-Id: I6c74a29f51febcff8553ac194c5ae57eaa50a460 Signed-off-by: Erich Keane Reviewed-on: https://gerrit.iotivity.org/gerrit/2483 Tested-by: jenkins-iotivity Reviewed-by: Patrick Lankswert --- .../csdk/stack/include/internal/ocpayloadcbor.h | 9 + resource/csdk/stack/src/ocpayloadconvert.c | 3 - resource/include/OCRepresentation.h | 1 + .../unittests/OCRepresentationEncodingTest.cpp | 630 +++++++++++++++++++++ resource/unittests/SConscript | 1 + 5 files changed, 641 insertions(+), 3 deletions(-) create mode 100644 resource/unittests/OCRepresentationEncodingTest.cpp diff --git a/resource/csdk/stack/include/internal/ocpayloadcbor.h b/resource/csdk/stack/include/internal/ocpayloadcbor.h index 3e39742..052afad 100644 --- a/resource/csdk/stack/include/internal/ocpayloadcbor.h +++ b/resource/csdk/stack/include/internal/ocpayloadcbor.h @@ -23,8 +23,17 @@ #include "octypes.h" +#ifdef __cplusplus +extern "C" +{ +#endif OCStackResult OCParsePayload(OCPayload** outPayload, OCPayloadType type, const uint8_t* payload, size_t payloadSize); OCStackResult OCConvertPayload(OCPayload* payload, uint8_t** outPayload, size_t* size); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/resource/csdk/stack/src/ocpayloadconvert.c b/resource/csdk/stack/src/ocpayloadconvert.c index 603a7f6..e838e4d 100644 --- a/resource/csdk/stack/src/ocpayloadconvert.c +++ b/resource/csdk/stack/src/ocpayloadconvert.c @@ -54,9 +54,6 @@ static int64_t AddTextStringToMap(CborEncoder* map, const char* key, size_t keyl static int64_t ConditionalAddTextStringToMap(CborEncoder* map, const char* key, size_t keylen, const char* value); -#define STRINGIFY(s) XSTRINGIFY(s) -#define XSTRINGIFY(s) #s - OCStackResult OCConvertPayload(OCPayload* payload, uint8_t** outPayload, size_t* size) { // TinyCbor Version 47a78569c0 or better on master is required for the re-allocation diff --git a/resource/include/OCRepresentation.h b/resource/include/OCRepresentation.h index 1beafa1..84e88e5 100644 --- a/resource/include/OCRepresentation.h +++ b/resource/include/OCRepresentation.h @@ -89,6 +89,7 @@ namespace OC class OCRepresentation { public: + friend bool operator==(const OC::OCRepresentation&, const OC::OCRepresentation&); // Note: Implementation of all constructors and destructors // are all placed in the same location due to a crash that // was observed in Android, where merely constructing/destructing diff --git a/resource/unittests/OCRepresentationEncodingTest.cpp b/resource/unittests/OCRepresentationEncodingTest.cpp new file mode 100644 index 0000000..dab9c74 --- /dev/null +++ b/resource/unittests/OCRepresentationEncodingTest.cpp @@ -0,0 +1,630 @@ +//****************************************************************** +// +// Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// 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. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +#include +#include +#include +#include +#include +#include +#include + +namespace OC +{ + bool operator==(const OC::NullType&, const OC::NullType&) + { + return true; + } + + bool operator==(const OC::OCRepresentation& lhs, const OC::OCRepresentation& rhs) + { + return lhs.getUri() == rhs.getUri() && + lhs.getChildren() == rhs.getChildren() && + lhs.getResourceInterfaces() == rhs.getResourceInterfaces() && + lhs.getResourceTypes() == rhs.getResourceTypes() && + lhs.m_values == rhs.m_values; + } +} +// these tests validate the OCRepresentation->OCPayload, OCPayload->CBOR, +// CBOR->OCPayload and OCPayload->OCRepresentation conversions +namespace OCRepresentationEncodingTest +{ + + static const char uri1[] = "/testuri"; + static const uint8_t sid1[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}; + static const char devicename1[] = "device name"; + static const char specver1[] = "spec version"; + static const char dmver1[] = "data model version"; + // Device Payloads + TEST(DeviceDiscoveryEncoding, Normal) + { + OCDevicePayload* device = OCDevicePayloadCreate( + uri1, + sid1, + devicename1, + specver1, + dmver1); + + EXPECT_STREQ(uri1, device->uri); + EXPECT_STREQ(devicename1, device->deviceName); + EXPECT_STREQ(specver1, device->specVersion); + EXPECT_STREQ(dmver1, device->dataModelVersion); + EXPECT_EQ(PAYLOAD_TYPE_DEVICE, ((OCPayload*)device)->type); + + for (uint8_t i = 1; i <= sizeof(sid1); ++i) + { + EXPECT_EQ(i, sid1[i - 1]); + } + + uint8_t* cborData; + size_t cborSize; + OCPayload* parsedDevice; + EXPECT_EQ(OC_STACK_OK, OCConvertPayload((OCPayload*)device, &cborData, &cborSize)); + EXPECT_EQ(OC_STACK_OK, OCParsePayload(&parsedDevice, PAYLOAD_TYPE_DEVICE, + cborData, cborSize)); + OICFree(cborData); + + EXPECT_STREQ(device->uri, ((OCDevicePayload*)parsedDevice)->uri); + EXPECT_STREQ(device->deviceName, ((OCDevicePayload*)parsedDevice)->deviceName); + EXPECT_STREQ(device->specVersion, ((OCDevicePayload*)parsedDevice)->specVersion); + EXPECT_STREQ(device->dataModelVersion, ((OCDevicePayload*)parsedDevice)->dataModelVersion); + EXPECT_EQ(device->base.type, ((OCDevicePayload*)parsedDevice)->base.type); + + OCPayloadDestroy((OCPayload*)device); + + OC::MessageContainer mc; + mc.setPayload(parsedDevice); + EXPECT_EQ(1u, mc.representations().size()); + const OC::OCRepresentation& r = mc.representations()[0]; + EXPECT_STREQ(uri1, r.getUri().c_str()); + EXPECT_STREQ(devicename1, r.getValue(OC_RSRVD_DEVICE_NAME).c_str()); + EXPECT_STREQ(specver1, r.getValue(OC_RSRVD_SPEC_VERSION).c_str()); + EXPECT_STREQ(dmver1, r.getValue(OC_RSRVD_DATA_MODEL_VERSION).c_str()); + + + OCPayloadDestroy(parsedDevice); + } + + static char pfid1[] = "pfid"; + static char mfgnm1[] = "mfgnm"; + static char mfgurl1[] = "mfgurl"; + static char modelnum1[] = "modelnum"; + static char dom1[] = "dom"; + static char pfver1[] = "pfver"; + static char osver1[] = "osver"; + static char hwver1[] = "hwver"; + static char fwver1[] = "fwver"; + static char url1[] = "url"; + static char time1[] = "time"; + + // Platform Payloads + TEST(PlatformDiscoveryEncoding, Normal) + { + OCPlatformInfo info {pfid1, mfgnm1, mfgurl1, modelnum1, dom1, pfver1, osver1, hwver1, + fwver1, url1, time1}; + OCPlatformPayload* platform = OCPlatformPayloadCreate(uri1, &info); + EXPECT_EQ(PAYLOAD_TYPE_PLATFORM, ((OCPayload*)platform)->type); + EXPECT_STREQ(uri1, platform->uri); + EXPECT_STREQ(pfid1, platform->info.platformID); + EXPECT_STREQ(mfgnm1, platform->info.manufacturerName); + EXPECT_STREQ(mfgurl1, platform->info.manufacturerUrl); + EXPECT_STREQ(modelnum1, platform->info.modelNumber); + EXPECT_STREQ(dom1, platform->info.dateOfManufacture); + EXPECT_STREQ(pfver1, platform->info.platformVersion); + EXPECT_STREQ(osver1, platform->info.operatingSystemVersion); + EXPECT_STREQ(hwver1, platform->info.hardwareVersion); + EXPECT_STREQ(fwver1, platform->info.firmwareVersion); + EXPECT_STREQ(url1, platform->info.supportUrl); + EXPECT_STREQ(time1, platform->info.systemTime); + + uint8_t* cborData; + size_t cborSize; + OCPayload* parsedPlatform; + EXPECT_EQ(OC_STACK_OK, OCConvertPayload((OCPayload*)platform, &cborData, &cborSize)); + EXPECT_EQ(OC_STACK_OK, OCParsePayload(&parsedPlatform, PAYLOAD_TYPE_PLATFORM, + cborData, cborSize)); + OICFree(cborData); + + EXPECT_EQ(platform->base.type, ((OCPlatformPayload*)parsedPlatform)->base.type); + OCPlatformPayload* platform2 = (OCPlatformPayload*)parsedPlatform; + EXPECT_STREQ(platform->uri, platform2->uri); + EXPECT_STREQ(platform->info.platformID, platform2->info.platformID); + EXPECT_STREQ(platform->info.manufacturerName, platform->info.manufacturerName); + EXPECT_STREQ(platform->info.manufacturerUrl, platform->info.manufacturerUrl); + EXPECT_STREQ(platform->info.modelNumber, platform->info.modelNumber); + EXPECT_STREQ(platform->info.dateOfManufacture, platform->info.dateOfManufacture); + EXPECT_STREQ(platform->info.platformVersion, platform->info.platformVersion); + EXPECT_STREQ(platform->info.operatingSystemVersion, platform->info.operatingSystemVersion); + EXPECT_STREQ(platform->info.hardwareVersion, platform->info.hardwareVersion); + EXPECT_STREQ(platform->info.firmwareVersion, platform->info.firmwareVersion); + EXPECT_STREQ(platform->info.supportUrl, platform->info.supportUrl); + EXPECT_STREQ(platform->info.systemTime, platform2->info.systemTime); + + OCPayloadDestroy((OCPayload*)platform); + + OC::MessageContainer mc; + mc.setPayload(parsedPlatform); + EXPECT_EQ(1u, mc.representations().size()); + const OC::OCRepresentation& r = mc.representations()[0]; + EXPECT_STREQ(uri1, r.getUri().c_str()); + EXPECT_STREQ(pfid1, r.getValue(OC_RSRVD_PLATFORM_ID).c_str()); + EXPECT_STREQ(mfgnm1, r.getValue(OC_RSRVD_MFG_NAME).c_str()); + EXPECT_STREQ(mfgurl1, r.getValue(OC_RSRVD_MFG_URL).c_str()); + EXPECT_STREQ(modelnum1, r.getValue(OC_RSRVD_MODEL_NUM).c_str()); + EXPECT_STREQ(dom1, r.getValue(OC_RSRVD_MFG_DATE).c_str()); + EXPECT_STREQ(pfver1, r.getValue(OC_RSRVD_PLATFORM_VERSION).c_str()); + EXPECT_STREQ(osver1, r.getValue(OC_RSRVD_OS_VERSION).c_str()); + EXPECT_STREQ(hwver1, r.getValue(OC_RSRVD_HARDWARE_VERSION).c_str()); + EXPECT_STREQ(fwver1, r.getValue(OC_RSRVD_FIRMWARE_VERSION).c_str()); + EXPECT_STREQ(url1, r.getValue(OC_RSRVD_SUPPORT_URL).c_str()); + EXPECT_STREQ(time1, r.getValue(OC_RSRVD_SYSTEM_TIME).c_str()); + + OCPayloadDestroy(parsedPlatform); + } + + // Representation Payloads + TEST(RepresentationEncoding, BaseAttributeTypes) + { + OC::OCRepresentation startRep; + startRep.setNULL("NullAttr"); + startRep.setValue("IntAttr", 77); + startRep.setValue("DoubleAttr", 3.333); + startRep.setValue("BoolAttr", true); + startRep.setValue("StringAttr", std::string("String attr")); + OC::MessageContainer mc1; + mc1.addRepresentation(startRep); + + OCRepPayload* cstart = mc1.getPayload(); + EXPECT_EQ(PAYLOAD_TYPE_REPRESENTATION, cstart->base.type); + + uint8_t* cborData; + size_t cborSize; + OCPayload* cparsed; + 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]; + + EXPECT_TRUE(r.isNULL("NullAttr")); + EXPECT_EQ(77, r.getValue("IntAttr")); + EXPECT_EQ(3.333, r.getValue("DoubleAttr")); + EXPECT_EQ(true, r.getValue("BoolAttr")); + EXPECT_STREQ("String attr", r.getValue("StringAttr").c_str()); + + OCPayloadDestroy(cparsed); + } + + TEST(RepresentationEncoding, RepAttribute) + { + OC::OCRepresentation startRep; + OC::OCRepresentation subRep; + subRep.setNULL("NullAttr"); + subRep.setValue("IntAttr", 77); + subRep.setValue("DoubleAttr", 3.333); + subRep.setValue("BoolAttr", true); + subRep.setValue("StringAttr", std::string("String attr")); + startRep.setValue("Sub", subRep); + + OC::MessageContainer mc1; + mc1.addRepresentation(startRep); + + OCRepPayload* cstart = mc1.getPayload(); + EXPECT_EQ(PAYLOAD_TYPE_REPRESENTATION, cstart->base.type); + + uint8_t* cborData; + size_t cborSize; + OCPayload* cparsed; + 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]; + + OC::OCRepresentation newSubRep = r["Sub"]; + + EXPECT_TRUE(newSubRep.isNULL("NullAttr")); + EXPECT_EQ(77, newSubRep.getValue("IntAttr")); + EXPECT_EQ(3.333, newSubRep.getValue("DoubleAttr")); + EXPECT_EQ(true, newSubRep.getValue("BoolAttr")); + EXPECT_STREQ("String attr", newSubRep.getValue("StringAttr").c_str()); + OCPayloadDestroy(cparsed); + } + + TEST(RepresentationEncoding, OneDVectors) + { + // Setup + OC::OCRepresentation startRep; + + OC::OCRepresentation subRep1; + OC::OCRepresentation subRep2; + OC::OCRepresentation subRep3; + subRep1.setNULL("NullAttr"); + subRep1.setValue("IntAttr", 77); + subRep2.setValue("DoubleAttr", 3.333); + subRep2.setValue("BoolAttr", true); + subRep3.setValue("StringAttr", std::string("String attr")); + + std::vector iarr {1,2,3,4,5,6,7,8,9}; + std::vector darr {1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9}; + std::vector barr {false, true, false, false, true, true}; + std::vector strarr {"item1", "item2", "item3", "item4"}; + std::vector objarr {subRep1, subRep2, subRep3}; + + startRep["iarr"] = iarr; + startRep["darr"] = darr; + startRep["barr"] = barr; + startRep["strarr"] = strarr; + startRep["objarr"] = objarr; + + // Encode/decode + OC::MessageContainer mc1; + mc1.addRepresentation(startRep); + + OCRepPayload* cstart = mc1.getPayload(); + EXPECT_EQ(PAYLOAD_TYPE_REPRESENTATION, cstart->base.type); + + uint8_t* cborData; + size_t cborSize; + OCPayload* cparsed; + 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]; + + // Test + std::vector iarr2 = r["iarr"]; + std::vector darr2 = r["darr"]; + std::vector barr2 = r["barr"]; + std::vector strarr2 = r["strarr"]; + std::vector objarr2 = r["objarr"]; + + EXPECT_EQ(iarr, iarr2); + EXPECT_EQ(darr, darr2); + EXPECT_EQ(barr, barr2); + EXPECT_EQ(strarr, strarr2); + EXPECT_EQ(objarr, objarr2); + OCPayloadDestroy(cparsed); + } + + TEST(RepresentationEncoding, TwoDVectors) + { + // Setup + OC::OCRepresentation startRep; + + OC::OCRepresentation subRep1; + OC::OCRepresentation subRep2; + OC::OCRepresentation subRep3; + subRep1.setNULL("NullAttr"); + subRep1.setValue("IntAttr", 77); + subRep2.setValue("DoubleAttr", 3.333); + subRep2.setValue("BoolAttr", true); + subRep3.setValue("StringAttr", std::string("String attr")); + + std::vector> iarr {{1,2,3},{4,5,6},{7,8,9}}; + std::vector> darr {{1.1,2.2,3.3},{4.4,5.5,6.6},{7.7,8.8,9.9}}; + std::vector> barr {{false, true}, {false, false}, {true, true}}; + std::vector> strarr {{"item1", "item2"}, {"item3", "item4"}}; + std::vector> objarr + {{subRep1, subRep2, subRep3}, {subRep3, subRep2, subRep1}}; + + startRep["iarr"] = iarr; + startRep["darr"] = darr; + startRep["barr"] = barr; + startRep["strarr"] = strarr; + startRep["objarr"] = objarr; + + // Encode/decode + OC::MessageContainer mc1; + mc1.addRepresentation(startRep); + + OCRepPayload* cstart = mc1.getPayload(); + EXPECT_EQ(PAYLOAD_TYPE_REPRESENTATION, cstart->base.type); + + uint8_t* cborData; + size_t cborSize; + OCPayload* cparsed; + 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]; + + // Test + std::vector> iarr2 = r["iarr"]; + std::vector> darr2 = r["darr"]; + std::vector> barr2 = r["barr"]; + std::vector> strarr2 = r["strarr"]; + std::vector> objarr2 = r["objarr"]; + + EXPECT_EQ(iarr, iarr2); + EXPECT_EQ(darr, darr2); + EXPECT_EQ(barr, barr2); + EXPECT_EQ(strarr, strarr2); + EXPECT_EQ(objarr, objarr2); + OCPayloadDestroy(cparsed); + } + + TEST(RepresentationEncoding, TwoDVectorsJagged) + { + // Setup + OC::OCRepresentation startRep; + + OC::OCRepresentation subRep1; + OC::OCRepresentation subRep2; + OC::OCRepresentation subRep3; + subRep1.setNULL("NullAttr"); + subRep1.setValue("IntAttr", 77); + subRep2.setValue("DoubleAttr", 3.333); + subRep2.setValue("BoolAttr", true); + subRep3.setValue("StringAttr", std::string("String attr")); + + std::vector> iarr {{1,2,3},{4,6},{7,8,9}}; + std::vector> darr {{1.1,2.2,3.3},{4.4,5.5,6.6},{8.8,9.9}}; + std::vector> barr {{false, true}, {false}, {true, true}}; + std::vector> strarr {{"item1"}, {"item3", "item4"}}; + std::vector> objarr + {{subRep1, subRep3}, {subRep3, subRep2, subRep1}}; + + startRep["iarr"] = iarr; + startRep["darr"] = darr; + startRep["barr"] = barr; + startRep["strarr"] = strarr; + startRep["objarr"] = objarr; + + // Encode/decode + OC::MessageContainer mc1; + mc1.addRepresentation(startRep); + + OCRepPayload* cstart = mc1.getPayload(); + EXPECT_EQ(PAYLOAD_TYPE_REPRESENTATION, cstart->base.type); + + uint8_t* cborData; + size_t cborSize; + OCPayload* cparsed; + 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]; + + // Test + std::vector> iarr2 = r["iarr"]; + std::vector> darr2 = r["darr"]; + std::vector> barr2 = r["barr"]; + std::vector> strarr2 = r["strarr"]; + std::vector> objarr2 = r["objarr"]; + + // Note: due to the way that the CSDK works, all 2d arrays need to be rectangular. + // Since std::vector doesn't require this, items received on the other side end up + // being backfilled. This section removes the backfilling + iarr2[1].pop_back(); + darr2[2].pop_back(); + barr2[1].pop_back(); + strarr2[0].pop_back(); + objarr2[0].pop_back(); + + EXPECT_EQ(iarr, iarr2); + EXPECT_EQ(darr, darr2); + EXPECT_EQ(barr, barr2); + EXPECT_EQ(strarr, strarr2); + EXPECT_EQ(objarr, objarr2); + OCPayloadDestroy(cparsed); + } + + TEST(RepresentationEncoding, ThreeDVectors) + { + // Setup + OC::OCRepresentation startRep; + + OC::OCRepresentation subRep1; + OC::OCRepresentation subRep2; + OC::OCRepresentation subRep3; + subRep1.setNULL("NullAttr"); + subRep1.setValue("IntAttr", 77); + subRep2.setValue("DoubleAttr", 3.333); + subRep2.setValue("BoolAttr", true); + subRep3.setValue("StringAttr", std::string("String attr")); + + std::vector>> iarr + {{{1,2,3},{4,5,6}},{{7,8,9},{10,11,12}},{{13,14,15},{16,17,18}}}; + std::vector>> darr + {{{1.1,2.2,3.3},{4.4,5.5,6.6}}, + {{7.7,8.7,9.7},{10.7,11.7,12.7}}, + {{13.7,14.7,15.7},{16.7,17.7,18.7}}}; + std::vector>> barr + {{{false, true},{true, false}},{{false, true},{true, false}}}; + std::vector>> strarr + { + {{"item1", "item2"},{"item3", "item4"}}, + {{"item5", "item6"},{"item7", "item8"}}, + {{"item9", "item10"},{"item11", ""}} + }; + std::vector>> objarr + { + {{subRep1, subRep2},{subRep3, subRep1}}, + {{subRep2, subRep3},{subRep2, subRep1}}, + {{subRep3, subRep2},{subRep1, subRep2}} + }; + + startRep["iarr"] = iarr; + startRep["darr"] = darr; + startRep["barr"] = barr; + startRep["strarr"] = strarr; + startRep["objarr"] = objarr; + + // Encode/decode + OC::MessageContainer mc1; + mc1.addRepresentation(startRep); + + OCRepPayload* cstart = mc1.getPayload(); + EXPECT_EQ(PAYLOAD_TYPE_REPRESENTATION, cstart->base.type); + + uint8_t* cborData; + size_t cborSize; + OCPayload* cparsed; + 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]; + + // Test + std::vector>> iarr2 = r["iarr"]; + std::vector>> darr2 = r["darr"]; + std::vector>> barr2 = r["barr"]; + std::vector>> strarr2 = r["strarr"]; + std::vector>> objarr2 = r["objarr"]; + + EXPECT_EQ(iarr, iarr2); + EXPECT_EQ(darr, darr2); + EXPECT_EQ(barr, barr2); + EXPECT_EQ(strarr, strarr2); + EXPECT_EQ(objarr, objarr2); + OCPayloadDestroy(cparsed); + } + + TEST(RepresentationEncoding, ThreeDVectorsJagged) + { + // Setup + OC::OCRepresentation startRep; + + OC::OCRepresentation subRep1; + OC::OCRepresentation subRep2; + OC::OCRepresentation subRep3; + subRep1.setNULL("NullAttr"); + subRep1.setValue("IntAttr", 77); + subRep2.setValue("DoubleAttr", 3.333); + subRep2.setValue("BoolAttr", true); + subRep3.setValue("StringAttr", std::string("String attr")); + + std::vector>> iarr + { + {{1,2,3},{4,5,6}}, + {{7,8,9},{10,12}}, + {{13,14,15},{16,17,18}} + }; + std::vector>> darr + { + {{1.1,2.2,3.3},{4.4,5.5,6.6}}, + {{7.7,8.7,9.7},{10.7,12.7}}, + {{13.7,14.7,15.7},{16.7,17.7,18.7}} + }; + std::vector>> barr + { + {{false, true},{true}}, + {{false, true},{true, false}} + }; + std::vector>> strarr + { + {{"item1", "item2"},{"item3", "item4"}}, + {{"item5", "item6"},{"item8"}}, + {{"item9", "item10"},{"item11", ""}} + }; + std::vector>> objarr + { + {{subRep1, subRep2},{subRep3, subRep1}}, + {{subRep2, subRep3},{subRep2}}, + {{subRep3, subRep2}} + }; + + startRep["iarr"] = iarr; + startRep["darr"] = darr; + startRep["barr"] = barr; + startRep["strarr"] = strarr; + startRep["objarr"] = objarr; + + // Encode/decode + OC::MessageContainer mc1; + mc1.addRepresentation(startRep); + + OCRepPayload* cstart = mc1.getPayload(); + EXPECT_EQ(PAYLOAD_TYPE_REPRESENTATION, cstart->base.type); + + uint8_t* cborData; + size_t cborSize; + OCPayload* cparsed; + 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]; + + // Test + std::vector>> iarr2 = r["iarr"]; + std::vector>> darr2 = r["darr"]; + std::vector>> barr2 = r["barr"]; + std::vector>> strarr2 = r["strarr"]; + std::vector>> objarr2 = r["objarr"]; + + // Note: due to the way that the CSDK works, all 3d arrays need to be cuboidal. + // Since std::vector doesn't require this, items received on the other side end up + // being backfilled. This section removes the backfilling + iarr2[1][1].pop_back(); + darr2[1][1].pop_back(); + barr2[0][1].pop_back(); + strarr2[1][1].pop_back(); + objarr2[1][1].pop_back(); + objarr2[2].pop_back(); + + EXPECT_EQ(iarr, iarr2); + EXPECT_EQ(darr, darr2); + EXPECT_EQ(barr, barr2); + EXPECT_EQ(strarr, strarr2); + EXPECT_EQ(objarr, objarr2); + OCPayloadDestroy(cparsed); + } +} diff --git a/resource/unittests/SConscript b/resource/unittests/SConscript index 4264736..0506303 100644 --- a/resource/unittests/SConscript +++ b/resource/unittests/SConscript @@ -69,6 +69,7 @@ if env.get('LOGGING'): unittests = unittests_env.Program('unittests', ['ConstructResourceTest.cpp', 'OCPlatformTest.cpp', 'OCRepresentationTest.cpp', + 'OCRepresentationEncodingTest.cpp', 'OCResourceTest.cpp', 'OCExceptionTest.cpp', 'OCResourceResponseTest.cpp', -- 2.7.4