aboutsummaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/binder_constants.cc23
-rw-r--r--common/binder_constants.h26
-rw-r--r--common/binder_utils.cc65
-rw-r--r--common/binder_utils.h63
-rw-r--r--common/data_conversion.cc263
-rw-r--r--common/data_conversion.h38
-rw-r--r--common/data_conversion_unittest.cc200
7 files changed, 678 insertions, 0 deletions
diff --git a/common/binder_constants.cc b/common/binder_constants.cc
new file mode 100644
index 0000000..b17962b
--- /dev/null
+++ b/common/binder_constants.cc
@@ -0,0 +1,23 @@
+// Copyright 2016 The Android Open Source Project
+//
+// 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 "common/binder_constants.h"
+
+namespace weaved {
+namespace binder {
+
+const char kWeaveServiceName[] = "weave_service";
+
+} // namespace binder
+} // namespace weaved
diff --git a/common/binder_constants.h b/common/binder_constants.h
new file mode 100644
index 0000000..82935cd
--- /dev/null
+++ b/common/binder_constants.h
@@ -0,0 +1,26 @@
+// Copyright 2016 The Android Open Source Project
+//
+// 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.
+
+#ifndef COMMON_BINDER_CONSTANTS_H_
+#define COMMON_BINDER_CONSTANTS_H_
+
+namespace weaved {
+namespace binder {
+
+extern const char kWeaveServiceName[];
+
+} // namespace binder
+} // namespace weaved
+
+#endif // COMMON_BINDER_CONSTANTS_H_
diff --git a/common/binder_utils.cc b/common/binder_utils.cc
new file mode 100644
index 0000000..6f66040
--- /dev/null
+++ b/common/binder_utils.cc
@@ -0,0 +1,65 @@
+// Copyright 2016 The Android Open Source Project
+//
+// 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 "common/binder_utils.h"
+
+#include <base/json/json_reader.h>
+#include <base/json/json_writer.h>
+
+namespace weaved {
+namespace binder_utils {
+
+android::binder::Status ToStatus(bool success, weave::ErrorPtr* error) {
+ if (success)
+ return android::binder::Status::ok();
+ return android::binder::Status::fromServiceSpecificError(
+ 1, android::String8{error->get()->GetMessage().c_str()});
+}
+
+bool StatusToError(android::binder::Status status, brillo::ErrorPtr* error) {
+ if (status.isOk())
+ return true;
+ brillo::Error::AddTo(error, FROM_HERE, "binder",
+ std::to_string(status.exceptionCode()),
+ status.exceptionMessage().string());
+ return false;
+}
+
+android::String16 ToString16(const base::Value& value) {
+ std::string json;
+ base::JSONWriter::Write(value, &json);
+ return ToString16(json);
+}
+
+android::binder::Status ParseDictionary(
+ const android::String16& json,
+ std::unique_ptr<base::DictionaryValue>* dict) {
+ int error = 0;
+ std::string message;
+ std::unique_ptr<base::Value> value{
+ base::JSONReader::ReadAndReturnError(ToString(json), base::JSON_PARSE_RFC,
+ &error, &message)
+ .release()};
+ base::DictionaryValue* dict_value = nullptr;
+ if (!value || !value->GetAsDictionary(&dict_value)) {
+ return android::binder::Status::fromServiceSpecificError(
+ error, android::String8{message.c_str()});
+ }
+ dict->reset(dict_value);
+ value.release(); // |dict| now owns the object.
+ return android::binder::Status::ok();
+}
+
+} // namespace binder_utils
+} // namespace weaved
diff --git a/common/binder_utils.h b/common/binder_utils.h
new file mode 100644
index 0000000..65b462d
--- /dev/null
+++ b/common/binder_utils.h
@@ -0,0 +1,63 @@
+// Copyright 2016 The Android Open Source Project
+//
+// 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.
+
+#ifndef COMMON_BINDER_UTILS_H_
+#define COMMON_BINDER_UTILS_H_
+
+#include <memory>
+#include <string>
+
+#include <base/values.h>
+#include <binder/Status.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include <weave/error.h>
+#include <brillo/errors/error.h>
+
+namespace weaved {
+namespace binder_utils {
+
+// Converts the result of weave API call into a binder Status object.
+// If |success| is true, return binder::Status::ok(), otherwise the method
+// constructs a service-specific failure status with an error message obtained
+// from the |error| object.
+android::binder::Status ToStatus(bool success, weave::ErrorPtr* error);
+
+// Converts a binder status code to a Brillo error object. Returns true if the
+// status was isOk(), otherwise returns false and provides error information
+// in the |error| object.
+bool StatusToError(android::binder::Status status, brillo::ErrorPtr* error);
+
+// Converts binder's UTF16 string into a regular UTF8-encoded standard string.
+inline std::string ToString(const android::String16& value) {
+ return android::String8{value}.string();
+}
+
+// Converts regular UTF8-encoded standard string into a binder's UTF16 string.
+inline android::String16 ToString16(const std::string& value) {
+ return android::String16{value.c_str()};
+}
+
+// Serializes a dictionary to a string for transferring over binder.
+android::String16 ToString16(const base::Value& value);
+
+// De-serializes a dictionary from a binder string.
+android::binder::Status ParseDictionary(
+ const android::String16& json,
+ std::unique_ptr<base::DictionaryValue>* dict);
+
+} // namespace binder_utils
+} // namespace weaved
+
+#endif // COMMON_BINDER_UTILS_H_
diff --git a/common/data_conversion.cc b/common/data_conversion.cc
new file mode 100644
index 0000000..fd20ad4
--- /dev/null
+++ b/common/data_conversion.cc
@@ -0,0 +1,263 @@
+// Copyright 2015 The Android Open Source Project
+//
+// 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 "common/data_conversion.h"
+
+#include <string>
+#include <vector>
+
+#include <brillo/type_name_undecorate.h>
+
+namespace weaved {
+
+namespace {
+
+// Helpers for JsonToAny().
+template <typename T>
+brillo::Any ValueToAny(const base::Value& json,
+ bool (base::Value::*fnc)(T*) const) {
+ T val;
+ CHECK((json.*fnc)(&val));
+ return val;
+}
+
+brillo::Any ValueToAny(const base::Value& json);
+
+template <typename T>
+brillo::Any ListToAny(const base::ListValue& list,
+ bool (base::Value::*fnc)(T*) const) {
+ std::vector<T> result;
+ result.reserve(list.GetSize());
+ for (const base::Value* v : list) {
+ T val;
+ CHECK((v->*fnc)(&val));
+ result.push_back(val);
+ }
+ return result;
+}
+
+brillo::Any DictListToAny(const base::ListValue& list) {
+ std::vector<brillo::VariantDictionary> result;
+ result.reserve(list.GetSize());
+ for (const base::Value* v : list) {
+ const base::DictionaryValue* dict = nullptr;
+ CHECK(v->GetAsDictionary(&dict));
+ result.push_back(details::DictionaryValueToVariantDictionary(*dict));
+ }
+ return result;
+}
+
+brillo::Any ListListToAny(const base::ListValue& list) {
+ std::vector<brillo::Any> result;
+ result.reserve(list.GetSize());
+ for (const base::Value* v : list)
+ result.push_back(ValueToAny(*v));
+ return result;
+}
+
+// Converts a JSON value into an Any so it can be sent over D-Bus using
+// UpdateState D-Bus method from Buffet.
+brillo::Any ValueToAny(const base::Value& json) {
+ brillo::Any prop_value;
+ switch (json.GetType()) {
+ case base::Value::TYPE_BOOLEAN:
+ prop_value = ValueToAny<bool>(json, &base::Value::GetAsBoolean);
+ break;
+ case base::Value::TYPE_INTEGER:
+ prop_value = ValueToAny<int>(json, &base::Value::GetAsInteger);
+ break;
+ case base::Value::TYPE_DOUBLE:
+ prop_value = ValueToAny<double>(json, &base::Value::GetAsDouble);
+ break;
+ case base::Value::TYPE_STRING:
+ prop_value = ValueToAny<std::string>(json, &base::Value::GetAsString);
+ break;
+ case base::Value::TYPE_DICTIONARY: {
+ const base::DictionaryValue* dict = nullptr;
+ CHECK(json.GetAsDictionary(&dict));
+ prop_value = details::DictionaryValueToVariantDictionary(*dict);
+ break;
+ }
+ case base::Value::TYPE_LIST: {
+ const base::ListValue* list = nullptr;
+ CHECK(json.GetAsList(&list));
+ if (list->empty()) {
+ // We don't know type of objects this list intended for, so we just use
+ // vector<brillo::Any>.
+ prop_value = ListListToAny(*list);
+ break;
+ }
+ auto type = (*list->begin())->GetType();
+ for (const base::Value* v : *list)
+ CHECK_EQ(v->GetType(), type) << "Unsupported different type elements";
+
+ switch (type) {
+ case base::Value::TYPE_BOOLEAN:
+ prop_value = ListToAny<bool>(*list, &base::Value::GetAsBoolean);
+ break;
+ case base::Value::TYPE_INTEGER:
+ prop_value = ListToAny<int>(*list, &base::Value::GetAsInteger);
+ break;
+ case base::Value::TYPE_DOUBLE:
+ prop_value = ListToAny<double>(*list, &base::Value::GetAsDouble);
+ break;
+ case base::Value::TYPE_STRING:
+ prop_value = ListToAny<std::string>(*list, &base::Value::GetAsString);
+ break;
+ case base::Value::TYPE_DICTIONARY:
+ prop_value = DictListToAny(*list);
+ break;
+ case base::Value::TYPE_LIST:
+ // We can't support Any{vector<vector<>>} as the type is only known
+ // in runtime when we need to instantiate templates in compile time.
+ // We can use Any{vector<Any>} instead.
+ prop_value = ListListToAny(*list);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported JSON value type for list element: "
+ << (*list->begin())->GetType();
+ }
+ break;
+ }
+ default:
+ LOG(FATAL) << "Unexpected JSON value type: " << json.GetType();
+ break;
+ }
+ return prop_value;
+}
+
+template <typename T>
+std::unique_ptr<base::Value> CreateValue(const T& value,
+ brillo::ErrorPtr* error) {
+ return std::unique_ptr<base::Value>{new base::FundamentalValue{value}};
+}
+
+std::unique_ptr<base::Value> CreateValue(const std::string& value,
+ brillo::ErrorPtr* error) {
+ return std::unique_ptr<base::Value>{new base::StringValue{value}};
+}
+
+std::unique_ptr<base::Value> CreateValue(const char* value,
+ brillo::ErrorPtr* error) {
+ return std::unique_ptr<base::Value>{new base::StringValue{value}};
+}
+
+template <>
+std::unique_ptr<base::Value> CreateValue<brillo::VariantDictionary>(
+ const brillo::VariantDictionary& value,
+ brillo::ErrorPtr* error) {
+ return details::VariantDictionaryToDictionaryValue(value, error);
+}
+
+template <typename T>
+std::unique_ptr<base::ListValue> CreateListValue(const std::vector<T>& value,
+ brillo::ErrorPtr* error) {
+ std::unique_ptr<base::ListValue> list{new base::ListValue};
+
+ for (const T& i : value) {
+ auto item = CreateValue(i, error);
+ if (!item)
+ return nullptr;
+ list->Append(item.release());
+ }
+
+ return list;
+}
+
+// Returns false only in case of error. True can be returned if type is not
+// matched.
+template <typename T>
+bool TryCreateValue(const brillo::Any& any,
+ std::unique_ptr<base::Value>* value,
+ brillo::ErrorPtr* error) {
+ if (any.IsTypeCompatible<T>()) {
+ *value = CreateValue(any.Get<T>(), error);
+ return *value != nullptr;
+ }
+
+ if (any.IsTypeCompatible<std::vector<T>>()) {
+ *value = CreateListValue(any.Get<std::vector<T>>(), error);
+ return *value != nullptr;
+ }
+
+ return true; // Not an error, we will try different type.
+}
+
+template <>
+std::unique_ptr<base::Value> CreateValue<brillo::Any>(
+ const brillo::Any& any,
+ brillo::ErrorPtr* error) {
+ std::unique_ptr<base::Value> result;
+ if (!TryCreateValue<bool>(any, &result, error) || result)
+ return result;
+
+ if (!TryCreateValue<int>(any, &result, error) || result)
+ return result;
+
+ if (!TryCreateValue<double>(any, &result, error) || result)
+ return result;
+
+ if (!TryCreateValue<std::string>(any, &result, error) || result)
+ return result;
+
+ if (any.IsTypeCompatible<const char*>())
+ return CreateValue(any.Get<const char*>(), error);
+
+ if (!TryCreateValue<brillo::VariantDictionary>(any, &result, error) ||
+ result) {
+ return result;
+ }
+
+ // This will collapse Any{Any{T}} and vector{Any{T}}.
+ if (!TryCreateValue<brillo::Any>(any, &result, error) || result)
+ return result;
+
+ brillo::Error::AddToPrintf(
+ error, FROM_HERE, "buffet", "unknown_type", "Type '%s' is not supported.",
+ any.GetUndecoratedTypeName().c_str());
+
+ return nullptr;
+}
+
+} // namespace
+
+namespace details {
+
+brillo::VariantDictionary DictionaryValueToVariantDictionary(
+ const base::DictionaryValue& object) {
+ brillo::VariantDictionary result;
+
+ for (base::DictionaryValue::Iterator it(object); !it.IsAtEnd(); it.Advance())
+ result.emplace(it.key(), ValueToAny(it.value()));
+
+ return result;
+}
+
+std::unique_ptr<base::DictionaryValue> VariantDictionaryToDictionaryValue(
+ const brillo::VariantDictionary& object,
+ brillo::ErrorPtr* error) {
+ std::unique_ptr<base::DictionaryValue> result{new base::DictionaryValue};
+
+ for (const auto& pair : object) {
+ auto value = CreateValue(pair.second, error);
+ if (!value)
+ return nullptr;
+ result->Set(pair.first, value.release());
+ }
+
+ return result;
+}
+
+} // namespace details
+} // namespace weaved
diff --git a/common/data_conversion.h b/common/data_conversion.h
new file mode 100644
index 0000000..accc520
--- /dev/null
+++ b/common/data_conversion.h
@@ -0,0 +1,38 @@
+// Copyright 2015 The Android Open Source Project
+//
+// 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.
+
+#ifndef COMMON_DATA_CONVERSION_H_
+#define COMMON_DATA_CONVERSION_H_
+
+#include <base/values.h>
+#include <brillo/any.h>
+#include <brillo/errors/error.h>
+#include <brillo/variant_dictionary.h>
+
+namespace weaved {
+namespace details {
+
+// Converts DictionaryValue to variant dictionary.
+brillo::VariantDictionary DictionaryValueToVariantDictionary(
+ const base::DictionaryValue& object);
+
+// Converts variant dictionary to DictionaryValue.
+std::unique_ptr<base::DictionaryValue> VariantDictionaryToDictionaryValue(
+ const brillo::VariantDictionary& object,
+ brillo::ErrorPtr* error);
+
+} // namespace details
+} // namespace weaved
+
+#endif // COMMON_DATA_CONVERSION_H_
diff --git a/common/data_conversion_unittest.cc b/common/data_conversion_unittest.cc
new file mode 100644
index 0000000..832fffb
--- /dev/null
+++ b/common/data_conversion_unittest.cc
@@ -0,0 +1,200 @@
+// Copyright 2015 The Android Open Source Project
+//
+// 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 "common/data_conversion.h"
+
+#include <limits>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <base/guid.h>
+#include <base/rand_util.h>
+#include <base/values.h>
+#include <brillo/variant_dictionary.h>
+#include <gtest/gtest.h>
+#include <weave/test/unittest_utils.h>
+
+namespace weaved {
+
+namespace {
+
+using brillo::Any;
+using brillo::VariantDictionary;
+using weave::test::CreateDictionaryValue;
+using weave::test::IsEqualValue;
+
+brillo::VariantDictionary ToVariant(const base::DictionaryValue& object) {
+ return details::DictionaryValueToVariantDictionary(object);
+}
+
+std::unique_ptr<base::DictionaryValue> FromVariant(
+ const brillo::VariantDictionary& object) {
+ brillo::ErrorPtr error;
+ auto result = details::VariantDictionaryToDictionaryValue(object, &error);
+ EXPECT_TRUE(result || error);
+ return result;
+}
+
+std::unique_ptr<base::Value> CreateRandomValue(int children);
+std::unique_ptr<base::Value> CreateRandomValue(int children,
+ base::Value::Type type);
+
+const base::Value::Type kRandomTypes[] = {
+ base::Value::TYPE_BOOLEAN, base::Value::TYPE_INTEGER,
+ base::Value::TYPE_DOUBLE, base::Value::TYPE_STRING,
+ base::Value::TYPE_DICTIONARY, base::Value::TYPE_LIST,
+};
+
+const base::Value::Type kRandomTypesWithChildren[] = {
+ base::Value::TYPE_DICTIONARY, base::Value::TYPE_LIST,
+};
+
+base::Value::Type CreateRandomValueType(bool with_children) {
+ if (with_children) {
+ return kRandomTypesWithChildren[base::RandInt(
+ 0, arraysize(kRandomTypesWithChildren) - 1)];
+ }
+ return kRandomTypes[base::RandInt(0, arraysize(kRandomTypes) - 1)];
+}
+
+std::unique_ptr<base::DictionaryValue> CreateRandomDictionary(int children) {
+ std::unique_ptr<base::DictionaryValue> result{new base::DictionaryValue};
+
+ while (children > 0) {
+ int sub_children = base::RandInt(1, children);
+ children -= sub_children;
+ result->Set(base::GenerateGUID(),
+ CreateRandomValue(sub_children).release());
+ }
+
+ return result;
+}
+
+std::unique_ptr<base::ListValue> CreateRandomList(int children) {
+ std::unique_ptr<base::ListValue> result{new base::ListValue};
+
+ base::Value::Type type = CreateRandomValueType(children > 0);
+ while (children > 0) {
+ size_t max_children =
+ (type != base::Value::TYPE_DICTIONARY && type != base::Value::TYPE_LIST)
+ ? 1
+ : children;
+ size_t sub_children = base::RandInt(1, max_children);
+ children -= sub_children;
+ result->Append(CreateRandomValue(sub_children, type).release());
+ }
+
+ return result;
+}
+
+std::unique_ptr<base::Value> CreateRandomValue(int children,
+ base::Value::Type type) {
+ CHECK_GE(children, 1);
+ switch (type) {
+ case base::Value::TYPE_INTEGER:
+ return std::unique_ptr<base::Value>{new base::FundamentalValue{
+ base::RandInt(std::numeric_limits<int>::min(),
+ std::numeric_limits<int>::max())}};
+ case base::Value::TYPE_DOUBLE:
+ return std::unique_ptr<base::Value>{
+ new base::FundamentalValue{base::RandDouble()}};
+ case base::Value::TYPE_STRING:
+ return std::unique_ptr<base::Value>{
+ new base::StringValue{base::GenerateGUID()}};
+ case base::Value::TYPE_DICTIONARY:
+ CHECK_GE(children, 1);
+ return CreateRandomDictionary(children - 1);
+ case base::Value::TYPE_LIST:
+ CHECK_GE(children, 1);
+ return CreateRandomList(children - 1);
+ default:
+ return std::unique_ptr<base::Value>{
+ new base::FundamentalValue{base::RandInt(0, 1) != 0}};
+ }
+}
+
+std::unique_ptr<base::Value> CreateRandomValue(int children) {
+ return CreateRandomValue(children, CreateRandomValueType(children > 0));
+}
+
+} // namespace
+
+TEST(DBusConversionTest, DictionaryToDBusVariantDictionary) {
+ EXPECT_EQ((VariantDictionary{{"bool", true}}),
+ ToVariant(*CreateDictionaryValue("{'bool': true}")));
+ EXPECT_EQ((VariantDictionary{{"int", 5}}),
+ ToVariant(*CreateDictionaryValue("{'int': 5}")));
+ EXPECT_EQ((VariantDictionary{{"double", 6.7}}),
+ ToVariant(*CreateDictionaryValue("{'double': 6.7}")));
+ EXPECT_EQ((VariantDictionary{{"string", std::string{"abc"}}}),
+ ToVariant(*CreateDictionaryValue("{'string': 'abc'}")));
+ EXPECT_EQ((VariantDictionary{{"object", VariantDictionary{{"bool", true}}}}),
+ ToVariant(*CreateDictionaryValue("{'object': {'bool': true}}")));
+ EXPECT_EQ((VariantDictionary{{"emptyList", std::vector<Any>{}}}),
+ ToVariant(*CreateDictionaryValue("{'emptyList': []}")));
+ EXPECT_EQ((VariantDictionary{{"intList", std::vector<int>{5}}}),
+ ToVariant(*CreateDictionaryValue("{'intList': [5]}")));
+ EXPECT_EQ((VariantDictionary{
+ {"intListList", std::vector<Any>{std::vector<int>{5},
+ std::vector<int>{6, 7}}}}),
+ ToVariant(*CreateDictionaryValue(
+ "{'intListList': [[5], [6, 7]]}")));
+ EXPECT_EQ((VariantDictionary{{"objList",
+ std::vector<VariantDictionary>{
+ {{"string", std::string{"abc"}}}}}}),
+ ToVariant(*CreateDictionaryValue(
+ "{'objList': [{'string': 'abc'}]}")));
+}
+
+TEST(DBusConversionTest, VariantDictionaryToDictionaryValue) {
+ EXPECT_JSON_EQ("{'bool': true}", *FromVariant({{"bool", true}}));
+ EXPECT_JSON_EQ("{'int': 5}", *FromVariant({{"int", 5}}));
+ EXPECT_JSON_EQ("{'double': 6.7}", *FromVariant({{"double", 6.7}}));
+ EXPECT_JSON_EQ("{'string': 'abc'}",
+ *FromVariant({{"string", std::string{"abc"}}}));
+ EXPECT_JSON_EQ("{'object': {'bool': true}}",
+ *FromVariant({{"object", VariantDictionary{{"bool", true}}}}));
+ EXPECT_JSON_EQ("{'emptyList': []}",
+ *FromVariant({{"emptyList", std::vector<bool>{}}}));
+ EXPECT_JSON_EQ("{'intList': [5]}",
+ *FromVariant({{"intList", std::vector<int>{5}}}));
+ EXPECT_JSON_EQ(
+ "{'intListList': [[5], [6, 7]]}",
+ *FromVariant({{"intListList",
+ std::vector<Any>{std::vector<int>{5},
+ std::vector<int>{6, 7}}}}));
+ EXPECT_JSON_EQ(
+ "{'objList': [{'string': 'abc'}]}",
+ *FromVariant({{"objList", std::vector<VariantDictionary>{
+ {{"string", std::string{"abc"}}}}}}));
+ EXPECT_JSON_EQ("{'int': 5}", *FromVariant({{"int", Any{Any{5}}}}));
+}
+
+TEST(DBusConversionTest, VariantDictionaryToDictionaryValueErrors) {
+ EXPECT_FALSE(FromVariant({{"cString", "abc"}}));
+ EXPECT_FALSE(FromVariant({{"float", 1.0f}}));
+ EXPECT_FALSE(FromVariant({{"listList", std::vector<std::vector<int>>{}}}));
+ EXPECT_FALSE(FromVariant({{"any", Any{}}}));
+ EXPECT_FALSE(FromVariant({{"null", nullptr}}));
+}
+
+TEST(DBusConversionTest, DBusRandomDictionaryConversion) {
+ auto dict = CreateRandomDictionary(10000);
+ auto varian_dict = ToVariant(*dict);
+ auto dict_restored = FromVariant(varian_dict);
+ EXPECT_PRED2(IsEqualValue, *dict, *dict_restored);
+}
+
+} // namespace buffet