| // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| import 'dart:ffi'; | |
| import 'dart:io'; | |
| import 'package:jni/jni.dart'; | |
| import 'package:jni/src/third_party/generated_bindings.dart'; | |
| import 'package:test/test.dart'; | |
| import 'test_util/test_util.dart'; | |
| void main() { | |
| // Don't forget to initialize JNI. | |
| if (!Platform.isAndroid) { | |
| checkDylibIsUpToDate(); | |
| spawnJvm(); | |
| } | |
| run(testRunner: test); | |
| } | |
| void run({required TestRunnerCallback testRunner}) { | |
| testRunner('Java boolean array', () { | |
| using((arena) { | |
| final array = JBooleanArray(3)..releasedBy(arena); | |
| var counter = 0; | |
| for (final element in array.asDart()) { | |
| expect(element, array[counter]); | |
| ++counter; | |
| } | |
| expect(counter, array.length); | |
| expect(array.length, 3); | |
| array[0] = true; | |
| array[1] = false; | |
| array[2] = false; | |
| expect(array[0], true); | |
| expect(array[1], false); | |
| expect(array[2], false); | |
| final firstTwo = array.getRange(0, 2); | |
| expect(firstTwo.length, 2); | |
| expect(firstTwo.elementSizeInBytes, sizeOf<JBooleanMarker>()); | |
| expect(firstTwo[0], 1); | |
| expect(firstTwo[1], 0); | |
| expect(() { | |
| array.getRange(0, 4); | |
| }, throwsRangeError); | |
| expect(() { | |
| array.setRange(0, 4, []); | |
| }, throwsRangeError); | |
| array.setRange(0, 3, [false, true, true, true], 1); | |
| expect(array[0], true); | |
| expect(array[1], true); | |
| expect(array[2], true); | |
| expect(() { | |
| final _ = array[-1]; | |
| }, throwsRangeError); | |
| expect(() { | |
| array[-1] = false; | |
| }, throwsRangeError); | |
| expect(() { | |
| array[3] = false; | |
| }, throwsRangeError); | |
| }); | |
| }); | |
| testRunner('Java char array', () { | |
| using((arena) { | |
| final array = JCharArray(3)..releasedBy(arena); | |
| var counter = 0; | |
| for (final element in array.asDart()) { | |
| expect(element, array[counter]); | |
| ++counter; | |
| } | |
| expect(counter, array.length); | |
| expect(array.length, 3); | |
| array[0] = 1; | |
| array[1] = 2; | |
| array[2] = 3 + 256 * 256 * 5; // Truncates the input. | |
| expect(array[0], 1); | |
| expect(array[1], 2); | |
| expect(array[2], 3); | |
| final firstTwo = array.getRange(0, 2); | |
| expect(firstTwo.length, 2); | |
| expect(firstTwo.elementSizeInBytes, sizeOf<JCharMarker>()); | |
| expect(firstTwo[0], 1); | |
| expect(firstTwo[1], 2); | |
| expect(() { | |
| array.getRange(0, 4); | |
| }, throwsRangeError); | |
| expect(() { | |
| array.setRange(0, 4, []); | |
| }, throwsRangeError); | |
| array.setRange(0, 3, [4, 5, 6, 7], 1); | |
| expect(array[0], 5); | |
| expect(array[1], 6); | |
| expect(array[2], 7); | |
| expect(() { | |
| final _ = array[-1]; | |
| }, throwsRangeError); | |
| expect(() { | |
| array[-1] = 4; | |
| }, throwsRangeError); | |
| expect(() { | |
| array[3] = 4; | |
| }, throwsRangeError); | |
| }); | |
| }); | |
| testRunner('Java byte array', () { | |
| using((arena) { | |
| expect(JByteArray.of([]).asDart(), isEmpty); | |
| expect(JByteArray.of([1]).asDart(), containsAllInOrder([1])); | |
| expect(JByteArray.of([1, 2]).asDart(), containsAllInOrder([1, 2])); | |
| expect(JByteArray.of([-1, -2]).asDart(), containsAllInOrder([-1, -2])); | |
| expect(JByteArray.of([127, 128, 129]).asDart(), | |
| containsAllInOrder([127, -128, -127])); | |
| final array = JByteArray(3)..releasedBy(arena); | |
| var counter = 0; | |
| for (final element in array.asDart()) { | |
| expect(element, array[counter]); | |
| ++counter; | |
| } | |
| expect(counter, array.length); | |
| expect(array.length, 3); | |
| array[0] = 1; | |
| array[1] = 2; | |
| array[2] = 3 + 256 * 5; // Truncates the input.; | |
| expect(array[0], 1); | |
| expect(array[1], 2); | |
| expect(array[2], 3); | |
| final firstTwo = array.getRange(0, 2); | |
| expect(firstTwo.length, 2); | |
| expect(firstTwo.elementSizeInBytes, sizeOf<JByteMarker>()); | |
| expect(firstTwo[0], 1); | |
| expect(firstTwo[1], 2); | |
| expect(() { | |
| array.getRange(0, 4); | |
| }, throwsRangeError); | |
| expect(() { | |
| array.setRange(0, 4, []); | |
| }, throwsRangeError); | |
| array.setRange(0, 3, [4, 5, 6, 7], 1); | |
| expect(array[0], 5); | |
| expect(array[1], 6); | |
| expect(array[2], 7); | |
| expect(() { | |
| final _ = array[-1]; | |
| }, throwsRangeError); | |
| expect(() { | |
| array[-1] = 4; | |
| }, throwsRangeError); | |
| expect(() { | |
| array[3] = 4; | |
| }, throwsRangeError); | |
| }); | |
| }); | |
| testRunner('Java short array', () { | |
| using((arena) { | |
| final array = JShortArray(3)..releasedBy(arena); | |
| var counter = 0; | |
| for (final element in array.asDart()) { | |
| expect(element, array[counter]); | |
| ++counter; | |
| } | |
| expect(counter, array.length); | |
| expect(array.length, 3); | |
| array[0] = 1; | |
| array[1] = 2; | |
| array[2] = 3 + 256 * 256 * 5; // Truncates the input. | |
| expect(array[0], 1); | |
| expect(array[1], 2); | |
| expect(array[2], 3); | |
| final firstTwo = array.getRange(0, 2); | |
| expect(firstTwo.length, 2); | |
| expect(firstTwo.elementSizeInBytes, sizeOf<JShortMarker>()); | |
| expect(firstTwo[0], 1); | |
| expect(firstTwo[1], 2); | |
| expect(() { | |
| array.getRange(0, 4); | |
| }, throwsRangeError); | |
| expect(() { | |
| array.setRange(0, 4, []); | |
| }, throwsRangeError); | |
| array.setRange(0, 3, [4, 5, 6, 7], 1); | |
| expect(array[0], 5); | |
| expect(array[1], 6); | |
| expect(array[2], 7); | |
| expect(() { | |
| final _ = array[-1]; | |
| }, throwsRangeError); | |
| expect(() { | |
| array[-1] = 4; | |
| }, throwsRangeError); | |
| expect(() { | |
| array[3] = 4; | |
| }, throwsRangeError); | |
| }); | |
| }); | |
| testRunner('Java int array', () { | |
| using((arena) { | |
| final array = JIntArray(3)..releasedBy(arena); | |
| var counter = 0; | |
| for (final element in array.asDart()) { | |
| expect(element, array[counter]); | |
| ++counter; | |
| } | |
| expect(counter, array.length); | |
| expect(array.length, 3); | |
| array[0] = 1; | |
| array[1] = 2; | |
| array[2] = 3 + 256 * 256 * 256 * 256 * 5; // Truncates the input. | |
| expect(array[0], 1); | |
| expect(array[1], 2); | |
| expect(array[2], 3); | |
| final firstTwo = array.getRange(0, 2); | |
| expect(firstTwo.length, 2); | |
| expect(firstTwo.elementSizeInBytes, sizeOf<JIntMarker>()); | |
| expect(firstTwo[0], 1); | |
| expect(firstTwo[1], 2); | |
| expect(() { | |
| array.getRange(0, 4); | |
| }, throwsRangeError); | |
| expect(() { | |
| array.setRange(0, 4, []); | |
| }, throwsRangeError); | |
| array.setRange(0, 3, [4, 5, 6, 7], 1); | |
| expect(array[0], 5); | |
| expect(array[1], 6); | |
| expect(array[2], 7); | |
| expect(() { | |
| final _ = array[-1]; | |
| }, throwsRangeError); | |
| expect(() { | |
| array[-1] = 4; | |
| }, throwsRangeError); | |
| expect(() { | |
| array[3] = 4; | |
| }, throwsRangeError); | |
| }); | |
| }); | |
| testRunner('Java long array', () { | |
| using((arena) { | |
| final array = JLongArray(3)..releasedBy(arena); | |
| var counter = 0; | |
| for (final element in array.asDart()) { | |
| expect(element, array[counter]); | |
| ++counter; | |
| } | |
| expect(counter, array.length); | |
| expect(array.length, 3); | |
| array[0] = 1; | |
| array[1] = 2; | |
| array[2] = 3 + 256 * 256 * 256 * 256 * 5; | |
| expect(array[0], 1); | |
| expect(array[1], 2); | |
| expect(array[2], 3 + 256 * 256 * 256 * 256 * 5); | |
| final firstTwo = array.getRange(0, 2); | |
| expect(firstTwo.length, 2); | |
| expect(firstTwo.elementSizeInBytes, sizeOf<JLongMarker>()); | |
| expect(firstTwo[0], 1); | |
| expect(firstTwo[1], 2); | |
| expect(() { | |
| array.getRange(0, 4); | |
| }, throwsRangeError); | |
| expect(() { | |
| array.setRange(0, 4, []); | |
| }, throwsRangeError); | |
| array.setRange(0, 3, [4, 5, 6, 7], 1); | |
| expect(array[0], 5); | |
| expect(array[1], 6); | |
| expect(array[2], 7); | |
| expect(() { | |
| final _ = array[-1]; | |
| }, throwsRangeError); | |
| expect(() { | |
| array[-1] = 4; | |
| }, throwsRangeError); | |
| expect(() { | |
| array[3] = 4; | |
| }, throwsRangeError); | |
| }); | |
| }); | |
| const epsilon = 1e-6; | |
| testRunner('Java float array', () { | |
| using((arena) { | |
| final array = JFloatArray(3)..releasedBy(arena); | |
| var counter = 0; | |
| for (final element in array.asDart()) { | |
| expect(element, array[counter]); | |
| ++counter; | |
| } | |
| expect(counter, array.length); | |
| expect(array.length, 3); | |
| array[0] = 0.5; | |
| array[1] = 2; | |
| array[2] = 3; | |
| expect(array[0], closeTo(0.5, epsilon)); | |
| expect(array[1], closeTo(2, epsilon)); | |
| expect(array[2], closeTo(3, epsilon)); | |
| final firstTwo = array.getRange(0, 2); | |
| expect(firstTwo.length, 2); | |
| expect(firstTwo.elementSizeInBytes, sizeOf<JFloatMarker>()); | |
| expect(firstTwo[0], closeTo(0.5, epsilon)); | |
| expect(firstTwo[1], closeTo(2, epsilon)); | |
| expect(() { | |
| array.getRange(0, 4); | |
| }, throwsRangeError); | |
| expect(() { | |
| array.setRange(0, 4, []); | |
| }, throwsRangeError); | |
| array.setRange(0, 3, [4, 5, 6, 7], 1); | |
| expect(array[0], closeTo(5, epsilon)); | |
| expect(array[1], closeTo(6, epsilon)); | |
| expect(array[2], closeTo(7, epsilon)); | |
| expect(() { | |
| final _ = array[-1]; | |
| }, throwsRangeError); | |
| expect(() { | |
| array[-1] = 4; | |
| }, throwsRangeError); | |
| expect(() { | |
| array[3] = 4; | |
| }, throwsRangeError); | |
| }); | |
| }); | |
| testRunner('Java double array', () { | |
| using((arena) { | |
| final array = JDoubleArray(3)..releasedBy(arena); | |
| var counter = 0; | |
| for (final element in array.asDart()) { | |
| expect(element, array[counter]); | |
| ++counter; | |
| } | |
| expect(counter, array.length); | |
| expect(array.length, 3); | |
| array[0] = 0.5; | |
| array[1] = 2; | |
| array[2] = 3; | |
| expect(array[0], closeTo(0.5, epsilon)); | |
| expect(array[1], closeTo(2, epsilon)); | |
| expect(array[2], closeTo(3, epsilon)); | |
| final firstTwo = array.getRange(0, 2); | |
| expect(firstTwo.length, 2); | |
| expect(firstTwo.elementSizeInBytes, sizeOf<JDoubleMarker>()); | |
| expect(firstTwo[0], closeTo(0.5, epsilon)); | |
| expect(firstTwo[1], closeTo(2, epsilon)); | |
| expect(() { | |
| array.getRange(0, 4); | |
| }, throwsRangeError); | |
| expect(() { | |
| array.setRange(0, 4, []); | |
| }, throwsRangeError); | |
| array.setRange(0, 3, [4, 5, 6, 7], 1); | |
| expect(array[0], closeTo(5, epsilon)); | |
| expect(array[1], closeTo(6, epsilon)); | |
| expect(array[2], closeTo(7, epsilon)); | |
| expect(() { | |
| final _ = array[-1]; | |
| }, throwsRangeError); | |
| expect(() { | |
| array[-1] = 4; | |
| }, throwsRangeError); | |
| expect(() { | |
| array[3] = 4; | |
| }, throwsRangeError); | |
| }); | |
| }); | |
| testRunner('Java string array', () { | |
| using((arena) { | |
| final array = JArray.withLength(JString.type, 3)..releasedBy(arena); | |
| var counter = 0; | |
| for (final element in array.asDart()) { | |
| expect(element, array[counter]); | |
| ++counter; | |
| } | |
| expect(counter, array.length); | |
| expect(array.length, 3); | |
| array[0] = 'ØØ³'.toJString()..releasedBy(arena); | |
| array[1] = '\$'.toJString()..releasedBy(arena); | |
| array[2] = '33'.toJString()..releasedBy(arena); | |
| expect(array[0]!.toDartString(releaseOriginal: true), 'ØØ³'); | |
| expect(array[1]!.toDartString(releaseOriginal: true), '\$'); | |
| expect(array[2]!.toDartString(releaseOriginal: true), '33'); | |
| array.setRange( | |
| 0, | |
| 3, | |
| [ | |
| '44'.toJString()..releasedBy(arena), | |
| '55'.toJString()..releasedBy(arena), | |
| '66'.toJString()..releasedBy(arena), | |
| '77'.toJString()..releasedBy(arena), | |
| ], | |
| 1, | |
| ); | |
| expect(array[0]!.toDartString(releaseOriginal: true), '55'); | |
| expect(array[1]!.toDartString(releaseOriginal: true), '66'); | |
| expect(array[2]!.toDartString(releaseOriginal: true), '77'); | |
| expect(() { | |
| final _ = array[-1]; | |
| }, throwsRangeError); | |
| expect(() { | |
| array[-1] = '44'.toJString()..releasedBy(arena); | |
| }, throwsRangeError); | |
| expect(() { | |
| array[3] = '44'.toJString()..releasedBy(arena); | |
| }, throwsRangeError); | |
| }); | |
| }); | |
| testRunner('Java object array', () { | |
| using((arena) { | |
| final array = JArray.withLength(JObject.type, 3)..releasedBy(arena); | |
| var counter = 0; | |
| for (final element in array.asDart()) { | |
| expect(element, array[counter]); | |
| ++counter; | |
| } | |
| expect(counter, array.length); | |
| expect(array.length, 3); | |
| expect(array[0], isNull); | |
| expect(array[1], isNull); | |
| expect(array[2], isNull); | |
| }); | |
| }); | |
| testRunner('Java 2d array', () { | |
| using((arena) { | |
| final array = JIntArray(3)..releasedBy(arena); | |
| array[0] = 1; | |
| array[1] = 2; | |
| array[2] = 3; | |
| final twoDimArray = JArray.withLength(JIntArray.type, 3) | |
| ..releasedBy(arena); | |
| expect(twoDimArray.length, 3); | |
| twoDimArray[0] = array; | |
| twoDimArray[1] = array; | |
| twoDimArray[2] = array; | |
| for (var i = 0; i < 3; ++i) { | |
| expect(twoDimArray[i]![0], 1); | |
| expect(twoDimArray[i]![1], 2); | |
| expect(twoDimArray[i]![2], 3); | |
| } | |
| twoDimArray[2]![2] = 4; | |
| expect(twoDimArray[2]![2], 4); | |
| }); | |
| }); | |
| testRunner('JArray.filled', () { | |
| using((arena) { | |
| final string = 'abc'.toJString()..releasedBy(arena); | |
| final array = JArray.filled(3, string)..releasedBy(arena); | |
| expect( | |
| () => JArray.filled(-3, 'abc'.toJString()..releasedBy(arena)), | |
| throwsA(isA<RangeError>()), | |
| ); | |
| expect(array.length, 3); | |
| expect(array[0].toDartString(releaseOriginal: true), 'abc'); | |
| expect(array[1].toDartString(releaseOriginal: true), 'abc'); | |
| expect(array[2].toDartString(releaseOriginal: true), 'abc'); | |
| }); | |
| }); | |
| testRunner('JArray.of', () { | |
| using((arena) { | |
| final array1 = JArray.of(JString.type, [ | |
| 'apple'.toJString()..releasedBy(arena), | |
| 'banana'.toJString()..releasedBy(arena) | |
| ]) | |
| ..releasedBy(arena); | |
| expect(array1.length, 2); | |
| expect(array1[0].toDartString(releaseOriginal: true), 'apple'); | |
| expect(array1[1].toDartString(releaseOriginal: true), 'banana'); | |
| final array2 = JArray.of(JString.type, [ | |
| 'apple'.toJString()..releasedBy(arena), | |
| null, | |
| 'banana'.toJString()..releasedBy(arena) | |
| ]); | |
| expect(array2.length, 3); | |
| expect(array2[0]!.toDartString(releaseOriginal: true), 'apple'); | |
| expect(array2[1], isNull); | |
| expect(array2[2]!.toDartString(releaseOriginal: true), 'banana'); | |
| final array3 = JArray.of<JObject>(JString.type, []); | |
| expect(array3.length, 0); | |
| final array4 = JArray.of<JObject?>(JString.type, []); | |
| expect(array4.length, 0); | |
| }); | |
| }); | |
| testRunner('JArray of JByte', () { | |
| using((arena) { | |
| final arr = JArray.withLength(JByte.type, 1)..releasedBy(arena); | |
| expect(arr[0], isNull); | |
| }); | |
| }); | |
| testRunner('JArray of JShort', () { | |
| using((arena) { | |
| final arr = JArray.withLength(JShort.type, 1)..releasedBy(arena); | |
| expect(arr[0], isNull); | |
| }); | |
| }); | |
| testRunner('JArray of JInteger', () { | |
| using((arena) { | |
| final arr = JArray.withLength(JInteger.type, 1)..releasedBy(arena); | |
| expect(arr[0], isNull); | |
| }); | |
| }); | |
| testRunner('JArray of JCharacter', () { | |
| using((arena) { | |
| final arr = JArray.withLength(JCharacter.type, 1)..releasedBy(arena); | |
| expect(arr[0], isNull); | |
| }); | |
| }); | |
| testRunner('JArray of JLong', () { | |
| using((arena) { | |
| final arr = JArray.withLength(JLong.type, 1)..releasedBy(arena); | |
| expect(arr[0], isNull); | |
| }); | |
| }); | |
| testRunner('JArray of JFloat', () { | |
| using((arena) { | |
| final arr = JArray.withLength(JFloat.type, 1)..releasedBy(arena); | |
| expect(arr[0], isNull); | |
| }); | |
| }); | |
| testRunner('JArray of JDouble', () { | |
| using((arena) { | |
| final arr = JArray.withLength(JDouble.type, 1)..releasedBy(arena); | |
| expect(arr[0], isNull); | |
| }); | |
| }); | |
| testRunner('JArray of JBoolean', () { | |
| using((arena) { | |
| final arr = JArray.withLength(JBoolean.type, 1)..releasedBy(arena); | |
| expect(arr[0], isNull); | |
| }); | |
| }); | |
| testRunner('JArray of JSet', () { | |
| using((arena) { | |
| final arr = JArray.withLength(JSet.type, 1)..releasedBy(arena); | |
| expect(arr[0], isNull); | |
| }); | |
| }); | |
| testRunner('JArray of JList', () { | |
| using((arena) { | |
| final arr = JArray.withLength(JList.type, 1)..releasedBy(arena); | |
| expect(arr[0], isNull); | |
| }); | |
| }); | |
| testRunner('JArray of JMap', () { | |
| using((arena) { | |
| final arr = JArray.withLength(JMap.type, 1)..releasedBy(arena); | |
| expect(arr[0], isNull); | |
| }); | |
| }); | |
| testRunner('JArray of JIterator', () { | |
| using((arena) { | |
| final arr = JArray.withLength(JIterator.type, 1)..releasedBy(arena); | |
| expect(arr[0], isNull); | |
| }); | |
| }); | |
| } |