blob: 06763f73f8fb92fdbb8e8c26b67113e926bf4a6a [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {MappedOptionalContainer, StringDictType, TestNode} from './web_ui_mojo_ts_test_mapped_types.js';
import {MojoResultTestCallbackRouter, MojoResultTestReceiver, MojoResultTestRemote, OptionalNumericsStruct, Result, TestEnum, WebUITsMojoTestCache} from './web_ui_ts_test.test-mojom-webui.js';
import {StringWrapper} from './web_ui_ts_test_types.test-mojom-webui.js';
const TEST_DATA: Array<{url: string, contents: string}> = [
{ url: 'https://google.com/', contents: 'i am in fact feeling lucky' },
{ url: 'https://youtube.com/', contents: 'probably cat videos?' },
{ url: 'https://example.com/', contents: 'internets wow' },
];
function assert(condition: any, msg: string) {
if (!condition) {
throw new Error('assertion failed: ' + msg);
}
}
function assertArrayEquals(a: Array<any>, b: Array<any>, msg: string) {
assert(a.length === b.length, msg);
for (let i = 0; i < a.length; ++i) {
assert(a[i] === b[i], msg);
}
}
function assertObjectEquals(a: any, b: any, msg: string) {
assert(Object.keys(a).length === Object.keys(b).length, msg);
for (let key of Object.keys(a)) {
assert(a[key] === b[key], msg);
}
}
async function doTest(): Promise<boolean> {
const cache = WebUITsMojoTestCache.getRemote();
for (const entry of TEST_DATA) {
cache.put({ url: entry.url }, entry.contents);
let stringWrapper = StringWrapper.getRemote();
stringWrapper.putString(entry.contents);
cache.addStringWrapper(stringWrapper);
}
const {items} = await cache.getAll();
if (items.length !== TEST_DATA.length) {
return false;
}
const entries: {[key: string]: string } = {};
for (const item of items) {
entries[item.url.url] = item.contents;
}
for (const entry of TEST_DATA) {
if (!(entry.url in entries)) {
return false;
}
if (entries[entry.url] != entry.contents) {
return false;
}
}
const {stringWrapperList} = await cache.getStringWrapperList();
if (stringWrapperList.length !== TEST_DATA.length) {
return false;
}
let stringsInList = [];
for (const stringWrapper of stringWrapperList) {
let {item} = await stringWrapper.getString();
stringsInList.push(item);
}
for (const entry of TEST_DATA) {
if (!stringsInList.includes(entry.contents)) {
return false;
}
}
{
const testStruct: OptionalNumericsStruct = {
optionalBool: true,
optionalUint8: null,
optionalEnum: TestEnum.kOne,
};
const {
optionalBool,
optionalUint8,
optionalEnum,
optionalNumerics,
optionalBools,
optionalInts,
optionalEnums,
boolMap,
intMap,
enumMap
} =
await cache.echo(
true, null, TestEnum.kOne, testStruct, [], [], [], {}, {}, {}, '',
new TestNode(), null);
if (optionalBool !== false) {
return false;
}
if (optionalUint8 !== null) {
return false;
}
if (optionalEnum !== TestEnum.kTwo) {
return false;
}
if (optionalNumerics.optionalBool !== false) {
return false;
}
if (optionalNumerics.optionalUint8 !== null) {
return false;
}
if (optionalNumerics.optionalEnum !== TestEnum.kTwo) {
return false;
}
for (const arr of [optionalBools, optionalInts, optionalEnums]) {
assertArrayEquals(arr, [], 'empty array');
}
for (const map of [boolMap, intMap, enumMap]) {
assertObjectEquals(map, [], 'empty map');
}
}
{
const testStruct: OptionalNumericsStruct = {
optionalBool: null,
optionalUint8: 1,
optionalEnum: null,
};
const inOptionalBools = [false, null, true];
const inOptionalInts = [null, 0, 1, null];
const inOptionalEnums = [null, 0, null, 1, null];
const inBoolMap = {0: true, 1: false, 2: null};
const inIntMap = {0: 0, 2: null};
const inEnumMap = {0: 0, 1: null};
const {
optionalBool,
optionalUint8,
optionalEnum,
optionalNumerics,
optionalBools,
optionalInts,
optionalEnums,
boolMap,
intMap,
enumMap
} =
await cache.echo(
null, 1, null, testStruct, inOptionalBools, inOptionalInts,
inOptionalEnums, inBoolMap, inIntMap, inEnumMap, '', new TestNode(),
null);
if (optionalBool !== null) {
return false;
}
if (optionalUint8 !== 254) {
return false;
}
if (optionalEnum !== null) {
return false;
}
if (optionalNumerics.optionalBool !== null) {
return false;
}
if (optionalNumerics.optionalUint8 !== 254) {
return false;
}
if (optionalNumerics.optionalEnum !== null) {
return false;
}
assertArrayEquals(inOptionalBools, optionalBools, 'optional bools');
assertArrayEquals(inOptionalInts, optionalInts, 'optional ints');
assertArrayEquals(inOptionalEnums, optionalEnums, 'optional enums');
assertObjectEquals(inBoolMap, boolMap, 'bool map');
assertObjectEquals(inIntMap, intMap, 'bool int');
assertObjectEquals(inEnumMap, enumMap, 'enum map');
}
const testStruct: OptionalNumericsStruct = {
optionalBool: null,
optionalUint8: null,
optionalEnum: null,
};
// Test simple mapped type where a struct is mapped to a string.
{
const str = 'foobear';
const result = await cache.echo(
null, 1, null, testStruct, [], [], [], {}, {}, {}, str, new TestNode(),
null);
if (result.simpleMappedType !== str) {
return false;
}
}
// Tests an empty nested struct to test basic encoding/decoding.
{
const result = await cache.echo(
null, 1, null, testStruct, [], [], [], {}, {}, {}, '', new TestNode(),
null);
assertObjectEquals(
new TestNode(), result.nestedMappedType,
'nested mappped type: got: ' + JSON.stringify(result.nestedMappedType) +
', expected: {next: null}');
}
// Tests a nested type where a struct includes itself.
{
const depth = 10;
const chain: TestNode = new TestNode();
let cursor = chain;
for (let i = 0; i < depth; ++i) {
cursor = cursor!.next = new TestNode();
}
const result = await cache.echo(
null, 1, null, testStruct, [], [], [], {}, {}, {}, '', chain, null);
if (JSON.stringify(chain) !== JSON.stringify(result.nestedMappedType)) {
throw new Error(
'nested mappped type: got: ' +
JSON.stringify(result.nestedMappedType) +
', expected: ' + JSON.stringify(chain));
}
}
{
let map: StringDictType = new Map<string, string>();
map.set('foo', 'bear');
map.set('some', 'where');
const result = await cache.echo(
null, 1, null, testStruct, [], [], [], {}, {}, {}, '', new TestNode(),
map);
for (const key of map.keys()) {
assert(
result.otherMappedType!.get(key) === map.get(key),
`Expected value: ${map.get(key)} for key: ${key}, got: ${
result.otherMappedType!.get(key)}`);
}
}
{
const result = await cache.echoTypemaps(new Date(12321));
assert(
result.time.getTime() === new Date(12321).getTime(),
`unexpected date received ${result.time.getTime()}`);
}
const assertTypemapContainerEquals =
(expected: MappedOptionalContainer, result: MappedOptionalContainer,
msg: string) => {
assert(expected.optionalInt === result.optionalInt, msg);
assertArrayEquals(expected.bools, result.bools, msg);
assertObjectEquals(expected.optionalMap, result.optionalMap, msg);
};
{
const withNulls = {
optionalInt: null,
bools: [null, null, null],
optionalMap: {'foo': null}
};
const result = await cache.echoOptionalTypemaps(withNulls);
assertTypemapContainerEquals(
withNulls, result.result,
`unexpected object ${JSON.stringify(result)}, expected: ${
JSON.stringify(withNulls)}`);
}
{
const withValues = {
optionalInt: 6,
bools: [null, false, null, true, null],
optionalMap: {'foo': null, 'bear': true}
};
const result = await cache.echoOptionalTypemaps(withValues);
assertTypemapContainerEquals(
withValues, result.result,
`unexpected object ${JSON.stringify(result.result)}, expected: ${
JSON.stringify(withValues)}`);
}
// Loopback test for result types.
{
// Test general success case.
const listener = {
testResult:
(():
Promise<Result> => {
return Promise.resolve({secretMessage: `it's all for naught`});
})
};
const service = new MojoResultTestReceiver(listener);
const client: MojoResultTestRemote = service.$.bindNewPipeAndPassRemote();
await client.testResult().then(result => {
assert(
result.secretMessage === `it's all for naught`,
`got unexpected msg: ${JSON.stringify(result)}`);
});
}
{
// Tests listener pattern.
const callbacks = new MojoResultTestCallbackRouter();
const client = callbacks.$.bindNewPipeAndPassRemote();
callbacks.testResult.addListener(
() => Promise.resolve({secretMessage: 'I listen'}));
await client.testResult().then(result => {
assert(
result.secretMessage === 'I listen',
`got unexpected msg: ${JSON.stringify(result)}`);
});
}
{
// Tests rejection.
const callbacks = new MojoResultTestCallbackRouter();
const client = callbacks.$.bindNewPipeAndPassRemote();
callbacks.testResult.addListener(
() => Promise.reject(new Error('cannot go on')));
await client.testResult()
.then(() => {
assert(false, 'should have failed');
})
.catch((error: Error) => {
assert(error.message === 'cannot go on', JSON.stringify(error));
});
}
{
// Tests loose js error encoding for JsError.
const callbacks = new MojoResultTestCallbackRouter();
const client = callbacks.$.bindNewPipeAndPassRemote();
callbacks.testResult.addListener(
() => Promise.reject({message: 'cannot go on'}));
await client.testResult()
.then(() => {
assert(false, 'should have failed');
})
.catch((error: Error) => {
assert(error.message === 'cannot go on', JSON.stringify(error));
});
}
{
// Tests throwing.
const callbacks = new MojoResultTestCallbackRouter();
const client = callbacks.$.bindNewPipeAndPassRemote();
callbacks.testResult.addListener(() => {
throw new Error('oh noes');
});
await client.testResult()
.then(() => {
assert(false, 'should have failed');
})
.catch((error: Error) => {
assert(error.message === 'oh noes', JSON.stringify(error));
});
}
{
// Tests unknown object to JsError mapping.
class Potato {}
const callbacks = new MojoResultTestCallbackRouter();
const client = callbacks.$.bindNewPipeAndPassRemote();
callbacks.testResult.addListener(() => {
throw new Potato();
});
await client.testResult()
.then(() => {
assert(false, 'should have failed');
})
.catch((error: Error) => {
assert(
error.message === 'unknown error has occured',
JSON.stringify(error));
});
}
return true;
}
async function runTest(): Promise<boolean> {
return doTest();
}
Object.assign(window, {runTest});