18
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-11-15 11:55:12 +01:00

fix(simulation): a test run that can't start ends with the error code and says why

- `--test` is looked for before the rest of the command line is read. An
  unknown option before it (e.g. `-s x.scn --test-timout 90 --test`) used
  to end the run with exit code 0, which a caller reads as a pass.
- `--test-timeout` without a value, or with one that isn't a number of
  seconds, fails the run instead of leaving the default or, through atof,
  turning the timeout off.
- These, a missing -s, a failed start and an exception caught in main()
  end the test through test_manager::conclude(), which writes the usual
  `test: error (exit code 5) ... : <reason>` line to stdout and the log.
  Before, `eu07 --test` alone exited with 5 and nothing anywhere: the
  error went to the log queue and the process ended before the log
  thread wrote it. In test mode main() now stops the log thread and
  waits for it before _Exit().

Outside the test mode nothing changes: conclude() does nothing there.
This commit is contained in:
jerrrrycho
2026-11-08 09:36:28 +01:00
parent 547706b54d
commit 4356e7c3fd
4 changed files with 63 additions and 8 deletions

View File

@@ -30,8 +30,15 @@ http://mozilla.org/MPL/2.0/.
#include "utilities/Timer.h"
#include "utilities/dictionary.h"
#include "version_info.h"
#include "simulation/simulationtest.h"
#include <algorithm>
#include <charconv>
#include <chrono>
#include <cmath>
#include <format>
#include <optional>
#include <span>
#include <string_view>
#include "utilities/translation.h"
#if WITH_DISCORD_RPC
@@ -1174,6 +1181,16 @@ void apply_test_mode_settings()
Global.random_seed = seed_of("test");
}
// seconds given on the command line: a number, not negative. returns nothing for anything else
std::optional<double> parse_seconds(std::string_view const Text)
{
auto const *const last{Text.data() + Text.size()};
double value{0.0};
if (auto const [parsed, status]{std::from_chars(Text.data(), last, value)}; status != std::errc{} || parsed != last || false == std::isfinite(value) || value < 0.0)
return std::nullopt;
return value;
}
} // namespace
int eu07_application::init_settings(int Argc, char *Argv[])
@@ -1191,6 +1208,10 @@ int eu07_application::init_settings(int Argc, char *Argv[])
Global.LoadIniFile("eu07.ini");
}
// a test run is known before the rest of the command line is read, so a command line it can't take
// ends with the error code of the test, not with 0, which would pass it
Global.test.enabled = std::ranges::any_of(std::span(Argv, static_cast<std::size_t>(Argc)), [](char const *Argument) { return std::string_view(Argument) == "--test"; });
// process command line arguments
bool sceneryfromcommandline{false};
bool editwithoutscenery{false};
@@ -1244,11 +1265,15 @@ int eu07_application::init_settings(int Argc, char *Argv[])
}
else if (token == "--test-timeout")
{
if (i + 1 < Argc)
auto const timeout{i + 1 < Argc ? parse_seconds(Argv[++i]) : std::nullopt};
if (false == timeout.has_value())
{
Global.test.timeout = std::max(0.0, std::atof(Argv[++i]));
Global.test.timeout_from_command_line = true;
// a typo would otherwise turn the timeout off
simulation::test().conclude(simulation::test_result::error, "--test-timeout needs a number of seconds");
return -1;
}
Global.test.timeout = *timeout;
Global.test.timeout_from_command_line = true;
}
else if (token == "-ini")
{
@@ -1267,6 +1292,7 @@ int eu07_application::init_settings(int Argc, char *Argv[])
<< " [-seed number|word]"
<< " [-ini settingsfile]"
<< " [--test [--test-timeout seconds]]" << std::endl;
simulation::test().conclude(simulation::test_result::error, std::format("unknown command line argument {}", token));
return -1;
}
}
@@ -1277,7 +1303,7 @@ int eu07_application::init_settings(int Argc, char *Argv[])
{
if (false == sceneryfromcommandline || Global.SceneryFile.empty())
{
ErrorLog("test: --test needs a scenery given with -s");
simulation::test().conclude(simulation::test_result::error, "--test needs a scenery given with -s");
return -1;
}
apply_test_mode_settings();