OLD | NEW |
(Empty) | |
| 1 <!DOCTYPE html> |
| 2 <script src="../resources/testharness.js"></script> |
| 3 <script src="../resources/testharnessreport.js"></script> |
| 4 <script src="../resources/mojo-helpers.js"></script> |
| 5 <script src="resources/validation_test_input_parser.js"></script> |
| 6 <script> |
| 7 'use strict'; |
| 8 |
| 9 setup({ explicit_done: true }); |
| 10 |
| 11 define([ |
| 12 'mojo/public/js/bindings', |
| 13 'mojo/public/js/buffer', |
| 14 'mojo/public/js/codec', |
| 15 'mojo/public/js/core', |
| 16 'mojo/resources/validation_test_input_parser', |
| 17 'mojo/public/interfaces/bindings/tests/validation_test_interfaces.mojom', |
| 18 'mojo/public/js/validator', |
| 19 ], function(bindings, |
| 20 buffer, |
| 21 codec, |
| 22 core, |
| 23 parser, |
| 24 testInterface, |
| 25 validator) { |
| 26 |
| 27 var noError = validator.validationError.NONE; |
| 28 |
| 29 function checkData(data, expectedData, input) { |
| 30 assert_equals(data.byteLength, expectedData.byteLength, |
| 31 'message length (' + data.byteLength + ') doesn\'t match ' + |
| 32 'expected length: ' + expectedData.byteLength + ' for ' + input); |
| 33 |
| 34 for (var i = 0; i < data.byteLength; i++) { |
| 35 assert_equals(data.getUint8(i), expectedData.getUint8(i), |
| 36 'message data mismatch at byte offset ' + i + 'for' + input); |
| 37 } |
| 38 } |
| 39 |
| 40 test(() => { |
| 41 var input = '[f]+.3e9 [d]-10.03'; |
| 42 var msg = parser.parseTestMessage(input); |
| 43 var expectedData = new buffer.Buffer(12); |
| 44 expectedData.setFloat32(0, +.3e9); |
| 45 expectedData.setFloat64(4, -10.03); |
| 46 checkData(msg.buffer, expectedData, input); |
| 47 }, 'message parser: float items'); |
| 48 |
| 49 test(() => { |
| 50 var input = '[u1]0x10// hello world !! \n\r \t [u2]65535 \n' + |
| 51 '[u4]65536 [u8]0xFFFFFFFFFFFFF 0 0Xff'; |
| 52 var msg = parser.parseTestMessage(input); |
| 53 var expectedData = new buffer.Buffer(17); |
| 54 expectedData.setUint8(0, 0x10); |
| 55 expectedData.setUint16(1, 65535); |
| 56 expectedData.setUint32(3, 65536); |
| 57 expectedData.setUint64(7, 0xFFFFFFFFFFFFF); |
| 58 expectedData.setUint8(15, 0); |
| 59 expectedData.setUint8(16, 0xff); |
| 60 checkData(msg.buffer, expectedData, input); |
| 61 }, 'message parser: unsigned integer items'); |
| 62 |
| 63 test(() => { |
| 64 var input = '[s8]-0x800 [s1]-128\t[s2]+0 [s4]-40'; |
| 65 var msg = parser.parseTestMessage(input); |
| 66 var expectedData = new buffer.Buffer(15); |
| 67 expectedData.setInt64(0, -0x800); |
| 68 expectedData.setInt8(8, -128); |
| 69 expectedData.setInt16(9, 0); |
| 70 expectedData.setInt32(11, -40); |
| 71 checkData(msg.buffer, expectedData, input); |
| 72 }, 'message parser: signed integer items'); |
| 73 |
| 74 test(() => { |
| 75 var input = '[b]00001011 [b]10000000 // hello world\n [b]00000000'; |
| 76 var msg = parser.parseTestMessage(input); |
| 77 var expectedData = new buffer.Buffer(3); |
| 78 expectedData.setUint8(0, 11); |
| 79 expectedData.setUint8(1, 128); |
| 80 expectedData.setUint8(2, 0); |
| 81 checkData(msg.buffer, expectedData, input); |
| 82 }, 'message parser: byte items'); |
| 83 |
| 84 test(() => { |
| 85 var input = '[dist4]foo 0 [dist8]bar 0 [anchr]foo [anchr]bar'; |
| 86 var msg = parser.parseTestMessage(input); |
| 87 var expectedData = new buffer.Buffer(14); |
| 88 expectedData.setUint32(0, 14); |
| 89 expectedData.setUint8(4, 0); |
| 90 expectedData.setUint64(5, 9); |
| 91 expectedData.setUint8(13, 0); |
| 92 checkData(msg.buffer, expectedData, input); |
| 93 }, 'message parser: anchors'); |
| 94 |
| 95 test(() => { |
| 96 var input = '// This message has handles! \n[handles]50 [u8]2'; |
| 97 var msg = parser.parseTestMessage(input); |
| 98 var expectedData = new buffer.Buffer(8); |
| 99 expectedData.setUint64(0, 2); |
| 100 |
| 101 assert_equals(msg.handleCount, 50, |
| 102 'wrong handle count (' + msg.handleConut + ') for ' + input); |
| 103 checkData(msg.buffer, expectedData, input); |
| 104 }, 'message parser: handles'); |
| 105 |
| 106 test(() => { |
| 107 var msg = parser.parseTestMessage(''); |
| 108 assert_equals(msg.buffer.byteLength, 0, 'expected empty message for '); |
| 109 }, 'message parser: empty input'); |
| 110 |
| 111 test(() => { |
| 112 var input = ' \t // hello world \n\r \t// the answer is 42 '; |
| 113 var msg = parser.parseTestMessage(input); |
| 114 assert_equals(msg.buffer.byteLength, 0, |
| 115 'expected empty message for ' + input); |
| 116 }, 'message parser: blank input'); |
| 117 |
| 118 test(() => { |
| 119 function parserShouldFail(input) { |
| 120 assert_throws(new parser.InputError(), function() { |
| 121 parser.parseTestMessage(input); |
| 122 }); |
| 123 } |
| 124 |
| 125 ['/ hello world', |
| 126 '[u1]x', |
| 127 '[u2]-1000', |
| 128 '[u1]0x100', |
| 129 '[s2]-0x8001', |
| 130 '[b]1', |
| 131 '[b]1111111k', |
| 132 '[dist4]unmatched', |
| 133 '[anchr]hello [dist8]hello', |
| 134 '[dist4]a [dist4]a [anchr]a', |
| 135 // '[dist4]a [anchr]a [dist4]a [anchr]a', |
| 136 '0 [handles]50' |
| 137 ].forEach(parserShouldFail); |
| 138 }, 'message parser: invalid input'); |
| 139 |
| 140 function fetchLite(url) { |
| 141 return new Promise((resolve, reject) => { |
| 142 var xhr = new XMLHttpRequest(); |
| 143 xhr.open('GET', url); |
| 144 xhr.onreadystatechange = () => { |
| 145 if (xhr.readyState != 4) return; |
| 146 resolve(xhr.responseText); |
| 147 }; |
| 148 xhr.send(); |
| 149 }); |
| 150 } |
| 151 |
| 152 function getMessageTestFiles(prefix) { |
| 153 let genDirectory = 'file:///gen/layout_test_data/'; |
| 154 return fetchLite(genDirectory + 'validation_files.txt').then((response) => { |
| 155 assert_not_equals(response, null); |
| 156 var testFiles = response.split(/\s+/); |
| 157 assert_greater_than(testFiles.length, 0); |
| 158 return testFiles.filter(function(s) { |
| 159 return s.substr(-5) == '.data' && s.indexOf(prefix) == 0; |
| 160 }).map(function(s) { |
| 161 return genDirectory + 'validation/' + s.slice(0, -5); |
| 162 }); |
| 163 }); |
| 164 } |
| 165 |
| 166 function readTestMessage(filename) { |
| 167 return fetchLite(filename + '.data').then((response) => { |
| 168 assert_not_equals(response, null); |
| 169 return parser.parseTestMessage(response); |
| 170 }); |
| 171 } |
| 172 |
| 173 function readTestExpected(filename) { |
| 174 return fetchLite(filename + '.expected').then((response) => { |
| 175 assert_not_equals(response, null); |
| 176 return response.trim(); |
| 177 }); |
| 178 } |
| 179 |
| 180 async function checkValidationResult(testFile, err) { |
| 181 var actualResult = (err === noError) ? 'PASS' : err; |
| 182 var expectedResult = await readTestExpected(testFile); |
| 183 assert_equals(actualResult, expectedResult, |
| 184 '[Test message validation failed: ' + testFile + ' ]'); |
| 185 } |
| 186 |
| 187 async function testMessageValidation(prefix, filters) { |
| 188 var testFiles = await getMessageTestFiles(prefix); |
| 189 assert_greater_than(testFiles.length, 0); |
| 190 |
| 191 for (var i = 0; i < testFiles.length; i++) { |
| 192 // TODO(hansmuller) Temporarily skipping array pointer overflow tests |
| 193 // because JS numbers are limited to 53 bits. |
| 194 // TODO(rudominer): Temporarily skipping 'no-such-method', |
| 195 // 'invalid_request_flags', and 'invalid_response_flags' until additional |
| 196 // logic in *RequestValidator and *ResponseValidator is ported from |
| 197 // cpp to js. |
| 198 // TODO(crbug/640298): Implement max recursion depth for JS. |
| 199 // TODO(crbug/628104): Support struct map keys for JS. |
| 200 if (testFiles[i].indexOf('overflow') != -1 || |
| 201 testFiles[i].indexOf('conformance_mthd19') != -1 || |
| 202 testFiles[i].indexOf('conformance_mthd20') != -1 || |
| 203 testFiles[i].indexOf('no_such_method') != -1 || |
| 204 testFiles[i].indexOf('invalid_request_flags') != -1 || |
| 205 testFiles[i].indexOf('invalid_response_flags') != -1) { |
| 206 console.log('[Skipping ' + testFiles[i] + ']'); |
| 207 continue; |
| 208 } |
| 209 |
| 210 var testMessage = await readTestMessage(testFiles[i]); |
| 211 var handles = new Array(testMessage.handleCount); |
| 212 var message = new codec.Message(testMessage.buffer, handles); |
| 213 var messageValidator = new validator.Validator(message); |
| 214 |
| 215 var err = messageValidator.validateMessageHeader(); |
| 216 for (var j = 0; err === noError && j < filters.length; ++j) |
| 217 err = filters[j](messageValidator); |
| 218 |
| 219 await checkValidationResult(testFiles[i], err); |
| 220 } |
| 221 } |
| 222 |
| 223 promise_test(() => { |
| 224 return testMessageValidation('conformance_', [ |
| 225 testInterface.ConformanceTestInterface.validateRequest]); |
| 226 }, 'conformance message validation'); |
| 227 |
| 228 promise_test(() => { |
| 229 return testMessageValidation('boundscheck_', [ |
| 230 testInterface.BoundsCheckTestInterface.validateRequest]); |
| 231 }, 'bounds check message validation'); |
| 232 |
| 233 promise_test(() => { |
| 234 return testMessageValidation('resp_conformance_', [ |
| 235 testInterface.ConformanceTestInterface.validateResponse]); |
| 236 }, 'response conformance message validation'); |
| 237 |
| 238 promise_test(() => { |
| 239 return testMessageValidation('resp_boundscheck_', [ |
| 240 testInterface.BoundsCheckTestInterface.validateResponse]); |
| 241 }, 'response bounds check message validation'); |
| 242 |
| 243 async function testIntegratedMessageValidation(testFilesPattern, endpoint) { |
| 244 var testFiles = await getMessageTestFiles(testFilesPattern); |
| 245 assert_greater_than(testFiles.length, 0); |
| 246 |
| 247 var testMessagePipe = core.createMessagePipe(); |
| 248 assert_equals(testMessagePipe.result, core.RESULT_OK); |
| 249 |
| 250 endpoint.bind(testMessagePipe.handle1); |
| 251 var observer = validator.ValidationErrorObserverForTesting.getInstance(); |
| 252 |
| 253 for (var i = 0; i < testFiles.length; i++) { |
| 254 var testMessage = await readTestMessage(testFiles[i]); |
| 255 var handles = new Array(testMessage.handleCount); |
| 256 |
| 257 var writeMessageValue = core.writeMessage( |
| 258 testMessagePipe.handle0, |
| 259 new Uint8Array(testMessage.buffer.arrayBuffer), |
| 260 new Array(testMessage.handleCount), |
| 261 core.WRITE_MESSAGE_FLAG_NONE); |
| 262 assert_equals(writeMessageValue, core.RESULT_OK); |
| 263 |
| 264 endpoint.waitForNextMessageForTesting(); |
| 265 await checkValidationResult(testFiles[i], observer.lastError); |
| 266 observer.reset(); |
| 267 } |
| 268 |
| 269 assert_equals(core.close(testMessagePipe.handle0), core.RESULT_OK); |
| 270 } |
| 271 |
| 272 promise_test(() => { |
| 273 return testIntegratedMessageValidation( |
| 274 'integration_msghdr', |
| 275 new bindings.Binding(testInterface.IntegrationTestInterface, {})) |
| 276 .then(() => { |
| 277 return testIntegratedMessageValidation( |
| 278 'integration_msghdr', |
| 279 new testInterface.IntegrationTestInterfacePtr().ptr); |
| 280 }); |
| 281 }, 'integrated message header validation'); |
| 282 |
| 283 promise_test(() => { |
| 284 return testIntegratedMessageValidation( |
| 285 'integration_intf_rqst', |
| 286 new bindings.Binding(testInterface.IntegrationTestInterface, {})); |
| 287 }, 'integrated request message validation'); |
| 288 |
| 289 promise_test(() => { |
| 290 return testIntegratedMessageValidation( |
| 291 'integration_intf_resp', |
| 292 new testInterface.IntegrationTestInterfacePtr().ptr); |
| 293 }, 'integrated response message validation'); |
| 294 |
| 295 done(); |
| 296 }); |
| 297 |
| 298 </script> |
OLD | NEW |