/***************************************************************************************************
Copyright (C) 2025 The Qt Company Ltd.
SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-3.0-only
***************************************************************************************************/
using System;
using System.Text;
namespace Test_Qt.DotNet.Project.Shared
{
///
/// Mirror of the native BridgeExitCode enum in QtTestSetupBase.h. Keep numeric values in
/// sync with the C++ definition.
///
enum ExitCode
{
Ok = 0,
QTestFailure = 1, // QTest will return 1 on test failure
LocateAssemblyFailed = 101,
WaitForReadyExitedEarly = 102,
WaitForReadyTimeout = 103,
InitAdapterFailed = 104,
FinalizeNotExited = 105,
FinalizeFailed = 106
};
internal static class ExitCodeHelper
{
///
/// Returns a friendly description for bridge-specific exit codes (>= 100).
///
public static string ToString(int exitCode)
{
if (!Enum.IsDefined(typeof(ExitCode), exitCode))
return $"Failed with unknown error, exit({exitCode})";
var code = (ExitCode)exitCode;
if (code is ExitCode.Ok or ExitCode.QTestFailure)
return ""; // 0 = OK, 1 = QTest failures
return code switch {
ExitCode.LocateAssemblyFailed
=> "Failed to locate the generated .NET test assembly",
ExitCode.WaitForReadyExitedEarly
=> "Host process exited before the .NET app signaled readiness",
ExitCode.WaitForReadyTimeout
=> "Timeout while waiting for the .NET app to signal readiness",
ExitCode.InitAdapterFailed
=> "Failed to initialize the Qt/.NET adapter",
ExitCode.FinalizeNotExited
=> "Finalize requested, but the .NET app did not exit in time",
ExitCode.FinalizeFailed
=> "Failed while finalizing the .NET app / adapter",
_ => code.ToString()
};
}
}
///
/// Provides shared helpers for building and running temporary Qt/.NET native test projects.
///
public abstract class ManagedTestBase
{
///
/// Creates the temp project, applies the given options, runs a build, saves the log
/// and asserts that the build succeeded.
///
protected async Task InitializeAndBuildAsync(
TempProject temp,
CreationOptions options,
Action configure = null)
{
ArgumentNullException.ThrowIfNull(temp);
options ??= new();
temp.Create(options);
configure?.Invoke(temp);
var build = await temp.BuildAsync();
temp.SaveLog();
Assert.IsTrue(build.Ok, build.Output);
}
///
/// Default options for a QtQuickTest native project (QtQuickTest harness).
/// The is the path (relative to the test bin dir)
/// where your main.cpp template lives, e.g. QtQuickTest\main.cpp.
///
protected static CreationOptions CreateQtQuickTestOptions(string mainCppTarget)
{
return new CreationOptions
{
PackageReferences = [Packages.QtBridge],
ReplaceGeneratedFiles =
[
// main.cpp from test project -> generated native source
(@"source\cpp\main.cpp", mainCppTarget),
// shared helper headers/sources
(@"source\hpp\QtTestSetupBase.h", @"Shared\QtTestSetupBase.h"),
(@"source\hpp\QtQuickTestSetup.h", @"Shared\QtQuickTestSetup.h"),
(@"source\cpp\QtQuickTestSetup.cpp",
@"Shared\QtQuickTestSetup.cpp"),
],
// Inject extra sources into CMakeLists.txt
AfterSdkTargets = CMake.InjectQtSourcesTargets(
"hpp/QtTestSetupBase.h",
"hpp/QtQuickTestSetup.h",
"cpp/QtQuickTestSetup.cpp")
};
}
///
/// Default options for a QtTest native project (QtTest harness).
/// The is the path (relative to the test bin dir)
/// where your main.cpp template lives, e.g. QtTest\main.cpp.
///
protected static CreationOptions CreateQtTestOptions(string mainCppTarget)
{
return new CreationOptions
{
PackageReferences = [Packages.QtBridge],
ReplaceGeneratedFiles =
[
(@"source\cpp\main.cpp", mainCppTarget),
(@"source\hpp\QtTestSetupBase.h", @"Shared\QtTestSetupBase.h"),
],
AfterSdkTargets = CMake.InjectQtSourcesTargets("hpp/QtTestSetupBase.h")
};
}
}
}