Source code

Revision control

Copy as Markdown

Other Tools

import rondpoint
let dico = Dictionnaire(un: .deux, deux: false, petitNombre: 0, grosNombre: 123456789)
let copyDico = copieDictionnaire(d: dico)
assert(dico == copyDico)
assert(copieEnumeration(e: .deux) == .deux)
assert(copieEnumerations(e: [.un, .deux]) == [.un, .deux])
assert(copieCarte(c:
["0": .zero,
"1": .un(premier: 1),
"2": .deux(premier: 2, second: "deux")
]) == [
"0": .zero,
"1": .un(premier: 1),
"2": .deux(premier: 2, second: "deux")
])
assert(EnumerationAvecDonnees.zero != EnumerationAvecDonnees.un(premier: 1))
assert(EnumerationAvecDonnees.un(premier: 1) == EnumerationAvecDonnees.un(premier: 1))
assert(EnumerationAvecDonnees.un(premier: 1) != EnumerationAvecDonnees.un(premier: 2))
assert(switcheroo(b: 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 swift and lifting into rust is symmetrical with
// lowering from rust and lifting into swift.
let rt = Retourneur()
// Booleans
[true, false].affirmAllerRetour(rt.identiqueBoolean)
// Bytes.
[.min, .max].affirmAllerRetour(rt.identiqueI8)
[0x00, 0xFF].map { $0 as UInt8 }.affirmAllerRetour(rt.identiqueU8)
// Shorts
[.min, .max].affirmAllerRetour(rt.identiqueI16)
[0x0000, 0xFFFF].map { $0 as UInt16 }.affirmAllerRetour(rt.identiqueU16)
// Ints
[0, 1, -1, .min, .max].affirmAllerRetour(rt.identiqueI32)
[0x00000000, 0xFFFFFFFF].map { $0 as UInt32 }.affirmAllerRetour(rt.identiqueU32)
// Longs
[.zero, 1, -1, .min, .max].affirmAllerRetour(rt.identiqueI64)
[.zero, 1, .min, .max].affirmAllerRetour(rt.identiqueU64)
// Floats
[.zero, 1, 0.25, .leastNonzeroMagnitude, .greatestFiniteMagnitude].affirmAllerRetour(rt.identiqueFloat)
// Doubles
[0.0, 1.0, .leastNonzeroMagnitude, .greatestFiniteMagnitude].affirmAllerRetour(rt.identiqueDouble)
// Strings
["", "abc", "null\0byte", "été", "ښي لاس ته لوستلو لوستل", "😻emoji 👨‍👧‍👦multi-emoji, 🇨🇭a flag, a canal, panama"]
.affirmAllerRetour(rt.identiqueString)
// 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 swift.
//
// This shows that the values are transformed into strings the same way in both swift and rust.
// i.e. if we assume that the string return works (we test this assumption elsewhere)
// we show that lowering from swift and lifting into rust has values that both swift 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 t 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.
let st = Stringifier()
// Test the effigacy of the string transport from rust. If this fails, but everything else
// works, then things are very weird.
let wellKnown = st.wellKnownString(value: "swift")
assert("uniffi 💚 swift!" == wellKnown, "wellKnownString 'uniffi 💚 swift!' == '\(wellKnown)'")
// Booleans
[true, false].affirmEnchaine(st.toStringBoolean)
// Bytes.
[.min, .max].affirmEnchaine(st.toStringI8)
[.min, .max].affirmEnchaine(st.toStringU8)
// Shorts
[.min, .max].affirmEnchaine(st.toStringI16)
[.min, .max].affirmEnchaine(st.toStringU16)
// Ints
[0, 1, -1, .min, .max].affirmEnchaine(st.toStringI32)
[0, 1, .min, .max].affirmEnchaine(st.toStringU32)
// Longs
[.zero, 1, -1, .min, .max].affirmEnchaine(st.toStringI64)
[.zero, 1, .min, .max].affirmEnchaine(st.toStringU64)
// Floats
[.zero, 1, -1, .leastNonzeroMagnitude, .greatestFiniteMagnitude].affirmEnchaine(st.toStringFloat) { Float.init($0) == $1 }
// Doubles
[.zero, 1, -1, .leastNonzeroMagnitude, .greatestFiniteMagnitude].affirmEnchaine(st.toStringDouble) { Double.init($0) == $1 }
// Some extension functions for testing the results of roundtripping and stringifying
extension Array where Element: Equatable {
static func defaultEquals(_ observed: String, expected: Element) -> Bool {
let exp = "\(expected)"
return observed == exp
}
func affirmEnchaine(_ fn: (Element) -> String, equals: (String, Element) -> Bool = defaultEquals) {
self.forEach { v in
let obs = fn(v)
assert(equals(obs, v), "toString_\(type(of:v))(\(v)): observed=\(obs), expected=\(v)")
}
}
func affirmAllerRetour(_ fn: (Element) -> Element) {
self.forEach { v in
assert(fn(v) == v, "identique_\(type(of:v))(\(v))")
}
}
}
// Prove to ourselves that default arguments are being used.
// Step 1: call the methods without arguments, and check against the UDL.
let op = Optionneur()
assert(op.sinonString() == "default")
assert(op.sinonBoolean() == false)
assert(op.sinonSequence() == [])
// optionals
assert(op.sinonNull() == nil)
assert(op.sinonZero() == 0)
// decimal integers
assert(op.sinonU8Dec() == UInt8(42))
assert(op.sinonI8Dec() == Int8(-42))
assert(op.sinonU16Dec() == UInt16(42))
assert(op.sinonI16Dec() == Int16(42))
assert(op.sinonU32Dec() == UInt32(42))
assert(op.sinonI32Dec() == Int32(42))
assert(op.sinonU64Dec() == UInt64(42))
assert(op.sinonI64Dec() == Int64(42))
// hexadecimal integers
assert(op.sinonU8Hex() == UInt8(0xff))
assert(op.sinonI8Hex() == Int8(-0x7f))
assert(op.sinonU16Hex() == UInt16(0xffff))
assert(op.sinonI16Hex() == Int16(0x7f))
assert(op.sinonU32Hex() == UInt32(0xffffffff))
assert(op.sinonI32Hex() == Int32(0x7fffffff))
assert(op.sinonU64Hex() == UInt64(0xffffffffffffffff))
assert(op.sinonI64Hex() == Int64(0x7fffffffffffffff))
// octal integers
assert(op.sinonU32Oct() == UInt32(0o755))
// floats
assert(op.sinonF32() == 42.0)
assert(op.sinonF64() == Double(42.1))
// enums
assert(op.sinonEnum() == .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.
["foo", "bar"].affirmAllerRetour(op.sinonString)
[true, false].affirmAllerRetour(op.sinonBoolean)
[["a", "b"], []].affirmAllerRetour(op.sinonSequence)
// optionals
["0", "1"].affirmAllerRetour(op.sinonNull)
[0, 1].affirmAllerRetour(op.sinonZero)
// integers
[0, 1].affirmAllerRetour(op.sinonU8Dec)
[0, 1].affirmAllerRetour(op.sinonI8Dec)
[0, 1].affirmAllerRetour(op.sinonU16Dec)
[0, 1].affirmAllerRetour(op.sinonI16Dec)
[0, 1].affirmAllerRetour(op.sinonU32Dec)
[0, 1].affirmAllerRetour(op.sinonI32Dec)
[0, 1].affirmAllerRetour(op.sinonU64Dec)
[0, 1].affirmAllerRetour(op.sinonI64Dec)
[0, 1].affirmAllerRetour(op.sinonU8Hex)
[0, 1].affirmAllerRetour(op.sinonI8Hex)
[0, 1].affirmAllerRetour(op.sinonU16Hex)
[0, 1].affirmAllerRetour(op.sinonI16Hex)
[0, 1].affirmAllerRetour(op.sinonU32Hex)
[0, 1].affirmAllerRetour(op.sinonI32Hex)
[0, 1].affirmAllerRetour(op.sinonU64Hex)
[0, 1].affirmAllerRetour(op.sinonI64Hex)
[0, 1].affirmAllerRetour(op.sinonU32Oct)
// floats
[0.0, 1.0].affirmAllerRetour(op.sinonF32)
[0.0, 1.0].affirmAllerRetour(op.sinonF64)
// enums
[.un, .deux, .trois].affirmAllerRetour(op.sinonEnum)
// Testing defaulting properties in record types.
let defaultes = OptionneurDictionnaire()
let explicites = OptionneurDictionnaire(
i8Var: Int8(-8),
u8Var: UInt8(8),
i16Var: Int16(-16),
u16Var: UInt16(0x10),
i32Var: -32,
u32Var: UInt32(32),
i64Var: Int64(-64),
u64Var: UInt64(64),
floatVar: Float(4.0),
doubleVar: Double(8.0),
booleanVar: true,
stringVar: "default",
listVar: [],
enumerationVar: .deux,
dictionnaireVar: nil
)
// …and makes sure they travel across and back the FFI.
assert(defaultes == explicites)
[defaultes].affirmAllerRetour(rt.identiqueOptionneurDictionnaire)