From 5f68b0bba679754b39f5d3d70d20b86fad8d3726 Mon Sep 17 00:00:00 2001 From: Daco Harkes Date: Thu, 9 Jul 2020 15:09:21 +0000 Subject: [PATCH] [test/ffi] Test struct workaround for external fields Make sure the individual getter/setter workaround for structs in NNBD works. That way structs can be migrated without having to opt in to the proposed --enable-experiment=external-abstract-variables for external fields. Note that this requires dart:ffi users to migrate twice for NNBD, once to the workaround, and later a cleanup to external fields. Change-Id: I2a9020ff7df3ebf08e04f71183f9297d87acb1b1 Cq-Include-Trybots:dart/try:vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64-try,vm-precomp-ffi-qemu-linux-release-arm-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/153777 Reviewed-by: Erik Ernst Commit-Queue: Daco Harkes --- tests/ffi/coordinate_nnbd_workaround.dart | 29 ++++++ tests/ffi/structs_nnbd_workaround_test.dart | 100 ++++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 tests/ffi/coordinate_nnbd_workaround.dart create mode 100644 tests/ffi/structs_nnbd_workaround_test.dart diff --git a/tests/ffi/coordinate_nnbd_workaround.dart b/tests/ffi/coordinate_nnbd_workaround.dart new file mode 100644 index 000000000000..515badd22d8a --- /dev/null +++ b/tests/ffi/coordinate_nnbd_workaround.dart @@ -0,0 +1,29 @@ +// Copyright (c) 2020, 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. + +library FfiTest; + +import 'dart:ffi'; +import "package:ffi/ffi.dart"; + +/// Sample struct for dart:ffi library. +class Coordinate extends Struct { + @Double() + external double get x; + external set x(double v); + + @Double() + external double get y; + external set y(double v); + + external Pointer get next; + external set next(Pointer v); + + factory Coordinate.allocate(double x, double y, Pointer next) { + return allocate().ref + ..x = x + ..y = y + ..next = next; + } +} diff --git a/tests/ffi/structs_nnbd_workaround_test.dart b/tests/ffi/structs_nnbd_workaround_test.dart new file mode 100644 index 000000000000..6501faf251b7 --- /dev/null +++ b/tests/ffi/structs_nnbd_workaround_test.dart @@ -0,0 +1,100 @@ +// Copyright (c) 2020, 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. +// +// Dart test program for testing dart:ffi struct pointers. +// +// VMOptions=--deterministic --optimization-counter-threshold=50 + +import 'dart:ffi'; + +import "package:expect/expect.dart"; +import "package:ffi/ffi.dart"; + +import 'coordinate_nnbd_workaround.dart'; + +void main() { + for (int i = 0; i < 100; i++) { + testStructAllocate(); + testStructFromAddress(); + testStructWithNulls(); + testTypeTest(); + testUtf8(); + } +} + +/// allocates each coordinate separately in c memory +void testStructAllocate() { + Pointer c1 = Coordinate.allocate(10.0, 10.0, nullptr).addressOf; + Pointer c2 = Coordinate.allocate(20.0, 20.0, c1).addressOf; + Pointer c3 = Coordinate.allocate(30.0, 30.0, c2).addressOf; + c1.ref.next = c3; + + Coordinate currentCoordinate = c1.ref; + Expect.equals(10.0, currentCoordinate.x); + currentCoordinate = currentCoordinate.next.ref; + Expect.equals(30.0, currentCoordinate.x); + currentCoordinate = currentCoordinate.next.ref; + Expect.equals(20.0, currentCoordinate.x); + currentCoordinate = currentCoordinate.next.ref; + Expect.equals(10.0, currentCoordinate.x); + + free(c1); + free(c2); + free(c3); +} + +/// allocates coordinates consecutively in c memory +void testStructFromAddress() { + Pointer c1 = allocate(count: 3); + Pointer c2 = c1.elementAt(1); + Pointer c3 = c1.elementAt(2); + c1.ref + ..x = 10.0 + ..y = 10.0 + ..next = c3; + c2.ref + ..x = 20.0 + ..y = 20.0 + ..next = c1; + c3.ref + ..x = 30.0 + ..y = 30.0 + ..next = c2; + + Coordinate currentCoordinate = c1.ref; + Expect.equals(10.0, currentCoordinate.x); + currentCoordinate = currentCoordinate.next.ref; + Expect.equals(30.0, currentCoordinate.x); + currentCoordinate = currentCoordinate.next.ref; + Expect.equals(20.0, currentCoordinate.x); + currentCoordinate = currentCoordinate.next.ref; + Expect.equals(10.0, currentCoordinate.x); + + free(c1); +} + +void testStructWithNulls() { + Pointer coordinate = + Coordinate.allocate(10.0, 10.0, nullptr).addressOf; + Expect.equals(coordinate.ref.next, nullptr); + coordinate.ref.next = coordinate; + Expect.notEquals(coordinate.ref.next, nullptr); + coordinate.ref.next = nullptr; + Expect.equals(coordinate.ref.next, nullptr); + free(coordinate); +} + +void testTypeTest() { + Coordinate c = Coordinate.allocate(10, 10, nullptr); + Expect.isTrue(c is Struct); + Expect.isTrue(c.addressOf is Pointer); + free(c.addressOf); +} + +void testUtf8() { + final String test = 'Hasta MaƱana'; + final Pointer medium = Utf8.toUtf8(test); + Expect.equals(test, Utf8.fromUtf8(medium)); + free(medium); +}