blob: d4c4ab19ebbf0a54d588c595513a148166b56833 [file] [log] [blame]
Alex Vakulenko7c36b672014-07-16 14:50:58 -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
5#include <gtest/gtest.h>
6
7#include "buffet/commands/command_dictionary.h"
8#include "buffet/commands/unittest_utils.h"
9
10using buffet::unittests::CreateDictionaryValue;
11
12TEST(CommandDictionary, Empty) {
13 buffet::CommandDictionary dict;
14 EXPECT_TRUE(dict.IsEmpty());
15 EXPECT_EQ(nullptr, dict.FindCommand("robot.jump"));
16 EXPECT_TRUE(dict.GetCommandNamesByCategory("robotd").empty());
17}
18
19TEST(CommandDictionary, LoadCommands) {
20 auto json = CreateDictionaryValue(R"({
21 'robot': {
22 'jump': {
23 'parameters': {
24 'height': 'integer',
25 '_jumpType': ['_withAirFlip', '_withSpin', '_withKick']
26 }
27 }
28 }
29 })");
30 buffet::CommandDictionary dict;
Alex Vakulenkofd448692014-07-22 07:46:53 -070031 EXPECT_TRUE(dict.LoadCommands(*json, "robotd", nullptr, nullptr));
Alex Vakulenko7c36b672014-07-16 14:50:58 -070032 EXPECT_EQ(1, dict.GetSize());
33 EXPECT_NE(nullptr, dict.FindCommand("robot.jump"));
34 json = CreateDictionaryValue(R"({
35 'base': {
36 'reboot': {
37 'parameters': {'delay': 'integer'}
38 },
39 'shutdown': {
40 'parameters': {}
41 }
42 }
43 })");
Alex Vakulenkofd448692014-07-22 07:46:53 -070044 EXPECT_TRUE(dict.LoadCommands(*json, "powerd", nullptr, nullptr));
Alex Vakulenko7c36b672014-07-16 14:50:58 -070045 EXPECT_EQ(3, dict.GetSize());
46 EXPECT_NE(nullptr, dict.FindCommand("robot.jump"));
47 EXPECT_NE(nullptr, dict.FindCommand("base.reboot"));
48 EXPECT_NE(nullptr, dict.FindCommand("base.shutdown"));
49 EXPECT_EQ(nullptr, dict.FindCommand("foo.bar"));
50 std::vector<std::string> expected_commands{"base.reboot", "base.shutdown"};
51 EXPECT_EQ(expected_commands, dict.GetCommandNamesByCategory("powerd"));
52}
53
54TEST(CommandDictionary, LoadCommands_Failures) {
55 buffet::CommandDictionary dict;
Alex Vakulenko5f472062014-08-14 17:54:04 -070056 chromeos::ErrorPtr error;
Alex Vakulenko7c36b672014-07-16 14:50:58 -070057
58 // Command definition missing 'parameters' property.
59 auto json = CreateDictionaryValue("{'robot':{'jump':{}}}");
Alex Vakulenkofd448692014-07-22 07:46:53 -070060 EXPECT_FALSE(dict.LoadCommands(*json, "robotd", nullptr, &error));
Alex Vakulenko7c36b672014-07-16 14:50:58 -070061 EXPECT_EQ("parameter_missing", error->GetCode());
62 EXPECT_EQ("Command definition 'robot.jump' is missing property 'parameters'",
63 error->GetMessage());
64 error.reset();
65
66 // Command definition is not an object.
67 json = CreateDictionaryValue("{'robot':{'jump':0}}");
Alex Vakulenkofd448692014-07-22 07:46:53 -070068 EXPECT_FALSE(dict.LoadCommands(*json, "robotd", nullptr, &error));
Alex Vakulenko7c36b672014-07-16 14:50:58 -070069 EXPECT_EQ("type_mismatch", error->GetCode());
70 EXPECT_EQ("Expecting an object for command 'jump'", error->GetMessage());
71 error.reset();
72
73 // Package definition is not an object.
74 json = CreateDictionaryValue("{'robot':'blah'}");
Alex Vakulenkofd448692014-07-22 07:46:53 -070075 EXPECT_FALSE(dict.LoadCommands(*json, "robotd", nullptr, &error));
Alex Vakulenko7c36b672014-07-16 14:50:58 -070076 EXPECT_EQ("type_mismatch", error->GetCode());
77 EXPECT_EQ("Expecting an object for package 'robot'", error->GetMessage());
78 error.reset();
79
80 // Invalid command definition is not an object.
81 json = CreateDictionaryValue("{'robot':{'jump':{'parameters':{'flip':0}}}}");
Alex Vakulenkofd448692014-07-22 07:46:53 -070082 EXPECT_FALSE(dict.LoadCommands(*json, "robotd", nullptr, &error));
Alex Vakulenko7c36b672014-07-16 14:50:58 -070083 EXPECT_EQ("invalid_object_schema", error->GetCode());
84 EXPECT_EQ("Invalid definition for command 'robot.jump'", error->GetMessage());
85 EXPECT_NE(nullptr, error->GetInnerError()); // Must have additional info.
86 error.reset();
87
Alex Vakulenkofd448692014-07-22 07:46:53 -070088 // Empty command name.
89 json = CreateDictionaryValue("{'robot':{'':{'parameters':{'flip':0}}}}");
90 EXPECT_FALSE(dict.LoadCommands(*json, "robotd", nullptr, &error));
91 EXPECT_EQ("invalid_command_name", error->GetCode());
92 EXPECT_EQ("Unnamed command encountered in package 'robot'",
93 error->GetMessage());
94 error.reset();
95}
96
97TEST(CommandDictionary, LoadCommands_RedefineInDifferentCategory) {
Alex Vakulenko7c36b672014-07-16 14:50:58 -070098 // Redefine commands in different category.
Alex Vakulenkofd448692014-07-22 07:46:53 -070099 buffet::CommandDictionary dict;
Alex Vakulenko5f472062014-08-14 17:54:04 -0700100 chromeos::ErrorPtr error;
Alex Vakulenkofd448692014-07-22 07:46:53 -0700101 auto json = CreateDictionaryValue("{'robot':{'jump':{'parameters':{}}}}");
102 dict.LoadCommands(*json, "category1", nullptr, &error);
103 EXPECT_FALSE(dict.LoadCommands(*json, "category2", nullptr, &error));
Alex Vakulenko7c36b672014-07-16 14:50:58 -0700104 EXPECT_EQ("duplicate_command_definition", error->GetCode());
105 EXPECT_EQ("Definition for command 'robot.jump' overrides an earlier "
106 "definition in category 'category1'", error->GetMessage());
107 error.reset();
108}
Alex Vakulenkofd448692014-07-22 07:46:53 -0700109
110TEST(CommandDictionary, LoadCommands_CustomCommandNaming) {
111 // Custom command must start with '_'.
112 buffet::CommandDictionary base_dict;
113 buffet::CommandDictionary dict;
Alex Vakulenko5f472062014-08-14 17:54:04 -0700114 chromeos::ErrorPtr error;
Alex Vakulenkofd448692014-07-22 07:46:53 -0700115 auto json = CreateDictionaryValue(R"({
116 'base': {
117 'reboot': {
118 'parameters': {'delay': 'integer'}
119 }
120 }
121 })");
122 base_dict.LoadCommands(*json, "", nullptr, &error);
123 EXPECT_TRUE(dict.LoadCommands(*json, "robotd", &base_dict, &error));
124 auto json2 = CreateDictionaryValue("{'base':{'jump':{'parameters':{}}}}");
125 EXPECT_FALSE(dict.LoadCommands(*json2, "robotd", &base_dict, &error));
126 EXPECT_EQ("invalid_command_name", error->GetCode());
127 EXPECT_EQ("The name of custom command 'jump' in package 'base' must start "
128 "with '_'", error->GetMessage());
129 error.reset();
130
131 // If the command starts with "_", then it's Ok.
132 json2 = CreateDictionaryValue("{'base':{'_jump':{'parameters':{}}}}");
133 EXPECT_TRUE(dict.LoadCommands(*json2, "robotd", &base_dict, nullptr));
134}
135
136TEST(CommandDictionary, LoadCommands_RedefineStdCommand) {
137 // Redefine commands parameter type.
138 buffet::CommandDictionary base_dict;
139 buffet::CommandDictionary dict;
Alex Vakulenko5f472062014-08-14 17:54:04 -0700140 chromeos::ErrorPtr error;
Alex Vakulenkofd448692014-07-22 07:46:53 -0700141 auto json = CreateDictionaryValue(R"({
142 'base': {
143 'reboot': {
144 'parameters': {'delay': 'integer'}
145 }
146 }
147 })");
148 base_dict.LoadCommands(*json, "", nullptr, &error);
149 auto json2 = CreateDictionaryValue(R"({
150 'base': {
151 'reboot': {
152 'parameters': {'delay': 'string'}
153 }
154 }
155 })");
156 EXPECT_FALSE(dict.LoadCommands(*json2, "robotd", &base_dict, &error));
157 EXPECT_EQ("invalid_object_schema", error->GetCode());
158 EXPECT_EQ("Invalid definition for command 'base.reboot'",
159 error->GetMessage());
160 EXPECT_EQ("invalid_parameter_definition", error->GetInnerError()->GetCode());
161 EXPECT_EQ("Error in definition of property 'delay'",
162 error->GetInnerError()->GetMessage());
163 EXPECT_EQ("param_type_changed", error->GetFirstError()->GetCode());
164 EXPECT_EQ("Redefining a property of type integer as string",
165 error->GetFirstError()->GetMessage());
166 error.reset();
167}
Alex Vakulenko45109442014-07-29 11:07:10 -0700168
169TEST(CommandDictionary, GetCommandsAsJson) {
170 auto json_base = CreateDictionaryValue(R"({
171 'base': {
172 'reboot': {
173 'parameters': {'delay': {'maximum': 100}}
174 },
175 'shutdown': {
176 'parameters': {}
177 }
178 }
179 })");
180 buffet::CommandDictionary base_dict;
181 base_dict.LoadCommands(*json_base, "base", nullptr, nullptr);
182
183 auto json = buffet::unittests::CreateDictionaryValue(R"({
184 'base': {
185 'reboot': {
186 'parameters': {'delay': {'minimum': 10}}
187 }
188 },
189 'robot': {
190 '_jump': {
191 'parameters': {'_height': 'integer'}
192 }
193 }
194 })");
195 buffet::CommandDictionary dict;
196 dict.LoadCommands(*json, "device", &base_dict, nullptr);
197
198 json = dict.GetCommandsAsJson(false, nullptr);
199 EXPECT_NE(nullptr, json.get());
200 EXPECT_EQ("{'base':{'reboot':{'parameters':{'delay':{'minimum':10}}}},"
201 "'robot':{'_jump':{'parameters':{'_height':'integer'}}}}",
202 buffet::unittests::ValueToString(json.get()));
203
204 json = dict.GetCommandsAsJson(true, nullptr);
205 EXPECT_NE(nullptr, json.get());
206 EXPECT_EQ("{'base':{'reboot':{'parameters':{'delay':{"
207 "'maximum':100,'minimum':10,'type':'integer'}}}},"
208 "'robot':{'_jump':{'parameters':{'_height':{'type':'integer'}}}}}",
209 buffet::unittests::ValueToString(json.get()));
210}