|
12 | 12 | package cz.vutbr.fit.interlockSim.gui |
13 | 13 |
|
14 | 14 | import assertk.assertThat |
15 | | -import assertk.assertions.isEqualTo |
16 | 15 | import assertk.assertions.isFalse |
17 | 16 | import assertk.assertions.isTrue |
18 | | -import cz.vutbr.fit.interlockSim.context.EditingContextFactory |
| 17 | +import cz.vutbr.fit.interlockSim.testutil.KoinTestBase |
19 | 18 | import cz.vutbr.fit.interlockSim.testutil.TestContextBuilder |
20 | | -import org.junit.jupiter.api.BeforeEach |
21 | 19 | import org.junit.jupiter.api.DisplayName |
22 | 20 | import org.junit.jupiter.api.Test |
23 | | -import org.junit.jupiter.api.Timeout |
24 | | -import org.junit.jupiter.api.io.TempDir |
25 | | -import org.koin.java.KoinJavaComponent.getKoin |
26 | | -import java.io.File |
27 | | -import java.nio.file.Path |
28 | | -import java.util.concurrent.TimeUnit |
29 | 21 |
|
30 | 22 | /** |
31 | 23 | * Tests for InOut validation during save operation. |
32 | 24 | * |
33 | 25 | * **Requirements (Issue #80):** |
34 | 26 | * - Save operation must validate InOut count before saving |
35 | | - * - Minimum 2 InOut elements required |
36 | | - * - User-friendly error dialog shown if validation fails |
| 27 | + * - Minimum [cz.vutbr.fit.interlockSim.xml.XMLContextFactory.MIN_INOUT_ELEMENTS] InOut required |
37 | 28 | * - Save operation blocked until requirement is met |
38 | 29 | * |
39 | 30 | * **Test Coverage:** |
40 | 31 | * - Save with 0 InOuts - should fail validation |
41 | | - * - Save with 1 InOut - should fail validation |
42 | | - * - Save with 2 InOuts - should succeed |
43 | | - * - Save with 3+ InOuts - should succeed |
| 32 | + * - Save with 1 InOut - should pass (min is 1 per PR #356 bidirectional operation) |
| 33 | + * - Save with 2 InOuts - should pass |
| 34 | + * - Save with 3+ InOuts - should pass |
44 | 35 | * |
45 | | - * Note: These tests verify the validation logic. GUI dialog appearance |
46 | | - * is not tested as it requires UI automation. |
| 36 | + * Tests call [MenuBar.validateForSave] directly — no dialogs, no EDT, no reflection. |
47 | 37 | */ |
48 | 38 | @DisplayName("InOut Save Validation") |
49 | | -class InOutSaveValidationTest : AbstractFrameTestBase() { |
50 | | - @TempDir |
51 | | - lateinit var tempDir: Path |
52 | | - |
53 | | - private lateinit var frame: Frame |
54 | | - private lateinit var contextFactory: EditingContextFactory |
55 | | - |
56 | | - @BeforeEach |
57 | | - override fun setUp() { |
58 | | - super.setUp() |
59 | | - |
60 | | - runOnEDT { |
61 | | - frame = Frame() |
62 | | - frames.add(frame) |
63 | | - contextFactory = getKoin().get() |
64 | | - } |
65 | | - } |
| 39 | +class InOutSaveValidationTest : KoinTestBase() { |
66 | 40 |
|
67 | 41 | @Test |
68 | | - @Timeout(value = 10, unit = TimeUnit.SECONDS) |
69 | 42 | @DisplayName("context with 0 InOuts cannot be saved") |
70 | 43 | fun contextWith0InOutsCannotBeSaved() { |
71 | | - val testFile = tempDir.resolve("test-0-inouts.xml").toFile() |
72 | | - |
73 | | - runOnEDT { |
74 | | - // Create empty context (0 InOuts) |
75 | | - val builder = TestContextBuilder() |
76 | | - val editingContext = builder.buildEditingContext() |
77 | | - |
78 | | - // Set context in frame |
79 | | - frame.setContext(editingContext) |
80 | | - |
81 | | - // Attempt to save - should fail validation |
82 | | - val menuBar = frame.jMenuBar as MenuBar |
83 | | - |
84 | | - // Use reflection to access performSave method |
85 | | - val performSaveMethod = MenuBar::class.java.getDeclaredMethod("performSave", File::class.java) |
86 | | - performSaveMethod.isAccessible = true |
87 | | - val result = performSaveMethod.invoke(menuBar, testFile) as Boolean |
88 | | - |
89 | | - // Verify save was blocked |
90 | | - assertThat(result).isFalse() |
91 | | - assertThat(testFile.exists()).isFalse() |
92 | | - |
93 | | - editingContext.close() |
94 | | - } |
| 44 | + val context = TestContextBuilder().buildEditingContext() |
| 45 | + assertThat(MenuBar.validateForSave(context)).isFalse() |
95 | 46 | } |
96 | 47 |
|
97 | 48 | @Test |
98 | | - @Timeout(value = 10, unit = TimeUnit.SECONDS) |
99 | | - @DisplayName("context with 1 InOut cannot be saved") |
100 | | - fun contextWith1InOutCannotBeSaved() { |
101 | | - val testFile = tempDir.resolve("test-1-inout.xml").toFile() |
102 | | - |
103 | | - runOnEDT { |
104 | | - // Create context with 1 InOut |
105 | | - val builder = TestContextBuilder() |
106 | | - .withInOut("OnlyEntry", 1, 1, true) |
107 | | - val editingContext = builder.buildEditingContext() |
108 | | - |
109 | | - // Set context in frame |
110 | | - frame.setContext(editingContext) |
111 | | - |
112 | | - // Attempt to save - should fail validation |
113 | | - val menuBar = frame.jMenuBar as MenuBar |
114 | | - |
115 | | - val performSaveMethod = MenuBar::class.java.getDeclaredMethod("performSave", File::class.java) |
116 | | - performSaveMethod.isAccessible = true |
117 | | - val result = performSaveMethod.invoke(menuBar, testFile) as Boolean |
118 | | - |
119 | | - // Verify save was blocked |
120 | | - assertThat(result).isFalse() |
121 | | - assertThat(testFile.exists()).isFalse() |
122 | | - |
123 | | - editingContext.close() |
124 | | - } |
| 49 | + @DisplayName("context with 1 InOut can be saved") |
| 50 | + fun contextWith1InOutCanBeSaved() { |
| 51 | + val context = TestContextBuilder() |
| 52 | + .withInOut("OnlyEntry", 1, 1, true) |
| 53 | + .buildEditingContext() |
| 54 | + assertThat(MenuBar.validateForSave(context)).isTrue() |
125 | 55 | } |
126 | 56 |
|
127 | 57 | @Test |
128 | | - @Timeout(value = 10, unit = TimeUnit.SECONDS) |
129 | 58 | @DisplayName("context with 2 InOuts can be saved") |
130 | 59 | fun contextWith2InOutsCanBeSaved() { |
131 | | - val testFile = tempDir.resolve("test-2-inouts.xml").toFile() |
132 | | - |
133 | | - runOnEDT { |
134 | | - // Create context with 2 InOuts |
135 | | - val builder = TestContextBuilder() |
136 | | - .withInOut("Entry", 1, 1, true) |
137 | | - .withInOut("Exit", 10, 10, false) |
138 | | - .withConnection(1, 1, 10, 10, 100.0, 80.0) |
139 | | - val editingContext = builder.buildEditingContext() |
140 | | - |
141 | | - // Set context in frame |
142 | | - frame.setContext(editingContext) |
143 | | - |
144 | | - // Attempt to save - should succeed |
145 | | - val menuBar = frame.jMenuBar as MenuBar |
146 | | - |
147 | | - val performSaveMethod = MenuBar::class.java.getDeclaredMethod("performSave", File::class.java) |
148 | | - performSaveMethod.isAccessible = true |
149 | | - val result = performSaveMethod.invoke(menuBar, testFile) as Boolean |
150 | | - |
151 | | - // Verify save succeeded |
152 | | - assertThat(result).isTrue() |
153 | | - assertThat(testFile.exists()).isTrue() |
154 | | - |
155 | | - editingContext.close() |
156 | | - } |
| 60 | + val context = TestContextBuilder() |
| 61 | + .withInOut("Entry", 1, 1, true) |
| 62 | + .withInOut("Exit", 10, 10, false) |
| 63 | + .buildEditingContext() |
| 64 | + assertThat(MenuBar.validateForSave(context)).isTrue() |
157 | 65 | } |
158 | 66 |
|
159 | 67 | @Test |
160 | | - @Timeout(value = 10, unit = TimeUnit.SECONDS) |
161 | 68 | @DisplayName("context with 3 InOuts can be saved") |
162 | 69 | fun contextWith3InOutsCanBeSaved() { |
163 | | - val testFile = tempDir.resolve("test-3-inouts.xml").toFile() |
164 | | - |
165 | | - runOnEDT { |
166 | | - // Create context with 3 InOuts |
167 | | - val builder = TestContextBuilder() |
168 | | - .withInOut("Entry1", 1, 1, true) |
169 | | - .withInOut("Exit1", 10, 10, false) |
170 | | - .withInOut("Entry2", 5, 5, true) |
171 | | - .withConnection(1, 1, 10, 10, 100.0, 80.0) |
172 | | - .withConnection(5, 5, 10, 10, 50.0, 80.0) |
173 | | - val editingContext = builder.buildEditingContext() |
174 | | - |
175 | | - // Set context in frame |
176 | | - frame.setContext(editingContext) |
177 | | - |
178 | | - // Attempt to save - should succeed |
179 | | - val menuBar = frame.jMenuBar as MenuBar |
180 | | - |
181 | | - val performSaveMethod = MenuBar::class.java.getDeclaredMethod("performSave", File::class.java) |
182 | | - performSaveMethod.isAccessible = true |
183 | | - val result = performSaveMethod.invoke(menuBar, testFile) as Boolean |
184 | | - |
185 | | - // Verify save succeeded |
186 | | - assertThat(result).isTrue() |
187 | | - assertThat(testFile.exists()).isTrue() |
188 | | - |
189 | | - editingContext.close() |
190 | | - } |
191 | | - } |
192 | | - |
193 | | - @Test |
194 | | - @Timeout(value = 10, unit = TimeUnit.SECONDS) |
195 | | - @DisplayName("validation message includes current InOut count") |
196 | | - fun validationMessageIncludesCurrentInOutCount() { |
197 | | - val testFile = tempDir.resolve("test-validation-message.xml").toFile() |
198 | | - |
199 | | - runOnEDT { |
200 | | - // Create context with 1 InOut |
201 | | - val builder = TestContextBuilder() |
202 | | - .withInOut("OnlyEntry", 1, 1, true) |
203 | | - val editingContext = builder.buildEditingContext() |
204 | | - |
205 | | - // Set context in frame |
206 | | - frame.setContext(editingContext) |
207 | | - |
208 | | - // Verify InOut count in context |
209 | | - assertThat(editingContext.getInOuts().size).isEqualTo(1) |
210 | | - |
211 | | - editingContext.close() |
212 | | - } |
| 70 | + val context = TestContextBuilder() |
| 71 | + .withInOut("Entry1", 1, 1, true) |
| 72 | + .withInOut("Exit1", 10, 10, false) |
| 73 | + .withInOut("Entry2", 5, 5, true) |
| 74 | + .buildEditingContext() |
| 75 | + assertThat(MenuBar.validateForSave(context)).isTrue() |
213 | 76 | } |
214 | 77 | } |
0 commit comments