WebAssembly JS API: check and test in-call / out-call values
[WebKit-https.git] / JSTests / wasm / assert.js
1 /*
2  * Copyright (C) 2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 const _fail = (msg, extra) => {
27     throw new Error(msg + (extra ? ": " + extra : ""));
28 };
29
30 export const isNotA = (v, t, msg) => {
31     if (typeof v === t)
32         _fail(`Shouldn't be ${t}`, msg);
33 };
34
35 export const isA = (v, t, msg) => {
36     if (typeof v !== t)
37         _fail(`Should be ${t}, got ${typeof(v)}`, msg);
38 };
39
40 export const isNotUndef = (v, msg) => isNotA(v, "undefined", msg);
41 export const isUndef = (v, msg) => isA(v, "undefined", msg);
42 export const notObject = (v, msg) => isNotA(v, "object", msg);
43 export const isObject = (v, msg) => isA(v, "object", msg);
44 export const notString = (v, msg) => isNotA(v, "string", msg);
45 export const isString = (v, msg) => isA(v, "string", msg);
46 export const notNumber = (v, msg) => isNotA(v, "number", msg);
47 export const isNumber = (v, msg) => isA(v, "number", msg);
48
49 export const hasObjectProperty = (o, p, msg) => {
50     isObject(o, msg);
51     isNotUndef(o[p], msg, `expected object to have property ${p}`);
52 };
53
54 export const isArray = (v, msg) => {
55     if (!Array.isArray(v))
56         _fail(`Expected an array, got ${typeof(v)}`, msg);
57 };
58
59 export const isNotArray = (v, msg) => {
60     if (Array.isArray(v))
61         _fail(`Expected to not be an array`, msg);
62 };
63
64 export const truthy = (v, msg) => {
65     if (!v)
66         _fail(`Expected truthy`, msg);
67 };
68
69 export const falsy = (v, msg) => {
70     if (v)
71         _fail(`Expected falsy`, msg);
72 };
73
74 export const eq = (lhs, rhs, msg) => {
75     if (typeof lhs !== typeof rhs)
76         _fail(`Not the same: "${lhs}" and "${rhs}"`, msg);
77     if (Array.isArray(lhs) && Array.isArray(rhs) && (lhs.length === rhs.length)) {
78         for (let i = 0; i !== lhs.length; ++i)
79             eq(lhs[i], rhs[i], msg);
80     } else if (lhs !== rhs) {
81         if (typeof lhs === "number" && isNaN(lhs) && isNaN(rhs))
82             return;
83         _fail(`Not the same: "${lhs}" and "${rhs}"`, msg);
84     } else {
85         if (typeof lhs === "number" && (1.0 / lhs !== 1.0 / rhs)) // Distinguish -0.0 from 0.0.
86             _fail(`Not the same: "${lhs}" and "${rhs}"`, msg);
87     }
88 };
89
90 const canonicalizeI32 = (number) => {
91     if (Math.round(number) === number && number >= 2 ** 31)
92         number = number - 2 ** 32;
93     return number;
94 }
95
96 export const eqI32 = (lhs, rhs, msg) => {
97     return eq(canonicalizeI32(lhs), canonicalizeI32(rhs), msg);
98 };
99
100 export const ge = (lhs, rhs, msg) => {
101     isNotUndef(lhs);
102     isNotUndef(rhs);
103     if (!(lhs >= rhs))
104         _fail(`Expected: "${lhs}" < "${rhs}"`, msg);
105 };
106
107 export const le = (lhs, rhs, msg) => {
108     isNotUndef(lhs);
109     isNotUndef(rhs);
110     if (!(lhs <= rhs))
111         _fail(`Expected: "${lhs}" > "${rhs}"`, msg);
112 };
113
114 // Ignore source information at the end of the error message if the expected message didn't specify that information. Sometimes it changes, or it's tricky to get just right.
115 const _sourceRe = new RegExp(/ \(evaluating '.*'\)/);
116
117 const _throws = (func, type, message, ...args) => {
118     try {
119         func(...args);
120     } catch (e) {
121         if (e instanceof type) {
122             if (e.message === message)
123                 return e;
124             const cleanMessage = e.message.replace(_sourceRe, '');
125             if (cleanMessage === message)
126                 return e;
127         }
128         _fail(`Expected to throw a ${type.name} with message "${message}", got ${e.name} with message "${e.message}"`);
129     }
130     _fail(`Expected to throw a ${type.name} with message "${message}"`);
131 };
132
133 const _instanceof = (obj, type, msg) => {
134     if (!(obj instanceof type))
135         _fail(`Expected a ${typeof(type)}, got ${typeof obj}`);
136 };
137
138 // Use underscore names to avoid clashing with builtin names.
139 export {
140     _throws as throws,
141     _instanceof as instanceof,
142 };