blob: f958bf5380c2f2cfc0076937ba076abe92282fea [file] [log] [blame]
Vitaly Buka4615e0d2015-10-14 15:35:12 -07001// Copyright 2015 The Weave Authors. All rights reserved.
Alex Vakulenko07216fe2014-09-19 15:31:09 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Stefan Sauer2d16dfa2015-09-25 17:08:35 +02005#include "src/states/state_package.h"
Alex Deymof6cbe322014-11-10 19:55:35 -08006
Alex Vakulenko07216fe2014-09-19 15:31:09 -07007#include <memory>
8#include <string>
9
10#include <base/values.h>
Alex Vakulenko07216fe2014-09-19 15:31:09 -070011#include <gtest/gtest.h>
12
Stefan Sauer2d16dfa2015-09-25 17:08:35 +020013#include "src/commands/schema_constants.h"
14#include "src/commands/unittest_utils.h"
15#include "src/states/error_codes.h"
Alex Vakulenko07216fe2014-09-19 15:31:09 -070016
Vitaly Bukab6f015a2015-07-09 14:59:23 -070017namespace weave {
Alex Vakulenko07216fe2014-09-19 15:31:09 -070018
Vitaly Buka0f6b2ec2015-08-20 15:35:19 -070019using test::CreateDictionaryValue;
Vitaly Buka32005de2015-05-01 12:33:31 -070020
Alex Vakulenko07216fe2014-09-19 15:31:09 -070021class StatePackageTestHelper {
22 public:
23 // Returns the state property definitions (types/constraints/etc).
24 static const ObjectSchema& GetTypes(const StatePackage& package) {
25 return package.types_;
26 }
27 // Returns the all state property values in this package.
Vitaly Buka774cdf52015-07-21 13:55:00 -070028 static const ValueMap& GetValues(const StatePackage& package) {
Alex Vakulenko07216fe2014-09-19 15:31:09 -070029 return package.values_;
30 }
31};
32
33namespace {
34std::unique_ptr<base::DictionaryValue> GetTestSchema() {
35 return CreateDictionaryValue(R"({
36 'light': 'boolean',
37 'color': 'string',
Vitaly Bukae527a642015-07-28 21:39:45 -070038 'direction':{
39 'properties':{
40 'azimuth': {'type': 'number', 'isRequired': true},
41 'altitude': {'maximum': 90.0}
42 }
43 },
Alex Vakulenko07216fe2014-09-19 15:31:09 -070044 'iso': [50, 100, 200, 400]
45 })");
46}
47
48std::unique_ptr<base::DictionaryValue> GetTestValues() {
49 return CreateDictionaryValue(R"({
50 'light': true,
51 'color': 'white',
52 'direction': {'azimuth':57.2957795, 'altitude':89.9},
53 'iso': 200
54 })");
55}
56
57inline const ObjectSchema& GetTypes(const StatePackage& package) {
58 return StatePackageTestHelper::GetTypes(package);
59}
60// Returns the all state property values in this package.
Vitaly Buka774cdf52015-07-21 13:55:00 -070061inline const ValueMap& GetValues(const StatePackage& package) {
Alex Vakulenko07216fe2014-09-19 15:31:09 -070062 return StatePackageTestHelper::GetValues(package);
63}
64
65} // anonymous namespace
66
67class StatePackageTest : public ::testing::Test {
68 public:
69 void SetUp() override {
70 package_.reset(new StatePackage("test"));
71 ASSERT_TRUE(package_->AddSchemaFromJson(GetTestSchema().get(), nullptr));
72 ASSERT_TRUE(package_->AddValuesFromJson(GetTestValues().get(), nullptr));
73 }
Vitaly Bukaa647c852015-07-06 14:51:01 -070074 void TearDown() override { package_.reset(); }
Alex Vakulenko07216fe2014-09-19 15:31:09 -070075 std::unique_ptr<StatePackage> package_;
76};
77
78TEST(StatePackage, Empty) {
79 StatePackage package("test");
80 EXPECT_EQ("test", package.GetName());
81 EXPECT_TRUE(GetTypes(package).GetProps().empty());
82 EXPECT_TRUE(GetValues(package).empty());
83}
84
85TEST(StatePackage, AddSchemaFromJson_OnEmpty) {
86 StatePackage package("test");
87 ASSERT_TRUE(package.AddSchemaFromJson(GetTestSchema().get(), nullptr));
88 EXPECT_EQ(4, GetTypes(package).GetProps().size());
89 EXPECT_EQ(4, GetValues(package).size());
Vitaly Buka7c82d292015-05-03 18:08:12 -070090
91 auto expected = R"({
92 'color': {
93 'type': 'string'
94 },
95 'direction': {
96 'additionalProperties': false,
97 'properties': {
98 'altitude': {
99 'maximum': 90.0,
100 'type': 'number'
101 },
102 'azimuth': {
103 'type': 'number'
104 }
105 },
Vitaly Bukae527a642015-07-28 21:39:45 -0700106 'type': 'object',
107 'required': [ 'azimuth' ]
Vitaly Buka7c82d292015-05-03 18:08:12 -0700108 },
109 'iso': {
110 'enum': [50, 100, 200, 400],
111 'type': 'integer'
112 },
113 'light': {
114 'type': 'boolean'
115 }
116 })";
Vitaly Buka6942e1f2015-07-28 15:33:55 -0700117 EXPECT_JSON_EQ(expected, *GetTypes(package).ToJson(true, false));
Vitaly Buka7c82d292015-05-03 18:08:12 -0700118
119 expected = R"({
120 'color': '',
121 'direction': {},
122 'iso': 0,
123 'light': false
124 })";
Vitaly Buka6942e1f2015-07-28 15:33:55 -0700125 EXPECT_JSON_EQ(expected, *package.GetValuesAsJson());
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700126}
127
128TEST(StatePackage, AddValuesFromJson_OnEmpty) {
129 StatePackage package("test");
130 ASSERT_TRUE(package.AddSchemaFromJson(GetTestSchema().get(), nullptr));
131 ASSERT_TRUE(package.AddValuesFromJson(GetTestValues().get(), nullptr));
132 EXPECT_EQ(4, GetValues(package).size());
Vitaly Buka7c82d292015-05-03 18:08:12 -0700133 auto expected = R"({
134 'color': 'white',
135 'direction': {
136 'altitude': 89.9,
137 'azimuth': 57.2957795
138 },
139 'iso': 200,
140 'light': true
141 })";
Vitaly Buka6942e1f2015-07-28 15:33:55 -0700142 EXPECT_JSON_EQ(expected, *package.GetValuesAsJson());
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700143}
144
145TEST_F(StatePackageTest, AddSchemaFromJson_AddMore) {
146 auto dict = CreateDictionaryValue("{'brightness':['low', 'medium', 'high']}");
147 ASSERT_TRUE(package_->AddSchemaFromJson(dict.get(), nullptr));
148 EXPECT_EQ(5, GetTypes(*package_).GetProps().size());
149 EXPECT_EQ(5, GetValues(*package_).size());
Vitaly Buka7c82d292015-05-03 18:08:12 -0700150 auto expected = R"({
151 'brightness': {
152 'enum': ['low', 'medium', 'high'],
153 'type': 'string'
154 },
155 'color': {
156 'type': 'string'
157 },
158 'direction': {
159 'additionalProperties': false,
160 'properties': {
161 'altitude': {
162 'maximum': 90.0,
163 'type': 'number'
164 },
165 'azimuth': {
166 'type': 'number'
167 }
168 },
Vitaly Bukae527a642015-07-28 21:39:45 -0700169 'type': 'object',
170 'required': [ 'azimuth' ]
Vitaly Buka7c82d292015-05-03 18:08:12 -0700171 },
172 'iso': {
173 'enum': [50, 100, 200, 400],
174 'type': 'integer'
175 },
176 'light': {
177 'type': 'boolean'
178 }
179 })";
Vitaly Buka6942e1f2015-07-28 15:33:55 -0700180 EXPECT_JSON_EQ(expected, *GetTypes(*package_).ToJson(true, false));
Vitaly Buka7c82d292015-05-03 18:08:12 -0700181
182 expected = R"({
183 'brightness': '',
184 'color': 'white',
185 'direction': {
186 'altitude': 89.9,
187 'azimuth': 57.2957795
188 },
189 'iso': 200,
190 'light': true
191 })";
Vitaly Buka6942e1f2015-07-28 15:33:55 -0700192 EXPECT_JSON_EQ(expected, *package_->GetValuesAsJson());
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700193}
194
195TEST_F(StatePackageTest, AddValuesFromJson_AddMore) {
196 auto dict = CreateDictionaryValue("{'brightness':['low', 'medium', 'high']}");
197 ASSERT_TRUE(package_->AddSchemaFromJson(dict.get(), nullptr));
198 dict = CreateDictionaryValue("{'brightness':'medium'}");
199 ASSERT_TRUE(package_->AddValuesFromJson(dict.get(), nullptr));
200 EXPECT_EQ(5, GetValues(*package_).size());
Vitaly Buka7c82d292015-05-03 18:08:12 -0700201 auto expected = R"({
202 'brightness': 'medium',
203 'color': 'white',
204 'direction': {
205 'altitude': 89.9,
206 'azimuth': 57.2957795
207 },
208 'iso': 200,
209 'light': true
210 })";
Vitaly Buka6942e1f2015-07-28 15:33:55 -0700211 EXPECT_JSON_EQ(expected, *package_->GetValuesAsJson());
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700212}
213
214TEST_F(StatePackageTest, AddSchemaFromJson_Error_Redefined) {
215 auto dict = CreateDictionaryValue("{'color':['white', 'blue', 'red']}");
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700216 ErrorPtr error;
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700217 EXPECT_FALSE(package_->AddSchemaFromJson(dict.get(), &error));
218 EXPECT_EQ(errors::state::kDomain, error->GetDomain());
219 EXPECT_EQ(errors::state::kPropertyRedefinition, error->GetCode());
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700220}
221
222TEST_F(StatePackageTest, AddValuesFromJson_Error_Undefined) {
223 auto dict = CreateDictionaryValue("{'brightness':'medium'}");
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700224 ErrorPtr error;
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700225 EXPECT_FALSE(package_->AddValuesFromJson(dict.get(), &error));
226 EXPECT_EQ(errors::state::kDomain, error->GetDomain());
227 EXPECT_EQ(errors::state::kPropertyNotDefined, error->GetCode());
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700228}
229
230TEST_F(StatePackageTest, GetPropertyValue) {
Vitaly Bukae527a642015-07-28 21:39:45 -0700231 EXPECT_JSON_EQ("'white'", *package_->GetPropertyValue("color", nullptr));
232 EXPECT_JSON_EQ("true", *package_->GetPropertyValue("light", nullptr));
233 EXPECT_JSON_EQ("200", *package_->GetPropertyValue("iso", nullptr));
234 EXPECT_JSON_EQ("{'altitude': 89.9, 'azimuth': 57.2957795}",
235 *package_->GetPropertyValue("direction", nullptr));
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700236}
237
238TEST_F(StatePackageTest, GetPropertyValue_Unknown) {
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700239 ErrorPtr error;
Vitaly Bukae527a642015-07-28 21:39:45 -0700240 EXPECT_EQ(nullptr, package_->GetPropertyValue("volume", &error));
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700241 EXPECT_EQ(errors::state::kDomain, error->GetDomain());
242 EXPECT_EQ(errors::state::kPropertyNotDefined, error->GetCode());
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700243}
244
245TEST_F(StatePackageTest, SetPropertyValue_Simple) {
Vitaly Bukaa647c852015-07-06 14:51:01 -0700246 EXPECT_TRUE(
Vitaly Bukae527a642015-07-28 21:39:45 -0700247 package_->SetPropertyValue("color", base::StringValue{"blue"}, nullptr));
248 EXPECT_JSON_EQ("'blue'", *package_->GetPropertyValue("color", nullptr));
249 EXPECT_TRUE(package_->SetPropertyValue("light", base::FundamentalValue{false},
250 nullptr));
251 bool light = false;
252 ASSERT_TRUE(
253 package_->GetPropertyValue("light", nullptr)->GetAsBoolean(&light));
254 EXPECT_FALSE(light);
255 EXPECT_TRUE(
256 package_->SetPropertyValue("iso", base::FundamentalValue{400}, nullptr));
257 EXPECT_JSON_EQ("400", *package_->GetPropertyValue("iso", nullptr));
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700258}
259
260TEST_F(StatePackageTest, SetPropertyValue_Object) {
Vitaly Bukae527a642015-07-28 21:39:45 -0700261 EXPECT_TRUE(package_->SetPropertyValue(
262 "direction",
263 *CreateDictionaryValue("{'altitude': 45.0, 'azimuth': 15.0}"), nullptr));
Vitaly Buka7c82d292015-05-03 18:08:12 -0700264
265 auto expected = R"({
266 'color': 'white',
267 'direction': {
268 'altitude': 45.0,
269 'azimuth': 15.0
270 },
271 'iso': 200,
272 'light': true
273 })";
Vitaly Buka6942e1f2015-07-28 15:33:55 -0700274 EXPECT_JSON_EQ(expected, *package_->GetValuesAsJson());
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700275}
276
277TEST_F(StatePackageTest, SetPropertyValue_Error_TypeMismatch) {
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700278 ErrorPtr error;
Vitaly Bukae527a642015-07-28 21:39:45 -0700279 ASSERT_FALSE(
280 package_->SetPropertyValue("color", base::FundamentalValue{12}, &error));
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700281 EXPECT_EQ(errors::commands::kDomain, error->GetDomain());
282 EXPECT_EQ(errors::commands::kTypeMismatch, error->GetCode());
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700283 error.reset();
284
Vitaly Bukae527a642015-07-28 21:39:45 -0700285 ASSERT_FALSE(
286 package_->SetPropertyValue("iso", base::FundamentalValue{false}, &error));
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700287 EXPECT_EQ(errors::commands::kDomain, error->GetDomain());
288 EXPECT_EQ(errors::commands::kTypeMismatch, error->GetCode());
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700289}
290
291TEST_F(StatePackageTest, SetPropertyValue_Error_OutOfRange) {
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700292 ErrorPtr error;
Vitaly Bukae527a642015-07-28 21:39:45 -0700293 ASSERT_FALSE(
294 package_->SetPropertyValue("iso", base::FundamentalValue{150}, &error));
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700295 EXPECT_EQ(errors::commands::kDomain, error->GetDomain());
296 EXPECT_EQ(errors::commands::kOutOfRange, error->GetCode());
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700297}
298
299TEST_F(StatePackageTest, SetPropertyValue_Error_Object_TypeMismatch) {
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700300 ErrorPtr error;
Vitaly Bukae527a642015-07-28 21:39:45 -0700301 ASSERT_FALSE(package_->SetPropertyValue(
Vitaly Bukac58a8282015-07-29 01:25:20 -0700302 "direction",
303 *CreateDictionaryValue("{'altitude': 45.0, 'azimuth': '15'}"), &error));
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700304 EXPECT_EQ(errors::commands::kDomain, error->GetDomain());
305 EXPECT_EQ(errors::commands::kInvalidPropValue, error->GetCode());
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700306 const Error* inner = error->GetInnerError();
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700307 EXPECT_EQ(errors::commands::kDomain, inner->GetDomain());
308 EXPECT_EQ(errors::commands::kTypeMismatch, inner->GetCode());
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700309}
310
311TEST_F(StatePackageTest, SetPropertyValue_Error_Object_OutOfRange) {
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700312 ErrorPtr error;
Vitaly Bukae527a642015-07-28 21:39:45 -0700313 ASSERT_FALSE(package_->SetPropertyValue(
314 "direction",
315 *CreateDictionaryValue("{'altitude': 100.0, 'azimuth': 290.0}"), &error));
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700316 EXPECT_EQ(errors::commands::kDomain, error->GetDomain());
317 EXPECT_EQ(errors::commands::kInvalidPropValue, error->GetCode());
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700318 const Error* inner = error->GetInnerError();
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700319 EXPECT_EQ(errors::commands::kDomain, inner->GetDomain());
320 EXPECT_EQ(errors::commands::kOutOfRange, inner->GetCode());
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700321}
322
323TEST_F(StatePackageTest, SetPropertyValue_Error_Object_UnknownProperty) {
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700324 ErrorPtr error;
Vitaly Bukae527a642015-07-28 21:39:45 -0700325 ASSERT_FALSE(package_->SetPropertyValue(
326 "direction", *CreateDictionaryValue(
327 "{'altitude': 10.0, 'azimuth': 20.0, 'spin': 30.0}"),
328 &error));
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700329 EXPECT_EQ(errors::commands::kDomain, error->GetDomain());
330 EXPECT_EQ(errors::commands::kUnknownProperty, error->GetCode());
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700331}
332
Vitaly Buka79c05e92015-07-29 12:25:37 -0700333TEST_F(StatePackageTest, SetPropertyValue_Object_OptionalProperty) {
334 EXPECT_JSON_EQ("{'altitude': 89.9, 'azimuth': 57.2957795}",
335 *package_->GetProperty("direction")->ToJson());
336 ASSERT_TRUE(package_->SetPropertyValue(
337 "direction", *CreateDictionaryValue("{'azimuth': 10.0}"), nullptr));
338 EXPECT_JSON_EQ("{'azimuth': 10.0}",
339 *package_->GetProperty("direction")->ToJson());
340}
341
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700342TEST_F(StatePackageTest, SetPropertyValue_Error_Object_MissingProperty) {
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700343 ErrorPtr error;
Vitaly Bukae527a642015-07-28 21:39:45 -0700344 ASSERT_FALSE(package_->SetPropertyValue(
345 "direction", *CreateDictionaryValue("{'altitude': 10.0}"), &error));
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700346 EXPECT_EQ(errors::commands::kDomain, error->GetDomain());
347 EXPECT_EQ(errors::commands::kPropertyMissing, error->GetCode());
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700348}
349
350TEST_F(StatePackageTest, SetPropertyValue_Error_Unknown) {
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700351 ErrorPtr error;
Vitaly Bukae527a642015-07-28 21:39:45 -0700352 ASSERT_FALSE(package_->SetPropertyValue("volume", base::FundamentalValue{100},
353 &error));
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700354 EXPECT_EQ(errors::state::kDomain, error->GetDomain());
355 EXPECT_EQ(errors::state::kPropertyNotDefined, error->GetCode());
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700356}
357
Vitaly Bukab6f015a2015-07-09 14:59:23 -0700358} // namespace weave