OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
| 5 #include "extensions/renderer/argument_spec.h" |
5 #include "base/memory/ptr_util.h" | 6 #include "base/memory/ptr_util.h" |
6 #include "base/values.h" | 7 #include "base/values.h" |
7 #include "extensions/renderer/api_binding_test_util.h" | 8 #include "extensions/renderer/api_binding_test_util.h" |
| 9 #include "extensions/renderer/api_invocation_errors.h" |
8 #include "extensions/renderer/api_type_reference_map.h" | 10 #include "extensions/renderer/api_type_reference_map.h" |
9 #include "extensions/renderer/argument_spec.h" | |
10 #include "gin/converter.h" | 11 #include "gin/converter.h" |
11 #include "gin/public/isolate_holder.h" | 12 #include "gin/public/isolate_holder.h" |
12 #include "gin/test/v8_test.h" | 13 #include "gin/test/v8_test.h" |
13 #include "testing/gtest/include/gtest/gtest.h" | 14 #include "testing/gtest/include/gtest/gtest.h" |
14 #include "v8/include/v8.h" | 15 #include "v8/include/v8.h" |
15 | 16 |
16 namespace extensions { | 17 namespace extensions { |
17 | 18 |
18 class ArgumentSpecUnitTest : public gin::V8Test { | 19 class ArgumentSpecUnitTest : public gin::V8Test { |
19 protected: | 20 protected: |
20 ArgumentSpecUnitTest() | 21 ArgumentSpecUnitTest() |
21 : type_refs_(APITypeReferenceMap::InitializeTypeCallback()) {} | 22 : type_refs_(APITypeReferenceMap::InitializeTypeCallback()) {} |
22 ~ArgumentSpecUnitTest() override {} | 23 ~ArgumentSpecUnitTest() override {} |
| 24 |
| 25 enum class TestResult { |
| 26 PASS, |
| 27 FAIL, |
| 28 THROW, |
| 29 }; |
| 30 |
| 31 struct RunTestParams { |
| 32 RunTestParams(const ArgumentSpec& spec, |
| 33 base::StringPiece script_source, |
| 34 TestResult result) |
| 35 : spec(spec), script_source(script_source), expected_result(result) {} |
| 36 |
| 37 const ArgumentSpec& spec; |
| 38 base::StringPiece script_source; |
| 39 TestResult expected_result; |
| 40 base::StringPiece expected_json; |
| 41 base::StringPiece expected_error; |
| 42 base::StringPiece expected_thrown_message; |
| 43 const base::Value* expected_value = nullptr; |
| 44 bool should_convert = true; |
| 45 }; |
| 46 |
23 void ExpectSuccess(const ArgumentSpec& spec, | 47 void ExpectSuccess(const ArgumentSpec& spec, |
24 const std::string& script_source, | 48 const std::string& script_source, |
25 const std::string& expected_json_single_quotes) { | 49 const std::string& expected_json_single_quotes) { |
26 RunTest(spec, script_source, true, TestResult::PASS, | 50 RunTestParams params(spec, script_source, TestResult::PASS); |
27 ReplaceSingleQuotes(expected_json_single_quotes), nullptr, | 51 std::string expected_json = |
28 std::string()); | 52 ReplaceSingleQuotes(expected_json_single_quotes); |
| 53 params.expected_json = expected_json; |
| 54 RunTest(params); |
29 } | 55 } |
30 | 56 |
31 void ExpectSuccess(const ArgumentSpec& spec, | 57 void ExpectSuccess(const ArgumentSpec& spec, |
32 const std::string& script_source, | 58 const std::string& script_source, |
33 const base::Value& expected_value) { | 59 const base::Value& expected_value) { |
34 RunTest(spec, script_source, true, TestResult::PASS, std::string(), | 60 RunTestParams params(spec, script_source, TestResult::PASS); |
35 &expected_value, std::string()); | 61 params.expected_value = &expected_value; |
| 62 RunTest(params); |
36 } | 63 } |
37 | 64 |
38 void ExpectSuccessWithNoConversion(const ArgumentSpec& spec, | 65 void ExpectSuccessWithNoConversion(const ArgumentSpec& spec, |
39 const std::string& script_source) { | 66 const std::string& script_source) { |
40 RunTest(spec, script_source, false, TestResult::PASS, std::string(), | 67 RunTestParams params(spec, script_source, TestResult::PASS); |
41 nullptr, std::string()); | 68 params.should_convert = false; |
| 69 RunTest(params); |
42 } | 70 } |
43 | 71 |
44 void ExpectFailure(const ArgumentSpec& spec, | 72 void ExpectFailure(const ArgumentSpec& spec, |
45 const std::string& script_source) { | 73 const std::string& script_source, |
46 RunTest(spec, script_source, true, TestResult::FAIL, std::string(), nullptr, | 74 const std::string& expected_error) { |
47 std::string()); | 75 RunTestParams params(spec, script_source, TestResult::FAIL); |
| 76 params.expected_error = expected_error; |
| 77 RunTest(params); |
48 } | 78 } |
49 | 79 |
50 void ExpectFailureWithNoConversion(const ArgumentSpec& spec, | 80 void ExpectFailureWithNoConversion(const ArgumentSpec& spec, |
51 const std::string& script_source) { | 81 const std::string& script_source, |
52 RunTest(spec, script_source, false, TestResult::FAIL, std::string(), | 82 const std::string& expected_error) { |
53 nullptr, std::string()); | 83 RunTestParams params(spec, script_source, TestResult::FAIL); |
| 84 params.should_convert = false; |
| 85 params.expected_error = expected_error; |
| 86 RunTest(params); |
54 } | 87 } |
55 | 88 |
56 void ExpectThrow(const ArgumentSpec& spec, | 89 void ExpectThrow(const ArgumentSpec& spec, |
57 const std::string& script_source, | 90 const std::string& script_source, |
58 const std::string& expected_thrown_message) { | 91 const std::string& expected_thrown_message) { |
59 RunTest(spec, script_source, true, TestResult::THROW, std::string(), | 92 RunTestParams params(spec, script_source, TestResult::THROW); |
60 nullptr, expected_thrown_message); | 93 params.expected_thrown_message = expected_thrown_message; |
| 94 RunTest(params); |
61 } | 95 } |
62 | 96 |
63 void AddTypeRef(const std::string& id, std::unique_ptr<ArgumentSpec> spec) { | 97 void AddTypeRef(const std::string& id, std::unique_ptr<ArgumentSpec> spec) { |
64 type_refs_.AddSpec(id, std::move(spec)); | 98 type_refs_.AddSpec(id, std::move(spec)); |
65 } | 99 } |
66 | 100 |
67 private: | 101 private: |
68 enum class TestResult { PASS, FAIL, THROW, }; | 102 void RunTest(const RunTestParams& params); |
69 | |
70 void RunTest(const ArgumentSpec& spec, | |
71 const std::string& script_source, | |
72 bool should_convert, | |
73 TestResult expected_result, | |
74 const std::string& expected_json, | |
75 const base::Value* expected_value, | |
76 const std::string& expected_thrown_message); | |
77 | 103 |
78 APITypeReferenceMap type_refs_; | 104 APITypeReferenceMap type_refs_; |
79 | 105 |
80 DISALLOW_COPY_AND_ASSIGN(ArgumentSpecUnitTest); | 106 DISALLOW_COPY_AND_ASSIGN(ArgumentSpecUnitTest); |
81 }; | 107 }; |
82 | 108 |
83 void ArgumentSpecUnitTest::RunTest(const ArgumentSpec& spec, | 109 void ArgumentSpecUnitTest::RunTest(const RunTestParams& params) { |
84 const std::string& script_source, | |
85 bool should_convert, | |
86 TestResult expected_result, | |
87 const std::string& expected_json, | |
88 const base::Value* expected_value, | |
89 const std::string& expected_thrown_message) { | |
90 v8::Isolate* isolate = instance_->isolate(); | 110 v8::Isolate* isolate = instance_->isolate(); |
91 v8::HandleScope handle_scope(instance_->isolate()); | 111 v8::HandleScope handle_scope(instance_->isolate()); |
92 | 112 |
93 v8::Local<v8::Context> context = | 113 v8::Local<v8::Context> context = |
94 v8::Local<v8::Context>::New(instance_->isolate(), context_); | 114 v8::Local<v8::Context>::New(instance_->isolate(), context_); |
95 v8::TryCatch try_catch(isolate); | 115 v8::TryCatch try_catch(isolate); |
96 v8::Local<v8::Value> val = V8ValueFromScriptSource(context, script_source); | 116 v8::Local<v8::Value> val = |
97 ASSERT_FALSE(val.IsEmpty()) << script_source; | 117 V8ValueFromScriptSource(context, params.script_source); |
| 118 ASSERT_FALSE(val.IsEmpty()) << params.script_source; |
98 | 119 |
99 std::string error; | 120 std::string error; |
100 std::unique_ptr<base::Value> out_value; | 121 std::unique_ptr<base::Value> out_value; |
101 bool did_succeed = | 122 bool did_succeed = params.spec.ParseArgument( |
102 spec.ParseArgument(context, val, type_refs_, | 123 context, val, type_refs_, params.should_convert ? &out_value : nullptr, |
103 should_convert ? &out_value : nullptr, &error); | 124 &error); |
104 bool should_succeed = expected_result == TestResult::PASS; | 125 bool should_succeed = params.expected_result == TestResult::PASS; |
105 ASSERT_EQ(should_succeed, did_succeed) << script_source << ", " << error; | 126 ASSERT_EQ(should_succeed, did_succeed) |
106 ASSERT_EQ(did_succeed && should_convert, !!out_value); | 127 << params.script_source << ", " << error; |
107 bool should_throw = expected_result == TestResult::THROW; | 128 ASSERT_EQ(did_succeed && params.should_convert, !!out_value); |
108 ASSERT_EQ(should_throw, try_catch.HasCaught()) << script_source; | 129 bool should_throw = params.expected_result == TestResult::THROW; |
109 if (should_succeed && should_convert) { | 130 ASSERT_EQ(should_throw, try_catch.HasCaught()) << params.script_source; |
| 131 |
| 132 if (!params.expected_error.empty()) |
| 133 EXPECT_EQ(params.expected_error, error) << params.script_source; |
| 134 |
| 135 if (should_succeed && params.should_convert) { |
110 ASSERT_TRUE(out_value); | 136 ASSERT_TRUE(out_value); |
111 if (expected_value) | 137 if (params.expected_value) |
112 EXPECT_TRUE(expected_value->Equals(out_value.get())) << script_source; | 138 EXPECT_TRUE(params.expected_value->Equals(out_value.get())) |
| 139 << params.script_source; |
113 else | 140 else |
114 EXPECT_EQ(expected_json, ValueToString(*out_value)); | 141 EXPECT_EQ(params.expected_json, ValueToString(*out_value)); |
115 } else if (should_throw) { | 142 } else if (should_throw) { |
116 EXPECT_EQ(expected_thrown_message, | 143 EXPECT_EQ(params.expected_thrown_message, |
117 gin::V8ToString(try_catch.Message()->Get())); | 144 gin::V8ToString(try_catch.Message()->Get())); |
118 } | 145 } |
119 } | 146 } |
120 | 147 |
121 TEST_F(ArgumentSpecUnitTest, Test) { | 148 TEST_F(ArgumentSpecUnitTest, Test) { |
| 149 using namespace api_errors; |
| 150 |
122 { | 151 { |
123 ArgumentSpec spec(*ValueFromString("{'type': 'integer'}")); | 152 ArgumentSpec spec(*ValueFromString("{'type': 'integer'}")); |
124 ExpectSuccess(spec, "1", "1"); | 153 ExpectSuccess(spec, "1", "1"); |
125 ExpectSuccess(spec, "-1", "-1"); | 154 ExpectSuccess(spec, "-1", "-1"); |
126 ExpectSuccess(spec, "0", "0"); | 155 ExpectSuccess(spec, "0", "0"); |
127 ExpectSuccess(spec, "0.0", "0"); | 156 ExpectSuccess(spec, "0.0", "0"); |
128 ExpectFailure(spec, "undefined"); | 157 ExpectFailure(spec, "undefined", InvalidType(kTypeInteger, kTypeUndefined)); |
129 ExpectFailure(spec, "null"); | 158 ExpectFailure(spec, "null", InvalidType(kTypeInteger, kTypeNull)); |
130 ExpectFailure(spec, "1.1"); | 159 ExpectFailure(spec, "1.1", InvalidType(kTypeInteger, kTypeDouble)); |
131 ExpectFailure(spec, "'foo'"); | 160 ExpectFailure(spec, "'foo'", InvalidType(kTypeInteger, kTypeString)); |
132 ExpectFailure(spec, "'1'"); | 161 ExpectFailure(spec, "'1'", InvalidType(kTypeInteger, kTypeString)); |
133 ExpectFailure(spec, "{}"); | 162 ExpectFailure(spec, "({})", InvalidType(kTypeInteger, kTypeObject)); |
134 ExpectFailure(spec, "[1]"); | 163 ExpectFailure(spec, "[1]", InvalidType(kTypeInteger, kTypeList)); |
135 } | 164 } |
136 | 165 |
137 { | 166 { |
138 ArgumentSpec spec(*ValueFromString("{'type': 'number'}")); | 167 ArgumentSpec spec(*ValueFromString("{'type': 'number'}")); |
139 ExpectSuccess(spec, "1", "1.0"); | 168 ExpectSuccess(spec, "1", "1.0"); |
140 ExpectSuccess(spec, "-1", "-1.0"); | 169 ExpectSuccess(spec, "-1", "-1.0"); |
141 ExpectSuccess(spec, "0", "0.0"); | 170 ExpectSuccess(spec, "0", "0.0"); |
142 ExpectSuccess(spec, "1.1", "1.1"); | 171 ExpectSuccess(spec, "1.1", "1.1"); |
143 ExpectSuccess(spec, "1.", "1.0"); | 172 ExpectSuccess(spec, "1.", "1.0"); |
144 ExpectSuccess(spec, ".1", "0.1"); | 173 ExpectSuccess(spec, ".1", "0.1"); |
145 ExpectFailure(spec, "undefined"); | 174 ExpectFailure(spec, "undefined", InvalidType(kTypeDouble, kTypeUndefined)); |
146 ExpectFailure(spec, "null"); | 175 ExpectFailure(spec, "null", InvalidType(kTypeDouble, kTypeNull)); |
147 ExpectFailure(spec, "'foo'"); | 176 ExpectFailure(spec, "'foo'", InvalidType(kTypeDouble, kTypeString)); |
148 ExpectFailure(spec, "'1.1'"); | 177 ExpectFailure(spec, "'1.1'", InvalidType(kTypeDouble, kTypeString)); |
149 ExpectFailure(spec, "{}"); | 178 ExpectFailure(spec, "({})", InvalidType(kTypeDouble, kTypeObject)); |
150 ExpectFailure(spec, "[1.1]"); | 179 ExpectFailure(spec, "[1.1]", InvalidType(kTypeDouble, kTypeList)); |
151 } | 180 } |
152 | 181 |
153 { | 182 { |
154 ArgumentSpec spec(*ValueFromString("{'type': 'integer', 'minimum': 1}")); | 183 ArgumentSpec spec(*ValueFromString("{'type': 'integer', 'minimum': 1}")); |
155 ExpectSuccess(spec, "2", "2"); | 184 ExpectSuccess(spec, "2", "2"); |
156 ExpectSuccess(spec, "1", "1"); | 185 ExpectSuccess(spec, "1", "1"); |
157 ExpectFailure(spec, "0"); | 186 ExpectFailure(spec, "0", NumberTooSmall(1)); |
158 ExpectFailure(spec, "-1"); | 187 ExpectFailure(spec, "-1", NumberTooSmall(1)); |
159 } | 188 } |
160 | 189 |
161 { | 190 { |
162 ArgumentSpec spec(*ValueFromString("{'type': 'integer', 'maximum': 10}")); | 191 ArgumentSpec spec(*ValueFromString("{'type': 'integer', 'maximum': 10}")); |
163 ExpectSuccess(spec, "10", "10"); | 192 ExpectSuccess(spec, "10", "10"); |
164 ExpectSuccess(spec, "1", "1"); | 193 ExpectSuccess(spec, "1", "1"); |
165 ExpectFailure(spec, "11"); | 194 ExpectFailure(spec, "11", NumberTooLarge(10)); |
166 } | 195 } |
167 | 196 |
168 { | 197 { |
169 ArgumentSpec spec(*ValueFromString("{'type': 'string'}")); | 198 ArgumentSpec spec(*ValueFromString("{'type': 'string'}")); |
170 ExpectSuccess(spec, "'foo'", "'foo'"); | 199 ExpectSuccess(spec, "'foo'", "'foo'"); |
171 ExpectSuccess(spec, "''", "''"); | 200 ExpectSuccess(spec, "''", "''"); |
172 ExpectFailure(spec, "1"); | 201 ExpectFailure(spec, "1", InvalidType(kTypeString, kTypeInteger)); |
173 ExpectFailure(spec, "{}"); | 202 ExpectFailure(spec, "({})", InvalidType(kTypeString, kTypeObject)); |
174 ExpectFailure(spec, "['foo']"); | 203 ExpectFailure(spec, "['foo']", InvalidType(kTypeString, kTypeList)); |
175 } | 204 } |
176 | 205 |
177 { | 206 { |
178 ArgumentSpec spec( | 207 ArgumentSpec spec( |
179 *ValueFromString("{'type': 'string', 'enum': ['foo', 'bar']}")); | 208 *ValueFromString("{'type': 'string', 'enum': ['foo', 'bar']}")); |
| 209 std::set<std::string> valid_enums = {"foo", "bar"}; |
180 ExpectSuccess(spec, "'foo'", "'foo'"); | 210 ExpectSuccess(spec, "'foo'", "'foo'"); |
181 ExpectSuccess(spec, "'bar'", "'bar'"); | 211 ExpectSuccess(spec, "'bar'", "'bar'"); |
182 ExpectFailure(spec, "['foo']"); | 212 ExpectFailure(spec, "['foo']", InvalidType(kTypeString, kTypeList)); |
183 ExpectFailure(spec, "'fo'"); | 213 ExpectFailure(spec, "'fo'", InvalidEnumValue(valid_enums)); |
184 ExpectFailure(spec, "'foobar'"); | 214 ExpectFailure(spec, "'foobar'", InvalidEnumValue(valid_enums)); |
185 ExpectFailure(spec, "'baz'"); | 215 ExpectFailure(spec, "'baz'", InvalidEnumValue(valid_enums)); |
186 ExpectFailure(spec, "''"); | 216 ExpectFailure(spec, "''", InvalidEnumValue(valid_enums)); |
187 } | 217 } |
188 | 218 |
189 { | 219 { |
190 ArgumentSpec spec(*ValueFromString( | 220 ArgumentSpec spec(*ValueFromString( |
191 "{'type': 'string', 'enum': [{'name': 'foo'}, {'name': 'bar'}]}")); | 221 "{'type': 'string', 'enum': [{'name': 'foo'}, {'name': 'bar'}]}")); |
| 222 std::set<std::string> valid_enums = {"foo", "bar"}; |
192 ExpectSuccess(spec, "'foo'", "'foo'"); | 223 ExpectSuccess(spec, "'foo'", "'foo'"); |
193 ExpectSuccess(spec, "'bar'", "'bar'"); | 224 ExpectSuccess(spec, "'bar'", "'bar'"); |
194 ExpectFailure(spec, "['foo']"); | 225 ExpectFailure(spec, "['foo']", InvalidType(kTypeString, kTypeList)); |
195 ExpectFailure(spec, "'fo'"); | 226 ExpectFailure(spec, "'fo'", InvalidEnumValue(valid_enums)); |
196 ExpectFailure(spec, "'foobar'"); | 227 ExpectFailure(spec, "'foobar'", InvalidEnumValue(valid_enums)); |
197 ExpectFailure(spec, "'baz'"); | 228 ExpectFailure(spec, "'baz'", InvalidEnumValue(valid_enums)); |
198 ExpectFailure(spec, "''"); | 229 ExpectFailure(spec, "''", InvalidEnumValue(valid_enums)); |
199 } | 230 } |
200 | 231 |
201 { | 232 { |
202 ArgumentSpec spec(*ValueFromString("{'type': 'boolean'}")); | 233 ArgumentSpec spec(*ValueFromString("{'type': 'boolean'}")); |
203 ExpectSuccess(spec, "true", "true"); | 234 ExpectSuccess(spec, "true", "true"); |
204 ExpectSuccess(spec, "false", "false"); | 235 ExpectSuccess(spec, "false", "false"); |
205 ExpectFailure(spec, "1"); | 236 ExpectFailure(spec, "1", InvalidType(kTypeBoolean, kTypeInteger)); |
206 ExpectFailure(spec, "'true'"); | 237 ExpectFailure(spec, "'true'", InvalidType(kTypeBoolean, kTypeString)); |
207 ExpectFailure(spec, "null"); | 238 ExpectFailure(spec, "null", InvalidType(kTypeBoolean, kTypeNull)); |
208 } | 239 } |
209 | 240 |
210 { | 241 { |
211 ArgumentSpec spec( | 242 ArgumentSpec spec( |
212 *ValueFromString("{'type': 'array', 'items': {'type': 'string'}}")); | 243 *ValueFromString("{'type': 'array', 'items': {'type': 'string'}}")); |
213 ExpectSuccess(spec, "[]", "[]"); | 244 ExpectSuccess(spec, "[]", "[]"); |
214 ExpectSuccess(spec, "['foo']", "['foo']"); | 245 ExpectSuccess(spec, "['foo']", "['foo']"); |
215 ExpectSuccess(spec, "['foo', 'bar']", "['foo','bar']"); | 246 ExpectSuccess(spec, "['foo', 'bar']", "['foo','bar']"); |
216 ExpectSuccess(spec, "var x = new Array(); x[0] = 'foo'; x;", "['foo']"); | 247 ExpectSuccess(spec, "var x = new Array(); x[0] = 'foo'; x;", "['foo']"); |
217 ExpectFailure(spec, "'foo'"); | 248 ExpectFailure(spec, "'foo'", InvalidType(kTypeList, kTypeString)); |
218 ExpectFailure(spec, "[1, 2]"); | 249 ExpectFailure(spec, "[1, 2]", |
219 ExpectFailure(spec, "['foo', 1]"); | 250 IndexError(0u, InvalidType(kTypeString, kTypeInteger))); |
| 251 ExpectFailure(spec, "['foo', 1]", |
| 252 IndexError(1u, InvalidType(kTypeString, kTypeInteger))); |
220 ExpectFailure(spec, | 253 ExpectFailure(spec, |
221 "var x = ['a', 'b', 'c'];" | 254 "var x = ['a', 'b', 'c'];" |
222 "x[4] = 'd';" // x[3] is undefined, violating the spec. | 255 "x[4] = 'd';" // x[3] is undefined, violating the spec. |
223 "x;"); | 256 "x;", |
| 257 IndexError(3u, InvalidType(kTypeString, kTypeUndefined))); |
224 ExpectThrow( | 258 ExpectThrow( |
225 spec, | 259 spec, |
226 "var x = [];" | 260 "var x = [];" |
227 "Object.defineProperty(" | 261 "Object.defineProperty(" |
228 " x, 0," | 262 " x, 0," |
229 " { get: () => { throw new Error('Badness'); } });" | 263 " { get: () => { throw new Error('Badness'); } });" |
230 "x;", | 264 "x;", |
231 "Uncaught Error: Badness"); | 265 "Uncaught Error: Badness"); |
232 } | 266 } |
233 | 267 |
234 { | 268 { |
235 const char kObjectSpec[] = | 269 const char kObjectSpec[] = |
236 "{" | 270 "{" |
237 " 'type': 'object'," | 271 " 'type': 'object'," |
238 " 'properties': {" | 272 " 'properties': {" |
239 " 'prop1': {'type': 'string'}," | 273 " 'prop1': {'type': 'string'}," |
240 " 'prop2': {'type': 'integer', 'optional': true}" | 274 " 'prop2': {'type': 'integer', 'optional': true}" |
241 " }" | 275 " }" |
242 "}"; | 276 "}"; |
243 ArgumentSpec spec(*ValueFromString(kObjectSpec)); | 277 ArgumentSpec spec(*ValueFromString(kObjectSpec)); |
244 ExpectSuccess(spec, "({prop1: 'foo', prop2: 2})", | 278 ExpectSuccess(spec, "({prop1: 'foo', prop2: 2})", |
245 "{'prop1':'foo','prop2':2}"); | 279 "{'prop1':'foo','prop2':2}"); |
246 ExpectSuccess(spec, "({prop1: 'foo'})", "{'prop1':'foo'}"); | 280 ExpectSuccess(spec, "({prop1: 'foo'})", "{'prop1':'foo'}"); |
247 ExpectSuccess(spec, "({prop1: 'foo', prop2: null})", "{'prop1':'foo'}"); | 281 ExpectSuccess(spec, "({prop1: 'foo', prop2: null})", "{'prop1':'foo'}"); |
248 ExpectSuccess(spec, "x = {}; x.prop1 = 'foo'; x;", "{'prop1':'foo'}"); | 282 ExpectSuccess(spec, "x = {}; x.prop1 = 'foo'; x;", "{'prop1':'foo'}"); |
249 ExpectFailure(spec, "({prop1: 'foo', prop2: 'bar'})"); | 283 ExpectFailure( |
250 ExpectFailure(spec, "({prop2: 2})"); | 284 spec, "({prop1: 'foo', prop2: 'bar'})", |
| 285 PropertyError("prop2", InvalidType(kTypeInteger, kTypeString))); |
| 286 ExpectFailure(spec, "({prop2: 2})", MissingRequiredProperty("prop1")); |
251 // Unknown properties are not allowed. | 287 // Unknown properties are not allowed. |
252 ExpectFailure(spec, "({prop1: 'foo', prop2: 2, prop3: 'blah'})"); | 288 ExpectFailure(spec, "({prop1: 'foo', prop2: 2, prop3: 'blah'})", |
| 289 UnexpectedProperty("prop3")); |
253 // We only consider properties on the object itself, not its prototype | 290 // We only consider properties on the object itself, not its prototype |
254 // chain. | 291 // chain. |
255 ExpectFailure(spec, | 292 ExpectFailure(spec, |
256 "function X() {}\n" | 293 "function X() {}\n" |
257 "X.prototype = { prop1: 'foo' };\n" | 294 "X.prototype = { prop1: 'foo' };\n" |
258 "var x = new X();\n" | 295 "var x = new X();\n" |
259 "x;"); | 296 "x;", |
| 297 MissingRequiredProperty("prop1")); |
260 ExpectFailure(spec, | 298 ExpectFailure(spec, |
261 "function X() {}\n" | 299 "function X() {}\n" |
262 "X.prototype = { prop1: 'foo' };\n" | 300 "X.prototype = { prop1: 'foo' };\n" |
263 "function Y() { this.__proto__ = X.prototype; }\n" | 301 "function Y() { this.__proto__ = X.prototype; }\n" |
264 "var z = new Y();\n" | 302 "var z = new Y();\n" |
265 "z;"); | 303 "z;", |
| 304 MissingRequiredProperty("prop1")); |
266 // Self-referential fun. Currently we don't have to worry about these much | 305 // Self-referential fun. Currently we don't have to worry about these much |
267 // because the spec won't match at some point (and V8ValueConverter has | 306 // because the spec won't match at some point (and V8ValueConverter has |
268 // cycle detection and will fail). | 307 // cycle detection and will fail). |
269 ExpectFailure(spec, "x = {}; x.prop1 = x; x;"); | 308 ExpectFailure( |
| 309 spec, "x = {}; x.prop1 = x; x;", |
| 310 PropertyError("prop1", InvalidType(kTypeString, kTypeObject))); |
270 ExpectThrow( | 311 ExpectThrow( |
271 spec, | 312 spec, |
272 "({ get prop1() { throw new Error('Badness'); }});", | 313 "({ get prop1() { throw new Error('Badness'); }});", |
273 "Uncaught Error: Badness"); | 314 "Uncaught Error: Badness"); |
274 ExpectThrow(spec, | 315 ExpectThrow(spec, |
275 "x = {prop1: 'foo'};\n" | 316 "x = {prop1: 'foo'};\n" |
276 "Object.defineProperty(\n" | 317 "Object.defineProperty(\n" |
277 " x, 'prop2',\n" | 318 " x, 'prop2',\n" |
278 " {\n" | 319 " {\n" |
279 " get: () => { throw new Error('Badness'); },\n" | 320 " get: () => { throw new Error('Badness'); },\n" |
(...skipping 13 matching lines...) Expand all Loading... |
293 } | 334 } |
294 | 335 |
295 { | 336 { |
296 const char kFunctionSpec[] = "{ 'type': 'function' }"; | 337 const char kFunctionSpec[] = "{ 'type': 'function' }"; |
297 ArgumentSpec spec(*ValueFromString(kFunctionSpec)); | 338 ArgumentSpec spec(*ValueFromString(kFunctionSpec)); |
298 // Functions are serialized as empty dictionaries. | 339 // Functions are serialized as empty dictionaries. |
299 ExpectSuccess(spec, "(function() {})", "{}"); | 340 ExpectSuccess(spec, "(function() {})", "{}"); |
300 ExpectSuccessWithNoConversion(spec, "(function() {})"); | 341 ExpectSuccessWithNoConversion(spec, "(function() {})"); |
301 ExpectSuccessWithNoConversion(spec, "(function(a, b) { a(); b(); })"); | 342 ExpectSuccessWithNoConversion(spec, "(function(a, b) { a(); b(); })"); |
302 ExpectSuccessWithNoConversion(spec, "(function(a, b) { a(); b(); })"); | 343 ExpectSuccessWithNoConversion(spec, "(function(a, b) { a(); b(); })"); |
303 ExpectFailureWithNoConversion(spec, "({a: function() {}})"); | 344 ExpectFailureWithNoConversion(spec, "({a: function() {}})", |
304 ExpectFailureWithNoConversion(spec, "([function() {}])"); | 345 InvalidType(kTypeFunction, kTypeObject)); |
305 ExpectFailureWithNoConversion(spec, "1"); | 346 ExpectFailureWithNoConversion(spec, "([function() {}])", |
| 347 InvalidType(kTypeFunction, kTypeList)); |
| 348 ExpectFailureWithNoConversion(spec, "1", |
| 349 InvalidType(kTypeFunction, kTypeInteger)); |
306 } | 350 } |
307 | 351 |
308 { | 352 { |
309 const char kBinarySpec[] = "{ 'type': 'binary' }"; | 353 const char kBinarySpec[] = "{ 'type': 'binary' }"; |
310 ArgumentSpec spec(*ValueFromString(kBinarySpec)); | 354 ArgumentSpec spec(*ValueFromString(kBinarySpec)); |
311 // Simple case: empty ArrayBuffer -> empty BinaryValue. | 355 // Simple case: empty ArrayBuffer -> empty BinaryValue. |
312 ExpectSuccess(spec, "(new ArrayBuffer())", | 356 ExpectSuccess(spec, "(new ArrayBuffer())", |
313 base::Value(base::Value::Type::BINARY)); | 357 base::Value(base::Value::Type::BINARY)); |
314 { | 358 { |
315 // A non-empty (but zero-filled) ArrayBufferView. | 359 // A non-empty (but zero-filled) ArrayBufferView. |
(...skipping 11 matching lines...) Expand all Loading... |
327 ASSERT_TRUE(expected_value); | 371 ASSERT_TRUE(expected_value); |
328 ExpectSuccess(spec, | 372 ExpectSuccess(spec, |
329 "var b = new ArrayBuffer(4);\n" | 373 "var b = new ArrayBuffer(4);\n" |
330 "var v = new Uint8Array(b);\n" | 374 "var v = new Uint8Array(b);\n" |
331 "var s = 'ping';\n" | 375 "var s = 'ping';\n" |
332 "for (var i = 0; i < s.length; ++i)\n" | 376 "for (var i = 0; i < s.length; ++i)\n" |
333 " v[i] = s.charCodeAt(i);\n" | 377 " v[i] = s.charCodeAt(i);\n" |
334 "b;", | 378 "b;", |
335 *expected_value); | 379 *expected_value); |
336 } | 380 } |
337 ExpectFailure(spec, "1"); | 381 ExpectFailure(spec, "1", InvalidType(kTypeBinary, kTypeInteger)); |
338 } | 382 } |
339 { | 383 { |
340 const char kAnySpec[] = "{ 'type': 'any' }"; | 384 const char kAnySpec[] = "{ 'type': 'any' }"; |
341 ArgumentSpec spec(*ValueFromString(kAnySpec)); | 385 ArgumentSpec spec(*ValueFromString(kAnySpec)); |
342 ExpectSuccess(spec, "42", "42"); | 386 ExpectSuccess(spec, "42", "42"); |
343 ExpectSuccess(spec, "'foo'", "'foo'"); | 387 ExpectSuccess(spec, "'foo'", "'foo'"); |
344 ExpectSuccess(spec, "({prop1:'bar'})", "{'prop1':'bar'}"); | 388 ExpectSuccess(spec, "({prop1:'bar'})", "{'prop1':'bar'}"); |
345 ExpectSuccess(spec, "[1, 2, 3]", "[1,2,3]"); | 389 ExpectSuccess(spec, "[1, 2, 3]", "[1,2,3]"); |
346 ExpectSuccess(spec, "[1, 'a']", "[1,'a']"); | 390 ExpectSuccess(spec, "[1, 'a']", "[1,'a']"); |
347 ExpectSuccess(spec, "null", base::Value()); | 391 ExpectSuccess(spec, "null", base::Value()); |
348 ExpectSuccess(spec, "({prop1: 'alpha', prop2: null})", | 392 ExpectSuccess(spec, "({prop1: 'alpha', prop2: null})", |
349 "{'prop1':'alpha','prop2':null}"); | 393 "{'prop1':'alpha','prop2':null}"); |
350 ExpectSuccess(spec, | 394 ExpectSuccess(spec, |
351 "x = {alpha: 'alpha'};\n" | 395 "x = {alpha: 'alpha'};\n" |
352 "y = {beta: 'beta', x: x};\n" | 396 "y = {beta: 'beta', x: x};\n" |
353 "y;", | 397 "y;", |
354 "{'beta':'beta','x':{'alpha':'alpha'}}"); | 398 "{'beta':'beta','x':{'alpha':'alpha'}}"); |
355 // We don't serialize undefined. | 399 // We don't serialize undefined. |
356 // TODO(devlin): This matches current behavior, but should it? Part of the | 400 // TODO(devlin): This matches current behavior, but should it? Part of the |
357 // problem is that base::Values don't differentiate between undefined and | 401 // problem is that base::Values don't differentiate between undefined and |
358 // null, which is a potentially important distinction. However, this means | 402 // null, which is a potentially important distinction. However, this means |
359 // that in serialization of an object {a: 1, foo:undefined}, we lose the | 403 // that in serialization of an object {a: 1, foo:undefined}, we lose the |
360 // 'foo' property. | 404 // 'foo' property. |
361 ExpectFailure(spec, "undefined"); | 405 ExpectFailure(spec, "undefined", UnserializableValue()); |
| 406 |
362 ExpectSuccess(spec, "({prop1: 1, prop2: undefined})", "{'prop1':1}"); | 407 ExpectSuccess(spec, "({prop1: 1, prop2: undefined})", "{'prop1':1}"); |
363 } | 408 } |
364 } | 409 } |
365 | 410 |
366 TEST_F(ArgumentSpecUnitTest, TypeRefsTest) { | 411 TEST_F(ArgumentSpecUnitTest, TypeRefsTest) { |
| 412 using namespace api_errors; |
367 const char kObjectType[] = | 413 const char kObjectType[] = |
368 "{" | 414 "{" |
369 " 'id': 'refObj'," | 415 " 'id': 'refObj'," |
370 " 'type': 'object'," | 416 " 'type': 'object'," |
371 " 'properties': {" | 417 " 'properties': {" |
372 " 'prop1': {'type': 'string'}," | 418 " 'prop1': {'type': 'string'}," |
373 " 'prop2': {'type': 'integer', 'optional': true}" | 419 " 'prop2': {'type': 'integer', 'optional': true}" |
374 " }" | 420 " }" |
375 "}"; | 421 "}"; |
376 const char kEnumType[] = | 422 const char kEnumType[] = |
377 "{'id': 'refEnum', 'type': 'string', 'enum': ['alpha', 'beta']}"; | 423 "{'id': 'refEnum', 'type': 'string', 'enum': ['alpha', 'beta']}"; |
378 AddTypeRef("refObj", | 424 AddTypeRef("refObj", |
379 base::MakeUnique<ArgumentSpec>(*ValueFromString(kObjectType))); | 425 base::MakeUnique<ArgumentSpec>(*ValueFromString(kObjectType))); |
380 AddTypeRef("refEnum", | 426 AddTypeRef("refEnum", |
381 base::MakeUnique<ArgumentSpec>(*ValueFromString(kEnumType))); | 427 base::MakeUnique<ArgumentSpec>(*ValueFromString(kEnumType))); |
| 428 std::set<std::string> valid_enums = {"alpha", "beta"}; |
382 | 429 |
383 { | 430 { |
384 const char kObjectWithRefEnumSpec[] = | 431 const char kObjectWithRefEnumSpec[] = |
385 "{" | 432 "{" |
386 " 'name': 'objWithRefEnum'," | 433 " 'name': 'objWithRefEnum'," |
387 " 'type': 'object'," | 434 " 'type': 'object'," |
388 " 'properties': {" | 435 " 'properties': {" |
389 " 'e': {'$ref': 'refEnum'}," | 436 " 'e': {'$ref': 'refEnum'}," |
390 " 'sub': {'type': 'integer'}" | 437 " 'sub': {'type': 'integer'}" |
391 " }" | 438 " }" |
392 "}"; | 439 "}"; |
393 ArgumentSpec spec(*ValueFromString(kObjectWithRefEnumSpec)); | 440 ArgumentSpec spec(*ValueFromString(kObjectWithRefEnumSpec)); |
394 ExpectSuccess(spec, "({e: 'alpha', sub: 1})", "{'e':'alpha','sub':1}"); | 441 ExpectSuccess(spec, "({e: 'alpha', sub: 1})", "{'e':'alpha','sub':1}"); |
395 ExpectSuccess(spec, "({e: 'beta', sub: 1})", "{'e':'beta','sub':1}"); | 442 ExpectSuccess(spec, "({e: 'beta', sub: 1})", "{'e':'beta','sub':1}"); |
396 ExpectFailure(spec, "({e: 'gamma', sub: 1})"); | 443 ExpectFailure(spec, "({e: 'gamma', sub: 1})", |
397 ExpectFailure(spec, "({e: 'alpha'})"); | 444 PropertyError("e", InvalidEnumValue(valid_enums))); |
| 445 ExpectFailure(spec, "({e: 'alpha'})", MissingRequiredProperty("sub")); |
398 } | 446 } |
399 | 447 |
400 { | 448 { |
401 const char kObjectWithRefObjectSpec[] = | 449 const char kObjectWithRefObjectSpec[] = |
402 "{" | 450 "{" |
403 " 'name': 'objWithRefObject'," | 451 " 'name': 'objWithRefObject'," |
404 " 'type': 'object'," | 452 " 'type': 'object'," |
405 " 'properties': {" | 453 " 'properties': {" |
406 " 'o': {'$ref': 'refObj'}" | 454 " 'o': {'$ref': 'refObj'}" |
407 " }" | 455 " }" |
408 "}"; | 456 "}"; |
409 ArgumentSpec spec(*ValueFromString(kObjectWithRefObjectSpec)); | 457 ArgumentSpec spec(*ValueFromString(kObjectWithRefObjectSpec)); |
410 ExpectSuccess(spec, "({o: {prop1: 'foo'}})", "{'o':{'prop1':'foo'}}"); | 458 ExpectSuccess(spec, "({o: {prop1: 'foo'}})", "{'o':{'prop1':'foo'}}"); |
411 ExpectSuccess(spec, "({o: {prop1: 'foo', prop2: 2}})", | 459 ExpectSuccess(spec, "({o: {prop1: 'foo', prop2: 2}})", |
412 "{'o':{'prop1':'foo','prop2':2}}"); | 460 "{'o':{'prop1':'foo','prop2':2}}"); |
413 ExpectFailure(spec, "({o: {prop1: 1}})"); | 461 ExpectFailure( |
| 462 spec, "({o: {prop1: 1}})", |
| 463 PropertyError("o", PropertyError("prop1", InvalidType(kTypeString, |
| 464 kTypeInteger)))); |
414 } | 465 } |
415 | 466 |
416 { | 467 { |
417 const char kRefEnumListSpec[] = | 468 const char kRefEnumListSpec[] = |
418 "{'type': 'array', 'items': {'$ref': 'refEnum'}}"; | 469 "{'type': 'array', 'items': {'$ref': 'refEnum'}}"; |
419 ArgumentSpec spec(*ValueFromString(kRefEnumListSpec)); | 470 ArgumentSpec spec(*ValueFromString(kRefEnumListSpec)); |
420 ExpectSuccess(spec, "['alpha']", "['alpha']"); | 471 ExpectSuccess(spec, "['alpha']", "['alpha']"); |
421 ExpectSuccess(spec, "['alpha', 'alpha']", "['alpha','alpha']"); | 472 ExpectSuccess(spec, "['alpha', 'alpha']", "['alpha','alpha']"); |
422 ExpectSuccess(spec, "['alpha', 'beta']", "['alpha','beta']"); | 473 ExpectSuccess(spec, "['alpha', 'beta']", "['alpha','beta']"); |
423 ExpectFailure(spec, "['alpha', 'beta', 'gamma']"); | 474 ExpectFailure(spec, "['alpha', 'beta', 'gamma']", |
| 475 IndexError(2u, InvalidEnumValue(valid_enums))); |
424 } | 476 } |
425 } | 477 } |
426 | 478 |
427 TEST_F(ArgumentSpecUnitTest, TypeChoicesTest) { | 479 TEST_F(ArgumentSpecUnitTest, TypeChoicesTest) { |
| 480 using namespace api_errors; |
428 { | 481 { |
429 const char kSimpleChoices[] = | 482 const char kSimpleChoices[] = |
430 "{'choices': [{'type': 'string'}, {'type': 'integer'}]}"; | 483 "{'choices': [{'type': 'string'}, {'type': 'integer'}]}"; |
431 ArgumentSpec spec(*ValueFromString(kSimpleChoices)); | 484 ArgumentSpec spec(*ValueFromString(kSimpleChoices)); |
432 ExpectSuccess(spec, "'alpha'", "'alpha'"); | 485 ExpectSuccess(spec, "'alpha'", "'alpha'"); |
433 ExpectSuccess(spec, "42", "42"); | 486 ExpectSuccess(spec, "42", "42"); |
434 ExpectFailure(spec, "true"); | 487 ExpectFailure(spec, "true", InvalidChoice()); |
435 } | 488 } |
436 | 489 |
437 { | 490 { |
438 const char kComplexChoices[] = | 491 const char kComplexChoices[] = |
439 "{" | 492 "{" |
440 " 'choices': [" | 493 " 'choices': [" |
441 " {'type': 'array', 'items': {'type': 'string'}}," | 494 " {'type': 'array', 'items': {'type': 'string'}}," |
442 " {'type': 'object', 'properties': {'prop1': {'type': 'string'}}}" | 495 " {'type': 'object', 'properties': {'prop1': {'type': 'string'}}}" |
443 " ]" | 496 " ]" |
444 "}"; | 497 "}"; |
445 ArgumentSpec spec(*ValueFromString(kComplexChoices)); | 498 ArgumentSpec spec(*ValueFromString(kComplexChoices)); |
446 ExpectSuccess(spec, "['alpha']", "['alpha']"); | 499 ExpectSuccess(spec, "['alpha']", "['alpha']"); |
447 ExpectSuccess(spec, "['alpha', 'beta']", "['alpha','beta']"); | 500 ExpectSuccess(spec, "['alpha', 'beta']", "['alpha','beta']"); |
448 ExpectSuccess(spec, "({prop1: 'alpha'})", "{'prop1':'alpha'}"); | 501 ExpectSuccess(spec, "({prop1: 'alpha'})", "{'prop1':'alpha'}"); |
449 ExpectFailure(spec, "({prop1: 1})"); | 502 ExpectFailure(spec, "({prop1: 1})", InvalidChoice()); |
450 ExpectFailure(spec, "'alpha'"); | 503 ExpectFailure(spec, "'alpha'", InvalidChoice()); |
451 ExpectFailure(spec, "42"); | 504 ExpectFailure(spec, "42", InvalidChoice()); |
452 } | 505 } |
453 } | 506 } |
454 | 507 |
455 TEST_F(ArgumentSpecUnitTest, AdditionalPropertiesTest) { | 508 TEST_F(ArgumentSpecUnitTest, AdditionalPropertiesTest) { |
| 509 using namespace api_errors; |
456 { | 510 { |
457 const char kOnlyAnyAdditionalProperties[] = | 511 const char kOnlyAnyAdditionalProperties[] = |
458 "{" | 512 "{" |
459 " 'type': 'object'," | 513 " 'type': 'object'," |
460 " 'additionalProperties': {'type': 'any'}" | 514 " 'additionalProperties': {'type': 'any'}" |
461 "}"; | 515 "}"; |
462 ArgumentSpec spec(*ValueFromString(kOnlyAnyAdditionalProperties)); | 516 ArgumentSpec spec(*ValueFromString(kOnlyAnyAdditionalProperties)); |
463 ExpectSuccess(spec, "({prop1: 'alpha', prop2: 42, prop3: {foo: 'bar'}})", | 517 ExpectSuccess(spec, "({prop1: 'alpha', prop2: 42, prop3: {foo: 'bar'}})", |
464 "{'prop1':'alpha','prop2':42,'prop3':{'foo':'bar'}}"); | 518 "{'prop1':'alpha','prop2':42,'prop3':{'foo':'bar'}}"); |
465 ExpectSuccess(spec, "({})", "{}"); | 519 ExpectSuccess(spec, "({})", "{}"); |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
526 " 'properties': {" | 580 " 'properties': {" |
527 " 'prop1': {'type': 'string'}" | 581 " 'prop1': {'type': 'string'}" |
528 " }," | 582 " }," |
529 " 'additionalProperties': {'type': 'any'}" | 583 " 'additionalProperties': {'type': 'any'}" |
530 "}"; | 584 "}"; |
531 ArgumentSpec spec(*ValueFromString(kPropertiesAndAnyAdditionalProperties)); | 585 ArgumentSpec spec(*ValueFromString(kPropertiesAndAnyAdditionalProperties)); |
532 ExpectSuccess(spec, "({prop1: 'alpha', prop2: 42, prop3: {foo: 'bar'}})", | 586 ExpectSuccess(spec, "({prop1: 'alpha', prop2: 42, prop3: {foo: 'bar'}})", |
533 "{'prop1':'alpha','prop2':42,'prop3':{'foo':'bar'}}"); | 587 "{'prop1':'alpha','prop2':42,'prop3':{'foo':'bar'}}"); |
534 // Additional properties are optional. | 588 // Additional properties are optional. |
535 ExpectSuccess(spec, "({prop1: 'foo'})", "{'prop1':'foo'}"); | 589 ExpectSuccess(spec, "({prop1: 'foo'})", "{'prop1':'foo'}"); |
536 ExpectFailure(spec, "({prop2: 42, prop3: {foo: 'bar'}})"); | 590 ExpectFailure(spec, "({prop2: 42, prop3: {foo: 'bar'}})", |
537 ExpectFailure(spec, "({prop1: 42})"); | 591 MissingRequiredProperty("prop1")); |
| 592 ExpectFailure( |
| 593 spec, "({prop1: 42})", |
| 594 PropertyError("prop1", InvalidType(kTypeString, kTypeInteger))); |
538 } | 595 } |
539 { | 596 { |
540 const char kTypedAdditionalProperties[] = | 597 const char kTypedAdditionalProperties[] = |
541 "{" | 598 "{" |
542 " 'type': 'object'," | 599 " 'type': 'object'," |
543 " 'additionalProperties': {'type': 'string'}" | 600 " 'additionalProperties': {'type': 'string'}" |
544 "}"; | 601 "}"; |
545 ArgumentSpec spec(*ValueFromString(kTypedAdditionalProperties)); | 602 ArgumentSpec spec(*ValueFromString(kTypedAdditionalProperties)); |
546 ExpectSuccess(spec, "({prop1: 'alpha', prop2: 'beta', prop3: 'gamma'})", | 603 ExpectSuccess(spec, "({prop1: 'alpha', prop2: 'beta', prop3: 'gamma'})", |
547 "{'prop1':'alpha','prop2':'beta','prop3':'gamma'}"); | 604 "{'prop1':'alpha','prop2':'beta','prop3':'gamma'}"); |
548 ExpectFailure(spec, "({prop1: 'alpha', prop2: 42})"); | 605 ExpectFailure( |
| 606 spec, "({prop1: 'alpha', prop2: 42})", |
| 607 PropertyError("prop2", InvalidType(kTypeString, kTypeInteger))); |
549 } | 608 } |
550 } | 609 } |
551 | 610 |
552 TEST_F(ArgumentSpecUnitTest, InstanceOfTest) { | 611 TEST_F(ArgumentSpecUnitTest, InstanceOfTest) { |
| 612 using namespace api_errors; |
553 { | 613 { |
554 const char kInstanceOfRegExp[] = | 614 const char kInstanceOfRegExp[] = |
555 "{" | 615 "{" |
556 " 'type': 'object'," | 616 " 'type': 'object'," |
557 " 'isInstanceOf': 'RegExp'" | 617 " 'isInstanceOf': 'RegExp'" |
558 "}"; | 618 "}"; |
559 ArgumentSpec spec(*ValueFromString(kInstanceOfRegExp)); | 619 ArgumentSpec spec(*ValueFromString(kInstanceOfRegExp)); |
560 ExpectSuccess(spec, "(new RegExp())", "{}"); | 620 ExpectSuccess(spec, "(new RegExp())", "{}"); |
561 ExpectSuccess(spec, "({ __proto__: RegExp.prototype })", "{}"); | 621 ExpectSuccess(spec, "({ __proto__: RegExp.prototype })", "{}"); |
562 ExpectSuccess(spec, | 622 ExpectSuccess(spec, |
563 "(function() {\n" | 623 "(function() {\n" |
564 " function subRegExp() {}\n" | 624 " function subRegExp() {}\n" |
565 " subRegExp.prototype = { __proto__: RegExp.prototype };\n" | 625 " subRegExp.prototype = { __proto__: RegExp.prototype };\n" |
566 " return new subRegExp();\n" | 626 " return new subRegExp();\n" |
567 "})()", | 627 "})()", |
568 "{}"); | 628 "{}"); |
569 ExpectSuccess(spec, | 629 ExpectSuccess(spec, |
570 "(function() {\n" | 630 "(function() {\n" |
571 " function RegExp() {}\n" | 631 " function RegExp() {}\n" |
572 " return new RegExp();\n" | 632 " return new RegExp();\n" |
573 "})()", | 633 "})()", |
574 "{}"); | 634 "{}"); |
575 ExpectFailure(spec, "({})"); | 635 ExpectFailure(spec, "({})", NotAnInstance("RegExp")); |
576 ExpectFailure(spec, "('')"); | 636 ExpectFailure(spec, "('')", InvalidType("RegExp", kTypeString)); |
577 ExpectFailure(spec, "('.*')"); | 637 ExpectFailure(spec, "('.*')", InvalidType("RegExp", kTypeString)); |
578 ExpectFailure(spec, "({ __proto__: Date.prototype })"); | 638 ExpectFailure(spec, "({ __proto__: Date.prototype })", |
| 639 NotAnInstance("RegExp")); |
579 } | 640 } |
580 | 641 |
581 { | 642 { |
582 const char kInstanceOfCustomClass[] = | 643 const char kInstanceOfCustomClass[] = |
583 "{" | 644 "{" |
584 " 'type': 'object'," | 645 " 'type': 'object'," |
585 " 'isInstanceOf': 'customClass'" | 646 " 'isInstanceOf': 'customClass'" |
586 "}"; | 647 "}"; |
587 ArgumentSpec spec(*ValueFromString(kInstanceOfCustomClass)); | 648 ArgumentSpec spec(*ValueFromString(kInstanceOfCustomClass)); |
588 ExpectSuccess(spec, | 649 ExpectSuccess(spec, |
589 "(function() {\n" | 650 "(function() {\n" |
590 " function customClass() {}\n" | 651 " function customClass() {}\n" |
591 " return new customClass();\n" | 652 " return new customClass();\n" |
592 "})()", | 653 "})()", |
593 "{}"); | 654 "{}"); |
594 ExpectSuccess(spec, | 655 ExpectSuccess(spec, |
595 "(function() {\n" | 656 "(function() {\n" |
596 " function customClass() {}\n" | 657 " function customClass() {}\n" |
597 " function otherClass() {}\n" | 658 " function otherClass() {}\n" |
598 " otherClass.prototype = \n" | 659 " otherClass.prototype = \n" |
599 " { __proto__: customClass.prototype };\n" | 660 " { __proto__: customClass.prototype };\n" |
600 " return new otherClass();\n" | 661 " return new otherClass();\n" |
601 "})()", | 662 "})()", |
602 "{}"); | 663 "{}"); |
603 ExpectFailure(spec, "({})"); | 664 ExpectFailure(spec, "({})", NotAnInstance("customClass")); |
604 ExpectFailure(spec, | 665 ExpectFailure(spec, |
605 "(function() {\n" | 666 "(function() {\n" |
606 " function otherClass() {}\n" | 667 " function otherClass() {}\n" |
607 " return new otherClass();\n" | 668 " return new otherClass();\n" |
608 "})()"); | 669 "})()", |
| 670 NotAnInstance("customClass")); |
609 } | 671 } |
610 } | 672 } |
611 | 673 |
612 TEST_F(ArgumentSpecUnitTest, MinAndMaxLengths) { | 674 TEST_F(ArgumentSpecUnitTest, MinAndMaxLengths) { |
| 675 using namespace api_errors; |
613 { | 676 { |
614 const char kMinLengthString[] = "{'type': 'string', 'minLength': 3}"; | 677 const char kMinLengthString[] = "{'type': 'string', 'minLength': 3}"; |
615 ArgumentSpec spec(*ValueFromString(kMinLengthString)); | 678 ArgumentSpec spec(*ValueFromString(kMinLengthString)); |
616 ExpectSuccess(spec, "'aaa'", "'aaa'"); | 679 ExpectSuccess(spec, "'aaa'", "'aaa'"); |
617 ExpectSuccess(spec, "'aaaa'", "'aaaa'"); | 680 ExpectSuccess(spec, "'aaaa'", "'aaaa'"); |
618 ExpectFailure(spec, "'aa'"); | 681 ExpectFailure(spec, "'aa'", TooFewStringChars(3, 2)); |
619 ExpectFailure(spec, "''"); | 682 ExpectFailure(spec, "''", TooFewStringChars(3, 0)); |
620 } | 683 } |
621 | 684 |
622 { | 685 { |
623 const char kMaxLengthString[] = "{'type': 'string', 'maxLength': 3}"; | 686 const char kMaxLengthString[] = "{'type': 'string', 'maxLength': 3}"; |
624 ArgumentSpec spec(*ValueFromString(kMaxLengthString)); | 687 ArgumentSpec spec(*ValueFromString(kMaxLengthString)); |
625 ExpectSuccess(spec, "'aaa'", "'aaa'"); | 688 ExpectSuccess(spec, "'aaa'", "'aaa'"); |
626 ExpectSuccess(spec, "'aa'", "'aa'"); | 689 ExpectSuccess(spec, "'aa'", "'aa'"); |
627 ExpectSuccess(spec, "''", "''"); | 690 ExpectSuccess(spec, "''", "''"); |
628 ExpectFailure(spec, "'aaaa'"); | 691 ExpectFailure(spec, "'aaaa'", TooManyStringChars(3, 4)); |
629 } | 692 } |
630 | 693 |
631 { | 694 { |
632 const char kMinLengthArray[] = | 695 const char kMinLengthArray[] = |
633 "{'type': 'array', 'items': {'type': 'integer'}, 'minItems': 3}"; | 696 "{'type': 'array', 'items': {'type': 'integer'}, 'minItems': 3}"; |
634 ArgumentSpec spec(*ValueFromString(kMinLengthArray)); | 697 ArgumentSpec spec(*ValueFromString(kMinLengthArray)); |
635 ExpectSuccess(spec, "[1, 2, 3]", "[1,2,3]"); | 698 ExpectSuccess(spec, "[1, 2, 3]", "[1,2,3]"); |
636 ExpectSuccess(spec, "[1, 2, 3, 4]", "[1,2,3,4]"); | 699 ExpectSuccess(spec, "[1, 2, 3, 4]", "[1,2,3,4]"); |
637 ExpectFailure(spec, "[1, 2]"); | 700 ExpectFailure(spec, "[1, 2]", TooFewArrayItems(3, 2)); |
638 ExpectFailure(spec, "[]"); | 701 ExpectFailure(spec, "[]", TooFewArrayItems(3, 0)); |
639 } | 702 } |
640 | 703 |
641 { | 704 { |
642 const char kMaxLengthArray[] = | 705 const char kMaxLengthArray[] = |
643 "{'type': 'array', 'items': {'type': 'integer'}, 'maxItems': 3}"; | 706 "{'type': 'array', 'items': {'type': 'integer'}, 'maxItems': 3}"; |
644 ArgumentSpec spec(*ValueFromString(kMaxLengthArray)); | 707 ArgumentSpec spec(*ValueFromString(kMaxLengthArray)); |
645 ExpectSuccess(spec, "[1, 2, 3]", "[1,2,3]"); | 708 ExpectSuccess(spec, "[1, 2, 3]", "[1,2,3]"); |
646 ExpectSuccess(spec, "[1, 2]", "[1,2]"); | 709 ExpectSuccess(spec, "[1, 2]", "[1,2]"); |
647 ExpectSuccess(spec, "[]", "[]"); | 710 ExpectSuccess(spec, "[]", "[]"); |
648 ExpectFailure(spec, "[1, 2, 3, 4]"); | 711 ExpectFailure(spec, "[1, 2, 3, 4]", TooManyArrayItems(3, 4)); |
649 } | 712 } |
650 } | 713 } |
651 | 714 |
652 } // namespace extensions | 715 } // namespace extensions |
OLD | NEW |