@@ -27,47 +27,55 @@ import org.koin.test.inject
2727private val logger = KotlinLogging .logger {}
2828
2929/* *
30- * Integration tests for Train .reverseDirection() functionality.
30+ * Unit tests for Timetable .reverseDirection() functionality.
3131 *
3232 * ## Purpose
3333 *
34- * These tests verify that trains can reverse their direction of travel during simulation,
35- * simulating the train engineer moving to the opposite end of the train.
34+ * These tests verify the timetable reversal logic that supports bidirectional
35+ * train operation. The reversal swaps the In/Out destinations and is used by
36+ * Train.reverseDirection().
3637 *
3738 * ## Test Scenarios
3839 *
3940 * Uses vyhybna.xml network configuration:
40- * - Train reverses direction when stopped
41- * - Validates preconditions (train must be stopped)
42- * - Verifies In/Out destinations are swapped
43- * - Tests that reversed train can complete journey
41+ * - Timetable reverses In/Out destinations
42+ * - Validates destination swap is correct
43+ * - Verifies other timetable properties remain unchanged
44+ * - Tests that reversed timetable is usable for train creation
45+ *
46+ * ## Note on Train.reverseDirection()
47+ *
48+ * Train.reverseDirection() includes additional simulation behavior (hold(30.0)
49+ * to simulate engineer movement) that requires running simulation. That full
50+ * integration test scenario requires stopping a train mid-simulation in jDisco,
51+ * which is complex to test. This test focuses on the core timetable reversal
52+ * logic that Train.reverseDirection() delegates to.
4453 *
4554 * ## Conservative Approach
4655 *
4756 * Per CLAUDE.md guidance for sim/ package:
4857 * - Uses existing vyhybna.xml network (realistic topology)
49- * - Short simulation times (30-60 seconds)
50- * - Validates train state without modifying Train class internals
51- * - Tests observe behavior through public APIs only
58+ * - Tests core logic without running full simulation
59+ * - Validates state through public APIs only
5260 *
5361 * ## Railway Context
5462 *
5563 * This feature simulates a simplified version of locomotive coupling/uncoupling:
5664 * - In reality, only possible with certain modern train types
5765 * - Simulation allows this for any train for flexibility
58- * - Engineer movement delay (30s) provides realistic timing
66+ * - Engineer movement delay (30s) in Train.reverseDirection() provides realistic timing
5967 *
6068 * @since 2026-02-06 (GitHub #62)
6169 */
6270@Tag(" integration-test" )
63- @DisplayName(" Train Reverse Direction - Integration Tests" )
71+ @DisplayName(" Timetable Reverse Direction - Unit Tests" )
6472class TrainReverseDirectionTest : KoinTestBase () {
6573 private val simulationContextFactory: SimulationContextFactory by inject()
6674 private lateinit var context: DefaultSimulationContext
6775
6876 @BeforeEach
6977 fun setUp () {
70- logger.info { " Loading vyhybna.xml for train reverse direction testing" }
78+ logger.info { " Loading vyhybna.xml for timetable reverse direction testing" }
7179
7280 // Load vyhybna.xml - realistic railway network
7381 val xml =
@@ -78,20 +86,19 @@ class TrainReverseDirectionTest : KoinTestBase() {
7886
7987 context = simulationContextFactory.createContext(xml) as DefaultSimulationContext
8088
81- logger.info { " Train reverse direction test setup complete" }
89+ logger.info { " Timetable reverse direction test setup complete" }
8290 }
8391
8492 @AfterEach
8593 fun tearDown () {
86- // Only stop if simulation was actually started
87- // These tests don't run the simulation, just test the API
94+ // These tests don't run the simulation, just test the timetable API
8895 if (::context.isInitialized) {
89- logger.info { " Train reverse direction test teardown complete" }
96+ logger.info { " Timetable reverse direction test teardown complete" }
9097 }
9198 }
9299
93100 @Test
94- fun `train can reverse direction when stopped ` () {
101+ fun `timetable can reverse In and Out destinations ` () {
95102 // Arrange
96103 val inOuts = context.getInOuts().toList()
97104 assertThat(inOuts.size >= 2 ).isEqualTo(true )
@@ -114,20 +121,13 @@ class TrainReverseDirectionTest : KoinTestBase() {
114121 assertThat(timetable.getIn()).isEqualTo(inPoint)
115122 assertThat(timetable.getOut()).isEqualTo(outPoint)
116123
117- // Act - Activate train but don't start simulation yet
118- // We'll test the reverseDirection method directly
119- // This is a unit-style test within an integration test framework
120-
121- // Since we can't easily stop a train mid-simulation in jDisco without
122- // running the full simulation, we'll test the method when train is in
123- // initial stopped state (velocity = 0)
124+ // Act - Test the timetable reversal logic directly
125+ // Note: Train.reverseDirection() calls this same method, but also includes
126+ // hold(30.0) simulation delay which requires running simulation context
124127 assertThat(train.getVelocity()).isEqualTo(0.0 )
125-
126- // Reverse direction (this will use hold() internally, so we need to activate as Process)
127- // For this test, we'll verify the timetable swap happened correctly
128128 timetable.reverseDirection()
129129
130- // Assert
130+ // Assert - Verify In/Out swap
131131 assertThat(timetable.getIn()).isEqualTo(outPoint)
132132 assertThat(timetable.getOut()).isEqualTo(inPoint)
133133 }
0 commit comments