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