| Index: third_party/WebKit/LayoutTests/mojo/validation.html
|
| diff --git a/third_party/WebKit/LayoutTests/mojo/validation.html b/third_party/WebKit/LayoutTests/mojo/validation.html
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..64dbc40e966017d4219569bfe8902cdf09c516bf
|
| --- /dev/null
|
| +++ b/third_party/WebKit/LayoutTests/mojo/validation.html
|
| @@ -0,0 +1,299 @@
|
| +<!DOCTYPE html>
|
| +<script src="../resources/testharness.js"></script>
|
| +<script src="../resources/testharnessreport.js"></script>
|
| +<script src="../resources/mojo-helpers.js"></script>
|
| +<script src="resources/validation_test_input_parser.js"></script>
|
| +<script>
|
| +'use strict';
|
| +
|
| +setup({ explicit_done: true });
|
| +
|
| +define(["mojo/public/interfaces/bindings/tests/validation_test_interfaces.mojom",
|
| + "mojo/public/js/bindings",
|
| + "mojo/public/js/buffer",
|
| + "mojo/public/js/codec",
|
| + "mojo/public/js/core",
|
| + "mojo/resources/validation_test_input_parser",
|
| + "mojo/public/js/validator",
|
| +], function(testInterface,
|
| + bindings,
|
| + buffer,
|
| + codec,
|
| + core,
|
| + parser,
|
| + validator) {
|
| +
|
| + var noError = validator.validationError.NONE;
|
| +
|
| + function checkData(data, expectedData, input) {
|
| + assert_equals(data.byteLength, expectedData.byteLength,
|
| + "message length (" + data.byteLength + ") doesn't match " +
|
| + "expected length: " + expectedData.byteLength + " for " + input);
|
| +
|
| + for (var i = 0; i < data.byteLength; i++) {
|
| + assert_equals(data.getUint8(i), expectedData.getUint8(i),
|
| + 'message data mismatch at byte offset ' + i + "for" + input);
|
| + }
|
| + }
|
| +
|
| + test(() => {
|
| + var input = '[f]+.3e9 [d]-10.03';
|
| + var msg = parser.parseTestMessage(input);
|
| + var expectedData = new buffer.Buffer(12);
|
| + expectedData.setFloat32(0, +.3e9);
|
| + expectedData.setFloat64(4, -10.03);
|
| + checkData(msg.buffer, expectedData, input);
|
| + }, 'message parser: float items');
|
| +
|
| + test(() => {
|
| + var input = '[u1]0x10// hello world !! \n\r \t [u2]65535 \n' +
|
| + '[u4]65536 [u8]0xFFFFFFFFFFFFF 0 0Xff';
|
| + var msg = parser.parseTestMessage(input);
|
| + var expectedData = new buffer.Buffer(17);
|
| + expectedData.setUint8(0, 0x10);
|
| + expectedData.setUint16(1, 65535);
|
| + expectedData.setUint32(3, 65536);
|
| + expectedData.setUint64(7, 0xFFFFFFFFFFFFF);
|
| + expectedData.setUint8(15, 0);
|
| + expectedData.setUint8(16, 0xff);
|
| + checkData(msg.buffer, expectedData, input);
|
| + }, 'message parser: unsigned integer items');
|
| +
|
| + test(() => {
|
| + var input = '[s8]-0x800 [s1]-128\t[s2]+0 [s4]-40';
|
| + var msg = parser.parseTestMessage(input);
|
| + var expectedData = new buffer.Buffer(15);
|
| + expectedData.setInt64(0, -0x800);
|
| + expectedData.setInt8(8, -128);
|
| + expectedData.setInt16(9, 0);
|
| + expectedData.setInt32(11, -40);
|
| + checkData(msg.buffer, expectedData, input);
|
| + }, 'message parser: signed integer items');
|
| +
|
| + test(() => {
|
| + var input = '[b]00001011 [b]10000000 // hello world\n [b]00000000';
|
| + var msg = parser.parseTestMessage(input);
|
| + var expectedData = new buffer.Buffer(3);
|
| + expectedData.setUint8(0, 11);
|
| + expectedData.setUint8(1, 128);
|
| + expectedData.setUint8(2, 0);
|
| + checkData(msg.buffer, expectedData, input);
|
| + }, 'message parser: byte items');
|
| +
|
| + test(() => {
|
| + var input = '[dist4]foo 0 [dist8]bar 0 [anchr]foo [anchr]bar';
|
| + var msg = parser.parseTestMessage(input);
|
| + var expectedData = new buffer.Buffer(14);
|
| + expectedData.setUint32(0, 14);
|
| + expectedData.setUint8(4, 0);
|
| + expectedData.setUint64(5, 9);
|
| + expectedData.setUint8(13, 0);
|
| + checkData(msg.buffer, expectedData, input);
|
| + }, 'message parser: anchors');
|
| +
|
| + test(() => {
|
| + var input = '// This message has handles! \n[handles]50 [u8]2';
|
| + var msg = parser.parseTestMessage(input);
|
| + var expectedData = new buffer.Buffer(8);
|
| + expectedData.setUint64(0, 2);
|
| +
|
| + assert_equals(msg.handleCount, 50,
|
| + 'wrong handle count (' + msg.handleConut + ') for ' + input);
|
| + checkData(msg.buffer, expectedData, input);
|
| + }, 'message parser: handles');
|
| +
|
| + test(() => {
|
| + var msg = parser.parseTestMessage('');
|
| + assert_equals(msg.buffer.byteLength, 0, 'expected empty message for ');
|
| + }, 'message parser: empty input');
|
| +
|
| + test(() => {
|
| + var input = ' \t // hello world \n\r \t// the answer is 42 ';
|
| + var msg = parser.parseTestMessage(input);
|
| + assert_equals(msg.buffer.byteLength, 0, 'expected empty message for ' + input);
|
| + }, 'message parser: blank input');
|
| +
|
| + test(() => {
|
| + function parserShouldFail(input) {
|
| + assert_throws(new parser.InputError(), function() {
|
| + parser.parseTestMessage(input);
|
| + });
|
| + }
|
| +
|
| + ['/ hello world',
|
| + '[u1]x',
|
| + '[u2]-1000',
|
| + '[u1]0x100',
|
| + '[s2]-0x8001',
|
| + '[b]1',
|
| + '[b]1111111k',
|
| + '[dist4]unmatched',
|
| + '[anchr]hello [dist8]hello',
|
| + '[dist4]a [dist4]a [anchr]a',
|
| + // '[dist4]a [anchr]a [dist4]a [anchr]a',
|
| + '0 [handles]50'
|
| + ].forEach(parserShouldFail);
|
| + }, 'message parser: invalid input');
|
| +
|
| + function fetchLite(url) {
|
| + return new Promise((resolve, reject) => {
|
| + var xhr = new XMLHttpRequest();
|
| + xhr.open('GET', url);
|
| + xhr.onreadystatechange = () => {
|
| + if (xhr.readyState != 4) return;
|
| + resolve(xhr.responseText);
|
| + };
|
| + xhr.send();
|
| + });
|
| + }
|
| +
|
| + function getMessageTestFiles(prefix) {
|
| + return fetchLite('/gen/mojo/public/interfaces/bindings/tests/data_files.txt').then((response) => {
|
| + assert_not_equals(response, null);
|
| + var testFiles = response.split('\n');
|
| + assert_greater_than(testFiles.length, 0);
|
| + return testFiles.filter(function(s) {
|
| + return s.indexOf(prefix) == 0;
|
| + }).map(function(s) {
|
| + return '../../../../mojo/public/interfaces/bindings/tests/data/validation/' + s;
|
| + });
|
| + });
|
| + }
|
| +
|
| + function readTestMessage(filename) {
|
| + return fetchLite(filename + '.data').then((response) => {
|
| + assert_not_equals(response, null);
|
| + return parser.parseTestMessage(response);
|
| + });
|
| + }
|
| +
|
| + function readTestExpected(filename) {
|
| + return fetchLite(filename + '.expected').then((response) => {
|
| + assert_not_equals(response, null);
|
| + return response.trim();
|
| + });
|
| + }
|
| +
|
| + async function checkValidationResult(testFile, err) {
|
| + var actualResult = (err === noError) ? "PASS" : err;
|
| + var expectedResult = await readTestExpected(testFile);
|
| + assert_equals(actualResult, expectedResult,
|
| + "[Test message validation failed: " + testFile + " ]");
|
| + }
|
| +
|
| + async function testMessageValidation(prefix, filters) {
|
| + var testFiles = await getMessageTestFiles(prefix);
|
| + assert_greater_than(testFiles.length, 0);
|
| +
|
| + for (var i = 0; i < testFiles.length; i++) {
|
| + // TODO(hansmuller) Temporarily skipping array pointer overflow tests
|
| + // because JS numbers are limited to 53 bits.
|
| + // TODO(rudominer): Temporarily skipping 'no-such-method',
|
| + // 'invalid_request_flags', and 'invalid_response_flags' until additional
|
| + // logic in *RequestValidator and *ResponseValidator is ported from
|
| + // cpp to js.
|
| + // TODO(crbug/640298): Implement max recursion depth for JS.
|
| + // TODO(crbug/628104): Support struct map keys for JS.
|
| + if (testFiles[i].indexOf("overflow") != -1 ||
|
| + testFiles[i].indexOf("conformance_mthd19") != -1 ||
|
| + testFiles[i].indexOf("conformance_mthd20") != -1 ||
|
| + testFiles[i].indexOf("no_such_method") != -1 ||
|
| + testFiles[i].indexOf("invalid_request_flags") != -1 ||
|
| + testFiles[i].indexOf("invalid_response_flags") != -1) {
|
| + console.log("[Skipping " + testFiles[i] + "]");
|
| + continue;
|
| + }
|
| +
|
| + var testMessage = await readTestMessage(testFiles[i]);
|
| + var handles = new Array(testMessage.handleCount);
|
| + var message = new codec.Message(testMessage.buffer, handles);
|
| + var messageValidator = new validator.Validator(message);
|
| +
|
| + var err = messageValidator.validateMessageHeader();
|
| + for (var j = 0; err === noError && j < filters.length; ++j)
|
| + err = filters[j](messageValidator);
|
| +
|
| + await checkValidationResult(testFiles[i], err);
|
| + }
|
| + }
|
| +
|
| + promise_test(() => {
|
| + return testMessageValidation("conformance_", [
|
| + testInterface.ConformanceTestInterface.validateRequest]);
|
| + }, 'conformance message validation');
|
| +
|
| + promise_test(() => {
|
| + return testMessageValidation("boundscheck_", [
|
| + testInterface.BoundsCheckTestInterface.validateRequest]);
|
| + }, 'bounds check message validation');
|
| +
|
| + promise_test(() => {
|
| + return testMessageValidation("resp_conformance_", [
|
| + testInterface.ConformanceTestInterface.validateResponse]);
|
| + }, 'response conformance message validation');
|
| +
|
| + promise_test(() => {
|
| + return testMessageValidation("resp_boundscheck_", [
|
| + testInterface.BoundsCheckTestInterface.validateResponse]);
|
| + }, 'response bounds check message validation');
|
| +
|
| + async function testIntegratedMessageValidation(testFilesPattern, endpoint) {
|
| + var testFiles = await getMessageTestFiles(testFilesPattern);
|
| + assert_greater_than(testFiles.length, 0);
|
| +
|
| + var testMessagePipe = core.createMessagePipe();
|
| + assert_equals(testMessagePipe.result, core.RESULT_OK);
|
| +
|
| + endpoint.bind(testMessagePipe.handle1);
|
| + var testingController = endpoint.enableTestingMode();
|
| +
|
| + var validationError;
|
| + testingController.setInvalidIncomingMessageHandler(function(error) {
|
| + validationError = error;
|
| + });
|
| +
|
| + for (var i = 0; i < testFiles.length; i++) {
|
| + validationError = noError;
|
| + var testMessage = await readTestMessage(testFiles[i]);
|
| + var handles = new Array(testMessage.handleCount);
|
| +
|
| + var writeMessageValue = core.writeMessage(
|
| + testMessagePipe.handle0,
|
| + new Uint8Array(testMessage.buffer.arrayBuffer),
|
| + new Array(testMessage.handleCount),
|
| + core.WRITE_MESSAGE_FLAG_NONE);
|
| + assert_equals(writeMessageValue, core.RESULT_OK);
|
| +
|
| + testingController.waitForNextMessage();
|
| + await checkValidationResult(testFiles[i], validationError);
|
| + }
|
| +
|
| + assert_equals(core.close(testMessagePipe.handle0), core.RESULT_OK);
|
| + }
|
| +
|
| + promise_test(() => {
|
| + return testIntegratedMessageValidation(
|
| + "integration_msghdr",
|
| + new bindings.Binding(testInterface.IntegrationTestInterface, {})).then(() => {
|
| + return testIntegratedMessageValidation(
|
| + "integration_msghdr",
|
| + new testInterface.IntegrationTestInterfacePtr().ptr);
|
| + });
|
| + }, 'integrated message header validation');
|
| +
|
| + promise_test(() => {
|
| + return testIntegratedMessageValidation(
|
| + "integration_intf_rqst",
|
| + new bindings.Binding(testInterface.IntegrationTestInterface, {}));
|
| + }, 'integrated request message validation');
|
| +
|
| + promise_test(() => {
|
| + return testIntegratedMessageValidation(
|
| + "integration_intf_resp",
|
| + new testInterface.IntegrationTestInterfacePtr().ptr);
|
| + }, 'integrated response message validation');
|
| +
|
| + done();
|
| +});
|
| +
|
| +</script>
|
|
|