summaryrefslogtreecommitdiffstats
path: root/toolkit/components/uniffi-fixtures/rondpoint/tests/bindings/test_rondpoint.kts
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/uniffi-fixtures/rondpoint/tests/bindings/test_rondpoint.kts')
-rw-r--r--toolkit/components/uniffi-fixtures/rondpoint/tests/bindings/test_rondpoint.kts250
1 files changed, 250 insertions, 0 deletions
diff --git a/toolkit/components/uniffi-fixtures/rondpoint/tests/bindings/test_rondpoint.kts b/toolkit/components/uniffi-fixtures/rondpoint/tests/bindings/test_rondpoint.kts
new file mode 100644
index 0000000000..cc5ddf2a86
--- /dev/null
+++ b/toolkit/components/uniffi-fixtures/rondpoint/tests/bindings/test_rondpoint.kts
@@ -0,0 +1,250 @@
+import uniffi.rondpoint.*
+
+val dico = Dictionnaire(Enumeration.DEUX, true, 0u, 123456789u)
+val copyDico = copieDictionnaire(dico)
+assert(dico == copyDico)
+
+assert(copieEnumeration(Enumeration.DEUX) == Enumeration.DEUX)
+assert(copieEnumerations(listOf(Enumeration.UN, Enumeration.DEUX)) == listOf(Enumeration.UN, Enumeration.DEUX))
+assert(copieCarte(mapOf(
+ "0" to EnumerationAvecDonnees.Zero,
+ "1" to EnumerationAvecDonnees.Un(1u),
+ "2" to EnumerationAvecDonnees.Deux(2u, "deux")
+)) == mapOf(
+ "0" to EnumerationAvecDonnees.Zero,
+ "1" to EnumerationAvecDonnees.Un(1u),
+ "2" to EnumerationAvecDonnees.Deux(2u, "deux")
+))
+
+val var1: EnumerationAvecDonnees = EnumerationAvecDonnees.Zero
+val var2: EnumerationAvecDonnees = EnumerationAvecDonnees.Un(1u)
+val var3: EnumerationAvecDonnees = EnumerationAvecDonnees.Un(2u)
+assert(var1 != var2)
+assert(var2 != var3)
+assert(var1 == EnumerationAvecDonnees.Zero)
+assert(var1 != EnumerationAvecDonnees.Un(1u))
+assert(var2 == EnumerationAvecDonnees.Un(1u))
+
+assert(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 kotlin and lifting into rust is symmetrical with
+// lowering from rust and lifting into kotlin.
+val rt = Retourneur()
+
+fun <T> List<T>.affirmAllerRetour(fn: (T) -> T) {
+ this.forEach { v ->
+ assert(fn.invoke(v) == v) { "$fn($v)" }
+ }
+}
+
+// Booleans
+listOf(true, false).affirmAllerRetour(rt::identiqueBoolean)
+
+// Bytes.
+listOf(Byte.MIN_VALUE, Byte.MAX_VALUE).affirmAllerRetour(rt::identiqueI8)
+listOf(0x00, 0xFF).map { it.toUByte() }.affirmAllerRetour(rt::identiqueU8)
+
+// Shorts
+listOf(Short.MIN_VALUE, Short.MAX_VALUE).affirmAllerRetour(rt::identiqueI16)
+listOf(0x0000, 0xFFFF).map { it.toUShort() }.affirmAllerRetour(rt::identiqueU16)
+
+// Ints
+listOf(0, 1, -1, Int.MIN_VALUE, Int.MAX_VALUE).affirmAllerRetour(rt::identiqueI32)
+listOf(0x00000000, 0xFFFFFFFF).map { it.toUInt() }.affirmAllerRetour(rt::identiqueU32)
+
+// Longs
+listOf(0L, 1L, -1L, Long.MIN_VALUE, Long.MAX_VALUE).affirmAllerRetour(rt::identiqueI64)
+listOf(0u, 1u, ULong.MIN_VALUE, ULong.MAX_VALUE).affirmAllerRetour(rt::identiqueU64)
+
+// Floats
+listOf(0.0F, 0.5F, 0.25F, Float.MIN_VALUE, Float.MAX_VALUE).affirmAllerRetour(rt::identiqueFloat)
+
+// Doubles
+listOf(0.0, 1.0, Double.MIN_VALUE, Double.MAX_VALUE).affirmAllerRetour(rt::identiqueDouble)
+
+// Strings
+listOf("", "abc", "null\u0000byte", "été", "ښي لاس ته لوستلو لوستل", "😻emoji 👨‍👧‍👦multi-emoji, 🇨🇭a flag, a canal, panama")
+ .affirmAllerRetour(rt::identiqueString)
+
+listOf(-1, 0, 1).map { DictionnaireNombresSignes(it.toByte(), it.toShort(), it.toInt(), it.toLong()) }
+ .affirmAllerRetour(rt::identiqueNombresSignes)
+
+listOf(0, 1).map { DictionnaireNombres(it.toUByte(), it.toUShort(), it.toUInt(), it.toULong()) }
+ .affirmAllerRetour(rt::identiqueNombres)
+
+
+rt.destroy()
+
+// 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 kotlin.
+//
+// This shows that the values are transformed into strings the same way in both kotlin and rust.
+// i.e. if we assume that the string return works (we test this assumption elsewhere)
+// we show that lowering from kotlin and lifting into rust has values that both kotlin 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.
+val st = Stringifier()
+
+typealias StringyEquals<T> = (observed: String, expected: T) -> Boolean
+fun <T> List<T>.affirmEnchaine(
+ fn: (T) -> String,
+ equals: StringyEquals<T> = { obs, exp -> obs == exp.toString() }
+) {
+ this.forEach { exp ->
+ val obs = fn.invoke(exp)
+ assert(equals(obs, exp)) { "$fn($exp): observed=$obs, expected=$exp" }
+ }
+}
+
+// Test the efficacy of the string transport from rust. If this fails, but everything else
+// works, then things are very weird.
+val wellKnown = st.wellKnownString("kotlin")
+assert("uniffi 💚 kotlin!" == wellKnown) { "wellKnownString 'uniffi 💚 kotlin!' == '$wellKnown'" }
+
+// Booleans
+listOf(true, false).affirmEnchaine(st::toStringBoolean)
+
+// Bytes.
+listOf(Byte.MIN_VALUE, Byte.MAX_VALUE).affirmEnchaine(st::toStringI8)
+listOf(UByte.MIN_VALUE, UByte.MAX_VALUE).affirmEnchaine(st::toStringU8)
+
+// Shorts
+listOf(Short.MIN_VALUE, Short.MAX_VALUE).affirmEnchaine(st::toStringI16)
+listOf(UShort.MIN_VALUE, UShort.MAX_VALUE).affirmEnchaine(st::toStringU16)
+
+// Ints
+listOf(0, 1, -1, Int.MIN_VALUE, Int.MAX_VALUE).affirmEnchaine(st::toStringI32)
+listOf(0u, 1u, UInt.MIN_VALUE, UInt.MAX_VALUE).affirmEnchaine(st::toStringU32)
+
+// Longs
+listOf(0L, 1L, -1L, Long.MIN_VALUE, Long.MAX_VALUE).affirmEnchaine(st::toStringI64)
+listOf(0u, 1u, ULong.MIN_VALUE, ULong.MAX_VALUE).affirmEnchaine(st::toStringU64)
+
+// Floats
+// MIN_VALUE is 1.4E-45. Accuracy and formatting get weird at small sizes.
+listOf(0.0F, 1.0F, -1.0F, Float.MIN_VALUE, Float.MAX_VALUE).affirmEnchaine(st::toStringFloat) { s, n -> s.toFloat() == n }
+
+// Doubles
+// MIN_VALUE is 4.9E-324. Accuracy and formatting get weird at small sizes.
+listOf(0.0, 1.0, -1.0, Double.MIN_VALUE, Double.MAX_VALUE).affirmEnchaine(st::toStringDouble) { s, n -> s.toDouble() == n }
+
+st.destroy()
+
+// Prove to ourselves that default arguments are being used.
+// Step 1: call the methods without arguments, and check against the UDL.
+val op = Optionneur()
+
+assert(op.sinonString() == "default")
+
+assert(op.sinonBoolean() == false)
+
+assert(op.sinonSequence() == listOf<String>())
+
+// optionals
+assert(op.sinonNull() == null)
+assert(op.sinonZero() == 0)
+
+// decimal integers
+assert(op.sinonI8Dec() == (-42).toByte())
+assert(op.sinonU8Dec() == 42.toUByte())
+assert(op.sinonI16Dec() == 42.toShort())
+assert(op.sinonU16Dec() == 42.toUShort())
+assert(op.sinonI32Dec() == 42)
+assert(op.sinonU32Dec() == 42.toUInt())
+assert(op.sinonI64Dec() == 42L)
+assert(op.sinonU64Dec() == 42uL)
+
+// hexadecimal integers
+assert(op.sinonI8Hex() == (-0x7f).toByte())
+assert(op.sinonU8Hex() == 0xff.toUByte())
+assert(op.sinonI16Hex() == 0x7f.toShort())
+assert(op.sinonU16Hex() == 0xffff.toUShort())
+assert(op.sinonI32Hex() == 0x7fffffff)
+assert(op.sinonU32Hex() == 0xffffffff.toUInt())
+assert(op.sinonI64Hex() == 0x7fffffffffffffffL)
+assert(op.sinonU64Hex() == 0xffffffffffffffffuL)
+
+// octal integers
+assert(op.sinonU32Oct() == 493u) // 0o755
+
+// floats
+assert(op.sinonF32() == 42.0f)
+assert(op.sinonF64() == 42.1)
+
+// enums
+assert(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.
+listOf("foo", "bar").affirmAllerRetour(op::sinonString)
+listOf(true, false).affirmAllerRetour(op::sinonBoolean)
+listOf(listOf("a", "b"), listOf()).affirmAllerRetour(op::sinonSequence)
+
+// optionals
+listOf("0", "1").affirmAllerRetour(op::sinonNull)
+listOf(0, 1).affirmAllerRetour(op::sinonZero)
+
+// integers
+listOf(0, 1).map { it.toUByte() }.affirmAllerRetour(op::sinonU8Dec)
+listOf(0, 1).map { it.toByte() }.affirmAllerRetour(op::sinonI8Dec)
+listOf(0, 1).map { it.toUShort() }.affirmAllerRetour(op::sinonU16Dec)
+listOf(0, 1).map { it.toShort() }.affirmAllerRetour(op::sinonI16Dec)
+listOf(0, 1).map { it.toUInt() }.affirmAllerRetour(op::sinonU32Dec)
+listOf(0, 1).map { it.toInt() }.affirmAllerRetour(op::sinonI32Dec)
+listOf(0, 1).map { it.toULong() }.affirmAllerRetour(op::sinonU64Dec)
+listOf(0, 1).map { it.toLong() }.affirmAllerRetour(op::sinonI64Dec)
+
+listOf(0, 1).map { it.toUByte() }.affirmAllerRetour(op::sinonU8Hex)
+listOf(0, 1).map { it.toByte() }.affirmAllerRetour(op::sinonI8Hex)
+listOf(0, 1).map { it.toUShort() }.affirmAllerRetour(op::sinonU16Hex)
+listOf(0, 1).map { it.toShort() }.affirmAllerRetour(op::sinonI16Hex)
+listOf(0, 1).map { it.toUInt() }.affirmAllerRetour(op::sinonU32Hex)
+listOf(0, 1).map { it.toInt() }.affirmAllerRetour(op::sinonI32Hex)
+listOf(0, 1).map { it.toULong() }.affirmAllerRetour(op::sinonU64Hex)
+listOf(0, 1).map { it.toLong() }.affirmAllerRetour(op::sinonI64Hex)
+
+listOf(0, 1).map { it.toUInt() }.affirmAllerRetour(op::sinonU32Oct)
+
+// floats
+listOf(0.0f, 1.0f).affirmAllerRetour(op::sinonF32)
+listOf(0.0, 1.0).affirmAllerRetour(op::sinonF64)
+
+// enums
+Enumeration.values().toList().affirmAllerRetour(op::sinonEnum)
+
+op.destroy()
+
+// Testing defaulting properties in record types.
+val defaultes = OptionneurDictionnaire()
+val explicites = OptionneurDictionnaire(
+ i8Var = -8,
+ u8Var = 8u,
+ i16Var = -16,
+ u16Var = 0x10u,
+ i32Var = -32,
+ u32Var = 32u,
+ i64Var = -64L,
+ u64Var = 64uL,
+ floatVar = 4.0f,
+ doubleVar = 8.0,
+ booleanVar = true,
+ stringVar = "default",
+ listVar = listOf(),
+ enumerationVar = Enumeration.DEUX,
+ dictionnaireVar = null
+)
+assert(defaultes == explicites)
+
+// …and makes sure they travel across and back the FFI.
+val rt2 = Retourneur()
+listOf(defaultes).affirmAllerRetour(rt2::identiqueOptionneurDictionnaire)
+
+rt2.destroy()