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

feat(simulation): test.no_movement_before_pass, a pass that doesn't wait for a stop

The config key from eu07/maszyna#541. By default (yes) a pass reported to
__test.result waits until every vehicle has stood still for 1 s; with no it
ends the test at once. The key is listed with the other test.* settings in the
log and in the test start line.

Scenario tests: new case test_mode_pass_while_moving reports the pass from
event2 of tor1k as the train runs onto it and checks the run ended with the
train still moving (new check ends_moving). The README lists the test.* keys
with their defaults and the input the test mode ignores.
This commit is contained in:
jerrrrycho
2026-11-07 17:38:38 +01:00
parent dd019d88ba
commit 6ccf4b14bf
6 changed files with 71 additions and 3 deletions

View File

@@ -82,9 +82,10 @@ void test_manager::start()
}
// a pause set by the scenery or the settings would never be lifted, nobody is there to press the key
Global.iPause = 0;
WriteLog(std::format("test: started, timeout {:.0f} s, standstill {:.0f} s{}{}", Global.test.timeout, Global.test.standstill,
WriteLog(std::format("test: started, timeout {:.0f} s, standstill {:.0f} s{}{}{}", Global.test.timeout, Global.test.standstill,
Global.test.pass_on_standstill ? ", standstill passes" : "",
Global.test.fail_if_stop_overran ? "" : ", signals passed at danger allowed"));
Global.test.fail_if_stop_overran ? "" : ", signals passed at danger allowed",
Global.test.no_movement_before_pass ? "" : ", pass without waiting for a stop"));
}
void test_manager::update(double const Deltatime)
@@ -103,6 +104,11 @@ void test_manager::update(double const Deltatime)
finish(test_result::fail, std::format("__test.result set to 0{}", reason));
return;
}
if (holds(value, 1.0) && false == Global.test.no_movement_before_pass)
{
finish(test_result::pass, std::format("__test.result set to 1{}", reason));
return;
}
if (holds(value, 1.0) && false == m_passrequested)
{
m_passrequested = true;

View File

@@ -23,6 +23,9 @@ With `--test` the simulator:
data) but no textures, and the window stays hidden,
- has no sound, no network, no python, no pause (not even one set by the scenery), and
no crash dialog,
- takes no input from outside: keys and mouse sent to its window, gamepad, UART (a cab
desk), ZeroMQ and commands sent by other programs (`WM_COPYDATA`) are all ignored, and
motion telemetry is off,
- runs the simulation as fast as it can in fixed steps of 0.03 s of simulation time per
frame (three 10 ms physics steps), whatever the real time, the time speed or the machine,
- seeds its random numbers with a fixed seed unless `-seed` or `randomseed` gives one, so two
@@ -48,7 +51,7 @@ The test ends with the first of these:
| exit code | result | when |
| --- | --- | --- |
| 0 | pass | `__test.result` was set to 1 and then every vehicle stood still for 1 s, so a train still moving towards a signal at stop has to stop first. Also the standstill end with `test.pass_on_standstill yes` |
| 0 | pass | `__test.result` was set to 1 and then every vehicle stood still for 1 s, so a train still moving towards a signal at stop has to stop first (with `test.no_movement_before_pass no` the pass ends the test at once). Also the standstill end with `test.pass_on_standstill yes` |
| 1 | fail | `__test.result` was set to 0; ends at once |
| 2 | signal passed at danger | a train went past a signal showing stop (`SetVelocity 0 0`; `SetVelocity 0 x` on automatic block, which may be passed after a stop, doesn't count); ends at once, unless `test.fail_if_stop_overran no` |
| 3 | timeout | `test.timeout` seconds of simulation time went by (default 3600) |
@@ -65,9 +68,18 @@ test.timeout 600
test.standstill 120
test.pass_on_standstill no
test.fail_if_stop_overran yes
test.no_movement_before_pass yes
endconfig
```
| key | default | meaning |
| --- | --- | --- |
| `test.timeout` | 3600 | seconds of simulation time before the test ends as `timeout`; 0 = never |
| `test.standstill` | 300 | seconds with every vehicle still and no result before the test ends as `standstill`; 0 = never |
| `test.pass_on_standstill` | no | the standstill end passes the test instead |
| `test.fail_if_stop_overran` | yes | a signal passed at danger ends the test; with `no` it's only logged |
| `test.no_movement_before_pass` | yes | a pass waits until every vehicle stands still; with `no` it ends the test at once |
`--test-timeout` on the command line wins over `test.timeout` of the scenery.
A signal is passed at danger when the head of a train goes past a signal which its driver
@@ -155,6 +167,8 @@ on `tor1k`, the track in front of the signal.
The `test_mode_*` cases show the ends of the test mode: `test_mode_pass` (exit 0, the pass
event), `test_mode_signal_passed_at_danger` (exit 2), `test_mode_timeout` (exit 3, from
`test.timeout`) and `test_mode_standstill` (exit 4, from `test.standstill`).
`test_mode_pass_while_moving` reports the pass from `event2` of `tor1k` (the direction the train runs), as the train runs onto
it, with `test.no_movement_before_pass no`, so the test ends with the train still moving.
Checks (speeds in km/h, times in seconds of physicslog time, distances in metres). Most use
the physicslog Velocity column, which is the wheel speed: it stays at 0 while the wheels are
@@ -178,6 +192,8 @@ the row instead, logged by builds from this branch on.
moving off, the wheels stop slipping within `within` seconds.
- `holds_still` `moving_speed`, `stop_speed`, `max_distance` (*vehicle speed*): once stopped
after moving off, moves no more than `max_distance` metres, e.g. no creeping on locked wheels.
- `ends_moving` `min_speed`: the last row of the physicslog is at `min_speed` or faster, e.g.
the test ended without waiting for the train to stop.
New check types go in `CHECKS` in `run.py`; each gets the physicslog rows and the check's
parameters and returns `(passed, detail)`.

View File

@@ -0,0 +1,28 @@
{
"description": "Test mode, pass without waiting for a stop: like test_mode_pass, but event2 of the track in front of the exit signal reports the pass as the train runs onto it, and with test.no_movement_before_pass no the test ends at once, the train still moving.",
"base_scenery": "td.scn",
"time": "10:34",
"fragment": "td_red_signal_pass.scn",
"track_events": {
"tor1k": "event2 test_pass"
},
"test_config": [
"test.no_movement_before_pass no"
],
"vars": {
"consist": "node -1 0 {{vehicle}} dynamic pkp\\4e_v1 4e-004 4e 0 headdriver 0 0 enddynamic"
},
"expect": "pass",
"timeout": 600,
"checks": [
{
"type": "starts",
"min_speed": 5,
"within": 150
},
{
"type": "ends_moving",
"min_speed": 3
}
]
}

View File

@@ -416,6 +416,15 @@ def check_holds_still(rows, moving_speed, stop_speed, max_distance):
return d <= max_distance, detail
def check_ends_moving(rows, min_speed):
"""The run ended with the vehicle still moving, e.g. a pass that didn't wait for the trains to stop."""
if not rows:
return False, "the physicslog is empty"
last = rows[-1]
ok = last[COL_VELOCITY] >= min_speed
return ok, f"last row t={last[COL_TIME]:.1f}s, v={last[COL_VELOCITY]:.1f} km/h (wanted >= {min_speed})"
def check_slip_clears(rows, moving_speed, stop_speed, within):
"""Once the vehicle has stopped after moving off, its wheels stop slipping within `within` seconds
(a vehicle left skidding on locked wheels keeps its brakes capped by the sliding adhesion)."""
@@ -444,6 +453,7 @@ CHECKS = {
"stops": check_stops,
"stays_stopped": check_stays_stopped,
"distance": check_distance,
"ends_moving": check_ends_moving,
}

View File

@@ -487,6 +487,12 @@ bool global_settings::ConfigParseTest(cParser& Parser, const std::string& token)
return true;
}
if (token == "test.no_movement_before_pass")
{
ParseOne(Parser, test.no_movement_before_pass);
return true;
}
return false;
}
@@ -1783,6 +1789,7 @@ global_settings::export_as_text( std::ostream &Output ) const {
export_as_text( Output, "test.standstill", test.standstill );
export_as_text( Output, "test.pass_on_standstill", test.pass_on_standstill );
export_as_text( Output, "test.fail_if_stop_overran", test.fail_if_stop_overran );
export_as_text( Output, "test.no_movement_before_pass", test.no_movement_before_pass );
export_as_text( Output, "gfx.envmap.enabled", gfx_envmap_enabled );
export_as_text( Output, "gfx.postfx.motionblur.enabled", gfx_postfx_motionblur_enabled );
export_as_text( Output, "gfx.postfx.motionblur.shutter", gfx_postfx_motionblur_shutter );

View File

@@ -93,6 +93,7 @@ struct global_settings {
double standstill{ 300.0 }; // [s] every vehicle standing still this long ends the test; 0 = never
bool pass_on_standstill{ false }; // the standstill end passes the test instead of failing it
bool fail_if_stop_overran{ true }; // a train passing a signal at stop ends the test as failed; with false it's only logged
bool no_movement_before_pass{ true }; // a pass waits until every vehicle stands still; with false it ends the test at once
bool timeout_from_command_line{ false }; // --test-timeout given, the scenery doesn't override it
} test;
bool editor_tracks{ false }; // F3 track workspace: draw and pick tracks without the scenery draw-range cap