diff options
author | Alex Vakulenko <avakulenko@google.com> | 2016-01-29 17:08:28 +0000 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2016-01-29 17:08:28 +0000 |
commit | 022e3852c19589ca91fd6cc337db8d042041717b (patch) | |
tree | 3e5d469764697c79d5e53758851a29b8d8bab1f4 | |
parent | ea8c5257f66186c982bd54cef8f2a75889564ccf (diff) | |
parent | b57ecfa6fbbb44522b404b13fe1e364366d5ba74 (diff) | |
download | platform_external_libbrillo-022e3852c19589ca91fd6cc337db8d042041717b.tar.gz platform_external_libbrillo-022e3852c19589ca91fd6cc337db8d042041717b.tar.bz2 platform_external_libbrillo-022e3852c19589ca91fd6cc337db8d042041717b.zip |
libbrillo: Add base::Value conversion functions
am: b57ecfa6fb
* commit 'b57ecfa6fbbb44522b404b13fe1e364366d5ba74':
libbrillo: Add base::Value conversion functions
-rw-r--r-- | Android.mk | 2 | ||||
-rw-r--r-- | brillo/value_conversion.cc | 60 | ||||
-rw-r--r-- | brillo/value_conversion.h | 139 | ||||
-rw-r--r-- | brillo/value_conversion_unittest.cc | 266 | ||||
-rw-r--r-- | libbrillo.gypi | 2 |
5 files changed, 469 insertions, 0 deletions
@@ -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', ] |