1 @file:OptIn(ExperimentalCoroutinesApi::class) 2 3 package expo.modules.kotlin.jni 4 5 import com.google.common.truth.Truth 6 import expo.modules.kotlin.typedarray.Float32Array 7 import expo.modules.kotlin.typedarray.Float64Array 8 import expo.modules.kotlin.typedarray.Int16Array 9 import expo.modules.kotlin.typedarray.Int32Array 10 import expo.modules.kotlin.typedarray.Int8Array 11 import expo.modules.kotlin.typedarray.Uint16Array 12 import expo.modules.kotlin.typedarray.Uint32Array 13 import expo.modules.kotlin.typedarray.Uint8Array 14 import kotlinx.coroutines.ExperimentalCoroutinesApi 15 import org.junit.Test 16 import java.nio.ByteBuffer 17 import java.nio.ByteOrder 18 19 internal class JavaScriptTypedArrayTest { 20 21 @Test <lambda>null22 fun kind_should_return_correct_type() = withJSIInterop { 23 val uint16Result = evaluateScript("new Uint16Array(4)") 24 val float32Result = evaluateScript("new Float32Array([1.2, 3.4])") 25 26 Truth.assertThat(uint16Result.isTypedArray()).isTrue() 27 Truth.assertThat(float32Result.isTypedArray()).isTrue() 28 29 val uintTypedArray = uint16Result.getTypedArray() 30 Truth.assertThat(uintTypedArray.kind).isEqualTo(TypedArrayKind.Uint16Array) 31 32 val float32TypedArray = float32Result.getTypedArray() 33 Truth.assertThat(float32TypedArray.kind).isEqualTo(TypedArrayKind.Float32Array) 34 } 35 36 @Test <lambda>null37 fun should_be_able_access_elements_via_object_api() = withJSIInterop { 38 val typedArray = evaluateScript("new Float32Array([1.2, 3.4])").getTypedArray() 39 40 val first = typedArray.getProperty("0").getDouble() 41 val second = typedArray.getProperty("1").getDouble() 42 43 Truth.assertThat(first).isWithin(1.0e-6).of(1.2) 44 Truth.assertThat(second).isWithin(1.0e-6).of(3.4) 45 } 46 47 @Test <lambda>null48 fun should_be_convertible_to_direct_buffer_float32() = withJSIInterop { 49 val typedArray = evaluateScript("new Float32Array([1.2, 3.4])").getTypedArray() 50 51 val buffer = typedArray.toDirectBuffer() 52 53 Truth.assertThat(buffer.isDirect).isTrue() 54 Truth.assertThat(buffer.isReadOnly).isFalse() 55 56 val first = buffer.getFloat(0) 57 val second = buffer.getFloat(4) 58 59 Truth.assertThat(first).isEqualTo(1.2f) 60 Truth.assertThat(second).isEqualTo(3.4f) 61 } 62 63 @Test <lambda>null64 fun should_be_convertible_to_direct_buffer_int32() = withJSIInterop { 65 val typedArray = evaluateScript("new Int32Array([21, 31])").getTypedArray() 66 67 val buffer = typedArray.toDirectBuffer() 68 69 Truth.assertThat(buffer.isDirect).isTrue() 70 Truth.assertThat(buffer.isReadOnly).isFalse() 71 72 val first = buffer.getInt(0) 73 val second = buffer.getInt(4) 74 75 Truth.assertThat(first).isEqualTo(21) 76 Truth.assertThat(second).isEqualTo(31) 77 } 78 79 @Test <lambda>null80 fun should_be_convertible_to_direct_buffer_int8() = withJSIInterop { 81 val typedArray = evaluateScript("new Int8Array([21, 31])").getTypedArray() 82 83 val buffer = typedArray.toDirectBuffer() 84 85 Truth.assertThat(buffer.isDirect).isTrue() 86 Truth.assertThat(buffer.isReadOnly).isFalse() 87 88 val first = buffer.get(0) 89 val second = buffer.get(1) 90 91 Truth.assertThat(first).isEqualTo(21) 92 Truth.assertThat(second).isEqualTo(31) 93 } 94 95 @Test <lambda>null96 fun raw_read() = withJSIInterop { 97 val typedArray = evaluateScript("new Int32Array([21, 31])").getTypedArray() 98 99 val firstBytes = ByteArray(4) 100 val secondBytes = ByteArray(4) 101 typedArray.read(firstBytes, 0, 4) 102 typedArray.read(secondBytes, 4, 4) 103 104 val first = wrapBytes(firstBytes).int 105 val second = wrapBytes(secondBytes).int 106 107 Truth.assertThat(first).isEqualTo(21) 108 Truth.assertThat(second).isEqualTo(31) 109 } 110 111 @Test <lambda>null112 fun raw_write() = withJSIInterop { 113 val typedArray = evaluateScript("new Int32Array([21, 31])").getTypedArray() 114 115 val bytes = ByteArray(4) 116 wrapBytes(bytes).putInt(21345) 117 118 typedArray.write(bytes, 4, 4) 119 120 val first = typedArray.getProperty("0").getDouble().toInt() 121 val second = typedArray.getProperty("1").getDouble().toInt() 122 123 Truth.assertThat(first).isEqualTo(21) 124 Truth.assertThat(second).isEqualTo(21345) 125 } 126 127 @Test <lambda>null128 fun int8_read() = withJSIInterop { 129 val rawTypedArray = evaluateScript("new Int8Array([-128, 127])").getTypedArray() 130 val typedArray = Int8Array(rawTypedArray) 131 132 val first = typedArray[0] 133 val second = typedArray[1] 134 135 Truth.assertThat(first).isEqualTo(-128) 136 Truth.assertThat(second).isEqualTo(127) 137 } 138 139 @Test <lambda>null140 fun int8_write() = withJSIInterop { 141 val rawTypedArray = evaluateScript("new Int8Array(2)").getTypedArray() 142 val typedArray = Int8Array(rawTypedArray) 143 144 typedArray[0] = -128 145 typedArray[1] = 127 146 147 val first = typedArray[0] 148 val second = typedArray[1] 149 150 Truth.assertThat(first).isEqualTo(-128) 151 Truth.assertThat(second).isEqualTo(127) 152 } 153 154 @Test <lambda>null155 fun int16_read() = withJSIInterop { 156 val rawTypedArray = evaluateScript("new Int16Array([-32768, 32767])").getTypedArray() 157 val typedArray = Int16Array(rawTypedArray) 158 159 val first = typedArray[0] 160 val second = typedArray[1] 161 162 Truth.assertThat(first).isEqualTo(-32768) 163 Truth.assertThat(second).isEqualTo(32767) 164 } 165 166 @Test <lambda>null167 fun int16_write() = withJSIInterop { 168 val rawTypedArray = evaluateScript("new Int16Array([0, 0])").getTypedArray() 169 val typedArray = Int16Array(rawTypedArray) 170 171 typedArray[0] = -32768 172 typedArray[1] = 32767 173 174 val first = typedArray[0] 175 val second = typedArray[1] 176 177 Truth.assertThat(first).isEqualTo(-32768) 178 Truth.assertThat(second).isEqualTo(32767) 179 } 180 181 @Test <lambda>null182 fun int32_read() = withJSIInterop { 183 val rawTypedArray = evaluateScript("new Int32Array([-2147483648, 2147483647])").getTypedArray() 184 val typedArray = Int32Array(rawTypedArray) 185 186 val first = typedArray[0] 187 val second = typedArray[1] 188 189 Truth.assertThat(first).isEqualTo(-2147483648) 190 Truth.assertThat(second).isEqualTo(2147483647) 191 } 192 193 @Test <lambda>null194 fun int32_write() = withJSIInterop { 195 val rawTypedArray = evaluateScript("new Int32Array(2)").getTypedArray() 196 val typedArray = Int32Array(rawTypedArray) 197 198 typedArray[0] = -2147483648 199 typedArray[1] = 2147483647 200 201 val first = typedArray[0] 202 val second = typedArray[1] 203 204 Truth.assertThat(first).isEqualTo(-2147483648) 205 Truth.assertThat(second).isEqualTo(2147483647) 206 } 207 208 @Test <lambda>null209 fun uint8_read() = withJSIInterop { 210 val rawTypedArray = evaluateScript("new Uint8Array([1, 255])").getTypedArray() 211 val typedArray = Uint8Array(rawTypedArray) 212 213 val first = typedArray[0] 214 val second = typedArray[1] 215 216 Truth.assertThat(first).isEqualTo(1.toUByte()) 217 Truth.assertThat(second).isEqualTo(255.toUByte()) 218 } 219 220 @Test <lambda>null221 fun uint8_write() = withJSIInterop { 222 val rawTypedArray = evaluateScript("new Uint8Array(2)").getTypedArray() 223 val typedArray = Uint8Array(rawTypedArray) 224 225 typedArray[0] = 10u 226 typedArray[1] = 255u 227 228 val first = typedArray[0] 229 val second = typedArray[1] 230 231 Truth.assertThat(first).isEqualTo(10.toUByte()) 232 Truth.assertThat(second).isEqualTo(255.toUByte()) 233 } 234 235 @Test <lambda>null236 fun uint8clamped_read() = withJSIInterop { 237 val rawTypedArray = evaluateScript("new Uint8ClampedArray([1, 255])").getTypedArray() 238 val typedArray = Uint8Array(rawTypedArray) 239 240 val first = typedArray[0] 241 val second = typedArray[1] 242 243 Truth.assertThat(first).isEqualTo(1.toUByte()) 244 Truth.assertThat(second).isEqualTo(255.toUByte()) 245 } 246 247 @Test <lambda>null248 fun uint8clamped_write() = withJSIInterop { 249 val rawTypedArray = evaluateScript("new Uint8ClampedArray(2)").getTypedArray() 250 val typedArray = Uint8Array(rawTypedArray) 251 252 typedArray[0] = 10u 253 typedArray[1] = 255u 254 255 val first = typedArray[0] 256 val second = typedArray[1] 257 258 Truth.assertThat(first).isEqualTo(10.toUByte()) 259 Truth.assertThat(second).isEqualTo(255.toUByte()) 260 } 261 262 @Test <lambda>null263 fun uint16_read() = withJSIInterop { 264 val rawTypedArray = evaluateScript("new Uint16Array([123, 65535])").getTypedArray() 265 val typedArray = Uint16Array(rawTypedArray) 266 267 val first = typedArray[0] 268 val second = typedArray[1] 269 270 Truth.assertThat(first).isEqualTo(123.toUShort()) 271 Truth.assertThat(second).isEqualTo(65535.toUShort()) 272 } 273 274 @Test <lambda>null275 fun uint16_write() = withJSIInterop { 276 val rawTypedArray = evaluateScript("new Uint16Array(2)").getTypedArray() 277 val typedArray = Uint16Array(rawTypedArray) 278 279 typedArray[0] = 123.toUShort() 280 typedArray[1] = 65535.toUShort() 281 282 val first = typedArray[0] 283 val second = typedArray[1] 284 285 Truth.assertThat(first).isEqualTo(123.toUShort()) 286 Truth.assertThat(second).isEqualTo(65535.toUShort()) 287 } 288 289 @Test <lambda>null290 fun uint32_read() = withJSIInterop { 291 val rawTypedArray = evaluateScript("new Uint32Array([123, 4294967295])").getTypedArray() 292 val typedArray = Uint32Array(rawTypedArray) 293 294 val first = typedArray[0] 295 val second = typedArray[1] 296 297 Truth.assertThat(first).isEqualTo(123.toUInt()) 298 Truth.assertThat(second).isEqualTo(4294967295.toUInt()) 299 } 300 301 @Test <lambda>null302 fun uint32_write() = withJSIInterop { 303 val rawTypedArray = evaluateScript("new Uint32Array(2)").getTypedArray() 304 val typedArray = Uint32Array(rawTypedArray) 305 306 typedArray[0] = 123.toUInt() 307 typedArray[1] = 4294967295.toUInt() 308 309 val first = typedArray[0] 310 val second = typedArray[1] 311 312 Truth.assertThat(first).isEqualTo(123.toUInt()) 313 Truth.assertThat(second).isEqualTo(4294967295.toUInt()) 314 } 315 316 @Test <lambda>null317 fun float32_read() = withJSIInterop { 318 val rawTypedArray = evaluateScript("new Float32Array([-1.12432, 987765.312])").getTypedArray() 319 val typedArray = Float32Array(rawTypedArray) 320 321 val first = typedArray[0] 322 val second = typedArray[1] 323 324 Truth.assertThat(first).isEqualTo(-1.12432f) 325 Truth.assertThat(second).isEqualTo(987765.312f) 326 } 327 328 @Test <lambda>null329 fun float32_write() = withJSIInterop { 330 val rawTypedArray = evaluateScript("new Float32Array(2)").getTypedArray() 331 val typedArray = Float32Array(rawTypedArray) 332 333 typedArray[0] = -1.12432f 334 typedArray[1] = 987765.312f 335 336 val first = typedArray[0] 337 val second = typedArray[1] 338 339 Truth.assertThat(first).isEqualTo(-1.12432f) 340 Truth.assertThat(second).isEqualTo(987765.312f) 341 } 342 343 @Test <lambda>null344 fun float64_read() = withJSIInterop { 345 val rawTypedArray = evaluateScript("new Float64Array([-1.12432, 987765.312])").getTypedArray() 346 val typedArray = Float64Array(rawTypedArray) 347 348 val first = typedArray[0] 349 val second = typedArray[1] 350 351 Truth.assertThat(first).isEqualTo(-1.12432) 352 Truth.assertThat(second).isEqualTo(987765.312) 353 } 354 355 @Test <lambda>null356 fun float64_write() = withJSIInterop { 357 val rawTypedArray = evaluateScript("new Float64Array(2)").getTypedArray() 358 val typedArray = Float64Array(rawTypedArray) 359 360 typedArray[0] = -1.12432 361 typedArray[1] = 987765.312 362 363 val first = typedArray[0] 364 val second = typedArray[1] 365 366 Truth.assertThat(first).isEqualTo(-1.12432) 367 Truth.assertThat(second).isEqualTo(987765.312) 368 } 369 370 @Test <lambda>null371 fun length_should_return_correct_value() = withJSIInterop { 372 val rawTypedArray = evaluateScript("new Float64Array(16)").getTypedArray() 373 val typedArray = Float64Array(rawTypedArray) 374 375 Truth.assertThat(typedArray.length).isEqualTo(16) 376 } 377 wrapBytesnull378 private fun wrapBytes(array: ByteArray): ByteBuffer = ByteBuffer.wrap(array).order(ByteOrder.nativeOrder()) 379 } 380