blob: 21518ad6cd04f9943cdad7db620832d37ea7a18c [file] [edit]
// 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.
@DefaultAsset('package:objective_c/objective_c.dylib')
library;
import 'dart:ffi';
import 'dart:io';
import 'package:ffi/ffi.dart';
import 'package:ffigen/ffigen.dart';
import 'package:ffigen/src/header_parser.dart' show parse;
import 'package:leak_tracker/leak_tracker.dart' as leak_tracker;
import 'package:logging/logging.dart';
import 'package:objective_c/objective_c.dart';
import 'package:objective_c/src/internal.dart'
as internal_for_testing
show isValidBlock, isValidClass;
import 'package:path/path.dart' as p;
import '../test_utils.dart';
void verifyBindings(
String testName, {
Logger? logger,
bool Function(String expected, String actual)? dartVerify,
bool Function(String expected, String actual)? objCVerify,
}) {
final thisDir = p.join(packagePathForTests, 'test', 'native_objc_test');
final configFile = p.join(thisDir, '${testName}_config.yaml');
final config = testConfigFromPath(configFile, logger: logger);
final context = testContext(config);
final library = parse(context);
final bindingsName = context.config.output.dartFile.pathSegments.last;
matchLibraryWithExpected(context, library, bindingsName, [
'test',
'native_objc_test',
bindingsName,
], verify: dartVerify);
final mFileName = context.config.output.objCFile.pathSegments.last;
matchObjCFileWithExpected(context, library, mFileName, [
'test',
'native_objc_test',
mFileName,
], verify: objCVerify);
}
// Dart_ExecuteInternalCommand("gc-now") doesn't work on flutter, so we use
// leak_tracker's forceGC function instead. It's less reliable, and to combat
// that we need to wait for quite a long time, which breaks autorelease pools.
Future<void> flutterDoGC() async {
await leak_tracker.forceGC();
await Future<void>.delayed(const Duration(milliseconds: 500));
}
// Defined in package:objective_c's test-only util, reference_tracker.h.
@Native<Void Function(Pointer<Void>, Pointer<Bool>)>(
symbol: 'attachReferenceTracker',
)
external void _attachReferenceTracker(
Pointer<Void> host,
Pointer<Bool> isAlive,
);
class ReferenceTracker {
Pointer<Void> _host = nullptr;
final Pointer<Bool> _isAlivePtr;
ReferenceTracker(Arena arena) : this._(arena, arena<Bool>()..value = true);
ReferenceTracker._(Arena arena, this._isAlivePtr);
bool get isAlive => _isAlivePtr.value;
Pointer<Void> get host => _host;
void track(ObjCObject host) {
assert(_host == nullptr);
final hostRef = host.ref;
_attachReferenceTracker(_host = hostRef.pointer.cast(), _isAlivePtr);
}
void trackBlock(ObjCBlock host) {
assert(_host == nullptr);
final hostRef = host.ref;
_attachReferenceTracker(_host = hostRef.pointer.cast(), _isAlivePtr);
}
}
bool isValidClass(Pointer<Void> clazz) =>
internal_for_testing.isValidClass(clazz.cast(), forceReloadClasses: true);
String findDylib(String name) =>
p.join(packagePathForTests, '.dart_tool', 'lib', '$name.dylib');