| 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 |