aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Vakulenko <avakulenko@google.com>2016-01-28 14:41:20 -0800
committerAlex Vakulenko <avakulenko@google.com>2016-01-28 14:48:39 -0800
commitb57ecfa6fbbb44522b404b13fe1e364366d5ba74 (patch)
tree3e5d469764697c79d5e53758851a29b8d8bab1f4
parenteb350bccd25b686cd669f54ca0abbcd595557a3e (diff)
downloadplatform_external_libbrillo-b57ecfa6fbbb44522b404b13fe1e364366d5ba74.tar.gz
platform_external_libbrillo-b57ecfa6fbbb44522b404b13fe1e364366d5ba74.tar.bz2
platform_external_libbrillo-b57ecfa6fbbb44522b404b13fe1e364366d5ba74.zip
libbrillo: Add base::Value conversion functions
This makes using base::Value less painful of an experience. BUG: 26558300 Change-Id: I6e202b863e049f33643c6547f9710991f2c56240
-rw-r--r--Android.mk2
-rw-r--r--brillo/value_conversion.cc60
-rw-r--r--brillo/value_conversion.h139
-rw-r--r--brillo/value_conversion_unittest.cc266
-rw-r--r--libbrillo.gypi2
5 files changed, 469 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk
index 61850a6..601ba3e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -40,6 +40,7 @@ libbrillo_core_sources := \
brillo/type_name_undecorate.cc \
brillo/url_utils.cc \
brillo/userdb_utils.cc \
+ brillo/value_conversion.cc \
libbrillo_linux_sources := \
brillo/asynchronous_signal_handler.cc \
@@ -129,6 +130,7 @@ libbrillo_test_sources := \
brillo/type_name_undecorate_unittest.cc \
brillo/unittest_utils.cc \
brillo/url_utils_unittest.cc \
+ brillo/value_conversion_unittest.cc \
libbrillo_dbus_test_sources := \
brillo/any_unittest.cc \
diff --git a/brillo/value_conversion.cc b/brillo/value_conversion.cc
new file mode 100644
index 0000000..aa5135b
--- /dev/null
+++ b/brillo/value_conversion.cc
@@ -0,0 +1,60 @@
+// 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 <brillo/value_conversion.h>
+
+#include <string>
+#include <vector>
+
+namespace brillo {
+
+bool FromValue(const base::Value& in_value,
+ std::unique_ptr<base::ListValue>* out_value) {
+ const base::ListValue* list = nullptr;
+ if (!in_value.GetAsList(&list))
+ return false;
+ out_value->reset(list->DeepCopy());
+ return true;
+}
+
+bool FromValue(const base::Value& in_value,
+ std::unique_ptr<base::DictionaryValue>* out_value) {
+ const base::DictionaryValue* dict = nullptr;
+ if (!in_value.GetAsDictionary(&dict))
+ return false;
+ out_value->reset(dict->DeepCopy());
+ return true;
+}
+
+std::unique_ptr<base::Value> ToValue(int value) {
+ return std::unique_ptr<base::Value>{new base::FundamentalValue{value}};
+}
+
+std::unique_ptr<base::Value> ToValue(bool value) {
+ return std::unique_ptr<base::Value>{new base::FundamentalValue{value}};
+}
+
+std::unique_ptr<base::Value> ToValue(double value) {
+ return std::unique_ptr<base::Value>{new base::FundamentalValue{value}};
+}
+
+std::unique_ptr<base::Value> ToValue(const char* value) {
+ return std::unique_ptr<base::Value>{new base::StringValue{value}};
+}
+
+std::unique_ptr<base::Value> ToValue(const std::string& value) {
+ return std::unique_ptr<base::Value>{new base::StringValue{value}};
+}
+
+} // namespace brillo
diff --git a/brillo/value_conversion.h b/brillo/value_conversion.h
new file mode 100644
index 0000000..820fe75
--- /dev/null
+++ b/brillo/value_conversion.h
@@ -0,0 +1,139 @@
+// 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 BRILLO_VALUE_CONVERSION_H_
+#define BRILLO_VALUE_CONVERSION_H_
+
+// This file provides a set of helper functions to convert between base::Value
+// and native types. Apart from handling standard types such as 'int' and
+// 'std::string' it also provides conversion to/from std::vector<T> (which
+// converts to Base::listValue) and std::map<std::string, T> (convertible to
+// base::DictionaryValue).
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <base/values.h>
+#include <brillo/brillo_export.h>
+
+namespace brillo {
+
+inline bool FromValue(const base::Value& in_value, bool* out_value) {
+ return in_value.GetAsBoolean(out_value);
+}
+
+inline bool FromValue(const base::Value& in_value, int* out_value) {
+ return in_value.GetAsInteger(out_value);
+}
+
+inline bool FromValue(const base::Value& in_value, double* out_value) {
+ return in_value.GetAsDouble(out_value);
+}
+
+inline bool FromValue(const base::Value& in_value, std::string* out_value) {
+ return in_value.GetAsString(out_value);
+}
+
+inline bool FromValue(const base::Value& in_value,
+ const base::ListValue** out_value) {
+ return in_value.GetAsList(out_value);
+}
+
+inline bool FromValue(const base::Value& in_value,
+ const base::DictionaryValue** out_value) {
+ return in_value.GetAsDictionary(out_value);
+}
+
+BRILLO_EXPORT bool FromValue(const base::Value& in_value,
+ std::unique_ptr<base::ListValue>* out_value);
+BRILLO_EXPORT bool FromValue(const base::Value& in_value,
+ std::unique_ptr<base::DictionaryValue>* out_value);
+
+template <typename T, typename Pred, typename Alloc>
+bool FromValue(const base::Value& in_value,
+ std::map<std::string, T, Pred, Alloc>* out_value);
+
+template <typename T, typename Alloc>
+bool FromValue(const base::Value& in_value, std::vector<T, Alloc>* out_value) {
+ const base::ListValue* list = nullptr;
+ if (!in_value.GetAsList(&list))
+ return false;
+ out_value->clear();
+ out_value->reserve(list->GetSize());
+ for (const base::Value* item : *list) {
+ T value{};
+ if (!FromValue(*item, &value))
+ return false;
+ out_value->push_back(std::move(value));
+ }
+ return true;
+}
+
+template <typename T, typename Pred, typename Alloc>
+bool FromValue(const base::Value& in_value,
+ std::map<std::string, T, Pred, Alloc>* out_value) {
+ const base::DictionaryValue* dict = nullptr;
+ if (!in_value.GetAsDictionary(&dict))
+ return false;
+ out_value->clear();
+ for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
+ if (!FromValue(it.value(), &(*out_value)[it.key()]))
+ return false;
+ }
+ return true;
+}
+
+template <typename T>
+T FromValue(const base::Value& value) {
+ T out_value{};
+ CHECK(FromValue(value, &out_value));
+ return out_value;
+}
+
+BRILLO_EXPORT std::unique_ptr<base::Value> ToValue(int value);
+BRILLO_EXPORT std::unique_ptr<base::Value> ToValue(bool value);
+BRILLO_EXPORT std::unique_ptr<base::Value> ToValue(double value);
+BRILLO_EXPORT std::unique_ptr<base::Value> ToValue(const std::string& value);
+// Implicit conversion of char* to 'bool' has precedence over the user-defined
+// std::string conversion. Override this behavior explicitly.
+BRILLO_EXPORT std::unique_ptr<base::Value> ToValue(const char* value);
+
+template <typename T, typename Pred, typename Alloc>
+std::unique_ptr<base::Value> ToValue(
+ const std::map<std::string, T, Pred, Alloc>& dictionary);
+
+template <typename T, typename Alloc>
+std::unique_ptr<base::Value> ToValue(const std::vector<T, Alloc>& list) {
+ std::unique_ptr<base::ListValue> result{new base::ListValue};
+ for (const auto& value : list) {
+ result->Append(ToValue(value).release());
+ }
+ return std::move(result);
+}
+
+template <typename T, typename Pred, typename Alloc>
+std::unique_ptr<base::Value> ToValue(
+ const std::map<std::string, T, Pred, Alloc>& dictionary) {
+ std::unique_ptr<base::DictionaryValue> result{new base::DictionaryValue};
+ for (const auto& pair : dictionary) {
+ result->Set(pair.first, ToValue(pair.second).release());
+ }
+ return std::move(result);
+}
+
+} // namespace brillo
+
+#endif // BRILLO_VALUE_CONVERSION_H_
diff --git a/brillo/value_conversion_unittest.cc b/brillo/value_conversion_unittest.cc
new file mode 100644
index 0000000..cf2afb7
--- /dev/null
+++ b/brillo/value_conversion_unittest.cc
@@ -0,0 +1,266 @@
+// 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 <brillo/value_conversion.h>
+
+#include <limits>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <base/json/json_reader.h>
+#include <base/json/json_writer.h>
+#include <gtest/gtest.h>
+
+namespace brillo {
+
+namespace {
+
+std::unique_ptr<base::Value> ParseValue(std::string json) {
+ std::replace(json.begin(), json.end(), '\'', '"');
+ std::string message;
+ std::unique_ptr<base::Value> value{
+ base::JSONReader::ReadAndReturnError(json, base::JSON_PARSE_RFC,nullptr,
+ &message)
+ .release()};
+ CHECK(value) << "Failed to load JSON: " << message << ", " << json;
+ return value;
+}
+
+inline bool IsEqualValue(const base::Value& val1, const base::Value& val2) {
+ return val1.Equals(&val2);
+}
+
+#define EXPECT_JSON_EQ(expected, actual) \
+ EXPECT_PRED2(IsEqualValue, *ParseValue(expected), actual)
+
+} // namespace
+
+TEST(ValueConversionTest, FromValueInt) {
+ int actual;
+ EXPECT_TRUE(FromValue(*ParseValue("123"), &actual));
+ EXPECT_EQ(123, actual);
+
+ EXPECT_TRUE(FromValue(*ParseValue("-123"), &actual));
+ EXPECT_EQ(-123, actual);
+
+ EXPECT_FALSE(FromValue(*ParseValue("true"), &actual));
+}
+
+TEST(ValueConversionTest, FromValueBool) {
+ bool actual;
+ EXPECT_TRUE(FromValue(*ParseValue("false"), &actual));
+ EXPECT_FALSE(actual);
+
+ EXPECT_TRUE(FromValue(*ParseValue("true"), &actual));
+ EXPECT_TRUE(actual);
+
+ EXPECT_FALSE(FromValue(*ParseValue("0"), &actual));
+ EXPECT_FALSE(FromValue(*ParseValue("1"), &actual));
+}
+
+TEST(ValueConversionTest, FromValueDouble) {
+ double actual;
+ EXPECT_TRUE(FromValue(*ParseValue("12.5"), &actual));
+ EXPECT_DOUBLE_EQ(12.5, actual);
+
+ EXPECT_TRUE(FromValue(*ParseValue("-0.1"), &actual));
+ EXPECT_DOUBLE_EQ(-0.1, actual);
+
+ EXPECT_TRUE(FromValue(*ParseValue("17"), &actual));
+ EXPECT_DOUBLE_EQ(17.0, actual);
+
+ EXPECT_FALSE(FromValue(*ParseValue("'1.0'"), &actual));
+}
+
+TEST(ValueConversionTest, FromValueString) {
+ std::string actual;
+ EXPECT_TRUE(FromValue(*ParseValue("'foo'"), &actual));
+ EXPECT_EQ("foo", actual);
+
+ EXPECT_TRUE(FromValue(*ParseValue("'bar'"), &actual));
+ EXPECT_EQ("bar", actual);
+
+ EXPECT_TRUE(FromValue(*ParseValue("''"), &actual));
+ EXPECT_TRUE(actual.empty());
+
+ EXPECT_FALSE(FromValue(*ParseValue("1"), &actual));
+}
+
+TEST(ValueConversionTest, FromValueListValue) {
+ const base::ListValue* list = nullptr;
+ auto in_value = ParseValue("[1, 2, 'foo']");
+ EXPECT_TRUE(FromValue(*in_value, &list));
+ EXPECT_JSON_EQ("[1, 2, 'foo']", *list);
+}
+
+TEST(ValueConversionTest, FromValueDictValue) {
+ const base::DictionaryValue* dict = nullptr;
+ auto in_value = ParseValue("{'foo':'bar','baz': 1}");
+ EXPECT_TRUE(FromValue(*in_value, &dict));
+ EXPECT_JSON_EQ("{'foo':'bar','baz': 1}", *dict);
+}
+
+TEST(ValueConversionTest, FromValueListValueUniquePtr) {
+ std::unique_ptr<base::ListValue> list;
+ EXPECT_TRUE(FromValue(*ParseValue("[1, 2, 'bar']"), &list));
+ EXPECT_JSON_EQ("[1, 2, 'bar']", *list);
+}
+
+TEST(ValueConversionTest, FromValueDictValueUniquePtr) {
+ std::unique_ptr<base::DictionaryValue> dict;
+ EXPECT_TRUE(FromValue(*ParseValue("{'foo':'bar','baz': 1}"), &dict));
+ EXPECT_JSON_EQ("{'foo':'bar','baz': 1}", *dict);
+}
+
+TEST(ValueConversionTest, FromValueVectorOfInt) {
+ std::vector<int> actual;
+ EXPECT_TRUE(FromValue(*ParseValue("[1, 2, 3, 4]"), &actual));
+ EXPECT_EQ((std::vector<int>{1, 2, 3, 4}), actual);
+
+ EXPECT_TRUE(FromValue(*ParseValue("[]"), &actual));
+ EXPECT_TRUE(actual.empty());
+
+ EXPECT_FALSE(FromValue(*ParseValue("[1, 2, 3, '4']"), &actual));
+}
+
+TEST(ValueConversionTest, FromValueVectorOfBool) {
+ std::vector<bool> actual;
+ EXPECT_TRUE(FromValue(*ParseValue("[true, true, false]"), &actual));
+ EXPECT_EQ((std::vector<bool>{true, true, false}), actual);
+
+ EXPECT_TRUE(FromValue(*ParseValue("[]"), &actual));
+ EXPECT_TRUE(actual.empty());
+
+ EXPECT_FALSE(FromValue(*ParseValue("[true, 0]"), &actual));
+}
+
+TEST(ValueConversionTest, FromValueVectorOfDouble) {
+ std::vector<double> actual;
+ EXPECT_TRUE(FromValue(*ParseValue("[1, 2.0, 6.5, -11.2]"), &actual));
+ EXPECT_EQ((std::vector<double>{1.0, 2.0, 6.5, -11.2}), actual);
+
+ EXPECT_TRUE(FromValue(*ParseValue("[]"), &actual));
+ EXPECT_TRUE(actual.empty());
+
+ EXPECT_FALSE(FromValue(*ParseValue("['s']"), &actual));
+}
+
+TEST(ValueConversionTest, FromValueVectorOfString) {
+ std::vector<std::string> actual;
+ EXPECT_TRUE(FromValue(*ParseValue("['', 'foo', 'bar']"), &actual));
+ EXPECT_EQ((std::vector<std::string>{"", "foo", "bar"}), actual);
+
+ EXPECT_TRUE(FromValue(*ParseValue("[]"), &actual));
+ EXPECT_TRUE(actual.empty());
+
+ EXPECT_FALSE(FromValue(*ParseValue("[100]"), &actual));
+}
+
+TEST(ValueConversionTest, FromValueVectorOfVectors) {
+ std::vector<std::vector<int>> actual;
+ EXPECT_TRUE(FromValue(*ParseValue("[[1,2], [], [3]]"), &actual));
+ EXPECT_EQ((std::vector<std::vector<int>>{{1,2}, {}, {3}}), actual);
+
+ EXPECT_TRUE(FromValue(*ParseValue("[]"), &actual));
+ EXPECT_TRUE(actual.empty());
+
+ EXPECT_FALSE(FromValue(*ParseValue("[100]"), &actual));
+}
+
+TEST(ValueConversionTest, FromValueMap) {
+ std::map<std::string, int> actual;
+ EXPECT_TRUE(FromValue(*ParseValue("{'foo':1, 'bar':2, 'baz':3}"), &actual));
+ EXPECT_EQ((std::map<std::string, int>{{"foo", 1}, {"bar", 2}, {"baz", 3}}),
+ actual);
+
+ EXPECT_TRUE(FromValue(*ParseValue("{}"), &actual));
+ EXPECT_TRUE(actual.empty());
+
+ EXPECT_FALSE(FromValue(*ParseValue("{'foo':1, 'bar':'2'}"), &actual));
+}
+
+TEST(ValueConversionTest, FromValueMapOfVectors) {
+ std::map<std::string, std::vector<int>> actual;
+ EXPECT_TRUE(FromValue(*ParseValue("{'foo':[1,2], 'bar':[]}"), &actual));
+ std::map<std::string, std::vector<int>> expected{
+ {"foo", {1, 2}}, {"bar", {}}};
+ EXPECT_EQ(expected, actual);
+
+ EXPECT_TRUE(FromValue(*ParseValue("{}"), &actual));
+ EXPECT_TRUE(actual.empty());
+
+ EXPECT_FALSE(FromValue(*ParseValue("{'foo':[1], 'bar':[2,'3']}"), &actual));
+}
+
+TEST(ValueConversionTest, FromValueVectorOfMaps) {
+ std::vector<std::map<std::string, int>> actual;
+ EXPECT_TRUE(FromValue(*ParseValue("[{'foo':1,'bar':2},{'baz':3}]"), &actual));
+ std::vector<std::map<std::string, int>> expected{
+ {{"foo", 1}, {"bar", 2}}, {{"baz", 3}}};
+ EXPECT_EQ(expected, actual);
+
+ EXPECT_TRUE(FromValue(*ParseValue("[]"), &actual));
+ EXPECT_TRUE(actual.empty());
+
+ EXPECT_FALSE(FromValue(*ParseValue("[{'foo':1}, 'bar']"), &actual));
+}
+
+TEST(ValueConversionTest, FromValueVectorOfLists) {
+ std::vector<std::unique_ptr<base::ListValue>> actual;
+ EXPECT_TRUE(FromValue(*ParseValue("[['foo',1],['bar',2],[true]]"), &actual));
+ ASSERT_EQ(3, actual.size());
+ EXPECT_JSON_EQ("['foo', 1]", *actual[0]);
+ EXPECT_JSON_EQ("['bar', 2]", *actual[1]);
+ EXPECT_JSON_EQ("[true]", *actual[2]);
+}
+
+TEST(ValueConversionTest, FromValueVectorOfDicts) {
+ std::vector<std::unique_ptr<base::DictionaryValue>> actual;
+ EXPECT_TRUE(FromValue(*ParseValue("[{'foo': 1}, {'bar': 2}]"), &actual));
+ ASSERT_EQ(2, actual.size());
+ EXPECT_JSON_EQ("{'foo': 1}", *actual[0]);
+ EXPECT_JSON_EQ("{'bar': 2}", *actual[1]);
+}
+
+TEST(ValueConversionTest, ToValueScalar) {
+ EXPECT_JSON_EQ("1234", *ToValue(1234));
+ EXPECT_JSON_EQ("true", *ToValue(true));
+ EXPECT_JSON_EQ("false", *ToValue(false));
+ EXPECT_JSON_EQ("12.5", *ToValue(12.5));
+ EXPECT_JSON_EQ("'foobar'", *ToValue("foobar"));
+}
+
+TEST(ValueConversionTest, ToValueVector) {
+ EXPECT_JSON_EQ("[1, 2, 3]", *ToValue(std::vector<int>{1, 2, 3}));
+ EXPECT_JSON_EQ("[]", *ToValue(std::vector<int>{}));
+ EXPECT_JSON_EQ("[true, false]", *ToValue(std::vector<bool>{true, false}));
+ EXPECT_JSON_EQ("['foo', 'bar']",
+ *ToValue(std::vector<std::string>{"foo", "bar"}));
+ EXPECT_JSON_EQ("[[1,2],[3]]",
+ *ToValue(std::vector<std::vector<int>>{{1, 2}, {3}}));
+}
+
+TEST(ValueConversionTest, ToValueMap) {
+ EXPECT_JSON_EQ("{'foo': 1, 'bar': 2}",
+ *ToValue(std::map<std::string, int>{{"foo", 1}, {"bar", 2}}));
+ EXPECT_JSON_EQ("{}", *ToValue(std::map<std::string, int>{}));
+ EXPECT_JSON_EQ("{'foo': true}",
+ *ToValue(std::map<std::string, bool>{{"foo", true}}));
+ EXPECT_JSON_EQ("{'foo': 1.1, 'bar': 2.2}",
+ *ToValue(std::map<std::string, double>{{"foo", 1.1},
+ {"bar", 2.2}}));
+}
+
+} // namespace brillo
diff --git a/libbrillo.gypi b/libbrillo.gypi
index f2d7882..2b5027b 100644
--- a/libbrillo.gypi
+++ b/libbrillo.gypi
@@ -89,6 +89,7 @@
'brillo/type_name_undecorate.cc',
'brillo/url_utils.cc',
'brillo/userdb_utils.cc',
+ 'brillo/value_conversion.cc',
],
},
{
@@ -360,6 +361,7 @@
'brillo/unittest_utils.cc',
'brillo/url_utils_unittest.cc',
'brillo/variant_dictionary_unittest.cc',
+ 'brillo/value_conversion_unittest.cc',
'testrunner.cc',
'<(proto_in_dir)/test.proto',
]