buffet: GCD command defintion. Compound object type support.
Added support for "object" type. Refactored parameter validation
to make sure we have object schema context when we validate
a value of parameter.
Parameter |schema| was used in two different contexts, as both
a base parameter definition and as a custom object definition.
Renamed the former to be 'base_schema' and latter as
'object_schema' to remove the confusion.
Extracted common data type manipulation functions into
schema_utils.cc/.h files.
BUG=chromium:374860
TEST=All unit tests pass.
Change-Id: I6c3549849a258bcc94b3d754acd14e072438d140
Reviewed-on: https://chromium-review.googlesource.com/204793
Tested-by: Alex Vakulenko <avakulenko@chromium.org>
Reviewed-by: Christopher Wiley <wiley@chromium.org>
Commit-Queue: Alex Vakulenko <avakulenko@chromium.org>
diff --git a/buffet/commands/schema_utils_unittest.cc b/buffet/commands/schema_utils_unittest.cc
new file mode 100644
index 0000000..6918186
--- /dev/null
+++ b/buffet/commands/schema_utils_unittest.cc
@@ -0,0 +1,210 @@
+// 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 <memory>
+#include <string>
+#include <vector>
+
+#include <base/json/json_reader.h>
+#include <base/json/json_writer.h>
+#include <base/values.h>
+#include <gtest/gtest.h>
+
+#include "buffet/commands/object_schema.h"
+#include "buffet/commands/prop_types.h"
+#include "buffet/commands/prop_values.h"
+#include "buffet/commands/schema_utils.h"
+
+namespace {
+// Helper method to create base::Value from a string as a smart pointer.
+// For ease of definition in C++ code, double-quotes in the source definition
+// are replaced with apostrophes.
+std::unique_ptr<base::Value> CreateValue(const char* json) {
+ std::string json2(json);
+ // Convert apostrophes to double-quotes so JSONReader can parse the string.
+ std::replace(json2.begin(), json2.end(), '\'', '"');
+ return std::unique_ptr<base::Value>(base::JSONReader::Read(json2));
+}
+
+// Helper method to create a JSON dictionary object from a string.
+std::unique_ptr<base::DictionaryValue> CreateDictionaryValue(const char* json) {
+ std::string json2(json);
+ std::replace(json2.begin(), json2.end(), '\'', '"');
+ base::Value* value = base::JSONReader::Read(json2);
+ base::DictionaryValue* dict;
+ value->GetAsDictionary(&dict);
+ return std::unique_ptr<base::DictionaryValue>(dict);
+}
+
+// Converts a JSON value to a string. It also converts double-quotes to
+// apostrophes for easy comparisons in C++ source code.
+std::string ValueToString(const base::Value* value) {
+ std::string json;
+ base::JSONWriter::Write(value, &json);
+ std::replace(json.begin(), json.end(), '"', '\'');
+ return json;
+}
+
+} // namespace
+
+TEST(CommandSchemaUtils, TypedValueToJson_Scalar) {
+ EXPECT_EQ("true",
+ ValueToString(buffet::TypedValueToJson(true, nullptr).get()));
+ EXPECT_EQ("false",
+ ValueToString(buffet::TypedValueToJson(false, nullptr).get()));
+
+ EXPECT_EQ("0", ValueToString(buffet::TypedValueToJson(0, nullptr).get()));
+ EXPECT_EQ("-10", ValueToString(buffet::TypedValueToJson(-10, nullptr).get()));
+ EXPECT_EQ("20", ValueToString(buffet::TypedValueToJson(20, nullptr).get()));
+
+ EXPECT_EQ("0.0", ValueToString(buffet::TypedValueToJson(0.0, nullptr).get()));
+ EXPECT_EQ("1.2", ValueToString(buffet::TypedValueToJson(1.2, nullptr).get()));
+
+ EXPECT_EQ("'abc'",
+ ValueToString(buffet::TypedValueToJson(std::string("abc"),
+ nullptr).get()));
+
+ std::vector<bool> bool_array{true, false};
+ EXPECT_EQ("[true,false]",
+ ValueToString(buffet::TypedValueToJson(bool_array, nullptr).get()));
+
+ std::vector<int> int_array{1, 2, 5};
+ EXPECT_EQ("[1,2,5]",
+ ValueToString(buffet::TypedValueToJson(int_array, nullptr).get()));
+
+ std::vector<double> dbl_array{1.1, 2.2};
+ EXPECT_EQ("[1.1,2.2]",
+ ValueToString(buffet::TypedValueToJson(dbl_array, nullptr).get()));
+
+ std::vector<std::string> str_array{"a", "bc"};
+ EXPECT_EQ("['a','bc']",
+ ValueToString(buffet::TypedValueToJson(str_array, nullptr).get()));
+}
+
+TEST(CommandSchemaUtils, TypedValueToJson_Object) {
+ buffet::IntPropType int_type;
+ buffet::native_types::Object object;
+
+ object.insert(std::make_pair("width", int_type.CreateValue(640)));
+ object.insert(std::make_pair("height", int_type.CreateValue(480)));
+ EXPECT_EQ("{'height':480,'width':640}",
+ ValueToString(buffet::TypedValueToJson(object, nullptr).get()));
+}
+
+TEST(CommandSchemaUtils, TypedValueFromJson_Bool) {
+ bool value;
+
+ EXPECT_TRUE(buffet::TypedValueFromJson(CreateValue("true").get(), nullptr,
+ &value, nullptr));
+ EXPECT_TRUE(value);
+
+ EXPECT_TRUE(buffet::TypedValueFromJson(CreateValue("false").get(), nullptr,
+ &value, nullptr));
+ EXPECT_FALSE(value);
+
+ buffet::ErrorPtr error;
+ EXPECT_FALSE(buffet::TypedValueFromJson(CreateValue("0").get(), nullptr,
+ &value, &error));
+ EXPECT_EQ("type_mismatch", error->GetCode());
+ error.reset();
+}
+
+TEST(CommandSchemaUtils, TypedValueFromJson_Int) {
+ int value;
+
+ EXPECT_TRUE(buffet::TypedValueFromJson(CreateValue("0").get(), nullptr,
+ &value, nullptr));
+ EXPECT_EQ(0, value);
+
+ EXPECT_TRUE(buffet::TypedValueFromJson(CreateValue("23").get(), nullptr,
+ &value, nullptr));
+ EXPECT_EQ(23, value);
+
+ EXPECT_TRUE(buffet::TypedValueFromJson(CreateValue("-1234").get(), nullptr,
+ &value, nullptr));
+ EXPECT_EQ(-1234, value);
+
+ buffet::ErrorPtr error;
+ EXPECT_FALSE(buffet::TypedValueFromJson(CreateValue("'abc'").get(), nullptr,
+ &value, &error));
+ EXPECT_EQ("type_mismatch", error->GetCode());
+ error.reset();
+}
+
+TEST(CommandSchemaUtils, TypedValueFromJson_Double) {
+ double value;
+
+ EXPECT_TRUE(buffet::TypedValueFromJson(CreateValue("0").get(), nullptr,
+ &value, nullptr));
+ EXPECT_DOUBLE_EQ(0.0, value);
+ EXPECT_TRUE(buffet::TypedValueFromJson(CreateValue("0.0").get(), nullptr,
+ &value, nullptr));
+ EXPECT_DOUBLE_EQ(0.0, value);
+
+ EXPECT_TRUE(buffet::TypedValueFromJson(CreateValue("23").get(), nullptr,
+ &value, nullptr));
+ EXPECT_EQ(23.0, value);
+ EXPECT_TRUE(buffet::TypedValueFromJson(CreateValue("23.1").get(), nullptr,
+ &value, nullptr));
+ EXPECT_EQ(23.1, value);
+
+ EXPECT_TRUE(buffet::TypedValueFromJson(CreateValue("-1.23E+02").get(),
+ nullptr, &value, nullptr));
+ EXPECT_EQ(-123.0, value);
+
+ buffet::ErrorPtr error;
+ EXPECT_FALSE(buffet::TypedValueFromJson(CreateValue("'abc'").get(), nullptr,
+ &value, &error));
+ EXPECT_EQ("type_mismatch", error->GetCode());
+ error.reset();
+}
+
+TEST(CommandSchemaUtils, TypedValueFromJson_String) {
+ std::string value;
+
+ EXPECT_TRUE(buffet::TypedValueFromJson(CreateValue("''").get(), nullptr,
+ &value, nullptr));
+ EXPECT_EQ("", value);
+
+ EXPECT_TRUE(buffet::TypedValueFromJson(CreateValue("'23'").get(), nullptr,
+ &value, nullptr));
+ EXPECT_EQ("23", value);
+
+ EXPECT_TRUE(buffet::TypedValueFromJson(CreateValue("'abc'").get(), nullptr,
+ &value, nullptr));
+ EXPECT_EQ("abc", value);
+
+ buffet::ErrorPtr error;
+ EXPECT_FALSE(buffet::TypedValueFromJson(CreateValue("12").get(), nullptr,
+ &value, &error));
+ EXPECT_EQ("type_mismatch", error->GetCode());
+ error.reset();
+}
+
+TEST(CommandSchemaUtils, TypedValueFromJson_Object) {
+ buffet::native_types::Object value;
+ buffet::ObjectSchema schema;
+
+ auto age_prop = std::make_shared<buffet::IntPropType>();
+ age_prop->AddMinMaxConstraint(0, 150);
+ schema.AddProp("age", age_prop);
+
+ auto name_prop = std::make_shared<buffet::StringPropType>();
+ name_prop->AddLengthConstraint(1, 30);
+ schema.AddProp("name", name_prop);
+
+ EXPECT_TRUE(buffet::TypedValueFromJson(
+ CreateValue("{'age':20,'name':'Bob'}").get(), &schema, &value, nullptr));
+ buffet::native_types::Object value2;
+ value2.insert(std::make_pair("age", age_prop->CreateValue(20)));
+ value2.insert(std::make_pair("name",
+ name_prop->CreateValue(std::string("Bob"))));
+ EXPECT_EQ(value2, value);
+
+ buffet::ErrorPtr error;
+ EXPECT_FALSE(buffet::TypedValueFromJson(CreateValue("'abc'").get(), nullptr,
+ &value, &error));
+ EXPECT_EQ("type_mismatch", error->GetCode());
+ error.reset();
+}