blob: 84057226794f31a516a74f275df9cdc56791c150 [file] [log] [blame]
Alex Vakulenko66ec2922014-06-17 15:30:22 -07001// Copyright 2014 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Alex Deymof6cbe322014-11-10 19:55:35 -08005#include "buffet/commands/schema_utils.h"
6
Alex Vakulenko66ec2922014-06-17 15:30:22 -07007#include <memory>
8#include <string>
9#include <vector>
10
Alex Vakulenko66ec2922014-06-17 15:30:22 -070011#include <base/values.h>
Alex Vakulenko576c9792014-09-22 16:49:45 -070012#include <chromeos/variant_dictionary.h>
Alex Vakulenko66ec2922014-06-17 15:30:22 -070013#include <gtest/gtest.h>
14
15#include "buffet/commands/object_schema.h"
16#include "buffet/commands/prop_types.h"
17#include "buffet/commands/prop_values.h"
Alex Vakulenkoa32d83a2014-09-19 15:05:24 -070018#include "buffet/commands/schema_constants.h"
Alex Vakulenko6201d2d2014-07-16 14:46:48 -070019#include "buffet/commands/unittest_utils.h"
Alex Vakulenko66ec2922014-06-17 15:30:22 -070020
Alex Vakulenkoa32d83a2014-09-19 15:05:24 -070021using buffet::unittests::CreateDictionaryValue;
Alex Vakulenko6201d2d2014-07-16 14:46:48 -070022using buffet::unittests::CreateValue;
23using buffet::unittests::ValueToString;
Alex Vakulenko576c9792014-09-22 16:49:45 -070024using chromeos::VariantDictionary;
Alex Vakulenko66ec2922014-06-17 15:30:22 -070025
26TEST(CommandSchemaUtils, TypedValueToJson_Scalar) {
27 EXPECT_EQ("true",
28 ValueToString(buffet::TypedValueToJson(true, nullptr).get()));
29 EXPECT_EQ("false",
30 ValueToString(buffet::TypedValueToJson(false, nullptr).get()));
31
32 EXPECT_EQ("0", ValueToString(buffet::TypedValueToJson(0, nullptr).get()));
33 EXPECT_EQ("-10", ValueToString(buffet::TypedValueToJson(-10, nullptr).get()));
34 EXPECT_EQ("20", ValueToString(buffet::TypedValueToJson(20, nullptr).get()));
35
36 EXPECT_EQ("0.0", ValueToString(buffet::TypedValueToJson(0.0, nullptr).get()));
37 EXPECT_EQ("1.2", ValueToString(buffet::TypedValueToJson(1.2, nullptr).get()));
38
39 EXPECT_EQ("'abc'",
40 ValueToString(buffet::TypedValueToJson(std::string("abc"),
41 nullptr).get()));
42
43 std::vector<bool> bool_array{true, false};
44 EXPECT_EQ("[true,false]",
45 ValueToString(buffet::TypedValueToJson(bool_array, nullptr).get()));
46
47 std::vector<int> int_array{1, 2, 5};
48 EXPECT_EQ("[1,2,5]",
49 ValueToString(buffet::TypedValueToJson(int_array, nullptr).get()));
50
51 std::vector<double> dbl_array{1.1, 2.2};
52 EXPECT_EQ("[1.1,2.2]",
53 ValueToString(buffet::TypedValueToJson(dbl_array, nullptr).get()));
54
55 std::vector<std::string> str_array{"a", "bc"};
56 EXPECT_EQ("['a','bc']",
57 ValueToString(buffet::TypedValueToJson(str_array, nullptr).get()));
58}
59
60TEST(CommandSchemaUtils, TypedValueToJson_Object) {
61 buffet::IntPropType int_type;
62 buffet::native_types::Object object;
63
Alex Vakulenko157ccaa2014-09-19 14:59:34 -070064 object.insert(std::make_pair("width", int_type.CreateValue(640, nullptr)));
65 object.insert(std::make_pair("height", int_type.CreateValue(480, nullptr)));
Alex Vakulenko66ec2922014-06-17 15:30:22 -070066 EXPECT_EQ("{'height':480,'width':640}",
67 ValueToString(buffet::TypedValueToJson(object, nullptr).get()));
68}
69
Alex Vakulenko29e64442015-03-20 13:59:19 -070070TEST(CommandSchemaUtils, TypedValueToJson_Array) {
71 buffet::IntPropType int_type;
72 buffet::native_types::Array arr;
73
74 arr.push_back(int_type.CreateValue(640, nullptr));
75 arr.push_back(int_type.CreateValue(480, nullptr));
76 EXPECT_EQ("[640,480]",
77 ValueToString(buffet::TypedValueToJson(arr, nullptr).get()));
78}
79
Alex Vakulenko66ec2922014-06-17 15:30:22 -070080TEST(CommandSchemaUtils, TypedValueFromJson_Bool) {
81 bool value;
82
83 EXPECT_TRUE(buffet::TypedValueFromJson(CreateValue("true").get(), nullptr,
84 &value, nullptr));
85 EXPECT_TRUE(value);
86
87 EXPECT_TRUE(buffet::TypedValueFromJson(CreateValue("false").get(), nullptr,
88 &value, nullptr));
89 EXPECT_FALSE(value);
90
Alex Vakulenko5f472062014-08-14 17:54:04 -070091 chromeos::ErrorPtr error;
Alex Vakulenko66ec2922014-06-17 15:30:22 -070092 EXPECT_FALSE(buffet::TypedValueFromJson(CreateValue("0").get(), nullptr,
93 &value, &error));
Alex Vakulenkoa32d83a2014-09-19 15:05:24 -070094 EXPECT_EQ(buffet::errors::commands::kTypeMismatch, error->GetCode());
Alex Vakulenko66ec2922014-06-17 15:30:22 -070095 error.reset();
96}
97
98TEST(CommandSchemaUtils, TypedValueFromJson_Int) {
99 int value;
100
101 EXPECT_TRUE(buffet::TypedValueFromJson(CreateValue("0").get(), nullptr,
102 &value, nullptr));
103 EXPECT_EQ(0, value);
104
105 EXPECT_TRUE(buffet::TypedValueFromJson(CreateValue("23").get(), nullptr,
106 &value, nullptr));
107 EXPECT_EQ(23, value);
108
109 EXPECT_TRUE(buffet::TypedValueFromJson(CreateValue("-1234").get(), nullptr,
110 &value, nullptr));
111 EXPECT_EQ(-1234, value);
112
Alex Vakulenko5f472062014-08-14 17:54:04 -0700113 chromeos::ErrorPtr error;
Alex Vakulenko66ec2922014-06-17 15:30:22 -0700114 EXPECT_FALSE(buffet::TypedValueFromJson(CreateValue("'abc'").get(), nullptr,
115 &value, &error));
Alex Vakulenkoa32d83a2014-09-19 15:05:24 -0700116 EXPECT_EQ(buffet::errors::commands::kTypeMismatch, error->GetCode());
Alex Vakulenko66ec2922014-06-17 15:30:22 -0700117 error.reset();
118}
119
120TEST(CommandSchemaUtils, TypedValueFromJson_Double) {
121 double value;
122
123 EXPECT_TRUE(buffet::TypedValueFromJson(CreateValue("0").get(), nullptr,
124 &value, nullptr));
125 EXPECT_DOUBLE_EQ(0.0, value);
126 EXPECT_TRUE(buffet::TypedValueFromJson(CreateValue("0.0").get(), nullptr,
127 &value, nullptr));
128 EXPECT_DOUBLE_EQ(0.0, value);
129
130 EXPECT_TRUE(buffet::TypedValueFromJson(CreateValue("23").get(), nullptr,
131 &value, nullptr));
132 EXPECT_EQ(23.0, value);
133 EXPECT_TRUE(buffet::TypedValueFromJson(CreateValue("23.1").get(), nullptr,
134 &value, nullptr));
135 EXPECT_EQ(23.1, value);
136
137 EXPECT_TRUE(buffet::TypedValueFromJson(CreateValue("-1.23E+02").get(),
138 nullptr, &value, nullptr));
139 EXPECT_EQ(-123.0, value);
140
Alex Vakulenko5f472062014-08-14 17:54:04 -0700141 chromeos::ErrorPtr error;
Alex Vakulenko66ec2922014-06-17 15:30:22 -0700142 EXPECT_FALSE(buffet::TypedValueFromJson(CreateValue("'abc'").get(), nullptr,
143 &value, &error));
Alex Vakulenkoa32d83a2014-09-19 15:05:24 -0700144 EXPECT_EQ(buffet::errors::commands::kTypeMismatch, error->GetCode());
Alex Vakulenko66ec2922014-06-17 15:30:22 -0700145 error.reset();
146}
147
148TEST(CommandSchemaUtils, TypedValueFromJson_String) {
149 std::string value;
150
151 EXPECT_TRUE(buffet::TypedValueFromJson(CreateValue("''").get(), nullptr,
152 &value, nullptr));
153 EXPECT_EQ("", value);
154
155 EXPECT_TRUE(buffet::TypedValueFromJson(CreateValue("'23'").get(), nullptr,
156 &value, nullptr));
157 EXPECT_EQ("23", value);
158
159 EXPECT_TRUE(buffet::TypedValueFromJson(CreateValue("'abc'").get(), nullptr,
160 &value, nullptr));
161 EXPECT_EQ("abc", value);
162
Alex Vakulenko5f472062014-08-14 17:54:04 -0700163 chromeos::ErrorPtr error;
Alex Vakulenko66ec2922014-06-17 15:30:22 -0700164 EXPECT_FALSE(buffet::TypedValueFromJson(CreateValue("12").get(), nullptr,
165 &value, &error));
Alex Vakulenkoa32d83a2014-09-19 15:05:24 -0700166 EXPECT_EQ(buffet::errors::commands::kTypeMismatch, error->GetCode());
Alex Vakulenko66ec2922014-06-17 15:30:22 -0700167 error.reset();
168}
169
170TEST(CommandSchemaUtils, TypedValueFromJson_Object) {
171 buffet::native_types::Object value;
Alex Vakulenko5ef75792015-03-19 15:50:44 -0700172 std::unique_ptr<buffet::ObjectSchema> schema{new buffet::ObjectSchema};
Alex Vakulenko66ec2922014-06-17 15:30:22 -0700173
Alex Vakulenko5ef75792015-03-19 15:50:44 -0700174 buffet::IntPropType age_prop;
175 age_prop.AddMinMaxConstraint(0, 150);
176 schema->AddProp("age", age_prop.Clone());
Alex Vakulenko66ec2922014-06-17 15:30:22 -0700177
Alex Vakulenko5ef75792015-03-19 15:50:44 -0700178 buffet::StringPropType name_prop;
179 name_prop.AddLengthConstraint(1, 30);
180 schema->AddProp("name", name_prop.Clone());
Alex Vakulenko66ec2922014-06-17 15:30:22 -0700181
Alex Vakulenkod94656e2015-03-18 09:54:37 -0700182 buffet::ObjectPropType type;
Alex Vakulenko5ef75792015-03-19 15:50:44 -0700183 type.SetObjectSchema(std::move(schema));
Alex Vakulenko66ec2922014-06-17 15:30:22 -0700184 EXPECT_TRUE(buffet::TypedValueFromJson(
Alex Vakulenkod94656e2015-03-18 09:54:37 -0700185 CreateValue("{'age':20,'name':'Bob'}").get(), &type, &value, nullptr));
Alex Vakulenko66ec2922014-06-17 15:30:22 -0700186 buffet::native_types::Object value2;
Alex Vakulenko5ef75792015-03-19 15:50:44 -0700187 value2.insert(std::make_pair("age", age_prop.CreateValue(20, nullptr)));
Alex Vakulenko66ec2922014-06-17 15:30:22 -0700188 value2.insert(std::make_pair("name",
Alex Vakulenko5ef75792015-03-19 15:50:44 -0700189 name_prop.CreateValue(std::string("Bob"),
190 nullptr)));
Alex Vakulenko66ec2922014-06-17 15:30:22 -0700191 EXPECT_EQ(value2, value);
192
Alex Vakulenko5f472062014-08-14 17:54:04 -0700193 chromeos::ErrorPtr error;
Alex Vakulenko66ec2922014-06-17 15:30:22 -0700194 EXPECT_FALSE(buffet::TypedValueFromJson(CreateValue("'abc'").get(), nullptr,
195 &value, &error));
Alex Vakulenkoa32d83a2014-09-19 15:05:24 -0700196 EXPECT_EQ(buffet::errors::commands::kTypeMismatch, error->GetCode());
Alex Vakulenko66ec2922014-06-17 15:30:22 -0700197 error.reset();
198}
Alex Vakulenkoa32d83a2014-09-19 15:05:24 -0700199
Alex Vakulenko29e64442015-03-20 13:59:19 -0700200TEST(CommandSchemaUtils, TypedValueFromJson_Array) {
201 buffet::native_types::Array arr;
202 buffet::StringPropType str_type;
203 str_type.AddLengthConstraint(3, 100);
204 buffet::ArrayPropType type;
205 type.SetItemType(str_type.Clone());
206
207 EXPECT_TRUE(buffet::TypedValueFromJson(
208 CreateValue("['foo', 'bar']").get(), &type, &arr, nullptr));
209 buffet::native_types::Array arr2;
210 arr2.push_back(str_type.CreateValue(std::string{"foo"}, nullptr));
211 arr2.push_back(str_type.CreateValue(std::string{"bar"}, nullptr));
212 EXPECT_EQ(arr2, arr);
213
214 chromeos::ErrorPtr error;
215 EXPECT_FALSE(buffet::TypedValueFromJson(
216 CreateValue("['baz', 'ab']").get(), &type, &arr, &error));
217 EXPECT_EQ(buffet::errors::commands::kOutOfRange, error->GetCode());
218 error.reset();
219}
220
Alex Vakulenkoa32d83a2014-09-19 15:05:24 -0700221TEST(CommandSchemaUtils, PropValueToDBusVariant) {
222 buffet::IntPropType int_type;
223 auto prop_value = int_type.CreateValue(5, nullptr);
224 EXPECT_EQ(5, PropValueToDBusVariant(prop_value.get()).Get<int>());
225
226 buffet::BooleanPropType bool_type;
227 prop_value = bool_type.CreateValue(true, nullptr);
228 EXPECT_TRUE(PropValueToDBusVariant(prop_value.get()).Get<bool>());
229
230 buffet::DoublePropType dbl_type;
231 prop_value = dbl_type.CreateValue(5.5, nullptr);
232 EXPECT_DOUBLE_EQ(5.5, PropValueToDBusVariant(prop_value.get()).Get<double>());
233
234 buffet::StringPropType str_type;
235 prop_value = str_type.CreateValue(std::string{"foo"}, nullptr);
236 EXPECT_EQ("foo", PropValueToDBusVariant(prop_value.get()).Get<std::string>());
237
238 buffet::ObjectPropType obj_type;
239 ASSERT_TRUE(obj_type.FromJson(CreateDictionaryValue(
240 "{'properties':{'width':'integer','height':'integer'},"
241 "'enum':[{'width':10,'height':20},{'width':100,'height':200}]}").get(),
242 nullptr, nullptr));
243 buffet::native_types::Object obj{
244 {"width", int_type.CreateValue(10, nullptr)},
245 {"height", int_type.CreateValue(20, nullptr)},
246 };
247 prop_value = obj_type.CreateValue(obj, nullptr);
Alex Vakulenko576c9792014-09-22 16:49:45 -0700248 VariantDictionary dict =
249 PropValueToDBusVariant(prop_value.get()).Get<VariantDictionary>();
Alex Vakulenkoa32d83a2014-09-19 15:05:24 -0700250 EXPECT_EQ(20, dict["height"].Get<int>());
251 EXPECT_EQ(10, dict["width"].Get<int>());
Alex Vakulenko72452612015-03-24 09:58:04 -0700252
253 buffet::ArrayPropType arr_type;
254 arr_type.SetItemType(str_type.Clone());
255 buffet::native_types::Array arr;
256 arr.push_back(str_type.CreateValue(std::string{"foo"}, nullptr));
257 arr.push_back(str_type.CreateValue(std::string{"bar"}, nullptr));
258 arr.push_back(str_type.CreateValue(std::string{"baz"}, nullptr));
259 prop_value = arr_type.CreateValue(arr, nullptr);
260 chromeos::Any any = PropValueToDBusVariant(prop_value.get());
261 ASSERT_TRUE(any.IsTypeCompatible<std::vector<std::string>>());
262 EXPECT_EQ((std::vector<std::string>{"foo", "bar", "baz"}),
263 any.Get<std::vector<std::string>>());
Alex Vakulenkoa32d83a2014-09-19 15:05:24 -0700264}
265
266TEST(CommandSchemaUtils, PropValueFromDBusVariant_Int) {
267 buffet::IntPropType int_type;
268 ASSERT_TRUE(int_type.FromJson(CreateDictionaryValue("{'enum':[1,2]}").get(),
269 nullptr, nullptr));
270
271 auto prop_value = PropValueFromDBusVariant(&int_type, 1, nullptr);
272 ASSERT_NE(nullptr, prop_value.get());
273 EXPECT_EQ(1, prop_value->GetValueAsAny().Get<int>());
274
275 chromeos::ErrorPtr error;
276 prop_value = PropValueFromDBusVariant(&int_type, 5, &error);
277 EXPECT_EQ(nullptr, prop_value.get());
278 ASSERT_NE(nullptr, error.get());
279 EXPECT_EQ(buffet::errors::commands::kOutOfRange, error->GetCode());
280}
281
282TEST(CommandSchemaUtils, PropValueFromDBusVariant_Bool) {
283 buffet::BooleanPropType bool_type;
284 ASSERT_TRUE(bool_type.FromJson(CreateDictionaryValue("{'enum':[true]}").get(),
285 nullptr, nullptr));
286
287 auto prop_value = PropValueFromDBusVariant(&bool_type, true, nullptr);
288 ASSERT_NE(nullptr, prop_value.get());
289 EXPECT_TRUE(prop_value->GetValueAsAny().Get<bool>());
290
291 chromeos::ErrorPtr error;
292 prop_value = PropValueFromDBusVariant(&bool_type, false, &error);
293 EXPECT_EQ(nullptr, prop_value.get());
294 ASSERT_NE(nullptr, error.get());
295 EXPECT_EQ(buffet::errors::commands::kOutOfRange, error->GetCode());
296}
297
298TEST(CommandSchemaUtils, PropValueFromDBusVariant_Double) {
299 buffet::DoublePropType dbl_type;
300 ASSERT_TRUE(dbl_type.FromJson(CreateDictionaryValue("{'maximum':2.0}").get(),
301 nullptr, nullptr));
302
303 auto prop_value = PropValueFromDBusVariant(&dbl_type, 1.0, nullptr);
304 ASSERT_NE(nullptr, prop_value.get());
305 EXPECT_DOUBLE_EQ(1.0, prop_value->GetValueAsAny().Get<double>());
306
307 chromeos::ErrorPtr error;
308 prop_value = PropValueFromDBusVariant(&dbl_type, 10.0, &error);
309 EXPECT_EQ(nullptr, prop_value.get());
310 ASSERT_NE(nullptr, error.get());
311 EXPECT_EQ(buffet::errors::commands::kOutOfRange, error->GetCode());
312}
313
314TEST(CommandSchemaUtils, PropValueFromDBusVariant_String) {
315 buffet::StringPropType str_type;
316 ASSERT_TRUE(str_type.FromJson(CreateDictionaryValue("{'minLength': 4}").get(),
317 nullptr, nullptr));
318
319 auto prop_value = PropValueFromDBusVariant(&str_type, std::string{"blah"},
320 nullptr);
321 ASSERT_NE(nullptr, prop_value.get());
322 EXPECT_EQ("blah", prop_value->GetValueAsAny().Get<std::string>());
323
324 chromeos::ErrorPtr error;
325 prop_value = PropValueFromDBusVariant(&str_type, std::string{"foo"}, &error);
326 EXPECT_EQ(nullptr, prop_value.get());
327 ASSERT_NE(nullptr, error.get());
328 EXPECT_EQ(buffet::errors::commands::kOutOfRange, error->GetCode());
329}
330
331TEST(CommandSchemaUtils, PropValueFromDBusVariant_Object) {
332 buffet::ObjectPropType obj_type;
333 ASSERT_TRUE(obj_type.FromJson(CreateDictionaryValue(
334 "{'properties':{'width':'integer','height':'integer'},"
335 "'enum':[{'width':10,'height':20},{'width':100,'height':200}]}").get(),
336 nullptr, nullptr));
337
Alex Vakulenko576c9792014-09-22 16:49:45 -0700338 VariantDictionary obj{
Alex Vakulenkoa32d83a2014-09-19 15:05:24 -0700339 {"width", 100},
340 {"height", 200},
341 };
342 auto prop_value = PropValueFromDBusVariant(&obj_type, obj, nullptr);
343 ASSERT_NE(nullptr, prop_value.get());
344 auto value = prop_value->GetValueAsAny().Get<buffet::native_types::Object>();
345 EXPECT_EQ(100, value["width"].get()->GetValueAsAny().Get<int>());
346 EXPECT_EQ(200, value["height"].get()->GetValueAsAny().Get<int>());
347
348 chromeos::ErrorPtr error;
349 obj["height"] = 20;
350 prop_value = PropValueFromDBusVariant(&obj_type, obj, &error);
351 EXPECT_EQ(nullptr, prop_value.get());
352 ASSERT_NE(nullptr, error.get());
353 EXPECT_EQ(buffet::errors::commands::kOutOfRange, error->GetCode());
354}
Alex Vakulenko72452612015-03-24 09:58:04 -0700355
356TEST(CommandSchemaUtils, PropValueFromDBusVariant_Array) {
357 buffet::ArrayPropType arr_type;
358 buffet::IntPropType int_type;
359 int_type.AddMinMaxConstraint(0, 100);
360 arr_type.SetItemType(int_type.Clone());
361 std::vector<int> data{0, 1, 1, 100};
362 auto prop_value = PropValueFromDBusVariant(&arr_type, data, nullptr);
363 ASSERT_NE(nullptr, prop_value.get());
364 auto arr = prop_value->GetValueAsAny().Get<buffet::native_types::Array>();
365 ASSERT_EQ(4u, arr.size());
366 EXPECT_EQ(0, arr[0]->GetInt()->GetValue());
367 EXPECT_EQ(1, arr[1]->GetInt()->GetValue());
368 EXPECT_EQ(1, arr[2]->GetInt()->GetValue());
369 EXPECT_EQ(100, arr[3]->GetInt()->GetValue());
370
371 chromeos::ErrorPtr error;
372 data.push_back(-1); // This value is out of bounds for |int_type|.
373 prop_value = PropValueFromDBusVariant(&arr_type, data, &error);
374 EXPECT_EQ(nullptr, prop_value.get());
375 ASSERT_NE(nullptr, error.get());
376 EXPECT_EQ(buffet::errors::commands::kOutOfRange, error->GetCode());
377}