#include #include #include #include #include #include #include #include #include "tests/rpc_serialize.h" extern "C" { #include "rpc/serialize.c" } /** Used because serialize message header loads di_time_get_stamp */ TEST(time, init) { di_time_init(); } static void rpc_serialize_dump_mem(const uint8_t *buf, size_t n) { for (size_t _n = 0; _n < n; _n++) printf("%02x ", buf[_n]); printf("\n"); } /** Test serialisation of composite data value */ TEST(rpc, serialize_data_value) { int ret; mpack_writer_t w; uint8_t data[128]; /** @note we should test here how mpack behaves when writing unsigned zeros? * This really depends on how mpack is configured because it can pack u64 zero write into a smaller stream. * And it trades CPU cycles for saved bandwidth */ struct { enum di_rpc_data_field field; union di_rpc_data_value value; const char *expect; // This is raw messagepack emitted by mpack library } tv[] = { { DI_RPC_DATA_FIELD_BOOL, { false }, "\xa1\x55\xc2" }, { DI_RPC_DATA_FIELD_BOOL, { false }, "\xa1\x55\xc3" }, { DI_RPC_DATA_FIELD_INT8, { false }, "\xa1\x55\xd0\x80" }, { DI_RPC_DATA_FIELD_INT8, { false }, "\xa1\x55\x7f" }, { DI_RPC_DATA_FIELD_INT16, { false }, "\xa1\x55\xd1\x80\x00" }, { DI_RPC_DATA_FIELD_INT16, { false }, "\xa1\x55\xcd\x7f\xff" }, { DI_RPC_DATA_FIELD_INT32, { false }, "\xa1\x55\xd2\x80\x00\x00\x00" }, { DI_RPC_DATA_FIELD_INT32, { false }, "\xa1\x55\xce\x7f\xff\xff\xff" }, { DI_RPC_DATA_FIELD_INT64, { false }, "\xa1\x55\xd3\x80\x00\x00\x00\x00\x00\x00\x00" }, { DI_RPC_DATA_FIELD_INT64, { false }, "\xa1\x55\xcf\x7f\xff\xff\xff\xff\xff\xff\xff" }, { DI_RPC_DATA_FIELD_UINT8, { false }, "\xa1\x55\xcc\xff" }, { DI_RPC_DATA_FIELD_UINT16, { false }, "\xa1\x55\xcd\xff\xff" }, { DI_RPC_DATA_FIELD_UINT32, { false }, "\xa1\x55\xce\xff\xff\xff\xff" }, { DI_RPC_DATA_FIELD_UINT64, { false }, "\xa1\x55\xcf\xff\xff\xff\xff\xff\xff\xff\xff" } }; /* NOTE: this is because GNU C++ compiler sucks and will emit (clang works): sorry, unimplemented: non-trivial designated initializers not supported */ /* Boolean */ tv[0].value.b = false; tv[1].value.b = true; /* Signed int */ tv[2].value.s8 = INT8_MIN; tv[3].value.s8 = INT8_MAX; tv[4].value.s16 = INT16_MIN; tv[5].value.s16 = INT16_MAX; tv[6].value.s32 = INT32_MIN; tv[7].value.s32 = INT32_MAX; tv[8].value.s64 = INT64_MIN; tv[9].value.s64 = INT64_MAX; /* Unsigned int */ tv[10].value.u8 = UINT8_MAX; tv[11].value.u16 = UINT16_MAX; tv[12].value.u32 = UINT32_MAX; tv[13].value.u64 = UINT64_MAX; for (size_t n = 0; n < sizeof(tv)/(sizeof(tv[0])); n++) { mpack_writer_init(&w, (char *)data, sizeof(data)); di_rpc_serialize_data_value(&w, (const char *)"U", tv[n].field, tv[n].value); ret = memcmp(tv[n].expect, data, mpack_writer_buffer_used(&w)); if (ret != 0) { printf("[tv: %2d] expect (msgpack): ", (int)n + 1); rpc_serialize_dump_mem((const uint8_t *)tv[n].expect, strlen(tv[n].expect)); printf(" got (msgpack): "); rpc_serialize_dump_mem(data, mpack_writer_buffer_used(&w)); } EXPECT_EQ(ret, 0); } } /** "notify:info", "bool" */ TEST(rpc, serialize_rpc_notify_info_bool) { auto writer = TEST_RPC_SERIALIZE_WRITER; struct di_rpc_info info; info.uid = 1; info.label = "test-rpc-serialize-bool"; info.data_type = DI_RPC_DATA_TYPE_BOOL; di_rpc_serialize_item(writer->get(), &info); } /** "notify:info", type "number" */ TEST(rpc, serialize_rpc_notify_info_number) { auto writer = TEST_RPC_SERIALIZE_WRITER; struct di_rpc_info info; info.uid = 2; info.label = "test-rpc-serialize-number"; info.data_type = DI_RPC_DATA_TYPE_NUMBER; di_rpc_serialize_item(writer->get(), &info); } /** "sensor:info", type "enum" */ TEST(rpc, serialize_rpc_sensor_info_number) { struct di_rpc_enum elist[] = { { "empty", 0 }, { "crit", 1 }, { "low", 2 }, { "half", 3 }, { "full", 4 } }; auto writer = TEST_RPC_SERIALIZE_WRITER; struct di_rpc_info info; info.uid = 3; info.label = "test-rpc-serialize-enum"; info.data_type = DI_RPC_DATA_TYPE_ENUM; info.enumerator.size = DI_ARRAY_SIZE(elist); info.enumerator.begin = elist; di_rpc_serialize_item(writer->get(), &info); } /* "sensor:data", type "gps" */ TEST(rpc, serialize_sensor_data_gps) { auto writer = TEST_RPC_SERIALIZE_WRITER; struct di_rpc_sensor_data_gps gps; memset(&gps, 0, sizeof(gps)); gps.hdop = 1.8f; gps.latitude = 0.1234; gps.longitude = 0.5678; di_rpc_serialize_result(writer->get(), &gps); } /* "device:info" */ TEST(rpc, serialize_device_info) { auto writer = TEST_RPC_SERIALIZE_WRITER; struct di_rpc_device_info d; const char l[] = "zkl-3000-rc"; struct di_rpc_device_info_version version[1]; version[0].key = "fw-main"; version[0].value = "v1.0.2"; d.version = version; d.versionn = 1; d.type = l; di_rpc_serialize_item(writer->get(), &d); } /* "config:info" */ TEST(rpc, serialize_config_info_token) { auto writer = TEST_RPC_SERIALIZE_WRITER; struct di_rpc_config_info info; info.uid = 1; info.label = "token"; info.data_type = DI_RPC_DATA_TYPE_NUMBER; info.field = DI_RPC_DATA_FIELD_UINT32; info.value.u32 = 0; di_rpc_serialize_item(writer->get(), &info); } /* Single struct di_error */ TEST(rpc, serialize_error) { auto writer = TEST_RPC_SERIALIZE_WRITER; struct di_rpc_error err; err.code = DNE_FIRMWARE_TILT; err.first = 1000; err.last = 2000; err.count = 10; di_rpc_serialize_item(writer->get(), &err); } /** Test serialize of a string array result */ TEST(rpc, serialize_string_array) { const char *strs[] = { "string1", "string2", "string3" }; auto writer = TEST_RPC_SERIALIZE_WRITER; di_rpc_serialize_result_string_array(writer->get(), strs, DI_ARRAY_SIZE(strs)); }