/* This file is part of KDDockWidgets. SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Sérgio Martins SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only Contact KDAB at for commercial licensing options. */ // A script that runs the tests but first ensures the bundle is built import 'dart:io'; import 'src/flutter/utils.dart'; bool isAOT = false; bool isASAN = false; bool isLSAN = false; bool useGDB = false; bool ubsanPrintStacks = false; String kddwSourceDir() { return Platform.script.path.replaceAll("run_flutter_tests.dart", ""); } Future runTests(String? singleTestName, List singleTestArgs, String buildDir) async { if (!await Directory(buildDir).exists()) { final presetName = buildDir .replaceAll(kddwSourceDir(), "") .replaceAll("build-", "") .replaceAll("/", ""); print("ERROR: Could not find $buildDir.\n" "Be sure to build the preset: $presetName"); return -1; } if (singleTestName != null && !await File("$buildDir/bin/$singleTestName").exists()) { print("ERROR: Could not find executable $buildDir/bin/$singleTestName\n"); return -1; } /// Make sure the C++ is built: int result = await runCommand("ninja", [], workingDirectory: buildDir); if (result != 0) { print("Failed to build C++"); return result; } /// Make sure the flutter bundle is built: final flutterEmbedderDir = "${kddwSourceDir()}/tests/flutter_tests_embedder/"; result = await runCommand( "flutter", ["build", "bundle", "--suppress-analytics"], workingDirectory: flutterEmbedderDir); if (result != 0) { print("Failed to build bundle"); return result; } if (isAOT) { result = await runCommand( "flutter", ["build", "linux", "--release", "--suppress-analytics"], workingDirectory: flutterEmbedderDir); if (result != 0) { print("Failed to build AOT snapshot (libapp.so)"); return result; } } final String aotValue = isAOT ? "1" : "0"; final String lsanValue = isLSAN ? "1" : "0"; final String asanOptions = "detect_leaks=$lsanValue"; final String ubsanOptions = ubsanPrintStacks ? "print_stacktrace=1" : ""; final String gensnapshotOptions = "--no-strip"; final String libraryPath = "$buildDir/lib/"; print("export KDDW_FLUTTER_TESTS_USE_AOT=$aotValue"); print("export ASAN_OPTIONS=$asanOptions"); if (ubsanPrintStacks) print("export UBSAN_OPTIONS=$ubsanOptions"); print("export DARTAGNAN_BINDINGSLIB_PATH=$libraryPath"); print("\n"); final env = { "KDDW_FLUTTER_TESTS_USE_AOT": aotValue, "ASAN_OPTIONS": asanOptions, "EXTRA_GEN_SNAPSHOT_OPTIONS": gensnapshotOptions, if (ubsanPrintStacks) "UBSAN_OPTIONS": ubsanOptions, "DARTAGNAN_BINDINGSLIB_PATH": libraryPath }; /// Now we can run the tests: if (singleTestName == null) { // Run everything: return await runCommand("ctest", ["-j1", "--output-on-failure"], workingDirectory: buildDir, env: env); } else { // Run a single test: final String executableName = useGDB ? "gdb" : "bin/$singleTestName"; List args = [ // "--disable-service-auth-codes", // "--verbose-logging", // "--start-paused" if (useGDB) ...[ "-ex=run", "--args", "bin/$singleTestName", ...singleTestArgs ] else ...singleTestArgs ]; return await runCommand(executableName, args, workingDirectory: buildDir, env: env); } } void printUsage() { print( "Usage: dart run_flutter_tests.dart [--aot] [--asan] [--lsan] [--ubsan-stacktraces]"); print("Or specify a single test to run:"); print( "dart run_flutter_tests.dart [--aot] [--asan] [--lsan] [--ubsan-stacktraces] [--gdb] [args]"); print("Use asan_symbolize.py if --lsan isn't symbolizing libapp.so"); } String calculateBuildDir() { String result; if (isAOT) { result = "build-dev-flutter-aot"; } else { result = "build-dev-flutter"; } if (isASAN) result += "-asan"; print("Using $result"); return "${kddwSourceDir()}${result}/"; } Future main(List args) async { final _args = List.from(args); isLSAN = _args.remove("--lsan"); isASAN = _args.remove("--asan") || isLSAN; isAOT = _args.remove("--aot") || isLSAN; // LSAN requires AOT for simbolization useGDB = _args.remove("--gdb"); ubsanPrintStacks = _args.remove("--ubsan-stacktraces"); final bool isHelp = _args.remove("--help") || _args.remove("-h"); if (isHelp) { printUsage(); exit(0); } if (ubsanPrintStacks && !isASAN) { print("ERROR: --ubsan-stacktraces requires --asan"); exit(1); } final String? singleTestName = _args.isEmpty ? null : _args.first; List singleTestArgs = _args.isEmpty ? [] : _args.sublist(1); final result = await runTests(singleTestName, singleTestArgs, calculateBuildDir()); final bool isSuccess = result == 0; if (isSuccess) print("SUCCESS!"); else print("ERROR!"); if (isLSAN && !isAOT && !isSuccess) { print("\nConsider using LSAN with AOT so you can get symbolized traces"); } exit(result); }