|  | // 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. | 
|  | // | 
|  | // SharedObjects=ffi_test_functions | 
|  | // | 
|  | // VMOptions=--trace-finalizers | 
|  |  | 
|  | import 'dart:ffi'; | 
|  |  | 
|  | import 'package:expect/expect.dart'; | 
|  | import 'package:ffi/ffi.dart'; | 
|  |  | 
|  | import 'dylib_utils.dart'; | 
|  | import 'ffi_test_helpers.dart'; | 
|  |  | 
|  | void main() { | 
|  | testFinalizerRuns(); | 
|  | testFinalizerDetach(); | 
|  | testDoubleDetach(); | 
|  | testDetachNonDetach(); | 
|  | testWrongArguments(); | 
|  | } | 
|  |  | 
|  | DynamicLibrary ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions"); | 
|  |  | 
|  | void testFinalizerRuns() { | 
|  | using((Arena allocator) { | 
|  | final token = allocator<IntPtr>(); | 
|  | createAndLoseFinalizable(token); | 
|  | doGC(); | 
|  | Expect.equals(42, token.value); | 
|  | }); | 
|  | } | 
|  |  | 
|  | void createAndLoseFinalizable(Pointer<IntPtr> token) { | 
|  | final myFinalizable = MyFinalizable(); | 
|  | setTokenFinalizer.attach(myFinalizable, token.cast()); | 
|  | Expect.equals(0, token.value); | 
|  | } | 
|  |  | 
|  | void testFinalizerDetach() { | 
|  | using((Arena allocator) { | 
|  | final token = allocator<IntPtr>(); | 
|  | attachAndDetach(token); | 
|  | doGC(); | 
|  | Expect.equals(0, token.value); | 
|  | }); | 
|  | } | 
|  |  | 
|  | class Detach { | 
|  | String identifier; | 
|  |  | 
|  | Detach(this.identifier); | 
|  | } | 
|  |  | 
|  | void attachAndDetach(Pointer<IntPtr> token) { | 
|  | final myFinalizable = MyFinalizable(); | 
|  | final detach = Detach('detach 123'); | 
|  | setTokenFinalizer.attach(myFinalizable, token.cast(), detach: detach); | 
|  | setTokenFinalizer.detach(detach); | 
|  | Expect.equals(0, token.value); | 
|  | } | 
|  |  | 
|  | void testDoubleDetach() { | 
|  | using((Arena allocator) { | 
|  | final token = allocator<IntPtr>(); | 
|  | final myFinalizable = MyFinalizable(); | 
|  | final detach = Detach('detach 321'); | 
|  | setTokenFinalizer.attach(myFinalizable, token.cast(), detach: detach); | 
|  | setTokenFinalizer.detach(detach); | 
|  | setTokenFinalizer.detach(detach); | 
|  | Expect.equals(0, token.value); | 
|  | }); | 
|  | } | 
|  |  | 
|  | void testDetachNonDetach() { | 
|  | final detach = Detach('detach 456'); | 
|  | setTokenFinalizer.detach(detach); | 
|  | setTokenFinalizer.detach(detach); | 
|  | } | 
|  |  | 
|  | void testWrongArguments() { | 
|  | using((Arena allocator) { | 
|  | final token = allocator<IntPtr>().cast<Void>(); | 
|  | Expect.throws(() { | 
|  | final myFinalizable = MyFinalizable(); | 
|  | setTokenFinalizer.attach(myFinalizable, token, externalSize: -1024); | 
|  | }); | 
|  | Expect.throws(() { | 
|  | final myFinalizable = MyFinalizable(); | 
|  | setTokenFinalizer.attach(myFinalizable, token, detach: 123); | 
|  | }); | 
|  | }); | 
|  | } |