Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

/* Any copyright is dedicated to the Public Domain.
const Rondpoint = ChromeUtils.importESModule(
);
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)
);
});