Home | History | Annotate | Download | only in bindings
      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/bindings/buffer",
     11     "mojo/public/js/bindings/codec",
     12     "mojo/public/js/bindings/connection",
     13     "mojo/public/js/bindings/connector",
     14     "mojo/public/js/bindings/core",
     15     "mojo/public/js/bindings/tests/validation_test_input_parser",
     16     "mojo/public/js/bindings/router",
     17     "mojo/public/js/bindings/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       if (testFiles[i].indexOf("overflow") != -1) {
    230         console.log("[Skipping " + testFiles[i] + "]");
    231         continue;
    232       }
    233 
    234       var testMessage = readTestMessage(testFiles[i]);
    235       var handles = new Array(testMessage.handleCount);
    236       var message = new codec.Message(testMessage.buffer, handles);
    237       var messageValidator = new validator.Validator(message);
    238 
    239       var err = messageValidator.validateMessageHeader();
    240       for (var j = 0; err === noError && j < filters.length; ++j)
    241         err = filters[j](messageValidator);
    242 
    243       checkValidationResult(testFiles[i], err);
    244     }
    245   }
    246 
    247   function testConformanceMessageValidation() {
    248     testMessageValidation("conformance_", [
    249         testInterface.ConformanceTestInterfaceStub.prototype.validator]);
    250   }
    251 
    252   function testNotImplementedMessageValidation() {
    253     testMessageValidation("not_implemented_", [
    254         testInterface.ConformanceTestInterfaceStub.prototype.validator]);
    255   }
    256 
    257   function testIntegratedMessageValidation() {
    258     var testFiles = getMessageTestFiles("integration_");
    259     expect(testFiles.length).toBeGreaterThan(0);
    260 
    261     for (var i = 0; i < testFiles.length; i++) {
    262       // TODO(hansmuller): Temporarily skipping array pointer overflow tests.
    263       if (testFiles[i].indexOf("overflow") != -1) {
    264         console.log("[Skipping " + testFiles[i] + "]");
    265         continue;
    266       }
    267 
    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.IntegrationTestInterface1Stub,
    283           testInterface.IntegrationTestInterface2Proxy);
    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   expect(checkTestMessageParser()).toBeNull();
    299   testConformanceMessageValidation();
    300   testIntegratedMessageValidation();
    301   this.result = "PASS";
    302 });
    303