diff --git a/src/main/kotlin/automaton/constructor/controller/TestsController.kt b/src/main/kotlin/automaton/constructor/controller/TestsController.kt index c5b4106..15b9d5b 100644 --- a/src/main/kotlin/automaton/constructor/controller/TestsController.kt +++ b/src/main/kotlin/automaton/constructor/controller/TestsController.kt @@ -4,10 +4,13 @@ import automaton.constructor.model.automaton.Automaton import automaton.constructor.model.data.MemoryUnitDescriptorData import automaton.constructor.model.data.serializersModule import automaton.constructor.model.memory.MemoryUnitDescriptor +import automaton.constructor.model.memory.Test +import automaton.constructor.model.memory.TestsForSerializing import automaton.constructor.model.module.executor.ExecutionStatus import automaton.constructor.model.module.executor.Executor import automaton.constructor.utils.I18N import automaton.constructor.utils.addOnSuccess +import automaton.constructor.utils.createExecutorAndRun import automaton.constructor.utils.runAsyncWithDialog import automaton.constructor.view.TestAndResult import automaton.constructor.view.TestsView @@ -25,23 +28,21 @@ import kotlinx.serialization.modules.SerializersModule import tornadofx.* import java.io.File -data class Test(val input: List) - -@Serializable -data class TestsForSerializing(val tests: List>, val automatonType: String) - class TestsController(val openedAutomaton: Automaton) : Controller() { var wereTestsModified = false + private val formatForSerializing = Json { serializersModule = SerializersModule { prettyPrint = true include(MemoryUnitDescriptorData.serializersModule) } } + fun saveTests(tests: List, uiComponent: UIComponent) { val file = chooseFile(FileChooserMode.Save) ?: return saveAsync(tests, uiComponent, file) } + private fun saveAsync(tests: List, uiComponent: UIComponent, file: File): Task { return uiComponent.runAsyncWithDialog( I18N.messages.getString("TestsController.Saving"), @@ -54,21 +55,31 @@ class TestsController(val openedAutomaton: Automaton) : Controller() { wereTestsModified = false } } + fun createTests() { val testsWindow = find(mapOf(TestsView::controller to this)) testsWindow.title = "Test" testsWindow.openWindow() } + private fun chooseFile(mode: FileChooserMode): File? = chooseFile( filters = arrayOf(FileChooser.ExtensionFilter("1", "*.json")), mode = mode ).firstOrNull() + fun openTests(uiComponent: UIComponent): List { val file = chooseFile(FileChooserMode.Single) ?: return listOf() - return openAsync(uiComponent, file).get() + val tests = openAsync(uiComponent, file).get() + return if (tests == null || !openedAutomaton.canUseTheseDescriptors(tests[0].input)) { + error(I18N.messages.getString("TestsController.UnableToOpen")) + listOf() + } else { + tests + } } - private fun openAsync(uiComponent: UIComponent, file: File): Task> { + + private fun openAsync(uiComponent: UIComponent, file: File): Task?> { return uiComponent.runAsyncWithDialog( I18N.messages.getString("TestsController.Opening"), daemon = false @@ -76,32 +87,26 @@ class TestsController(val openedAutomaton: Automaton) : Controller() { val deserializedTests = formatForSerializing.decodeFromString(file.readText()) if (deserializedTests.automatonType != openedAutomaton::class.simpleName!!) { - throw RuntimeException( - I18N.messages.getString("TestsController.UnableToOpen") - ) + null + } else { + deserializedTests.tests.map { test -> Test(test.map { it.createDescriptor() }) } } - deserializedTests.tests.map { test -> Test(test.map { it.createDescriptor() }) } } addOnSuccess { wereTestsModified = false } } + fun runOnTests(tests: List) { val testsAndResults = mutableListOf() tests.forEach { test -> val memory = openedAutomaton.memoryDescriptors.zip(test.input).map { (descriptor, content) -> descriptor.createMemoryUnit(content) } - val executor = Executor(openedAutomaton) - executor.start(memory) - executor.runFor() - val executionResult = when (executor.status) { - ExecutionStatus.ACCEPTED -> I18N.messages.getString("ExecutorController.Executor.Status.Accepted") - ExecutionStatus.REJECTED -> I18N.messages.getString("ExecutorController.Executor.Status.Rejected") - ExecutionStatus.FROZEN -> I18N.messages.getString("ExecutorController.Executor.Status.Frozen") - ExecutionStatus.RUNNING -> I18N.messages.getString("ExecutorController.Executor.Status.Running") + val executorResult = createExecutorAndRun(openedAutomaton, memory) + if (executorResult == null) { + return@runOnTests } - val graphic = executor.acceptedExeStates.firstOrNull()?.let { executionLeafView(it) } - testsAndResults.add(TestAndResult(test, executionResult, graphic)) + testsAndResults.add(TestAndResult(test, executorResult.executionResult, executorResult.graphic)) } val testsResultsWindow = find(mapOf(TestsResultsFragment::testsAndResults to testsAndResults)) testsResultsWindow.title = "Tests results" diff --git a/src/main/kotlin/automaton/constructor/controller/module/executor/ExecutorController.kt b/src/main/kotlin/automaton/constructor/controller/module/executor/ExecutorController.kt index 58d4c33..c50dd76 100644 --- a/src/main/kotlin/automaton/constructor/controller/module/executor/ExecutorController.kt +++ b/src/main/kotlin/automaton/constructor/controller/module/executor/ExecutorController.kt @@ -1,12 +1,11 @@ package automaton.constructor.controller.module.executor import automaton.constructor.model.automaton.Automaton -import automaton.constructor.model.module.executor.ExecutionStatus.* import automaton.constructor.model.module.executor.Executor import automaton.constructor.model.module.executor.SteppingStrategy -import automaton.constructor.model.module.problems import automaton.constructor.utils.I18N -import automaton.constructor.view.module.executor.executionLeafView +import automaton.constructor.utils.createExecutorAndRun +import automaton.constructor.utils.getNewExecutorOrNull import tornadofx.* class ExecutorController(viewedAutomaton: Automaton, private val uiComponent: UIComponent) : Controller() { @@ -20,40 +19,20 @@ class ExecutorController(viewedAutomaton: Automaton, private val uiComponent: UI it.automaton.clearExecutionStates() // faster analog of executor.stop() debuggingExecutor = null } ?: run { - val executor = startNewExecutorOrNull() ?: return@toggleRun - executor.runFor() - val executionResult = when (executor.status) { - ACCEPTED -> I18N.messages.getString("ExecutorController.Executor.Status.Accepted") - REJECTED -> I18N.messages.getString("ExecutorController.Executor.Status.Rejected") - FROZEN -> I18N.messages.getString("ExecutorController.Executor.Status.Frozen") - RUNNING -> I18N.messages.getString("ExecutorController.Executor.Status.Running") + val executorResult = createExecutorAndRun(selectedAutomaton) + if (executorResult != null) { + information( + I18N.messages.getString("ExecutorController.ExecutionResult"), + executorResult.executionResult, + graphic = executorResult.graphic, + title = I18N.messages.getString("Dialog.information"), + owner = uiComponent.currentWindow + ) } - val graphic = executor.acceptedExeStates.firstOrNull()?.let { executionLeafView(it) } - executor.automaton.clearExecutionStates() // faster analog of executor.stop() - information( - I18N.messages.getString("ExecutorController.ExecutionResult"), - executionResult, - graphic = graphic, - title = I18N.messages.getString("Dialog.information"), - owner = uiComponent.currentWindow - ) } } fun step(strategy: SteppingStrategy) = debuggingExecutor?.step(strategy) ?: run { - debuggingExecutor = startNewExecutorOrNull() - } - - private fun startNewExecutorOrNull(): Executor? { - if (selectedAutomaton.problems.isNotEmpty()) { - error( - I18N.messages.getString("ExecutorController.Error.ExecutionFailed"), - selectedAutomaton.problems.joinToString("\n") { it.message }, - title = I18N.messages.getString("Dialog.error"), - owner = uiComponent.currentWindow - ) - return null - } - return Executor(selectedAutomaton).apply { start() } + debuggingExecutor = getNewExecutorOrNull(selectedAutomaton) } } diff --git a/src/main/kotlin/automaton/constructor/model/automaton/AbstractAutomaton.kt b/src/main/kotlin/automaton/constructor/model/automaton/AbstractAutomaton.kt index 24158d3..3481f88 100644 --- a/src/main/kotlin/automaton/constructor/model/automaton/AbstractAutomaton.kt +++ b/src/main/kotlin/automaton/constructor/model/automaton/AbstractAutomaton.kt @@ -8,6 +8,7 @@ import automaton.constructor.model.action.transition.RemoveTransitionAction import automaton.constructor.model.element.* import automaton.constructor.model.memory.MemoryUnit import automaton.constructor.model.memory.MemoryUnitDescriptor +import automaton.constructor.model.memory.tape.MultiTrackTapeDescriptor import automaton.constructor.model.module.AutomatonModule import automaton.constructor.model.property.EPSILON_VALUE import automaton.constructor.model.transformation.AutomatonTransformation @@ -240,6 +241,20 @@ abstract class AbstractAutomaton( private val modules = mutableMapOf<(Automaton) -> AutomatonModule, AutomatonModule>() + override fun canUseTheseDescriptors(newDescriptors: List): Boolean { + if (newDescriptors.size != memoryDescriptors.size) { + return false + } + for (index in memoryDescriptors.indices) { + if (memoryDescriptors[index]::class != newDescriptors[index]::class || + memoryDescriptors[index] is MultiTrackTapeDescriptor && + (memoryDescriptors[index] as MultiTrackTapeDescriptor).trackCount != + (newDescriptors[index] as MultiTrackTapeDescriptor).trackCount) { + return false + } + } + return true + } companion object { private const val STATE_NAME_PREFIX = "S" diff --git a/src/main/kotlin/automaton/constructor/model/automaton/Automaton.kt b/src/main/kotlin/automaton/constructor/model/automaton/Automaton.kt index 1c7ff7f..411f22c 100644 --- a/src/main/kotlin/automaton/constructor/model/automaton/Automaton.kt +++ b/src/main/kotlin/automaton/constructor/model/automaton/Automaton.kt @@ -143,6 +143,8 @@ interface Automaton { * it's not invoked again and cached result of the previous invocation is returned */ fun getModule(moduleFactory: (Automaton) -> T): T + + fun canUseTheseDescriptors(newDescriptors: List): Boolean } // Get automaton characteristics diff --git a/src/main/kotlin/automaton/constructor/model/automaton/FiniteAutomaton.kt b/src/main/kotlin/automaton/constructor/model/automaton/FiniteAutomaton.kt index 4982c2b..524756a 100644 --- a/src/main/kotlin/automaton/constructor/model/automaton/FiniteAutomaton.kt +++ b/src/main/kotlin/automaton/constructor/model/automaton/FiniteAutomaton.kt @@ -5,6 +5,7 @@ import automaton.constructor.model.action.transition.SimplifyRegexEntirelyTransi import automaton.constructor.model.action.transition.SimplifyRegexTransitionAction import automaton.constructor.model.automaton.flavours.AutomatonWithInputTape import automaton.constructor.model.data.FiniteAutomatonData +import automaton.constructor.model.memory.MemoryUnitDescriptor import automaton.constructor.model.memory.tape.InputTapeDescriptor import automaton.constructor.model.transformation.DeterminizeAutomatonAction import automaton.constructor.utils.I18N diff --git a/src/main/kotlin/automaton/constructor/model/automaton/MealyMooreMachine.kt b/src/main/kotlin/automaton/constructor/model/automaton/MealyMooreMachine.kt index 1507bb1..75016d7 100644 --- a/src/main/kotlin/automaton/constructor/model/automaton/MealyMooreMachine.kt +++ b/src/main/kotlin/automaton/constructor/model/automaton/MealyMooreMachine.kt @@ -6,6 +6,7 @@ import automaton.constructor.model.action.state.MooreToMealyAction import automaton.constructor.model.automaton.flavours.AutomatonWithInputTape import automaton.constructor.model.automaton.flavours.AutomatonWithOutputTape import automaton.constructor.model.data.MealyMooreMachineData +import automaton.constructor.model.memory.MemoryUnitDescriptor import automaton.constructor.model.memory.tape.InputTapeDescriptor import automaton.constructor.model.memory.tape.OutputTapeDescriptor import automaton.constructor.model.transformation.StatewiseTransformationAction diff --git a/src/main/kotlin/automaton/constructor/model/automaton/MultiTapeTuringMachine.kt b/src/main/kotlin/automaton/constructor/model/automaton/MultiTapeTuringMachine.kt index 4075156..becb8c9 100644 --- a/src/main/kotlin/automaton/constructor/model/automaton/MultiTapeTuringMachine.kt +++ b/src/main/kotlin/automaton/constructor/model/automaton/MultiTapeTuringMachine.kt @@ -2,6 +2,7 @@ package automaton.constructor.model.automaton import automaton.constructor.model.automaton.flavours.AutomatonWithTapes import automaton.constructor.model.data.MultiTapeTuringMachineData +import automaton.constructor.model.memory.MemoryUnitDescriptor import automaton.constructor.model.memory.tape.MultiTrackTapeDescriptor import automaton.constructor.utils.I18N diff --git a/src/main/kotlin/automaton/constructor/model/automaton/MultiTrackTuringMachine.kt b/src/main/kotlin/automaton/constructor/model/automaton/MultiTrackTuringMachine.kt index de2e775..f931763 100644 --- a/src/main/kotlin/automaton/constructor/model/automaton/MultiTrackTuringMachine.kt +++ b/src/main/kotlin/automaton/constructor/model/automaton/MultiTrackTuringMachine.kt @@ -2,6 +2,7 @@ package automaton.constructor.model.automaton import automaton.constructor.model.automaton.flavours.AutomatonWithTracks import automaton.constructor.model.data.MultiTrackTuringMachineData +import automaton.constructor.model.memory.MemoryUnitDescriptor import automaton.constructor.model.memory.tape.MultiTrackTapeDescriptor import automaton.constructor.utils.I18N diff --git a/src/main/kotlin/automaton/constructor/model/automaton/PushdownAutomaton.kt b/src/main/kotlin/automaton/constructor/model/automaton/PushdownAutomaton.kt index 27976c0..ab29441 100644 --- a/src/main/kotlin/automaton/constructor/model/automaton/PushdownAutomaton.kt +++ b/src/main/kotlin/automaton/constructor/model/automaton/PushdownAutomaton.kt @@ -4,6 +4,7 @@ import automaton.constructor.model.action.transition.EliminateEpsilonTransitionA import automaton.constructor.model.automaton.flavours.AutomatonWithInputTape import automaton.constructor.model.automaton.flavours.AutomatonWithStacks import automaton.constructor.model.data.PushdownAutomatonData +import automaton.constructor.model.memory.MemoryUnitDescriptor import automaton.constructor.model.memory.StackDescriptor import automaton.constructor.model.memory.tape.InputTapeDescriptor import automaton.constructor.utils.I18N diff --git a/src/main/kotlin/automaton/constructor/model/memory/Test.kt b/src/main/kotlin/automaton/constructor/model/memory/Test.kt new file mode 100644 index 0000000..be7ad5b --- /dev/null +++ b/src/main/kotlin/automaton/constructor/model/memory/Test.kt @@ -0,0 +1,9 @@ +package automaton.constructor.model.memory + +import automaton.constructor.model.data.MemoryUnitDescriptorData +import kotlinx.serialization.Serializable + +data class Test(val input: List) + +@Serializable +data class TestsForSerializing(val tests: List>, val automatonType: String) diff --git a/src/main/kotlin/automaton/constructor/model/memory/tape/MultitrackTape.kt b/src/main/kotlin/automaton/constructor/model/memory/tape/MultitrackTape.kt index 6a883cf..a7869db 100644 --- a/src/main/kotlin/automaton/constructor/model/memory/tape/MultitrackTape.kt +++ b/src/main/kotlin/automaton/constructor/model/memory/tape/MultitrackTape.kt @@ -16,8 +16,8 @@ import java.text.MessageFormat class MultiTrackTapeDescriptor(val trackCount: Int) : MemoryUnitDescriptor { val valueProperties = List(trackCount) { "".toProperty() } - constructor(trackCount: Int, initValues: List) : this(trackCount) { - valueProperties.zip(initValues).forEach { (a, b) -> a.value = b } + constructor(newTrackCount: Int, initialValues: List) : this(newTrackCount) { + valueProperties.zip(initialValues).forEach { (a, b) -> a.value = b } } val headMoveDirection = diff --git a/src/main/kotlin/automaton/constructor/utils/ExecutorUtils.kt b/src/main/kotlin/automaton/constructor/utils/ExecutorUtils.kt new file mode 100644 index 0000000..d43bf09 --- /dev/null +++ b/src/main/kotlin/automaton/constructor/utils/ExecutorUtils.kt @@ -0,0 +1,47 @@ +package automaton.constructor.utils + +import automaton.constructor.model.automaton.Automaton +import automaton.constructor.model.memory.MemoryUnit +import automaton.constructor.model.module.executor.ExecutionStatus +import automaton.constructor.model.module.executor.Executor +import automaton.constructor.model.module.problems +import automaton.constructor.view.module.executor.executionLeafView + +data class ExecutorResult( + val executionResult: String, + val graphic: SettingGroupEditor? +) + +fun getNewExecutorOrNull(automaton: Automaton): Executor? { + if (automaton.problems.isNotEmpty()) { + tornadofx.error( + I18N.messages.getString("ExecutorController.Error.ExecutionFailed"), + automaton.problems.joinToString("\n") { it.message }, + title = I18N.messages.getString("Dialog.error") + ) + return null + } + return Executor(automaton) +} + +fun createExecutorAndRun(automaton: Automaton, memory: List? = null): ExecutorResult? { + val executor = getNewExecutorOrNull(automaton) + if (executor == null) { + return null + } + if (memory == null) { + executor.start() + } else { + executor.start(memory) + } + executor.runFor() + val executionResult = when (executor.status) { + ExecutionStatus.ACCEPTED -> I18N.messages.getString("ExecutorController.Executor.Status.Accepted") + ExecutionStatus.REJECTED -> I18N.messages.getString("ExecutorController.Executor.Status.Rejected") + ExecutionStatus.FROZEN -> I18N.messages.getString("ExecutorController.Executor.Status.Frozen") + ExecutionStatus.RUNNING -> I18N.messages.getString("ExecutorController.Executor.Status.Running") + } + val graphic = executor.acceptedExeStates.firstOrNull()?.let { executionLeafView(it) } + automaton.clearExecutionStates() + return ExecutorResult(executionResult, graphic) +} diff --git a/src/main/kotlin/automaton/constructor/view/ExamplesView.kt b/src/main/kotlin/automaton/constructor/view/ExamplesView.kt index a73ea39..f9a454c 100644 --- a/src/main/kotlin/automaton/constructor/view/ExamplesView.kt +++ b/src/main/kotlin/automaton/constructor/view/ExamplesView.kt @@ -19,10 +19,7 @@ import kotlin.io.path.Path @Serializable data class Example(val name: String, val description: String) -class ExampleCell( - private val counter: IntegerProperty, - private val automatonName: StringProperty -): ListCell() { +class ExampleCell(private val automatonName: StringProperty): ListCell() { init { this.setOnMouseClicked { if (it.clickCount == 2 && this.item != null) @@ -32,7 +29,6 @@ class ExampleCell( override fun updateItem(item: Example?, empty: Boolean) { super.updateItem(item, empty) graphic = if (item != null) { - counter.set(counter.value + 1) // this whole counter thing obviously needs to be remade Text().apply { text = I18N.automatonExamples.getString("ExamplesFragment.${item.name}") } } else null @@ -52,22 +48,20 @@ class ExamplesView: View() { val description = Text().apply { text = I18N.messages.getString("ExamplesFragment.Choose") } val image = ImageView() val descriptionVBox = VBox(description, image) - val counter = 0.toProperty() val automatonName = "".toProperty() minWidth = 800.0 + add(descriptionVBox) - examplesListView.setCellFactory { ExampleCell(counter, automatonName) } - counter.addListener(ChangeListener { _, _, _ -> - val selectedCellIndex = examplesListView.selectionModel.selectedIndex - if (selectedCellIndex != -1) { - description.text = - I18N.automatonExamples.getString( - "ExamplesFragment.${examples[selectedCellIndex].name}Description") - image.image = Image( - "file:///${System.getProperty("user.dir")}/src/main/resources/examples/images/${examples[selectedCellIndex].name}.png", - true) - } + + examplesListView.setCellFactory { ExampleCell(automatonName) } + + examplesListView.selectionModel.selectedItemProperty().addListener(ChangeListener { _, _, newValue -> + description.text = I18N.automatonExamples.getString("ExamplesFragment.${newValue.name}Description") + image.image = Image( + "file:///${System.getProperty("user.dir")}/src/main/resources/examples/images/${newValue.name}.png", + true) }) + automatonName.addListener(ChangeListener { _, _, newValue -> val automatonsPath = Path("${System.getProperty("user.dir")}/src/main/resources/examples/automatons") Files.walk(automatonsPath).forEach { diff --git a/src/main/kotlin/automaton/constructor/view/TestsResultsFragment.kt b/src/main/kotlin/automaton/constructor/view/TestsResultsFragment.kt index 35cba7a..742bcd5 100644 --- a/src/main/kotlin/automaton/constructor/view/TestsResultsFragment.kt +++ b/src/main/kotlin/automaton/constructor/view/TestsResultsFragment.kt @@ -1,6 +1,6 @@ package automaton.constructor.view -import automaton.constructor.controller.Test +import automaton.constructor.model.memory.Test import automaton.constructor.utils.I18N import automaton.constructor.utils.SettingGroup import automaton.constructor.utils.SettingGroupEditor diff --git a/src/main/kotlin/automaton/constructor/view/TestsView.kt b/src/main/kotlin/automaton/constructor/view/TestsView.kt index 82b9ee5..50a3ea6 100644 --- a/src/main/kotlin/automaton/constructor/view/TestsView.kt +++ b/src/main/kotlin/automaton/constructor/view/TestsView.kt @@ -1,7 +1,7 @@ package automaton.constructor.view -import automaton.constructor.controller.Test import automaton.constructor.controller.TestsController +import automaton.constructor.model.memory.Test import automaton.constructor.utils.* import tornadofx.* import javafx.scene.control.Button @@ -33,6 +33,7 @@ class TestCell(val controller: TestsController): ListCell() { class TestsView: View() { val controller: TestsController by param() private val tests = mutableListOf().asObservable() + override fun onDock() { currentWindow?.setOnCloseRequest { if (!controller.suggestSavingChanges(tests, this)) @@ -41,12 +42,14 @@ class TestsView: View() { tests.clear() } } + override val root = vbox { val addButton = Button(I18N.messages.getString("TestsFragment.Add")) val deleteButton = Button(I18N.messages.getString("TestsFragment.Delete")) val saveButton = Button(I18N.messages.getString("TestsFragment.Save")) val loadButton = Button(I18N.messages.getString("TestsFragment.Load")) minWidth = 500.0 // just for testing + hbox { add(addButton) add(deleteButton) @@ -61,18 +64,22 @@ class TestsView: View() { } testsListView.setCellFactory { TestCell(controller) } + addButton.setOnAction { tests.add(Test(controller.openedAutomaton.memoryDescriptors.map { it.copy() })) } + deleteButton.setOnAction { val selectedCellIndex = testsListView.selectionModel.selectedIndex if (selectedCellIndex != -1) { tests.removeAt(selectedCellIndex) } } + saveButton.setOnAction { controller.saveTests(tests, this@TestsView) } + loadButton.setOnAction { val openedTests = controller.openTests(this@TestsView) openedTests.forEach { test -> tests.add(test) } diff --git a/src/main/resources/examples/automatons/correctBracketSeqRecognizer.atmtn b/src/main/resources/examples/automatons/correctBracketSeqRecognizer.atmtn index 5c93c2f..dc111de 100644 --- a/src/main/resources/examples/automatons/correctBracketSeqRecognizer.atmtn +++ b/src/main/resources/examples/automatons/correctBracketSeqRecognizer.atmtn @@ -10,73 +10,34 @@ ] }, "vertices": [ - { - "type": "state", - "id": 5, - "name": "S5", - "x": 497707.5165449231, - "y": 500085.0165449231, - "isFinal": true - }, - { - "type": "state", - "id": 0, - "name": "S0", - "x": 498787.5, - "y": 500075.0, - "isInitial": true - }, - { - "type": "state", - "id": 3, - "name": "S3", - "x": 499860.0165449231, - "y": 500712.5165449231 - }, { "type": "state", "id": 1, "name": "S1", - "x": 499857.5165449231, - "y": 499382.5165449231 - }, - { - "type": "state", - "id": 6, - "name": "S6", - "x": 497705.0165449231, - "y": 500720.0165449231, - "isFinal": true + "x": 499154.9762463273, + "y": 500132.4762463273 }, { "type": "state", - "id": 4, - "name": "S4", - "x": 497712.5165449231, - "y": 499375.0165449231, + "id": 2, + "name": "S2", + "x": 499837.47535379225, + "y": 500127.47535379225, "isFinal": true }, { "type": "state", - "id": 2, - "name": "S2", - "x": 499855.0165449231, - "y": 500057.5165449231 + "id": 0, + "name": "S0", + "x": 498464.990869239, + "y": 500139.990869239, + "isInitial": true } ], "transitions": [ { - "source": 6, - "target": 0, - "properties": [ - "ε", - "ε", - "ε" - ] - }, - { - "source": 0, - "target": 3, + "source": 1, + "target": 1, "properties": [ "[", "ε", @@ -84,94 +45,67 @@ ] }, { - "source": 0, - "target": 2, - "properties": [ - "{", - "ε", - "{" - ] - }, - { - "source": 3, - "target": 0, + "source": 1, + "target": 1, "properties": [ - "ε", - "ε", + ")", + "(", "ε" ] }, { - "source": 0, - "target": 5, + "source": 1, + "target": 1, "properties": [ - "}", - "{", + "]", + "[", "ε" ] }, { - "source": 5, - "target": 0, + "source": 1, + "target": 1, "properties": [ + "{", "ε", - "ε", - "ε" + "{" ] }, { "source": 1, - "target": 0, + "target": 2, "properties": [ "ε", - "ε", + "$", "ε" ] }, { - "source": 4, - "target": 0, + "source": 0, + "target": 1, "properties": [ "ε", "ε", - "ε" + "$" ] }, { - "source": 0, - "target": 6, - "properties": [ - "]", - "[", - "ε" - ] - }, - { - "source": 0, - "target": 4, + "source": 1, + "target": 1, "properties": [ - ")", - "(", + "}", + "{", "ε" ] }, { - "source": 0, + "source": 1, "target": 1, "properties": [ "(", "ε", "(" ] - }, - { - "source": 2, - "target": 0, - "properties": [ - "ε", - "ε", - "ε" - ] } ] } \ No newline at end of file diff --git a/src/main/resources/examples/images/binaryNumberAdder.png b/src/main/resources/examples/images/binaryNumberAdder.png index 9eebf8e..238a5c5 100644 Binary files a/src/main/resources/examples/images/binaryNumberAdder.png and b/src/main/resources/examples/images/binaryNumberAdder.png differ diff --git a/src/main/resources/examples/images/correctBracketSeqRecognizer.png b/src/main/resources/examples/images/correctBracketSeqRecognizer.png index 974d832..dad8451 100644 Binary files a/src/main/resources/examples/images/correctBracketSeqRecognizer.png and b/src/main/resources/examples/images/correctBracketSeqRecognizer.png differ diff --git a/src/main/resources/examples/images/evenBinaryNumbersRecognizer.png b/src/main/resources/examples/images/evenBinaryNumbersRecognizer.png index a3e3e98..6d934ab 100644 Binary files a/src/main/resources/examples/images/evenBinaryNumbersRecognizer.png and b/src/main/resources/examples/images/evenBinaryNumbersRecognizer.png differ diff --git a/src/main/resources/examples/images/evenPalindromesRecognizer.png b/src/main/resources/examples/images/evenPalindromesRecognizer.png index 79c64ee..aaf2056 100644 Binary files a/src/main/resources/examples/images/evenPalindromesRecognizer.png and b/src/main/resources/examples/images/evenPalindromesRecognizer.png differ diff --git a/src/main/resources/examples/images/threeZerosAndOneOne.png b/src/main/resources/examples/images/threeZerosAndOneOne.png index a49a133..4fe3d3d 100644 Binary files a/src/main/resources/examples/images/threeZerosAndOneOne.png and b/src/main/resources/examples/images/threeZerosAndOneOne.png differ diff --git a/src/main/resources/examples/images/zeroRemover.png b/src/main/resources/examples/images/zeroRemover.png index 7917384..73a1cbe 100644 Binary files a/src/main/resources/examples/images/zeroRemover.png and b/src/main/resources/examples/images/zeroRemover.png differ diff --git a/src/test/kotlin/automaton/constructor/model/TestingTests.kt b/src/test/kotlin/automaton/constructor/model/TestingTests.kt index 9e986c1..a430f1c 100644 --- a/src/test/kotlin/automaton/constructor/model/TestingTests.kt +++ b/src/test/kotlin/automaton/constructor/model/TestingTests.kt @@ -2,19 +2,17 @@ package automaton.constructor.model import automaton.constructor.AutomatonConstructorApp import automaton.constructor.utils.I18N -import automaton.constructor.view.MainWindow import javafx.application.Application import javafx.scene.Node import javafx.stage.Stage import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.Assumptions.assumeFalse import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.testfx.api.FxAssert.verifyThat import org.testfx.api.FxToolkit import org.testfx.framework.junit5.ApplicationTest import org.testfx.matcher.control.TableViewMatchers.hasTableCell -import tornadofx.* - class TestingTests: ApplicationTest() { private lateinit var app: Application @@ -46,6 +44,10 @@ class TestingTests: ApplicationTest() { @Test fun runningTestOnFiniteAutomatonTest() { + assumeFalse( + System.getProperty("testfx.headless") == "true", + "Tests requiring graphical UI will be skipped in headless mode" + ) openExampleAndRunTest(I18N.automatonExamples.getString( "ExamplesFragment.evenBinaryNumbersRecognizer"), "1") verifyThat(".table-view", hasTableCell(I18N.messages.getString( @@ -54,6 +56,10 @@ class TestingTests: ApplicationTest() { @Test fun runningTestOnCorrectBracketSequenceRecognizer() { + assumeFalse( + System.getProperty("testfx.headless") == "true", + "Tests requiring graphical UI will be skipped in headless mode" + ) openExampleAndRunTest(I18N.automatonExamples.getString( "ExamplesFragment.correctBracketSeqRecognizer"), "()[]{}") verifyThat(".table-view", hasTableCell(I18N.messages.getString( @@ -62,6 +68,10 @@ class TestingTests: ApplicationTest() { @Test fun runningTestOnTuringMachine() { + assumeFalse( + System.getProperty("testfx.headless") == "true", + "Tests requiring graphical UI will be skipped in headless mode" + ) openExampleAndRunTest(I18N.automatonExamples.getString( "ExamplesFragment.binaryNumberAdder"), "100+111") verifyThat(".table-view", hasTableCell(I18N.messages.getString( @@ -70,6 +80,10 @@ class TestingTests: ApplicationTest() { @Test fun runningTestOnEvenPalindromesRecognizer() { + assumeFalse( + System.getProperty("testfx.headless") == "true", + "Tests requiring graphical UI will be skipped in headless mode" + ) openExampleAndRunTest(I18N.automatonExamples.getString( "ExamplesFragment.evenPalindromesRecognizer"), "110011") verifyThat(".table-view", hasTableCell(I18N.messages.getString( @@ -78,6 +92,10 @@ class TestingTests: ApplicationTest() { @Test fun runningTestOnRegisterAutomaton() { + assumeFalse( + System.getProperty("testfx.headless") == "true", + "Tests requiring graphical UI will be skipped in headless mode" + ) openExampleAndRunTest(I18N.automatonExamples.getString( "ExamplesFragment.threeZerosAndOneOne"), "110011") verifyThat(".table-view", hasTableCell(I18N.messages.getString( @@ -86,6 +104,10 @@ class TestingTests: ApplicationTest() { @Test fun runningTestOnMealyMooreMachine() { + assumeFalse( + System.getProperty("testfx.headless") == "true", + "Tests requiring graphical UI will be skipped in headless mode" + ) openExampleAndRunTest(I18N.automatonExamples.getString( "ExamplesFragment.zeroRemover"), "110011") verifyThat(".table-view", hasTableCell(I18N.messages.getString( diff --git a/src/test/kotlin/automaton/constructor/model/module/executor/ExecutorTest.kt b/src/test/kotlin/automaton/constructor/model/module/executor/ExecutorTest.kt index d98bc23..af9d4a0 100644 --- a/src/test/kotlin/automaton/constructor/model/module/executor/ExecutorTest.kt +++ b/src/test/kotlin/automaton/constructor/model/module/executor/ExecutorTest.kt @@ -18,7 +18,7 @@ import kotlin.test.assertEquals class ExecutorTest { companion object { - const val MAX_RUN_MILLIS = 100L + const val MAX_RUN_MILLIS = 200L } @Nested