diff options
author | hashimoto@chromium.org <hashimoto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-16 23:08:42 +0000 |
---|---|---|
committer | hashimoto@chromium.org <hashimoto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-16 23:08:42 +0000 |
commit | a5aae12d00dd5efc48921d180e94208841a49f35 (patch) | |
tree | b3b6e326e7b3cdcb73b378940ef0364ff496d6df /dbus | |
parent | 275c245cea2d44f7d90b2b4d17ed2c79bc6eb661 (diff) | |
download | chromium_src-a5aae12d00dd5efc48921d180e94208841a49f35.zip chromium_src-a5aae12d00dd5efc48921d180e94208841a49f35.tar.gz chromium_src-a5aae12d00dd5efc48921d180e94208841a49f35.tar.bz2 |
Add dbus::PopDataAsValue
BUG=chromium-os:16557
TEST=dbus_unittests --gtest_filter="ValuesUtilTest.*"
Review URL: http://codereview.chromium.org/9702094
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@127287 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'dbus')
-rw-r--r-- | dbus/dbus.gyp | 3 | ||||
-rw-r--r-- | dbus/values_util.cc | 185 | ||||
-rw-r--r-- | dbus/values_util.h | 25 | ||||
-rw-r--r-- | dbus/values_util_unittest.cc | 321 |
4 files changed, 534 insertions, 0 deletions
diff --git a/dbus/dbus.gyp b/dbus/dbus.gyp index 296ac53..0e30503 100644 --- a/dbus/dbus.gyp +++ b/dbus/dbus.gyp @@ -32,6 +32,8 @@ 'property.cc', 'property.h', 'scoped_dbus_error.h', + 'values_util.cc', + 'values_util.h', ], }, { @@ -88,6 +90,7 @@ 'property_unittest.cc', 'test_service.cc', 'test_service.h', + 'values_util_unittest.cc', ], 'include_dirs': [ '..', diff --git a/dbus/values_util.cc b/dbus/values_util.cc new file mode 100644 index 0000000..c422374 --- /dev/null +++ b/dbus/values_util.cc @@ -0,0 +1,185 @@ +// Copyright (c) 2012 The Chromium 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 "dbus/values_util.h" + +#include "base/json/json_writer.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/values.h" +#include "dbus/message.h" + +namespace dbus { + +namespace { + +// Returns whether |value| is exactly representable by double or not. +template<typename T> +bool IsExactlyRepresentableByDouble(T value) { + return value == static_cast<T>(static_cast<double>(value)); +} + +// Pops values from |reader| and appends them to |list_value|. +bool PopListElements(MessageReader* reader, ListValue* list_value) { + while (reader->HasMoreData()) { + Value* element_value = PopDataAsValue(reader); + if (!element_value) + return false; + list_value->Append(element_value); + } + return true; +} + +// Pops dict-entries from |reader| and sets them to |dictionary_value| +bool PopDictionaryEntries(MessageReader* reader, + DictionaryValue* dictionary_value) { + while (reader->HasMoreData()) { + DCHECK_EQ(Message::DICT_ENTRY, reader->GetDataType()); + MessageReader entry_reader(NULL); + if (!reader->PopDictEntry(&entry_reader)) + return false; + // Get key as a string. + std::string key_string; + if (entry_reader.GetDataType() == Message::STRING) { + // If the type of keys is STRING, pop it directly. + if (!entry_reader.PopString(&key_string)) + return false; + } else { + // If the type of keys is not STRING, convert it to string. + scoped_ptr<Value> key(PopDataAsValue(&entry_reader)); + if (!key.get()) + return false; + // Use JSONWriter to convert an arbitrary value to a string. + base::JSONWriter::Write(key.get(), &key_string); + } + // Get the value and set the key-value pair. + Value* value = PopDataAsValue(&entry_reader); + if (!value) + return false; + dictionary_value->Set(key_string, value); + } + return true; +} + +} // namespace + +Value* PopDataAsValue(MessageReader* reader) { + Value* result = NULL; + switch (reader->GetDataType()) { + case Message::INVALID_DATA: + // Do nothing. + break; + case Message::BYTE: { + uint8 value = 0; + if (reader->PopByte(&value)) + result = Value::CreateIntegerValue(value); + break; + } + case Message::BOOL: { + bool value = false; + if (reader->PopBool(&value)) + result = Value::CreateBooleanValue(value); + break; + } + case Message::INT16: { + int16 value = 0; + if (reader->PopInt16(&value)) + result = Value::CreateIntegerValue(value); + break; + } + case Message::UINT16: { + uint16 value = 0; + if (reader->PopUint16(&value)) + result = Value::CreateIntegerValue(value); + break; + } + case Message::INT32: { + int32 value = 0; + if (reader->PopInt32(&value)) + result = Value::CreateIntegerValue(value); + break; + } + case Message::UINT32: { + uint32 value = 0; + if (reader->PopUint32(&value)) + result = Value::CreateDoubleValue(value); + break; + } + case Message::INT64: { + int64 value = 0; + if (reader->PopInt64(&value)) { + DLOG_IF(WARNING, !IsExactlyRepresentableByDouble(value)) << + value << " is not exactly representable by double"; + result = Value::CreateDoubleValue(value); + } + break; + } + case Message::UINT64: { + uint64 value = 0; + if (reader->PopUint64(&value)) { + DLOG_IF(WARNING, !IsExactlyRepresentableByDouble(value)) << + value << " is not exactly representable by double"; + result = Value::CreateDoubleValue(value); + } + break; + } + case Message::DOUBLE: { + double value = 0; + if (reader->PopDouble(&value)) + result = Value::CreateDoubleValue(value); + break; + } + case Message::STRING: { + std::string value; + if (reader->PopString(&value)) + result = Value::CreateStringValue(value); + break; + } + case Message::OBJECT_PATH: { + ObjectPath value; + if (reader->PopObjectPath(&value)) + result = Value::CreateStringValue(value.value()); + break; + } + case Message::ARRAY: { + MessageReader sub_reader(NULL); + if (reader->PopArray(&sub_reader)) { + // If the type of the array's element is DICT_ENTRY, create a + // DictionaryValue, otherwise create a ListValue. + if (sub_reader.GetDataType() == Message::DICT_ENTRY) { + scoped_ptr<DictionaryValue> dictionary_value(new DictionaryValue); + if (PopDictionaryEntries(&sub_reader, dictionary_value.get())) + result = dictionary_value.release(); + } else { + scoped_ptr<ListValue> list_value(new ListValue); + if (PopListElements(&sub_reader, list_value.get())) + result = list_value.release(); + } + } + break; + } + case Message::STRUCT: { + MessageReader sub_reader(NULL); + if (reader->PopStruct(&sub_reader)) { + scoped_ptr<ListValue> list_value(new ListValue); + if (PopListElements(&sub_reader, list_value.get())) + result = list_value.release(); + } + break; + } + case Message::DICT_ENTRY: + // DICT_ENTRY must be popped as an element of an array. + NOTREACHED(); + break; + case Message::VARIANT: { + MessageReader sub_reader(NULL); + if (reader->PopVariant(&sub_reader)) + result = PopDataAsValue(&sub_reader); + break; + } + } + return result; +} + +} // namespace dbus diff --git a/dbus/values_util.h b/dbus/values_util.h new file mode 100644 index 0000000..cfb31a5 --- /dev/null +++ b/dbus/values_util.h @@ -0,0 +1,25 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef DBUS_VALUES_UTIL_H_ +#define DBUS_VALUES_UTIL_H_ +#pragma once + +namespace base { +class Value; +} + +namespace dbus { + +class MessageReader; + +// Pops a value from |reader| as a base::Value. +// Returns NULL if an error occurs. +// Note: Integer values larger than int32 (including uint32) are converted to +// double. Non-string diciontary keys are converted to strings. +base::Value* PopDataAsValue(MessageReader* reader); + +} // namespace dbus + +#endif // DBUS_VALUES_UTIL_H_ diff --git a/dbus/values_util_unittest.cc b/dbus/values_util_unittest.cc new file mode 100644 index 0000000..1f97cdc --- /dev/null +++ b/dbus/values_util_unittest.cc @@ -0,0 +1,321 @@ +// Copyright (c) 2012 The Chromium 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 "dbus/values_util.h" + +#include <vector> + +#include "base/float_util.h" +#include "base/json/json_writer.h" +#include "base/memory/scoped_ptr.h" +#include "base/values.h" +#include "dbus/message.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(ValuesUtilTest, PopBasicTypes) { + scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty()); + // Append basic type values. + dbus::MessageWriter writer(response.get()); + const uint8 kByteValue = 42; + writer.AppendByte(kByteValue); + const bool kBoolValue = true; + writer.AppendBool(kBoolValue); + const int16 kInt16Value = -43; + writer.AppendInt16(kInt16Value); + const uint16 kUint16Value = 44; + writer.AppendUint16(kUint16Value); + const int32 kInt32Value = -45; + writer.AppendInt32(kInt32Value); + const uint32 kUint32Value = 46; + writer.AppendUint32(kUint32Value); + const int64 kInt64Value = -47; + writer.AppendInt64(kInt64Value); + const uint64 kUint64Value = 48; + writer.AppendUint64(kUint64Value); + const double kDoubleValue = 4.9; + writer.AppendDouble(kDoubleValue); + const std::string kStringValue = "fifty"; + writer.AppendString(kStringValue); + const std::string kEmptyStringValue; + writer.AppendString(kEmptyStringValue); + const dbus::ObjectPath kObjectPathValue("ObjectPath"); + writer.AppendObjectPath(kObjectPathValue); + + dbus::MessageReader reader(response.get()); + scoped_ptr<Value> value; + // Pop a byte. + value.reset(dbus::PopDataAsValue(&reader)); + EXPECT_TRUE(value.get() != NULL); + EXPECT_TRUE(value->Equals(Value::CreateIntegerValue(kByteValue))); + // Pop a bool. + value.reset(dbus::PopDataAsValue(&reader)); + EXPECT_TRUE(value.get() != NULL); + EXPECT_TRUE(value->Equals(Value::CreateBooleanValue(kBoolValue))); + // Pop an int16. + value.reset(dbus::PopDataAsValue(&reader)); + EXPECT_TRUE(value.get() != NULL); + EXPECT_TRUE(value->Equals(Value::CreateIntegerValue(kInt16Value))); + // Pop a uint16. + value.reset(dbus::PopDataAsValue(&reader)); + EXPECT_TRUE(value.get() != NULL); + EXPECT_TRUE(value->Equals(Value::CreateIntegerValue(kUint16Value))); + // Pop an int32. + value.reset(dbus::PopDataAsValue(&reader)); + EXPECT_TRUE(value.get() != NULL); + EXPECT_TRUE(value->Equals(Value::CreateIntegerValue(kInt32Value))); + // Pop a uint32. + value.reset(dbus::PopDataAsValue(&reader)); + EXPECT_TRUE(value.get() != NULL); + EXPECT_TRUE(value->Equals(Value::CreateDoubleValue(kUint32Value))); + // Pop an int64. + value.reset(dbus::PopDataAsValue(&reader)); + EXPECT_TRUE(value.get() != NULL); + EXPECT_TRUE(value->Equals(Value::CreateDoubleValue(kInt64Value))); + // Pop a uint64. + value.reset(dbus::PopDataAsValue(&reader)); + EXPECT_TRUE(value.get() != NULL); + EXPECT_TRUE(value->Equals(Value::CreateDoubleValue(kUint64Value))); + // Pop a double. + value.reset(dbus::PopDataAsValue(&reader)); + EXPECT_TRUE(value.get() != NULL); + EXPECT_TRUE(value->Equals(Value::CreateDoubleValue(kDoubleValue))); + // Pop a string. + value.reset(dbus::PopDataAsValue(&reader)); + EXPECT_TRUE(value.get() != NULL); + EXPECT_TRUE(value->Equals(Value::CreateStringValue(kStringValue))); + // Pop an empty string. + value.reset(dbus::PopDataAsValue(&reader)); + EXPECT_TRUE(value.get() != NULL); + EXPECT_TRUE(value->Equals(Value::CreateStringValue(kEmptyStringValue))); + // Pop an object path. + value.reset(dbus::PopDataAsValue(&reader)); + EXPECT_TRUE(value.get() != NULL); + EXPECT_TRUE( + value->Equals(Value::CreateStringValue(kObjectPathValue.value()))); +} + +TEST(ValuesUtilTest, PopVariant) { + scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty()); + // Append variant values. + dbus::MessageWriter writer(response.get()); + const bool kBoolValue = true; + writer.AppendVariantOfBool(kBoolValue); + const int32 kInt32Value = -45; + writer.AppendVariantOfInt32(kInt32Value); + const double kDoubleValue = 4.9; + writer.AppendVariantOfDouble(kDoubleValue); + const std::string kStringValue = "fifty"; + writer.AppendVariantOfString(kStringValue); + + dbus::MessageReader reader(response.get()); + scoped_ptr<Value> value; + // Pop a bool. + value.reset(dbus::PopDataAsValue(&reader)); + EXPECT_TRUE(value.get() != NULL); + EXPECT_TRUE(value->Equals(Value::CreateBooleanValue(kBoolValue))); + // Pop an int32. + value.reset(dbus::PopDataAsValue(&reader)); + EXPECT_TRUE(value.get() != NULL); + EXPECT_TRUE(value->Equals(Value::CreateIntegerValue(kInt32Value))); + // Pop a double. + value.reset(dbus::PopDataAsValue(&reader)); + EXPECT_TRUE(value.get() != NULL); + EXPECT_TRUE(value->Equals(Value::CreateDoubleValue(kDoubleValue))); + // Pop a string. + value.reset(dbus::PopDataAsValue(&reader)); + EXPECT_TRUE(value.get() != NULL); + EXPECT_TRUE(value->Equals(Value::CreateStringValue(kStringValue))); +} + +// Pop extremely large integers which cannot be precisely represented in +// double. +TEST(ValuesUtilTest, PopExtremelyLargeIntegers) { + scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty()); + // Append large integers. + dbus::MessageWriter writer(response.get()); + const int64 kInt64Value = -123456789012345689LL; + writer.AppendInt64(kInt64Value); + const uint64 kUint64Value = 9876543210987654321ULL; + writer.AppendUint64(kUint64Value); + + dbus::MessageReader reader(response.get()); + scoped_ptr<Value> value; + double double_value = 0; + // Pop an int64. + value.reset(dbus::PopDataAsValue(&reader)); + EXPECT_TRUE(value.get() != NULL); + EXPECT_TRUE(value->Equals(Value::CreateDoubleValue(kInt64Value))); + ASSERT_TRUE(value->GetAsDouble(&double_value)); + EXPECT_NE(kInt64Value, static_cast<int64>(double_value)); + // Pop a uint64. + value.reset(dbus::PopDataAsValue(&reader)); + EXPECT_TRUE(value.get() != NULL); + EXPECT_TRUE(value->Equals(Value::CreateDoubleValue(kUint64Value))); + ASSERT_TRUE(value->GetAsDouble(&double_value)); + EXPECT_NE(kUint64Value, static_cast<uint64>(double_value)); +} + +TEST(ValuesUtilTest, PopIntArray) { + scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty()); + // Append an int32 array. + dbus::MessageWriter writer(response.get()); + dbus::MessageWriter sub_writer(NULL); + std::vector<int32> data; + data.push_back(0); + data.push_back(1); + data.push_back(2); + writer.OpenArray("i", &sub_writer); + for (size_t i = 0; i != data.size(); ++i) + sub_writer.AppendInt32(data[i]); + writer.CloseContainer(&sub_writer); + + // Create the expected value. + ListValue* list_value = new ListValue; + for (size_t i = 0; i != data.size(); ++i) + list_value->Append(Value::CreateIntegerValue(data[i])); + + // Pop an int32 array. + dbus::MessageReader reader(response.get()); + scoped_ptr<Value> value(dbus::PopDataAsValue(&reader)); + EXPECT_TRUE(value.get() != NULL); + EXPECT_TRUE(value->Equals(list_value)); +} + +TEST(ValuesUtilTest, PopStringArray) { + scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty()); + // Append a string array. + dbus::MessageWriter writer(response.get()); + dbus::MessageWriter sub_writer(NULL); + std::vector<std::string> data; + data.push_back("Dreamlifter"); + data.push_back("Beluga"); + data.push_back("Mriya"); + writer.AppendArrayOfStrings(data); + + // Create the expected value. + ListValue* list_value = new ListValue; + for (size_t i = 0; i != data.size(); ++i) + list_value->Append(Value::CreateStringValue(data[i])); + + // Pop a string array. + dbus::MessageReader reader(response.get()); + scoped_ptr<Value> value(dbus::PopDataAsValue(&reader)); + EXPECT_TRUE(value.get() != NULL); + EXPECT_TRUE(value->Equals(list_value)); +} + +TEST(ValuesUtilTest, PopStruct) { + scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty()); + // Append a struct. + dbus::MessageWriter writer(response.get()); + dbus::MessageWriter sub_writer(NULL); + writer.OpenStruct(&sub_writer); + const bool kBoolValue = true; + sub_writer.AppendBool(kBoolValue); + const int32 kInt32Value = -123; + sub_writer.AppendInt32(kInt32Value); + const double kDoubleValue = 1.23; + sub_writer.AppendDouble(kDoubleValue); + const std::string kStringValue = "one two three"; + sub_writer.AppendString(kStringValue); + writer.CloseContainer(&sub_writer); + + // Create the expected value. + ListValue list_value; + list_value.Append(Value::CreateBooleanValue(kBoolValue)); + list_value.Append(Value::CreateIntegerValue(kInt32Value)); + list_value.Append(Value::CreateDoubleValue(kDoubleValue)); + list_value.Append(Value::CreateStringValue(kStringValue)); + + // Pop a struct. + dbus::MessageReader reader(response.get()); + scoped_ptr<Value> value(dbus::PopDataAsValue(&reader)); + EXPECT_TRUE(value.get() != NULL); + EXPECT_TRUE(value->Equals(&list_value)); +} + +TEST(ValuesUtilTest, PopStringToVariantDictionary) { + scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty()); + // Append a dictionary. + dbus::MessageWriter writer(response.get()); + dbus::MessageWriter sub_writer(NULL); + dbus::MessageWriter entry_writer(NULL); + writer.OpenArray("{sv}", &sub_writer); + sub_writer.OpenDictEntry(&entry_writer); + const std::string kKey1 = "one"; + entry_writer.AppendString(kKey1); + const bool kBoolValue = true; + entry_writer.AppendVariantOfBool(kBoolValue); + sub_writer.CloseContainer(&entry_writer); + sub_writer.OpenDictEntry(&entry_writer); + const std::string kKey2 = "two"; + entry_writer.AppendString(kKey2); + const int32 kInt32Value = -45; + entry_writer.AppendVariantOfInt32(kInt32Value); + sub_writer.CloseContainer(&entry_writer); + sub_writer.OpenDictEntry(&entry_writer); + const std::string kKey3 = "three"; + entry_writer.AppendString(kKey3); + const double kDoubleValue = 4.9; + entry_writer.AppendVariantOfDouble(kDoubleValue); + sub_writer.CloseContainer(&entry_writer); + sub_writer.OpenDictEntry(&entry_writer); + const std::string kKey4 = "four"; + entry_writer.AppendString(kKey4); + const std::string kStringValue = "fifty"; + entry_writer.AppendVariantOfString(kStringValue); + sub_writer.CloseContainer(&entry_writer); + writer.CloseContainer(&sub_writer); + + // Create the expected value. + DictionaryValue dictionary_value; + dictionary_value.SetBoolean(kKey1, kBoolValue); + dictionary_value.SetInteger(kKey2, kInt32Value); + dictionary_value.SetDouble(kKey3, kDoubleValue); + dictionary_value.SetString(kKey4, kStringValue); + + // Pop a dictinoary. + dbus::MessageReader reader(response.get()); + scoped_ptr<Value> value(dbus::PopDataAsValue(&reader)); + EXPECT_TRUE(value.get() != NULL); + EXPECT_TRUE(value->Equals(&dictionary_value)); +} + +TEST(ValuesUtilTest, PopDoubleToIntDictionary) { + // Create test data. + const int32 kValues[] = {0, 1, 1, 2, 3, 5, 8, 13, 21}; + const std::vector<int32> values(kValues, kValues + arraysize(kValues)); + std::vector<double> keys(values.size()); + for (size_t i = 0; i != values.size(); ++i) + keys[i] = sqrt(values[i]); + + // Append a dictionary. + scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty()); + dbus::MessageWriter writer(response.get()); + dbus::MessageWriter sub_writer(NULL); + writer.OpenArray("{di}", &sub_writer); + for (size_t i = 0; i != values.size(); ++i) { + dbus::MessageWriter entry_writer(NULL); + sub_writer.OpenDictEntry(&entry_writer); + entry_writer.AppendDouble(keys[i]); + entry_writer.AppendInt32(values[i]); + sub_writer.CloseContainer(&entry_writer); + } + writer.CloseContainer(&sub_writer); + + // Create the expected value. + DictionaryValue dictionary_value; + for (size_t i = 0; i != values.size(); ++i) { + scoped_ptr<Value> key_value(Value::CreateDoubleValue(keys[i])); + std::string key_string; + base::JSONWriter::Write(key_value.get(), &key_string); + dictionary_value.SetInteger(key_string, values[i]); + } + + // Pop a dictionary. + dbus::MessageReader reader(response.get()); + scoped_ptr<Value> value(dbus::PopDataAsValue(&reader)); + EXPECT_TRUE(value.get() != NULL); + EXPECT_TRUE(value->Equals(&dictionary_value)); +} |