332 lines
10 KiB
JavaScript
332 lines
10 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||
|
||
const Rondpoint = ChromeUtils.importESModule(
|
||
"resource://gre/modules/RustRondpoint.sys.mjs"
|
||
);
|
||
|
||
const {
|
||
Dictionnaire,
|
||
Enumeration,
|
||
copieDictionnaire,
|
||
copieEnumeration,
|
||
copieEnumerations,
|
||
copieCarte,
|
||
EnumerationAvecDonnees,
|
||
switcheroo,
|
||
Retourneur,
|
||
DictionnaireNombresSignes,
|
||
DictionnaireNombres,
|
||
Stringifier,
|
||
Optionneur,
|
||
OptionneurDictionnaire,
|
||
} = Rondpoint;
|
||
add_task(async function () {
|
||
const dico = new Dictionnaire({
|
||
un: Enumeration.DEUX,
|
||
deux: true,
|
||
petitNombre: 0,
|
||
grosNombre: 1235,
|
||
});
|
||
const copyDico = await copieDictionnaire(dico);
|
||
Assert.deepEqual(dico, copyDico);
|
||
|
||
Assert.equal(await copieEnumeration(Enumeration.DEUX), Enumeration.DEUX);
|
||
Assert.deepEqual(
|
||
await copieEnumerations([Enumeration.UN, Enumeration.DEUX]),
|
||
[Enumeration.UN, Enumeration.DEUX]
|
||
);
|
||
const obj = {
|
||
0: new EnumerationAvecDonnees.Zero(),
|
||
1: new EnumerationAvecDonnees.Un(1),
|
||
2: new EnumerationAvecDonnees.Deux(2, "deux"),
|
||
};
|
||
|
||
Assert.deepEqual(await copieCarte(obj), obj);
|
||
|
||
const zero = new EnumerationAvecDonnees.Zero();
|
||
const one = new EnumerationAvecDonnees.Un(1);
|
||
const two = new EnumerationAvecDonnees.Deux(2);
|
||
Assert.notEqual(zero, one);
|
||
Assert.notEqual(one, two);
|
||
|
||
Assert.deepEqual(zero, new EnumerationAvecDonnees.Zero());
|
||
Assert.deepEqual(one, new EnumerationAvecDonnees.Un(1));
|
||
Assert.notDeepEqual(one, new EnumerationAvecDonnees.Un(4));
|
||
|
||
Assert.ok(await switcheroo(false));
|
||
// Test the roundtrip across the FFI.
|
||
// This shows that the values we send come back in exactly the same state as we sent them.
|
||
// i.e. it shows that lowering from JS and lifting into rust is symmetrical with
|
||
// lowering from rust and lifting into JS.
|
||
|
||
const rt = await Retourneur.init();
|
||
|
||
const affirmAllerRetour = async (arr, fn, equalFn) => {
|
||
for (const member of arr) {
|
||
if (equalFn) {
|
||
equalFn(await fn(member), member);
|
||
} else {
|
||
Assert.equal(await fn(member), member);
|
||
}
|
||
}
|
||
};
|
||
|
||
// Booleans
|
||
await affirmAllerRetour([true, false], rt.identiqueBoolean.bind(rt));
|
||
|
||
// Bytes
|
||
await affirmAllerRetour([-128, 127], rt.identiqueI8.bind(rt));
|
||
await affirmAllerRetour([0, 0xff], rt.identiqueU8.bind(rt));
|
||
|
||
// Shorts
|
||
await affirmAllerRetour([-32768, 32767], rt.identiqueI16.bind(rt));
|
||
await affirmAllerRetour([0, 0xffff], rt.identiqueU16.bind(rt));
|
||
|
||
// Ints
|
||
await affirmAllerRetour(
|
||
[0, 1, -1, -2147483648, 2147483647],
|
||
rt.identiqueI32.bind(rt)
|
||
);
|
||
await affirmAllerRetour([0, 0xffffffff], rt.identiqueU32.bind(rt));
|
||
|
||
// Longs
|
||
// NOTE: we cannot represent greater than `Number.MAX_SAFE_INTEGER`
|
||
await affirmAllerRetour(
|
||
[0, 1, -1, Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER],
|
||
rt.identiqueI64.bind(rt)
|
||
);
|
||
await affirmAllerRetour(
|
||
[0, Number.MAX_SAFE_INTEGER],
|
||
rt.identiqueU64.bind(rt)
|
||
);
|
||
|
||
// Floats
|
||
const equalFloats = (a, b) => Assert.ok(Math.abs(a - b) <= Number.EPSILON);
|
||
await affirmAllerRetour(
|
||
[0.0, 0.5, 0.25, 1.5],
|
||
rt.identiqueFloat.bind(rt),
|
||
equalFloats
|
||
);
|
||
// Some float value's precision gets messed up, an example is 3.22, 100.223, etc
|
||
// await affirmAllerRetour([0.0, 0.5, 0.25, 1.5, 100.223], rt.identiqueFloat.bind(rt), equalFloats);
|
||
|
||
// Double (although on the JS side doubles are limited since they are also represented by Number)
|
||
await affirmAllerRetour(
|
||
[0.0, 0.5, 0.25, 1.5],
|
||
rt.identiqueDouble.bind(rt),
|
||
equalFloats
|
||
);
|
||
|
||
// Strings
|
||
await affirmAllerRetour(
|
||
[
|
||
"",
|
||
"abc",
|
||
"null\u0000byte",
|
||
"été",
|
||
"ښي لاس ته لوستلو لوستل",
|
||
"😻emoji 👨👧👦multi-emoji, 🇨🇭a flag, a canal, panama",
|
||
],
|
||
rt.identiqueString.bind(rt)
|
||
);
|
||
|
||
await affirmAllerRetour(
|
||
[-1, 0, 1].map(
|
||
n =>
|
||
new DictionnaireNombresSignes({
|
||
petitNombre: n,
|
||
courtNombre: n,
|
||
nombreSimple: n,
|
||
grosNombre: n,
|
||
})
|
||
),
|
||
rt.identiqueNombresSignes.bind(rt),
|
||
(a, b) => Assert.deepEqual(a, b)
|
||
);
|
||
|
||
await affirmAllerRetour(
|
||
[0, 1].map(
|
||
n =>
|
||
new DictionnaireNombres({
|
||
petitNombre: n,
|
||
courtNombre: n,
|
||
nombreSimple: n,
|
||
grosNombre: n,
|
||
})
|
||
),
|
||
rt.identiqueNombres.bind(rt),
|
||
(a, b) => Assert.deepEqual(a, b)
|
||
);
|
||
|
||
// Test one way across the FFI.
|
||
//
|
||
// We send one representation of a value to lib.rs, and it transforms it into another, a string.
|
||
// lib.rs sends the string back, and then we compare here in js.
|
||
//
|
||
// This shows that the values are transformed into strings the same way in both js and rust.
|
||
// i.e. if we assume that the string return works (we test this assumption elsewhere)
|
||
// we show that lowering from js and lifting into rust has values that both js and rust
|
||
// both stringify in the same way. i.e. the same values.
|
||
//
|
||
// If we roundtripping proves the symmetry of our lowering/lifting from here to rust, and lowering/lifting from rust to here,
|
||
// and this convinces us that lowering/lifting from here to rust is correct, then
|
||
// together, we've shown the correctness of the return leg.
|
||
const st = await Stringifier.init();
|
||
|
||
const affirmEnchaine = async (arr, fn) => {
|
||
for (const member of arr) {
|
||
Assert.equal(await fn(member), String(member));
|
||
}
|
||
};
|
||
|
||
// Booleans
|
||
await affirmEnchaine([true, false], st.toStringBoolean.bind(st));
|
||
|
||
// Bytes
|
||
await affirmEnchaine([-128, 127], st.toStringI8.bind(st));
|
||
await affirmEnchaine([0, 0xff], st.toStringU8.bind(st));
|
||
|
||
// Shorts
|
||
await affirmEnchaine([-32768, 32767], st.toStringI16.bind(st));
|
||
await affirmEnchaine([0, 0xffff], st.toStringU16.bind(st));
|
||
|
||
// Ints
|
||
await affirmEnchaine(
|
||
[0, 1, -1, -2147483648, 2147483647],
|
||
st.toStringI32.bind(st)
|
||
);
|
||
await affirmEnchaine([0, 0xffffffff], st.toStringU32.bind(st));
|
||
|
||
// Longs
|
||
// NOTE: we cannot represent greater than `Number.MAX_SAFE_INTEGER`
|
||
await affirmEnchaine(
|
||
[0, 1, -1, Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER],
|
||
st.toStringI64.bind(st)
|
||
);
|
||
await affirmEnchaine([0, Number.MAX_SAFE_INTEGER], st.toStringU64.bind(st));
|
||
|
||
// Floats
|
||
await affirmEnchaine([0.0, 0.5, 0.25, 1.5], st.toStringFloat.bind(st));
|
||
|
||
// Doubles
|
||
await affirmEnchaine([0.0, 0.5, 0.25, 1.5], st.toStringDouble.bind(st));
|
||
|
||
// Prove to ourselves that default arguments are being used.
|
||
// Step 1: call the methods without arguments, and check against the UDL.
|
||
const op = await Optionneur.init();
|
||
|
||
Assert.equal(await op.sinonString(), "default");
|
||
|
||
Assert.ok(!(await op.sinonBoolean()));
|
||
|
||
Assert.deepEqual(await op.sinonSequence(), []);
|
||
|
||
Assert.equal(await op.sinonNull(), null);
|
||
Assert.equal(await op.sinonZero(), 0);
|
||
|
||
// decimal integers
|
||
Assert.equal(await op.sinonI8Dec(), -42);
|
||
Assert.equal(await op.sinonU8Dec(), 42);
|
||
Assert.equal(await op.sinonI16Dec(), 42);
|
||
Assert.equal(await op.sinonU16Dec(), 42);
|
||
Assert.equal(await op.sinonI32Dec(), 42);
|
||
Assert.equal(await op.sinonU32Dec(), 42);
|
||
Assert.equal(await op.sinonI64Dec(), 42);
|
||
Assert.equal(await op.sinonU64Dec(), 42);
|
||
|
||
// hexadecimal integers
|
||
Assert.equal(await op.sinonI8Hex(), -0x7f);
|
||
Assert.equal(await op.sinonU8Hex(), 0xff);
|
||
Assert.equal(await op.sinonI16Hex(), 0x7f);
|
||
Assert.equal(await op.sinonU16Hex(), 0xffff);
|
||
Assert.equal(await op.sinonI32Hex(), 0x7fffffff);
|
||
Assert.equal(await op.sinonU32Hex(), 0xffffffff);
|
||
// The following are too big to be represented by js `Number`
|
||
// Assert.equal(await op.sinonI64Hex(), 0x7fffffffffffffff);
|
||
// Assert.equal(await op.sinonU64Hex(), 0xffffffffffffffff);
|
||
|
||
// octal integers
|
||
Assert.equal(await op.sinonU32Oct(), 0o755);
|
||
|
||
// floats
|
||
Assert.equal(await op.sinonF32(), 42.0);
|
||
Assert.equal(await op.sinonF64(), 42.1);
|
||
|
||
// enums
|
||
Assert.equal(await op.sinonEnum(), Enumeration.TROIS);
|
||
|
||
// Step 2. Convince ourselves that if we pass something else, then that changes the output.
|
||
// We have shown something coming out of the sinon methods, but without eyeballing the Rust
|
||
// we can't be sure that the arguments will change the return value.
|
||
|
||
await affirmAllerRetour(["foo", "bar"], op.sinonString.bind(op));
|
||
await affirmAllerRetour([true, false], op.sinonBoolean.bind(op));
|
||
await affirmAllerRetour([["a", "b"], []], op.sinonSequence.bind(op), (a, b) =>
|
||
Assert.deepEqual(a, b)
|
||
);
|
||
|
||
// Optionals
|
||
await affirmAllerRetour(["0", "1"], op.sinonNull.bind(op));
|
||
await affirmAllerRetour([0, 1], op.sinonZero.bind(op));
|
||
|
||
// integers
|
||
await affirmAllerRetour([0, 1], op.sinonU8Dec.bind(op));
|
||
await affirmAllerRetour([0, 1], op.sinonI8Dec.bind(op));
|
||
await affirmAllerRetour([0, 1], op.sinonU16Dec.bind(op));
|
||
await affirmAllerRetour([0, 1], op.sinonI16Dec.bind(op));
|
||
await affirmAllerRetour([0, 1], op.sinonU32Dec.bind(op));
|
||
await affirmAllerRetour([0, 1], op.sinonI32Dec.bind(op));
|
||
await affirmAllerRetour([0, 1], op.sinonU64Dec.bind(op));
|
||
await affirmAllerRetour([0, 1], op.sinonI64Dec.bind(op));
|
||
|
||
await affirmAllerRetour([0, 1], op.sinonU8Hex.bind(op));
|
||
await affirmAllerRetour([0, 1], op.sinonI8Hex.bind(op));
|
||
await affirmAllerRetour([0, 1], op.sinonU16Hex.bind(op));
|
||
await affirmAllerRetour([0, 1], op.sinonI16Hex.bind(op));
|
||
await affirmAllerRetour([0, 1], op.sinonU32Hex.bind(op));
|
||
await affirmAllerRetour([0, 1], op.sinonI32Hex.bind(op));
|
||
await affirmAllerRetour([0, 1], op.sinonU64Hex.bind(op));
|
||
await affirmAllerRetour([0, 1], op.sinonI64Hex.bind(op));
|
||
await affirmAllerRetour([0, 1], op.sinonU32Oct.bind(op));
|
||
|
||
// Floats
|
||
await affirmAllerRetour([0.0, 1.0], op.sinonF32.bind(op));
|
||
await affirmAllerRetour([0.0, 1.0], op.sinonF64.bind(op));
|
||
|
||
// enums
|
||
await affirmAllerRetour(
|
||
[Enumeration.UN, Enumeration.DEUX, Enumeration.TROIS],
|
||
op.sinonEnum.bind(op)
|
||
);
|
||
|
||
// Testing defaulting properties in record types.
|
||
const defaultes = new OptionneurDictionnaire();
|
||
const explicite = new OptionneurDictionnaire(
|
||
-8,
|
||
8,
|
||
-16,
|
||
0x10,
|
||
-32,
|
||
32,
|
||
-64,
|
||
64,
|
||
4.0,
|
||
8.0,
|
||
true,
|
||
"default",
|
||
[],
|
||
Enumeration.DEUX,
|
||
null
|
||
);
|
||
|
||
Assert.deepEqual(defaultes, explicite);
|
||
|
||
// …and makes sure they travel across and back the FFI.
|
||
|
||
await affirmAllerRetour(
|
||
[defaultes, explicite],
|
||
rt.identiqueOptionneurDictionnaire.bind(rt),
|
||
(a, b) => Assert.deepEqual(a, b)
|
||
);
|
||
});
|