| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 The Chromium 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 define([ | |
| 6 "console", | |
| 7 "file", | |
| 8 "gin/test/expect", | |
| 9 "mojo/public/interfaces/bindings/tests/validation_test_interfaces.mojom", | |
| 10 "mojo/public/js/buffer", | |
| 11 "mojo/public/js/codec", | |
| 12 "mojo/public/js/connection", | |
| 13 "mojo/public/js/connector", | |
| 14 "mojo/public/js/core", | |
| 15 "mojo/public/js/test/validation_test_input_parser", | |
| 16 "mojo/public/js/router", | |
| 17 "mojo/public/js/validator", | |
| 18 ], function(console, | |
| 19 file, | |
| 20 expect, | |
| 21 testInterface, | |
| 22 buffer, | |
| 23 codec, | |
| 24 connection, | |
| 25 connector, | |
| 26 core, | |
| 27 parser, | |
| 28 router, | |
| 29 validator) { | |
| 30 | |
| 31 var noError = validator.validationError.NONE; | |
| 32 | |
| 33 function checkTestMessageParser() { | |
| 34 function TestMessageParserFailure(message, input) { | |
| 35 this.message = message; | |
| 36 this.input = input; | |
| 37 } | |
| 38 | |
| 39 TestMessageParserFailure.prototype.toString = function() { | |
| 40 return 'Error: ' + this.message + ' for "' + this.input + '"'; | |
| 41 } | |
| 42 | |
| 43 function checkData(data, expectedData, input) { | |
| 44 if (data.byteLength != expectedData.byteLength) { | |
| 45 var s = "message length (" + data.byteLength + ") doesn't match " + | |
| 46 "expected length: " + expectedData.byteLength; | |
| 47 throw new TestMessageParserFailure(s, input); | |
| 48 } | |
| 49 | |
| 50 for (var i = 0; i < data.byteLength; i++) { | |
| 51 if (data.getUint8(i) != expectedData.getUint8(i)) { | |
| 52 var s = 'message data mismatch at byte offset ' + i; | |
| 53 throw new TestMessageParserFailure(s, input); | |
| 54 } | |
| 55 } | |
| 56 } | |
| 57 | |
| 58 function testFloatItems() { | |
| 59 var input = '[f]+.3e9 [d]-10.03'; | |
| 60 var msg = parser.parseTestMessage(input); | |
| 61 var expectedData = new buffer.Buffer(12); | |
| 62 expectedData.setFloat32(0, +.3e9); | |
| 63 expectedData.setFloat64(4, -10.03); | |
| 64 checkData(msg.buffer, expectedData, input); | |
| 65 } | |
| 66 | |
| 67 function testUnsignedIntegerItems() { | |
| 68 var input = '[u1]0x10// hello world !! \n\r \t [u2]65535 \n' + | |
| 69 '[u4]65536 [u8]0xFFFFFFFFFFFFF 0 0Xff'; | |
| 70 var msg = parser.parseTestMessage(input); | |
| 71 var expectedData = new buffer.Buffer(17); | |
| 72 expectedData.setUint8(0, 0x10); | |
| 73 expectedData.setUint16(1, 65535); | |
| 74 expectedData.setUint32(3, 65536); | |
| 75 expectedData.setUint64(7, 0xFFFFFFFFFFFFF); | |
| 76 expectedData.setUint8(15, 0); | |
| 77 expectedData.setUint8(16, 0xff); | |
| 78 checkData(msg.buffer, expectedData, input); | |
| 79 } | |
| 80 | |
| 81 function testSignedIntegerItems() { | |
| 82 var input = '[s8]-0x800 [s1]-128\t[s2]+0 [s4]-40'; | |
| 83 var msg = parser.parseTestMessage(input); | |
| 84 var expectedData = new buffer.Buffer(15); | |
| 85 expectedData.setInt64(0, -0x800); | |
| 86 expectedData.setInt8(8, -128); | |
| 87 expectedData.setInt16(9, 0); | |
| 88 expectedData.setInt32(11, -40); | |
| 89 checkData(msg.buffer, expectedData, input); | |
| 90 } | |
| 91 | |
| 92 function testByteItems() { | |
| 93 var input = '[b]00001011 [b]10000000 // hello world\n [b]00000000'; | |
| 94 var msg = parser.parseTestMessage(input); | |
| 95 var expectedData = new buffer.Buffer(3); | |
| 96 expectedData.setUint8(0, 11); | |
| 97 expectedData.setUint8(1, 128); | |
| 98 expectedData.setUint8(2, 0); | |
| 99 checkData(msg.buffer, expectedData, input); | |
| 100 } | |
| 101 | |
| 102 function testAnchors() { | |
| 103 var input = '[dist4]foo 0 [dist8]bar 0 [anchr]foo [anchr]bar'; | |
| 104 var msg = parser.parseTestMessage(input); | |
| 105 var expectedData = new buffer.Buffer(14); | |
| 106 expectedData.setUint32(0, 14); | |
| 107 expectedData.setUint8(4, 0); | |
| 108 expectedData.setUint64(5, 9); | |
| 109 expectedData.setUint8(13, 0); | |
| 110 checkData(msg.buffer, expectedData, input); | |
| 111 } | |
| 112 | |
| 113 function testHandles() { | |
| 114 var input = '// This message has handles! \n[handles]50 [u8]2'; | |
| 115 var msg = parser.parseTestMessage(input); | |
| 116 var expectedData = new buffer.Buffer(8); | |
| 117 expectedData.setUint64(0, 2); | |
| 118 | |
| 119 if (msg.handleCount != 50) { | |
| 120 var s = 'wrong handle count (' + msg.handleCount + ')'; | |
| 121 throw new TestMessageParserFailure(s, input); | |
| 122 } | |
| 123 checkData(msg.buffer, expectedData, input); | |
| 124 } | |
| 125 | |
| 126 function testEmptyInput() { | |
| 127 var msg = parser.parseTestMessage(''); | |
| 128 if (msg.buffer.byteLength != 0) | |
| 129 throw new TestMessageParserFailure('expected empty message', ''); | |
| 130 } | |
| 131 | |
| 132 function testBlankInput() { | |
| 133 var input = ' \t // hello world \n\r \t// the answer is 42 '; | |
| 134 var msg = parser.parseTestMessage(input); | |
| 135 if (msg.buffer.byteLength != 0) | |
| 136 throw new TestMessageParserFailure('expected empty message', input); | |
| 137 } | |
| 138 | |
| 139 function testInvalidInput() { | |
| 140 function parserShouldFail(input) { | |
| 141 try { | |
| 142 parser.parseTestMessage(input); | |
| 143 } catch (e) { | |
| 144 if (e instanceof parser.InputError) | |
| 145 return; | |
| 146 throw new TestMessageParserFailure( | |
| 147 'unexpected exception ' + e.toString(), input); | |
| 148 } | |
| 149 throw new TestMessageParserFailure("didn't detect invalid input", file); | |
| 150 } | |
| 151 | |
| 152 ['/ hello world', | |
| 153 '[u1]x', | |
| 154 '[u2]-1000', | |
| 155 '[u1]0x100', | |
| 156 '[s2]-0x8001', | |
| 157 '[b]1', | |
| 158 '[b]1111111k', | |
| 159 '[dist4]unmatched', | |
| 160 '[anchr]hello [dist8]hello', | |
| 161 '[dist4]a [dist4]a [anchr]a', | |
| 162 // '[dist4]a [anchr]a [dist4]a [anchr]a', | |
| 163 '0 [handles]50' | |
| 164 ].forEach(parserShouldFail); | |
| 165 } | |
| 166 | |
| 167 try { | |
| 168 testFloatItems(); | |
| 169 testUnsignedIntegerItems(); | |
| 170 testSignedIntegerItems(); | |
| 171 testByteItems(); | |
| 172 testInvalidInput(); | |
| 173 testEmptyInput(); | |
| 174 testBlankInput(); | |
| 175 testHandles(); | |
| 176 testAnchors(); | |
| 177 } catch (e) { | |
| 178 return e.toString(); | |
| 179 } | |
| 180 return null; | |
| 181 } | |
| 182 | |
| 183 function getMessageTestFiles(key) { | |
| 184 var sourceRoot = file.getSourceRootDirectory(); | |
| 185 expect(sourceRoot).not.toBeNull(); | |
| 186 | |
| 187 var testDir = sourceRoot + | |
| 188 "/mojo/public/interfaces/bindings/tests/data/validation/"; | |
| 189 var testFiles = file.getFilesInDirectory(testDir); | |
| 190 expect(testFiles).not.toBeNull(); | |
| 191 expect(testFiles.length).toBeGreaterThan(0); | |
| 192 | |
| 193 // The matching ".data" pathnames with the extension removed. | |
| 194 return testFiles.filter(function(s) { | |
| 195 return s.substr(-5) == ".data"; | |
| 196 }).map(function(s) { | |
| 197 return testDir + s.slice(0, -5); | |
| 198 }).filter(function(s) { | |
| 199 return s.indexOf(key) != -1; | |
| 200 }); | |
| 201 } | |
| 202 | |
| 203 function readTestMessage(filename) { | |
| 204 var contents = file.readFileToString(filename + ".data"); | |
| 205 expect(contents).not.toBeNull(); | |
| 206 return parser.parseTestMessage(contents); | |
| 207 } | |
| 208 | |
| 209 function readTestExpected(filename) { | |
| 210 var contents = file.readFileToString(filename + ".expected"); | |
| 211 expect(contents).not.toBeNull(); | |
| 212 return contents.trim(); | |
| 213 } | |
| 214 | |
| 215 function checkValidationResult(testFile, err) { | |
| 216 var actualResult = (err === noError) ? "PASS" : err; | |
| 217 var expectedResult = readTestExpected(testFile); | |
| 218 if (actualResult != expectedResult) | |
| 219 console.log("[Test message validation failed: " + testFile + " ]"); | |
| 220 expect(actualResult).toEqual(expectedResult); | |
| 221 } | |
| 222 | |
| 223 function testMessageValidation(key, filters) { | |
| 224 var testFiles = getMessageTestFiles(key); | |
| 225 expect(testFiles.length).toBeGreaterThan(0); | |
| 226 | |
| 227 for (var i = 0; i < testFiles.length; i++) { | |
| 228 // TODO(hansmuller) Temporarily skipping array pointer overflow tests | |
| 229 // because JS numbers are limited to 53 bits. | |
| 230 // TODO(yzshen) Skipping struct versioning tests (tests with "mthd11" | |
| 231 // in the name) because the feature is not supported in JS yet. | |
| 232 // TODO(rudominer): Temporarily skipping 'no-such-method', | |
| 233 // 'invalid_request_flags', and 'invalid_response_flags' until additional | |
| 234 // logic in *RequestValidator and *ResponseValidator is ported from | |
| 235 // cpp to js. | |
| 236 if (testFiles[i].indexOf("overflow") != -1 || | |
| 237 testFiles[i].indexOf("mthd11") != -1 || | |
| 238 testFiles[i].indexOf("no_such_method") != -1 || | |
| 239 testFiles[i].indexOf("invalid_request_flags") != -1 || | |
| 240 testFiles[i].indexOf("invalid_response_flags") != -1) { | |
| 241 console.log("[Skipping " + testFiles[i] + "]"); | |
| 242 continue; | |
| 243 } | |
| 244 | |
| 245 var testMessage = readTestMessage(testFiles[i]); | |
| 246 var handles = new Array(testMessage.handleCount); | |
| 247 var message = new codec.Message(testMessage.buffer, handles); | |
| 248 var messageValidator = new validator.Validator(message); | |
| 249 | |
| 250 var err = messageValidator.validateMessageHeader(); | |
| 251 for (var j = 0; err === noError && j < filters.length; ++j) | |
| 252 err = filters[j](messageValidator); | |
| 253 | |
| 254 checkValidationResult(testFiles[i], err); | |
| 255 } | |
| 256 } | |
| 257 | |
| 258 function testConformanceMessageValidation() { | |
| 259 testMessageValidation("conformance_", [ | |
| 260 testInterface.ConformanceTestInterface.validateRequest]); | |
| 261 } | |
| 262 | |
| 263 function testIntegratedMessageValidation(testFilesPattern) { | |
| 264 var testFiles = getMessageTestFiles(testFilesPattern); | |
| 265 expect(testFiles.length).toBeGreaterThan(0); | |
| 266 | |
| 267 for (var i = 0; i < testFiles.length; i++) { | |
| 268 var testMessage = readTestMessage(testFiles[i]); | |
| 269 var handles = new Array(testMessage.handleCount); | |
| 270 var testMessagePipe = new core.createMessagePipe(); | |
| 271 expect(testMessagePipe.result).toBe(core.RESULT_OK); | |
| 272 | |
| 273 var writeMessageValue = core.writeMessage( | |
| 274 testMessagePipe.handle0, | |
| 275 new Uint8Array(testMessage.buffer.arrayBuffer), | |
| 276 new Array(testMessage.handleCount), | |
| 277 core.WRITE_MESSAGE_FLAG_NONE); | |
| 278 expect(writeMessageValue).toBe(core.RESULT_OK); | |
| 279 | |
| 280 var testConnection = new connection.TestConnection( | |
| 281 testMessagePipe.handle1, | |
| 282 testInterface.IntegrationTestInterface.stubClass, | |
| 283 testInterface.IntegrationTestInterface.proxyClass); | |
| 284 | |
| 285 var validationError = noError; | |
| 286 testConnection.router_.validationErrorHandler = function(err) { | |
| 287 validationError = err; | |
| 288 } | |
| 289 | |
| 290 testConnection.router_.connector_.deliverMessage(); | |
| 291 checkValidationResult(testFiles[i], validationError); | |
| 292 | |
| 293 testConnection.close(); | |
| 294 expect(core.close(testMessagePipe.handle0)).toBe(core.RESULT_OK); | |
| 295 } | |
| 296 } | |
| 297 | |
| 298 function testIntegratedMessageHeaderValidation() { | |
| 299 testIntegratedMessageValidation("integration_msghdr"); | |
| 300 } | |
| 301 | |
| 302 function testIntegratedRequestMessageValidation() { | |
| 303 testIntegratedMessageValidation("integration_intf_rqst"); | |
| 304 } | |
| 305 | |
| 306 function testIntegratedResponseMessageValidation() { | |
| 307 testIntegratedMessageValidation("integration_intf_resp"); | |
| 308 } | |
| 309 | |
| 310 expect(checkTestMessageParser()).toBeNull(); | |
| 311 testConformanceMessageValidation(); | |
| 312 testIntegratedMessageHeaderValidation(); | |
| 313 testIntegratedResponseMessageValidation(); | |
| 314 testIntegratedRequestMessageValidation(); | |
| 315 this.result = "PASS"; | |
| 316 }); | |
| OLD | NEW |