Skip to content

Commit 92db2b3

Browse files
CopilotbedaHovorka
andauthored
Address code review: import order, debug logging, flushEDT() helpers in tests
Agent-Logs-Url: https://github.com/bedaHovorka/interlockSim/sessions/a05d505b-27f4-4dc3-8ad6-c336a6ca4ec8 Co-authored-by: bedaHovorka <5263405+bedaHovorka@users.noreply.github.com>
1 parent c6aaf6c commit 92db2b3

4 files changed

Lines changed: 43 additions & 26 deletions

File tree

desktop-ui/src/main/kotlin/cz/vutbr/fit/interlockSim/gui/SimulationController.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,11 @@ internal class SimulationController(
9898
// Wire speed indicator: notify StatusBar whenever SimulationRunner speed changes.
9999
// The listener is removed when the simulation stops (in stop() or monitor finally).
100100
val listener = PropertyChangeListener { evt ->
101-
val multiplier = evt.newValue as? Double ?: return@PropertyChangeListener
101+
val multiplier = evt.newValue as? Double
102+
if (multiplier == null) {
103+
logger.debug { "Ignoring unexpected ${SimulationRunner.PROP_SPEED_MULTIPLIER} value: ${evt.newValue}" }
104+
return@PropertyChangeListener
105+
}
102106
statusBar?.updateSpeedIndicator(multiplier)
103107
}
104108
speedListener = listener

desktop-ui/src/main/kotlin/cz/vutbr/fit/interlockSim/gui/StatusBar.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ import java.awt.Dimension
1818
import java.awt.event.MouseEvent
1919
import java.awt.event.MouseMotionListener
2020
import javax.swing.JLabel
21-
import kotlin.math.abs
2221
import javax.swing.SwingUtilities
22+
import kotlin.math.abs
2323

2424
/**
2525
* Status bar for displaying context information and mouse motion status

desktop-ui/src/test/kotlin/cz/vutbr/fit/interlockSim/gui/SimulationControllerTest.kt

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -468,8 +468,7 @@ class SimulationControllerTest {
468468
controller.runner!!.speedMultiplier = 2.0
469469

470470
// Flush EDT twice (listener calls invokeLater, so two flushes are needed)
471-
SwingUtilities.invokeAndWait { /* flush 1 */ }
472-
SwingUtilities.invokeAndWait { /* flush 2 */ }
471+
flushEDT()
473472

