blob: e48fd0a57294fc152833a94c14df5d0f0c96116d [file] [log] [blame]
// 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:io';
import 'package:jnigen/jnigen.dart';
import 'package:path/path.dart' hide equals;
import 'package:test/test.dart';
import 'package:logging/logging.dart' show Level;
import 'package:jnigen/src/logging/logging.dart' show printError;
final _currentDirectory = Directory(".");
Directory getTempDir(String prefix) {
return _currentDirectory.createTempSync(prefix);
}
Future<bool> isEmptyOrNotExistDir(String path) async {
final dir = Directory(path);
return (!await dir.exists()) || (await dir.list().length == 0);
}
/// Runs command, and prints output only if the exit status is non-zero.
Future<int> runCommand(String exec, List<String> args,
{String? workingDirectory, bool runInShell = false}) async {
final proc = await Process.run(exec, args,
workingDirectory: workingDirectory, runInShell: runInShell);
if (proc.exitCode != 0) {
printError('command exited with exit status ${proc.exitCode}:\n'
'$exec ${args.join(" ")}\n');
printError(proc.stdout);
printError(proc.stderr);
}
return proc.exitCode;
}
/// List all JAR files in [testRoot]/jar
Future<List<String>> getJarPaths(String testRoot) async {
final jarPath = join(testRoot, 'jar');
if (!await Directory(jarPath).exists()) {
return [];
}
return Directory(jarPath)
.list()
.map((entry) => entry.path)
.where((path) => path.endsWith('.jar'))
.toList();
}
/// Read file normalizing CRLF to LF.
String readFile(File file) => file.readAsStringSync().replaceAll('\r\n', '\n');
/// Compares 2 hierarchies using `git diff --no-index`.
void comparePaths(String path1, String path2) {
final proc = Process.runSync("git", [
"diff",
"--no-index",
if (stderr.supportsAnsiEscapes) "--color=always",
path1,
path2,
]);
if (proc.exitCode != 0) {
stderr.writeln('\n${proc.stdout}');
throw Exception("Files differ: ($path1, $path2)");
}
}
Future<void> _generateTempBindings(Config config, Directory tempDir) async {
final tempSrc = tempDir.uri.resolve("src/");
final singleFile =
config.outputConfig.dartConfig.structure == OutputStructure.singleFile;
final tempLib = singleFile
? tempDir.uri.resolve("generated.dart")
: tempDir.uri.resolve("lib/");
if (config.outputConfig.bindingsType == BindingsType.cBased) {
config.outputConfig.cConfig!.path = tempSrc;
}
config.outputConfig.dartConfig.path = tempLib;
config.logLevel = Level.WARNING;
await generateJniBindings(config);
}
/// Generates and compares bindings with reference bindings.
///
/// [dartReferenceBindings] can be directory or file depending on output
/// configuration.
///
/// If the config generates C code, [cReferenceBindings] must be a non-null
/// directory path.
Future<void> generateAndCompareBindings(Config config,
String dartReferenceBindings, String? cReferenceBindings) async {
final currentDir = Directory.current;
final tempDir = currentDir.createTempSync("jnigen_test_temp");
final tempSrc = tempDir.uri.resolve("src/");
final singleFile =
config.outputConfig.dartConfig.structure == OutputStructure.singleFile;
final tempLib = singleFile
? tempDir.uri.resolve("generated.dart")
: tempDir.uri.resolve("lib/");
try {
await _generateTempBindings(config, tempDir);
comparePaths(dartReferenceBindings, tempLib.toFilePath());
if (config.outputConfig.bindingsType == BindingsType.cBased) {
comparePaths(cReferenceBindings!, tempSrc.toFilePath());
}
} finally {
tempDir.deleteSync(recursive: true);
}
}
Future<void> generateAndAnalyzeBindings(Config config) async {
final tempDir = Directory.current.createTempSync("jnigen_test_temp");
try {
await _generateTempBindings(config, tempDir);
final analyzeResult = Process.runSync("dart", ["analyze", tempDir.path]);
expect(analyzeResult.exitCode, equals(0),
reason: "Analyzer exited with non-zero status");
} finally {
tempDir.deleteSync(recursive: true);
}
}