// Copyright 2014 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include #include #include #include #include #include "brillo/dbus/test.pb.h" using dbus::Message; using dbus::MessageReader; using dbus::MessageWriter; using dbus::ObjectPath; using dbus::Response; namespace brillo { namespace dbus_utils { TEST(DBusUtils, Supported_BasicTypes) { EXPECT_TRUE(IsTypeSupported::value); EXPECT_TRUE(IsTypeSupported::value); EXPECT_TRUE(IsTypeSupported::value); EXPECT_TRUE(IsTypeSupported::value); EXPECT_TRUE(IsTypeSupported::value); EXPECT_TRUE(IsTypeSupported::value); EXPECT_TRUE(IsTypeSupported::value); EXPECT_TRUE(IsTypeSupported::value); EXPECT_TRUE(IsTypeSupported::value); EXPECT_TRUE(IsTypeSupported::value); EXPECT_TRUE(IsTypeSupported::value); EXPECT_TRUE(IsTypeSupported::value); EXPECT_TRUE(IsTypeSupported::value); EXPECT_TRUE(IsTypeSupported::value); EXPECT_TRUE(IsTypeSupported::value); EXPECT_TRUE(IsTypeSupported::value); } TEST(DBusUtils, Unsupported_BasicTypes) { EXPECT_FALSE(IsTypeSupported::value); EXPECT_FALSE(IsTypeSupported::value); } TEST(DBusUtils, Supported_ComplexTypes) { EXPECT_TRUE(IsTypeSupported>::value); EXPECT_TRUE(IsTypeSupported>::value); EXPECT_TRUE((IsTypeSupported>::value)); EXPECT_TRUE( (IsTypeSupported>>::value)); EXPECT_TRUE((IsTypeSupported>::value)); EXPECT_TRUE( IsTypeSupported>::value); } TEST(DBusUtils, Unsupported_ComplexTypes) { EXPECT_FALSE(IsTypeSupported>::value); EXPECT_FALSE((IsTypeSupported>::value)); EXPECT_FALSE((IsTypeSupported>::value)); EXPECT_FALSE((IsTypeSupported>::value)); EXPECT_FALSE((IsTypeSupported>::value)); EXPECT_FALSE((IsTypeSupported>::value)); } TEST(DBusUtils, Supported_TypeSet) { EXPECT_TRUE((IsTypeSupported::value)); EXPECT_TRUE((IsTypeSupported, uint8_t>::value)); } TEST(DBusUtils, Unupported_TypeSet) { EXPECT_FALSE((IsTypeSupported::value)); EXPECT_FALSE( (IsTypeSupported, uint8_t>>::value)); EXPECT_FALSE((IsTypeSupported::value)); EXPECT_FALSE((IsTypeSupported, float>::value)); } TEST(DBusUtils, Signatures_BasicTypes) { EXPECT_EQ("b", GetDBusSignature()); EXPECT_EQ("y", GetDBusSignature()); EXPECT_EQ("n", GetDBusSignature()); EXPECT_EQ("q", GetDBusSignature()); EXPECT_EQ("i", GetDBusSignature()); EXPECT_EQ("u", GetDBusSignature()); EXPECT_EQ("x", GetDBusSignature()); EXPECT_EQ("t", GetDBusSignature()); EXPECT_EQ("d", GetDBusSignature()); EXPECT_EQ("s", GetDBusSignature()); EXPECT_EQ("o", GetDBusSignature()); EXPECT_EQ("h", GetDBusSignature()); EXPECT_EQ("h", GetDBusSignature()); EXPECT_EQ("v", GetDBusSignature()); } TEST(DBusUtils, Signatures_Arrays) { EXPECT_EQ("ab", GetDBusSignature>()); EXPECT_EQ("ay", GetDBusSignature>()); EXPECT_EQ("an", GetDBusSignature>()); EXPECT_EQ("aq", GetDBusSignature>()); EXPECT_EQ("ai", GetDBusSignature>()); EXPECT_EQ("au", GetDBusSignature>()); EXPECT_EQ("ax", GetDBusSignature>()); EXPECT_EQ("at", GetDBusSignature>()); EXPECT_EQ("ad", GetDBusSignature>()); EXPECT_EQ("as", GetDBusSignature>()); EXPECT_EQ("ao", GetDBusSignature>()); EXPECT_EQ("ah", GetDBusSignature>()); EXPECT_EQ("ah", GetDBusSignature>()); EXPECT_EQ("av", GetDBusSignature>()); EXPECT_EQ("a(is)", (GetDBusSignature>>())); EXPECT_EQ("aad", GetDBusSignature>>()); } TEST(DBusUtils, Signatures_Maps) { EXPECT_EQ("a{sb}", (GetDBusSignature>())); EXPECT_EQ("a{ss}", (GetDBusSignature>())); EXPECT_EQ("a{sv}", (GetDBusSignature>())); EXPECT_EQ("a{id}", (GetDBusSignature>())); EXPECT_EQ( "a{ia{ss}}", (GetDBusSignature>>())); } TEST(DBusUtils, Signatures_Pairs) { EXPECT_EQ("(sb)", (GetDBusSignature>())); EXPECT_EQ("(sv)", (GetDBusSignature>())); EXPECT_EQ("(id)", (GetDBusSignature>())); } TEST(DBusUtils, Signatures_Tuples) { EXPECT_EQ("(i)", (GetDBusSignature>())); EXPECT_EQ("(sv)", (GetDBusSignature>())); EXPECT_EQ("(id(si))", (GetDBusSignature< std::tuple>>())); } TEST(DBusUtils, Signatures_Protobufs) { EXPECT_EQ("ay", (GetDBusSignature())); EXPECT_EQ("ay", (GetDBusSignature())); } // Test that a byte can be properly written and read. We only have this // test for byte, as repeating this for other basic types is too redundant. TEST(DBusUtils, AppendAndPopByte) { std::unique_ptr message = Response::CreateEmpty(); MessageWriter writer(message.get()); AppendValueToWriter(&writer, uint8_t{123}); EXPECT_EQ("y", message->GetSignature()); MessageReader reader(message.get()); EXPECT_TRUE(reader.HasMoreData()); // Should have data to read. EXPECT_EQ(Message::BYTE, reader.GetDataType()); bool bool_value = false; // Should fail as the type is not bool here. EXPECT_FALSE(PopValueFromReader(&reader, &bool_value)); uint8_t byte_value = 0; EXPECT_TRUE(PopValueFromReader(&reader, &byte_value)); EXPECT_EQ(123, byte_value); // Should match with the input. EXPECT_FALSE(reader.HasMoreData()); // Should not have more data to read. // Try to get another byte. Should fail. EXPECT_FALSE(PopValueFromReader(&reader, &byte_value)); } // Check all basic types can be properly written and read. TEST(DBusUtils, AppendAndPopBasicDataTypes) { std::unique_ptr message = Response::CreateEmpty(); MessageWriter writer(message.get()); // Append 0, true, 2, 3, 4, 5, 6, 7, 8.0, "string", "/object/path". AppendValueToWriter(&writer, uint8_t{0}); AppendValueToWriter(&writer, bool{true}); AppendValueToWriter(&writer, int16_t{2}); AppendValueToWriter(&writer, uint16_t{3}); AppendValueToWriter(&writer, int32_t{4}); AppendValueToWriter(&writer, uint32_t{5}); AppendValueToWriter(&writer, int64_t{6}); AppendValueToWriter(&writer, uint64_t{7}); AppendValueToWriter(&writer, double{8.0}); AppendValueToWriter(&writer, std::string{"string"}); AppendValueToWriter(&writer, ObjectPath{"/object/path"}); EXPECT_EQ("ybnqiuxtdso", message->GetSignature()); uint8_t byte_value = 0; bool bool_value = false; int16_t int16_value = 0; uint16_t uint16_value = 0; int32_t int32_value = 0; uint32_t uint32_value = 0; int64_t int64_value = 0; uint64_t uint64_value = 0; double double_value = 0; std::string string_value; ObjectPath object_path_value; MessageReader reader(message.get()); EXPECT_TRUE(reader.HasMoreData()); EXPECT_TRUE(PopValueFromReader(&reader, &byte_value)); EXPECT_TRUE(PopValueFromReader(&reader, &bool_value)); EXPECT_TRUE(PopValueFromReader(&reader, &int16_value)); EXPECT_TRUE(PopValueFromReader(&reader, &uint16_value)); EXPECT_TRUE(PopValueFromReader(&reader, &int32_value)); EXPECT_TRUE(PopValueFromReader(&reader, &uint32_value)); EXPECT_TRUE(PopValueFromReader(&reader, &int64_value)); EXPECT_TRUE(PopValueFromReader(&reader, &uint64_value)); EXPECT_TRUE(PopValueFromReader(&reader, &double_value)); EXPECT_TRUE(PopValueFromReader(&reader, &string_value)); EXPECT_TRUE(PopValueFromReader(&reader, &object_path_value)); EXPECT_FALSE(reader.HasMoreData()); // 0, true, 2, 3, 4, 5, 6, 7, 8, "string", "/object/path" should be returned. EXPECT_EQ(0, byte_value); EXPECT_TRUE(bool_value); EXPECT_EQ(2, int16_value); EXPECT_EQ(3U, uint16_value); EXPECT_EQ(4, int32_value); EXPECT_EQ(5U, uint32_value); EXPECT_EQ(6, int64_value); EXPECT_EQ(7U, uint64_value); EXPECT_DOUBLE_EQ(8.0, double_value); EXPECT_EQ("string", string_value); EXPECT_EQ(ObjectPath{"/object/path"}, object_path_value); } // Check all basic types can be properly written and read. TEST(DBusUtils, AppendAndPopFileDescriptor) { if (!dbus::IsDBusTypeUnixFdSupported()) { LOG(WARNING) << "FD passing is not supported"; return; } std::unique_ptr message = Response::CreateEmpty(); MessageWriter writer(message.get()); // Append stdout. FileDescriptor temp = 1; AppendValueToWriter(&writer, temp); EXPECT_EQ("h", message->GetSignature()); base::ScopedFD fd_value; MessageReader reader(message.get()); EXPECT_TRUE(reader.HasMoreData()); EXPECT_TRUE(PopValueFromReader(&reader, &fd_value)); EXPECT_FALSE(reader.HasMoreData()); EXPECT_TRUE(fd_value.is_valid()); } // Check all variant types can be properly written and read. TEST(DBusUtils, AppendAndPopVariantDataTypes) { std::unique_ptr message = Response::CreateEmpty(); MessageWriter writer(message.get()); // Append 10, false, 12, 13, 14, 15, 16, 17, 18.5, "data", "/obj/path". AppendValueToWriterAsVariant(&writer, uint8_t{10}); AppendValueToWriterAsVariant(&writer, bool{false}); AppendValueToWriterAsVariant(&writer, int16_t{12}); AppendValueToWriterAsVariant(&writer, uint16_t{13}); AppendValueToWriterAsVariant(&writer, int32_t{14}); AppendValueToWriterAsVariant(&writer, uint32_t{15}); AppendValueToWriterAsVariant(&writer, int64_t{16}); AppendValueToWriterAsVariant(&writer, uint64_t{17}); AppendValueToWriterAsVariant(&writer, double{18.5}); AppendValueToWriterAsVariant(&writer, std::string{"data"}); AppendValueToWriterAsVariant(&writer, ObjectPath{"/obj/path"}); AppendValueToWriterAsVariant(&writer, Any{17}); AppendValueToWriterAsVariant(&writer, Any{std::vector>{{6, 7}}}); EXPECT_EQ("vvvvvvvvvvvvv", message->GetSignature()); uint8_t byte_value = 0; bool bool_value = true; int16_t int16_value = 0; uint16_t uint16_value = 0; int32_t int32_value = 0; uint32_t uint32_value = 0; int64_t int64_value = 0; uint64_t uint64_value = 0; double double_value = 0; std::string string_value; ObjectPath object_path_value; Any any_value; Any any_vector_vector; MessageReader reader(message.get()); EXPECT_TRUE(reader.HasMoreData()); EXPECT_TRUE(PopVariantValueFromReader(&reader, &byte_value)); EXPECT_TRUE(PopVariantValueFromReader(&reader, &bool_value)); EXPECT_TRUE(PopVariantValueFromReader(&reader, &int16_value)); EXPECT_TRUE(PopVariantValueFromReader(&reader, &uint16_value)); EXPECT_TRUE(PopVariantValueFromReader(&reader, &int32_value)); EXPECT_TRUE(PopVariantValueFromReader(&reader, &uint32_value)); EXPECT_TRUE(PopVariantValueFromReader(&reader, &int64_value)); EXPECT_TRUE(PopVariantValueFromReader(&reader, &uint64_value)); EXPECT_TRUE(PopVariantValueFromReader(&reader, &double_value)); EXPECT_TRUE(PopVariantValueFromReader(&reader, &string_value)); EXPECT_TRUE(PopVariantValueFromReader(&reader, &object_path_value)); EXPECT_TRUE(PopVariantValueFromReader(&reader, &any_value)); // Not implemented. EXPECT_FALSE(PopVariantValueFromReader(&reader, &any_vector_vector)); EXPECT_FALSE(reader.HasMoreData()); EXPECT_EQ(10, byte_value); EXPECT_FALSE(bool_value); EXPECT_EQ(12, int16_value); EXPECT_EQ(13U, uint16_value); EXPECT_EQ(14, int32_value); EXPECT_EQ(15U, uint32_value); EXPECT_EQ(16, int64_value); EXPECT_EQ(17U, uint64_value); EXPECT_DOUBLE_EQ(18.5, double_value); EXPECT_EQ("data", string_value); EXPECT_EQ(ObjectPath{"/obj/path"}, object_path_value); EXPECT_EQ(17, any_value.Get()); EXPECT_TRUE(any_vector_vector.IsEmpty()); } TEST(DBusUtils, AppendAndPopBasicAny) { std::unique_ptr message = Response::CreateEmpty(); MessageWriter writer(message.get()); // Append 10, true, 12, 13, 14, 15, 16, 17, 18.5, "data", "/obj/path". AppendValueToWriter(&writer, Any(uint8_t{10})); AppendValueToWriter(&writer, Any(bool{true})); AppendValueToWriter(&writer, Any(int16_t{12})); AppendValueToWriter(&writer, Any(uint16_t{13})); AppendValueToWriter(&writer, Any(int32_t{14})); AppendValueToWriter(&writer, Any(uint32_t{15})); AppendValueToWriter(&writer, Any(int64_t{16})); AppendValueToWriter(&writer, Any(uint64_t{17})); AppendValueToWriter(&writer, Any(double{18.5})); AppendValueToWriter(&writer, Any(std::string{"data"})); AppendValueToWriter(&writer, Any(ObjectPath{"/obj/path"})); EXPECT_EQ("vvvvvvvvvvv", message->GetSignature()); Any byte_value; Any bool_value; Any int16_value; Any uint16_value; Any int32_value; Any uint32_value; Any int64_value; Any uint64_value; Any double_value; Any string_value; Any object_path_value; MessageReader reader(message.get()); EXPECT_TRUE(reader.HasMoreData()); EXPECT_TRUE(PopValueFromReader(&reader, &byte_value)); EXPECT_TRUE(PopValueFromReader(&reader, &bool_value)); EXPECT_TRUE(PopValueFromReader(&reader, &int16_value)); EXPECT_TRUE(PopValueFromReader(&reader, &uint16_value)); EXPECT_TRUE(PopValueFromReader(&reader, &int32_value)); EXPECT_TRUE(PopValueFromReader(&reader, &uint32_value)); EXPECT_TRUE(PopValueFromReader(&reader, &int64_value)); EXPECT_TRUE(PopValueFromReader(&reader, &uint64_value)); EXPECT_TRUE(PopValueFromReader(&reader, &double_value)); EXPECT_TRUE(PopValueFromReader(&reader, &string_value)); EXPECT_TRUE(PopValueFromReader(&reader, &object_path_value)); EXPECT_FALSE(reader.HasMoreData()); // Must be: 10, true, 12, 13, 14, 15, 16, 17, 18.5, "data", "/obj/path". EXPECT_EQ(10, byte_value.Get()); EXPECT_TRUE(bool_value.Get()); EXPECT_EQ(12, int16_value.Get()); EXPECT_EQ(13U, uint16_value.Get()); EXPECT_EQ(14, int32_value.Get()); EXPECT_EQ(15U, uint32_value.Get()); EXPECT_EQ(16, int64_value.Get()); EXPECT_EQ(17U, uint64_value.Get()); EXPECT_DOUBLE_EQ(18.5, double_value.Get()); EXPECT_EQ("data", string_value.Get()); EXPECT_EQ(ObjectPath{"/obj/path"}, object_path_value.Get()); } TEST(DBusUtils, ArrayOfBytes) { std::unique_ptr message = Response::CreateEmpty(); MessageWriter writer(message.get()); std::vector bytes{1, 2, 3}; AppendValueToWriter(&writer, bytes); EXPECT_EQ("ay", message->GetSignature()); MessageReader reader(message.get()); std::vector bytes_out; EXPECT_TRUE(PopValueFromReader(&reader, &bytes_out)); EXPECT_FALSE(reader.HasMoreData()); EXPECT_EQ(bytes, bytes_out); } TEST(DBusUtils, ArrayOfBytes_Empty) { std::unique_ptr message = Response::CreateEmpty(); MessageWriter writer(message.get()); std::vector bytes; AppendValueToWriter(&writer, bytes); EXPECT_EQ("ay", message->GetSignature()); MessageReader reader(message.get()); std::vector bytes_out; EXPECT_TRUE(PopValueFromReader(&reader, &bytes_out)); EXPECT_FALSE(reader.HasMoreData()); EXPECT_EQ(bytes, bytes_out); } TEST(DBusUtils, ArrayOfStrings) { std::unique_ptr message = Response::CreateEmpty(); MessageWriter writer(message.get()); std::vector strings{"foo", "bar", "baz"}; AppendValueToWriter(&writer, strings); EXPECT_EQ("as", message->GetSignature()); MessageReader reader(message.get()); std::vector strings_out; EXPECT_TRUE(PopValueFromReader(&reader, &strings_out)); EXPECT_FALSE(reader.HasMoreData()); EXPECT_EQ(strings, strings_out); } TEST(DBusUtils, ArrayOfInt64) { std::unique_ptr message = Response::CreateEmpty(); MessageWriter writer(message.get()); std::vector values{-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, std::numeric_limits::min(), std::numeric_limits::max()}; AppendValueToWriter(&writer, values); EXPECT_EQ("ax", message->GetSignature()); MessageReader reader(message.get()); std::vector values_out; EXPECT_TRUE(PopValueFromReader(&reader, &values_out)); EXPECT_FALSE(reader.HasMoreData()); EXPECT_EQ(values, values_out); } TEST(DBusUtils, ArrayOfObjectPaths) { std::unique_ptr message = Response::CreateEmpty(); MessageWriter writer(message.get()); std::vector object_paths{ ObjectPath("/object/path/1"), ObjectPath("/object/path/2"), ObjectPath("/object/path/3"), }; AppendValueToWriter(&writer, object_paths); EXPECT_EQ("ao", message->GetSignature()); MessageReader reader(message.get()); std::vector object_paths_out; EXPECT_TRUE(PopValueFromReader(&reader, &object_paths_out)); EXPECT_FALSE(reader.HasMoreData()); EXPECT_EQ(object_paths, object_paths_out); } TEST(DBusUtils, ArraysAsVariant) { std::unique_ptr message = Response::CreateEmpty(); MessageWriter writer(message.get()); std::vector int_array{1, 2, 3}; std::vector str_array{"foo", "bar", "baz"}; std::vector dbl_array_empty{}; std::map dict_ss{{"k1", "v1"}, {"k2", "v2"}}; VariantDictionary dict_sv{{"k1", 1}, {"k2", "v2"}}; using ComplexStructArray = std::vector>>; ComplexStructArray complex_struct_array{ {123, true, {0xaa, 0xbb, 0xcc}}, {456, false, {0xdd}}, {789, false, {}}, }; AppendValueToWriterAsVariant(&writer, int_array); AppendValueToWriterAsVariant(&writer, str_array); AppendValueToWriterAsVariant(&writer, dbl_array_empty); AppendValueToWriterAsVariant(&writer, dict_ss); AppendValueToWriterAsVariant(&writer, dict_sv); AppendValueToWriterAsVariant(&writer, complex_struct_array); EXPECT_EQ("vvvvvv", message->GetSignature()); Any int_array_out; Any str_array_out; Any dbl_array_out; Any dict_ss_out; Any dict_sv_out; Any complex_struct_array_out; MessageReader reader(message.get()); EXPECT_TRUE(PopValueFromReader(&reader, &int_array_out)); EXPECT_TRUE(PopValueFromReader(&reader, &str_array_out)); EXPECT_TRUE(PopValueFromReader(&reader, &dbl_array_out)); EXPECT_TRUE(PopValueFromReader(&reader, &dict_ss_out)); EXPECT_TRUE(PopValueFromReader(&reader, &dict_sv_out)); EXPECT_TRUE(PopValueFromReader(&reader, &complex_struct_array_out)); EXPECT_FALSE(reader.HasMoreData()); EXPECT_EQ(int_array, int_array_out.Get>()); EXPECT_EQ(str_array, str_array_out.Get>()); EXPECT_EQ(dbl_array_empty, dbl_array_out.Get>()); EXPECT_EQ(dict_ss, (dict_ss_out.Get>())); EXPECT_EQ(dict_sv["k1"].Get(), dict_sv_out.Get().at("k1").Get()); EXPECT_EQ(dict_sv["k2"].Get(), dict_sv_out.Get().at("k2").Get()); EXPECT_EQ(complex_struct_array, complex_struct_array_out.Get()); } TEST(DBusUtils, StructsAsVariant) { std::unique_ptr message = Response::CreateEmpty(); MessageWriter writer(message.get()); VariantDictionary dict_sv{{"k1", 1}, {"k2", "v2"}}; std::tuple u32_dict_sv_struct = std::make_tuple(1, dict_sv); AppendValueToWriterAsVariant(&writer, u32_dict_sv_struct); EXPECT_EQ("v", message->GetSignature()); Any u32_dict_sv_struct_out_any; MessageReader reader(message.get()); EXPECT_TRUE(PopValueFromReader(&reader, &u32_dict_sv_struct_out_any)); EXPECT_FALSE(reader.HasMoreData()); auto u32_dict_sv_struct_out = u32_dict_sv_struct_out_any.Get>(); EXPECT_EQ(std::get<0>(u32_dict_sv_struct), std::get<0>(u32_dict_sv_struct_out)); VariantDictionary dict_sv_out = std::get<1>(u32_dict_sv_struct_out); EXPECT_EQ(dict_sv.size(), dict_sv_out.size()); EXPECT_EQ(dict_sv["k1"].Get(), dict_sv_out["k1"].Get()); EXPECT_EQ(dict_sv["k2"].Get(), dict_sv_out["k2"].Get()); } TEST(DBusUtils, VariantDictionary) { std::unique_ptr message = Response::CreateEmpty(); MessageWriter writer(message.get()); VariantDictionary values{ {"key1", uint8_t{10}}, {"key2", bool{true}}, {"key3", int16_t{12}}, {"key4", uint16_t{13}}, {"key5", int32_t{14}}, {"key6", uint32_t{15}}, {"key7", int64_t{16}}, {"key8", uint64_t{17}}, {"key9", double{18.5}}, {"keyA", std::string{"data"}}, {"keyB", ObjectPath{"/obj/path"}}, }; AppendValueToWriter(&writer, values); EXPECT_EQ("a{sv}", message->GetSignature()); MessageReader reader(message.get()); VariantDictionary values_out; EXPECT_TRUE(PopValueFromReader(&reader, &values_out)); EXPECT_FALSE(reader.HasMoreData()); EXPECT_EQ(values.size(), values_out.size()); EXPECT_EQ(values["key1"].Get(), values_out["key1"].Get()); EXPECT_EQ(values["key2"].Get(), values_out["key2"].Get()); EXPECT_EQ(values["key3"].Get(), values_out["key3"].Get()); EXPECT_EQ(values["key4"].Get(), values_out["key4"].Get()); EXPECT_EQ(values["key5"].Get(), values_out["key5"].Get()); EXPECT_EQ(values["key6"].Get(), values_out["key6"].Get()); EXPECT_EQ(values["key7"].Get(), values_out["key7"].Get()); EXPECT_EQ(values["key8"].Get(), values_out["key8"].Get()); EXPECT_EQ(values["key9"].Get(), values_out["key9"].Get()); EXPECT_EQ(values["keyA"].Get(), values_out["keyA"].Get()); EXPECT_EQ(values["keyB"].Get(), values_out["keyB"].Get()); } TEST(DBusUtils, StringToStringMap) { std::unique_ptr message = Response::CreateEmpty(); MessageWriter writer(message.get()); std::map values{ {"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}, {"key4", "value4"}, {"key5", "value5"}, }; AppendValueToWriter(&writer, values); EXPECT_EQ("a{ss}", message->GetSignature()); MessageReader reader(message.get()); std::map values_out; EXPECT_TRUE(PopValueFromReader(&reader, &values_out)); EXPECT_FALSE(reader.HasMoreData()); EXPECT_EQ(values, values_out); } TEST(DBusUtils, Pair) { std::unique_ptr message = Response::CreateEmpty(); MessageWriter writer(message.get()); std::pair struct1{"value2", 3}; AppendValueToWriter(&writer, struct1); std::pair> struct2{1, {2, 3}}; AppendValueToWriter(&writer, struct2); EXPECT_EQ("(si)(i(ii))", message->GetSignature()); std::pair struct1_out; std::pair> struct2_out; MessageReader reader(message.get()); EXPECT_TRUE(PopValueFromReader(&reader, &struct1_out)); EXPECT_TRUE(PopValueFromReader(&reader, &struct2_out)); EXPECT_FALSE(reader.HasMoreData()); EXPECT_EQ(struct1, struct1_out); EXPECT_EQ(struct2, struct2_out); } TEST(DBusUtils, Tuple) { std::unique_ptr message = Response::CreateEmpty(); MessageWriter writer(message.get()); std::tuple struct1{"value2", 3}; AppendValueToWriter(&writer, struct1); std::tuple>> struct2{ 1, "a", {{2, 3}} }; AppendValueToWriter(&writer, struct2); EXPECT_EQ("(si)(isa(ii))", message->GetSignature()); std::tuple struct1_out; std::tuple>> struct2_out; MessageReader reader(message.get()); EXPECT_TRUE(PopValueFromReader(&reader, &struct1_out)); EXPECT_TRUE(PopValueFromReader(&reader, &struct2_out)); EXPECT_FALSE(reader.HasMoreData()); EXPECT_EQ(struct1, struct1_out); EXPECT_EQ(struct2, struct2_out); } TEST(DBusUtils, ReinterpretVariant) { std::unique_ptr message = Response::CreateEmpty(); MessageWriter writer(message.get()); std::vector str_array{"foo", "bar", "baz"}; std::map dict_ss{{"k1", "v1"}, {"k2", "v2"}}; VariantDictionary dict_sv{{"k1", "v1"}, {"k2", "v2"}}; AppendValueToWriterAsVariant(&writer, 123); AppendValueToWriterAsVariant(&writer, str_array); AppendValueToWriterAsVariant(&writer, 1.7); AppendValueToWriterAsVariant(&writer, dict_ss); AppendValueToWriter(&writer, dict_sv); EXPECT_EQ("vvvva{sv}", message->GetSignature()); int int_out = 0; std::vector str_array_out; double dbl_out = 0.0; std::map dict_ss_out; std::map dict_ss_out2; MessageReader reader(message.get()); EXPECT_TRUE(PopValueFromReader(&reader, &int_out)); EXPECT_TRUE(PopValueFromReader(&reader, &str_array_out)); EXPECT_TRUE(PopValueFromReader(&reader, &dbl_out)); EXPECT_TRUE(PopValueFromReader(&reader, &dict_ss_out)); EXPECT_TRUE(PopValueFromReader(&reader, &dict_ss_out2)); // Read "a{sv}" as "a{ss}". EXPECT_FALSE(reader.HasMoreData()); EXPECT_EQ(123, int_out); EXPECT_EQ(str_array, str_array_out); EXPECT_DOUBLE_EQ(1.7, dbl_out); EXPECT_EQ(dict_ss, dict_ss_out); EXPECT_EQ(dict_ss, dict_ss_out2); } // Test handling of custom data types. struct Person { std::string first_name; std::string last_name; int age; // Provide == operator so we can easily compare arrays of Person. bool operator==(const Person& rhs) const { return first_name == rhs.first_name && last_name == rhs.last_name && age == rhs.age; } }; // Overload AppendValueToWriter() for "Person" structure. void AppendValueToWriter(dbus::MessageWriter* writer, const Person& value) { dbus::MessageWriter struct_writer(nullptr); writer->OpenStruct(&struct_writer); AppendValueToWriter(&struct_writer, value.first_name); AppendValueToWriter(&struct_writer, value.last_name); AppendValueToWriter(&struct_writer, value.age); writer->CloseContainer(&struct_writer); } // Overload PopValueFromReader() for "Person" structure. bool PopValueFromReader(dbus::MessageReader* reader, Person* value) { dbus::MessageReader variant_reader(nullptr); dbus::MessageReader struct_reader(nullptr); if (!details::DescendIntoVariantIfPresent(&reader, &variant_reader) || !reader->PopStruct(&struct_reader)) return false; return PopValueFromReader(&struct_reader, &value->first_name) && PopValueFromReader(&struct_reader, &value->last_name) && PopValueFromReader(&struct_reader, &value->age); } // Specialize DBusType for "Person" structure. template<> struct DBusType { inline static std::string GetSignature() { return GetStructDBusSignature(); } inline static void Write(dbus::MessageWriter* writer, const Person& value) { AppendValueToWriter(writer, value); } inline static bool Read(dbus::MessageReader* reader, Person* value) { return PopValueFromReader(reader, value); } }; TEST(DBusUtils, CustomStruct) { std::unique_ptr message = Response::CreateEmpty(); MessageWriter writer(message.get()); std::vector people{{"John", "Doe", 32}, {"Jane", "Smith", 48}}; AppendValueToWriter(&writer, people); AppendValueToWriterAsVariant(&writer, people); AppendValueToWriterAsVariant(&writer, people); EXPECT_EQ("a(ssi)vv", message->GetSignature()); std::vector people_out1; std::vector people_out2; std::vector people_out3; MessageReader reader(message.get()); EXPECT_TRUE(PopValueFromReader(&reader, &people_out1)); EXPECT_TRUE(PopValueFromReader(&reader, &people_out2)); EXPECT_TRUE(PopVariantValueFromReader(&reader, &people_out3)); EXPECT_FALSE(reader.HasMoreData()); EXPECT_EQ(people, people_out1); EXPECT_EQ(people, people_out2); EXPECT_EQ(people, people_out3); } TEST(DBusUtils, CustomStructInComplexTypes) { std::unique_ptr message = Response::CreateEmpty(); MessageWriter writer(message.get()); std::vector people{{"John", "Doe", 32}, {"Jane", "Smith", 48}}; std::vector> data{ { {1, Person{"John", "Doe", 32}}, {2, Person{"Jane", "Smith", 48}}, } }; AppendValueToWriter(&writer, data); EXPECT_EQ("aa{i(ssi)}", message->GetSignature()); std::vector> data_out; MessageReader reader(message.get()); EXPECT_TRUE(PopValueFromReader(&reader, &data_out)); EXPECT_FALSE(reader.HasMoreData()); EXPECT_EQ(data, data_out); } TEST(DBusUtils, EmptyVariant) { std::unique_ptr message = Response::CreateEmpty(); MessageWriter writer(message.get()); EXPECT_DEATH(AppendValueToWriter(&writer, Any{}), "Must not be called on an empty Any"); } TEST(DBusUtils, IncompatibleVariant) { std::unique_ptr message = Response::CreateEmpty(); MessageWriter writer(message.get()); EXPECT_DEATH(AppendValueToWriter(&writer, Any{2.2f}), "Type 'float' is not supported by D-Bus"); } TEST(DBusUtils, Protobuf) { std::unique_ptr message = Response::CreateEmpty(); MessageWriter writer(message.get()); dbus_utils_test::TestMessage test_message; test_message.set_foo(123); test_message.set_bar("abcd"); AppendValueToWriter(&writer, test_message); EXPECT_EQ("ay", message->GetSignature()); dbus_utils_test::TestMessage test_message_out; MessageReader reader(message.get()); EXPECT_TRUE(PopValueFromReader(&reader, &test_message_out)); EXPECT_FALSE(reader.HasMoreData()); EXPECT_EQ(123, test_message_out.foo()); EXPECT_EQ("abcd", test_message_out.bar()); } } // namespace dbus_utils } // namespace brillo