474473
SwingUtilities.invokeAndWait {
475474
assertThat(findSpeedText(statusBar)).isEqualTo("Speed: 2.0x")
@@ -499,15 +498,13 @@ class SimulationControllerTest {
499498

500499
// Set non-default speed, then stop
501500
controller.runner!!.speedMultiplier = 3.0
502-
SwingUtilities.invokeAndWait { /* flush */ }
503-
SwingUtilities.invokeAndWait { /* flush invokeLater */ }
501+
flushEDT()
504502

505503
controller.stop()
506504
blockSim.countDown()
507505

508506
// Stop calls updateSpeedIndicator(DEFAULT_SPEED) via invokeLater
509-
SwingUtilities.invokeAndWait { /* flush stop's invokeLater */ }
510-
SwingUtilities.invokeAndWait { /* flush nested */ }
507+
flushEDT()
511508

512509
SwingUtilities.invokeAndWait {
513510
assertThat(statusBar.isVisible).isFalse()
@@ -516,6 +513,17 @@ class SimulationControllerTest {
516513

517514
// ── helpers ───────────────────────────────────────────────────────────────
518515

516+
/**
517+
* Flushes the EDT queue by calling [SwingUtilities.invokeAndWait] the given number of times.
518+
*
519+
* Two flushes are typically needed when a background thread fires an event handled by
520+
* [SwingUtilities.invokeLater]: the first flush dispatches the invokeLater task, and the
521+
* second flush ensures any nested EDT work queued by the task is also completed.
522+
*/
523+
private fun flushEDT(times: Int = 2) {
524+
repeat(times) { SwingUtilities.invokeAndWait { /* flush */ } }
525+
}
526+
519527
private fun findSpeedText(statusBar: StatusBar): String? =
520528
statusBar.text.takeIf { it.startsWith("Speed:") }
521529

desktop-ui/src/test/kotlin/cz/vutbr/fit/interlockSim/gui/StatusBarTest.kt

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import assertk.assertions.isEqualTo
1717
import assertk.assertions.isFalse
1818
import assertk.assertions.isTrue
1919
import cz.vutbr.fit.interlockSim.PROGRAM_NAME
20+
import cz.vutbr.fit.interlockSim.objects.core.ContextChangeEvent
2021
import cz.vutbr.fit.interlockSim.testutil.KoinTestBase
2122
import cz.vutbr.fit.interlockSim.testutil.testModuleFull
2223
import io.mockk.mockk
@@ -27,7 +28,7 @@ import org.junit.jupiter.api.Test
2728
import org.koin.core.module.Module
2829
import java.awt.Component
2930
import java.awt.event.MouseEvent
30-
import cz.vutbr.fit.interlockSim.objects.core.ContextChangeEvent
31+
import javax.swing.SwingUtilities
3132

3233
/**
3334
* Tests for StatusBar GUI component.
@@ -165,11 +166,9 @@ class StatusBarTest : KoinTestBase() {
165166
@Test
166167
@DisplayName("updateSpeedIndicator shows speed text when multiplier is not 1.0x")
167168
fun updateSpeedIndicatorShowsSpeedText() {
168-
// updateSpeedIndicator uses invokeLater; use invokeAndWait to flush
169-
javax.swing.SwingUtilities.invokeAndWait {
170-
statusBar.updateSpeedIndicator(2.0)
171-
}
172-
javax.swing.SwingUtilities.invokeAndWait { /* flush invokeLater */ }
169+
// updateSpeedIndicator uses invokeLater; call from non-EDT and flush twice
170+
statusBar.updateSpeedIndicator(2.0)
171+
flushEDT()
173172

174173
assertThat(statusBar.text).isEqualTo("Speed: 2.0x")
175174
assertThat(statusBar.isVisible).isTrue()
@@ -179,30 +178,36 @@ class StatusBarTest : KoinTestBase() {
179178
@DisplayName("updateSpeedIndicator hides status bar at default speed (1.0x)")
180179
fun updateSpeedIndicatorHidesAtDefaultSpeed() {
181180
// First show at non-default speed, then reset
182-
javax.swing.SwingUtilities.invokeAndWait {
183-
statusBar.updateSpeedIndicator(3.0)
184-
}
185-
javax.swing.SwingUtilities.invokeAndWait { /* flush */ }
181+
statusBar.updateSpeedIndicator(3.0)
182+
flushEDT()
186183

187-
javax.swing.SwingUtilities.invokeAndWait {
188-
statusBar.updateSpeedIndicator(1.0)
189-
}
190-
javax.swing.SwingUtilities.invokeAndWait { /* flush */ }
184+
statusBar.updateSpeedIndicator(1.0)
185+
flushEDT()
191186

192187
assertThat(statusBar.isVisible).isFalse()
193188
}
194189

195190
@Test
196191
@DisplayName("updateSpeedIndicator formats multiplier to one decimal place")
197192
fun updateSpeedIndicatorFormatsMultiplier() {
198-
javax.swing.SwingUtilities.invokeAndWait {
199-
statusBar.updateSpeedIndicator(0.5)
200-
}
201-
javax.swing.SwingUtilities.invokeAndWait { /* flush */ }
193+
statusBar.updateSpeedIndicator(0.5)
194+
flushEDT()
202195

203196
assertThat(statusBar.text).isEqualTo("Speed: 0.5x")
204197
}
205198

199+
/**
200+
* Flushes the EDT queue by calling [SwingUtilities.invokeAndWait] twice.
201+
*
202+
* Two flushes are needed when code under test uses [SwingUtilities.invokeLater]:
203+
* the first flush lets the invokeLater task land on EDT, and the second flush
204+
* runs it.
205+
*/
206+
private fun flushEDT() {
207+
SwingUtilities.invokeAndWait { /* flush 1 */ }
208+
SwingUtilities.invokeAndWait { /* flush 2 */ }
209+
}
210+
206211
/**
207212
* Test implementation of StatusProducer as a Component.
208213
* This allows us to test the actual mouse listener behavior.

0 commit comments

Comments
 (0)