/* Crafter® Build Copyright (C) 2026 Catcrafts® Catcrafts.net This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3.0 as published by the Free Software Foundation; This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ module; #include "Crafter.Build-Api.h" export module Crafter.Build:Test; import std; import :Clang; export namespace Crafter { // One row in a SIMD-march fan-out: a single Test variant compiles the // shared source with `-march= -mtune=`. Passed by span to // Configuration::AddMarchVariants — see Crafter.Math/project.cpp. struct MarchTier { std::string march; std::string mtune; }; // Fluent helper returned by Configuration::AddTest. Holds a back-pointer // to the parent Configuration and the index of the just-pushed Test, so // mutations survive any vector reallocation that subsequent AddTest // calls might trigger. Each setter returns `*this` to support chaining. // // Note: source files (interfaces + implementations) are fixed at // AddTest-time — pass them via the AddTest overload that takes // interfaces. The builder only mutates compile state, deps, runtime // args, and requires; it deliberately does NOT expose Sources() to // avoid the double-`GetInterfacesAndImplementations` footgun (calling // it twice would re-parse the same .cppm files into duplicate Module // entries). struct CRAFTER_API TestBuilder { Configuration* parent; std::size_t index; Test& test() const { return parent->tests[index]; } // Override the path the test's sources resolve against. Defaults to // "./" (project root, where tests//main.cpp lives). Override // only when the test source layout sits under a subdir. TestBuilder& Path(std::filesystem::path p); TestBuilder& Target(std::string t); TestBuilder& March(std::string m); TestBuilder& Mtune(std::string m); TestBuilder& Sysroot(std::filesystem::path s); TestBuilder& Debug(bool d = true); TestBuilder& Define(std::string name, std::string value = ""); TestBuilder& Timeout(std::chrono::seconds s); // Replaces any previously-set args. TestBuilder& Args(std::vector a); // Appends one require entry ("tool:foo" / "file:..." / "env:VAR"). TestBuilder& Requires(std::string r); // Replaces the dependency list. Pointers must outlive the build. TestBuilder& Dependencies(std::vector deps); // Append a single linker flag (-l..., -L..., etc.). TestBuilder& LinkFlag(std::string f); // Append a single compile flag. TestBuilder& CompileFlag(std::string f); }; struct RunTestsOptions { std::vector globs; int jobs = 0; std::optional timeoutOverride; bool listOnly = false; // Single-target run: only tests whose Configuration::target matches // are included. Empty (default) = run every distinct target declared // across discovered tests, plus the host target. Set from --target=... // (when omitted, the harness sweeps all declared targets so cross-arch // tests run by default without the user having to know which targets // exist). std::string targetFilter; // CLI override for --runner=: applies to every test in the run. // Target scoping is unnecessary because targetFilter ensures the run // contains only one target's tests. std::optional runnerOverride; }; struct TestSummary { int passed = 0; int failed = 0; int crashed = 0; int timedOut = 0; int skipped = 0; std::vector results; bool AllPassed() const { return failed == 0 && crashed == 0 && timedOut == 0; } }; CRAFTER_API TestSummary RunTests(Configuration& projectCfg, const RunTestsOptions& opts, std::span projectArgs = {}); CRAFTER_API TestResult RunSingleTest(const Test& test, const std::filesystem::path& binary, std::chrono::seconds timeout); // Parent-project access for test fixtures. Run() sets the pointer to the // root project's Configuration before discovery; fixtures call ParentLib() // to obtain a Configuration* for one of the parent's libraries (or the // parent itself) so they can declare it as a dependency without rebuilding // the lib config from scratch. Lookup is by Configuration::name and // recurses through the parent's dependency graph. CRAFTER_API void SetParentProject(Configuration* parent); CRAFTER_API Configuration* ParentLib(std::string_view name); }