From 5ecae048160e75c95ba8e05bcaa82f6fada6a3d8 Mon Sep 17 00:00:00 2001 From: GreenCrowDev Date: Sat, 14 Dec 2024 22:31:30 +0100 Subject: [PATCH] Add gdUnit4 --- .github/actions/build-project/action.yml | 2 +- .github/workflows/linux_builds.yml | 12 ++- .github/workflows/runner.yml | 4 + .gitignore | 5 + SConstruct | 8 +- demo/addons/neuron_fsm/neuron_fsm.gdextension | 36 +++---- demo/test/test_fsm.gd | 100 ++++++++++++++++++ demo/test/test_state.gd | 55 ++++++++++ 8 files changed, 198 insertions(+), 24 deletions(-) create mode 100644 demo/test/test_fsm.gd create mode 100644 demo/test/test_state.gd diff --git a/.github/actions/build-project/action.yml b/.github/actions/build-project/action.yml index fb4e20a..4580adc 100644 --- a/.github/actions/build-project/action.yml +++ b/.github/actions/build-project/action.yml @@ -33,7 +33,7 @@ runs: - name: SCons Build shell: sh env: - SCONSFLAGS: ${{ inputs.sconsflags }} + SCONSFLAGS: ${{ inputs.scons-flags }} run: | echo "Building with flags:" platform=${{ inputs.platform }} arch=${{ inputs.arch }} target=${{ inputs.build-target-type }} ${{ env.SCONSFLAGS }} diff --git a/.github/workflows/linux_builds.yml b/.github/workflows/linux_builds.yml index 18e4e62..9a1ef69 100644 --- a/.github/workflows/linux_builds.yml +++ b/.github/workflows/linux_builds.yml @@ -48,7 +48,7 @@ jobs: arch: x86_64 float-precision: 'single' build-target-type: ${{ matrix.target }} - scons-flags: ${{ env.SCONSFLAGS }} ${{ matrix.cpp_compiler == 'llvm' && 'use_llvm=yes' || ''}} + scons-flags: ${{ env.SCONSFLAGS }} ${{ matrix.cpp_compiler == 'llvm' && 'use_llvm=yes' || '' }} ${{ matrix.target == 'editor' && 'dev_build=yes' || '' }} - name: Save build cache uses: ./.github/actions/cache-save @@ -57,3 +57,13 @@ jobs: arch: x86_64 float-precision: 'single' build-target-type: ${{ matrix.target }} + + - name: Test with GdUnit4 + if: ${{ matrix.target == 'editor' }} + uses: MikeSchulze/gdUnit4-action@v1.1.1 + with: + godot-version: '4.3' + version: 'v4.5.0' + project_dir: '${{ github.workspace }}/demo/' + paths: 'res://test' + upload-report: false diff --git a/.github/workflows/runner.yml b/.github/workflows/runner.yml index bbadd8c..53db835 100644 --- a/.github/workflows/runner.yml +++ b/.github/workflows/runner.yml @@ -22,11 +22,15 @@ jobs: uses: ./.github/workflows/linux_builds.yml macos-build: + # TODO: DELETE + if: false name: 🍎 macOS needs: static-checks uses: ./.github/workflows/macos_builds.yml windows-build: + # TODO: DELETE + if: false name: 🪟 Windows needs: static-checks uses: ./.github/workflows/windows_builds.yml diff --git a/.gitignore b/.gitignore index ac21979..35e003f 100644 --- a/.gitignore +++ b/.gitignore @@ -51,3 +51,8 @@ build *.exp *.pdb *.ilk + +# TODO: DELETE +# GdUnit4 +/demo/addons/gdUnit4/ +GdUnitRunner.cfg \ No newline at end of file diff --git a/SConstruct b/SConstruct index dbfd53b..a0f274b 100644 --- a/SConstruct +++ b/SConstruct @@ -32,7 +32,7 @@ sources += Glob("src/util/io/*.cpp") if env_fsm["platform"] == "macos": library = env_fsm.SharedLibrary( - "demo/addons/neuron_fsm/neuron_fsm.{}.{}.framework/neuron_fsm.{}.{}".format( + "demo/addons/neuron_fsm/libneuron_fsm.{}.{}.framework/neuron_fsm.{}.{}".format( env_fsm["platform"], env_fsm["target"], env_fsm["platform"], env_fsm["target"] ), source=sources, @@ -40,17 +40,17 @@ if env_fsm["platform"] == "macos": elif env_fsm["platform"] == "ios": if env_fsm["ios_simulator"]: library = env_fsm.StaticLibrary( - "demo/addons/neuron_fsm/neuron_fsm.{}.{}.simulator.a".format(env_fsm["platform"], env_fsm["target"]), + "demo/addons/neuron_fsm/libneuron_fsm.{}.{}.simulator.a".format(env_fsm["platform"], env_fsm["target"]), source=sources, ) else: library = env_fsm.StaticLibrary( - "demo/addons/neuron_fsm/neuron_fsm.{}.{}.a".format(env_fsm["platform"], env_fsm["target"]), + "demo/addons/neuron_fsm/libneuron_fsm.{}.{}.a".format(env_fsm["platform"], env_fsm["target"]), source=sources, ) else: library = env_fsm.SharedLibrary( - "demo/addons/neuron_fsm/neuron_fsm{}{}".format(env_fsm["suffix"], env_fsm["SHLIBSUFFIX"]), + "demo/addons/neuron_fsm/libneuron_fsm{}{}".format(env_fsm["suffix"], env_fsm["SHLIBSUFFIX"]), source=sources, ) diff --git a/demo/addons/neuron_fsm/neuron_fsm.gdextension b/demo/addons/neuron_fsm/neuron_fsm.gdextension index 852b4c5..6c9d0bb 100644 --- a/demo/addons/neuron_fsm/neuron_fsm.gdextension +++ b/demo/addons/neuron_fsm/neuron_fsm.gdextension @@ -6,24 +6,24 @@ reloadable = true [libraries] -macos.debug = "res://addons/neuron_fsm/neuron_fsm.macos.editor.dev.framework" -macos.release = "res://addons/neuron_fsm/neuron_fsm.macos.template_release.framework" -ios.debug = "res://addons/neuron_fsm/neuron_fsm.ios.editor.dev.xcframework" -ios.release = "res://addons/neuron_fsm/neuron_fsm.ios.template_release.xcframework" -windows.debug.x86_32 = "res://addons/neuron_fsm/neuron_fsm.windows.editor.dev.x86_32.dll" -windows.release.x86_32 = "res://addons/neuron_fsm/neuron_fsm.windows.template_release.x86_32.dll" -windows.debug.x86_64 = "res://addons/neuron_fsm/neuron_fsm.windows.editor.dev.x86_64.dll" -windows.release.x86_64 = "res://addons/neuron_fsm/neuron_fsm.windows.template_release.x86_64.dll" -linux.debug.x86_64 = "res://addons/neuron_fsm/neuron_fsm.linux.editor.dev.x86_64.so" -linux.release.x86_64 = "res://addons/neuron_fsm/neuron_fsm.linux.template_release.x86_64.so" -linux.debug.arm64 = "res://addons/neuron_fsm/neuron_fsm.linux.editor.dev.arm64.so" -linux.release.arm64 = "res://addons/neuron_fsm/neuron_fsm.linux.template_release.arm64.so" -linux.debug.rv64 = "res://addons/neuron_fsm/neuron_fsm.linux.editor.dev.rv64.so" -linux.release.rv64 = "res://addons/neuron_fsm/neuron_fsm.linux.template_release.rv64.so" -android.debug.x86_64 = "res://addons/neuron_fsm/neuron_fsm.android.editor.dev.x86_64.so" -android.release.x86_64 = "res://addons/neuron_fsm/neuron_fsm.android.template_release.x86_64.so" -android.debug.arm64 = "res://addons/neuron_fsm/neuron_fsm.android.editor.dev.arm64.so" -android.release.arm64 = "res://addons/neuron_fsm/neuron_fsm.android.template_release.arm64.so" +macos.debug = "res://addons/neuron_fsm/libneuron_fsm.macos.editor.dev.framework" +macos.release = "res://addons/neuron_fsm/libneuron_fsm.macos.template_release.framework" +ios.debug = "res://addons/neuron_fsm/libneuron_fsm.ios.editor.dev.xcframework" +ios.release = "res://addons/neuron_fsm/libneuron_fsm.ios.template_release.xcframework" +windows.debug.x86_32 = "res://addons/neuron_fsm/libneuron_fsm.windows.editor.dev.x86_32.dll" +windows.release.x86_32 = "res://addons/neuron_fsm/libneuron_fsm.windows.template_release.x86_32.dll" +windows.debug.x86_64 = "res://addons/neuron_fsm/libneuron_fsm.windows.editor.dev.x86_64.dll" +windows.release.x86_64 = "res://addons/neuron_fsm/libneuron_fsm.windows.template_release.x86_64.dll" +linux.debug.x86_64 = "res://addons/neuron_fsm/libneuron_fsm.linux.editor.dev.x86_64.so" +linux.release.x86_64 = "res://addons/neuron_fsm/libneuron_fsm.linux.template_release.x86_64.so" +linux.debug.arm64 = "res://addons/neuron_fsm/libneuron_fsm.linux.editor.dev.arm64.so" +linux.release.arm64 = "res://addons/neuron_fsm/libneuron_fsm.linux.template_release.arm64.so" +linux.debug.rv64 = "res://addons/neuron_fsm/libneuron_fsm.linux.editor.dev.rv64.so" +linux.release.rv64 = "res://addons/neuron_fsm/libneuron_fsm.linux.template_release.rv64.so" +android.debug.x86_64 = "res://addons/neuron_fsm/libneuron_fsm.android.editor.dev.x86_64.so" +android.release.x86_64 = "res://addons/neuron_fsm/libneuron_fsm.android.template_release.x86_64.so" +android.debug.arm64 = "res://addons/neuron_fsm/libneuron_fsm.android.editor.dev.arm64.so" +android.release.arm64 = "res://addons/neuron_fsm/libneuron_fsm.android.template_release.arm64.so" [dependencies] ios.debug = { diff --git a/demo/test/test_fsm.gd b/demo/test/test_fsm.gd new file mode 100644 index 0000000..e221557 --- /dev/null +++ b/demo/test/test_fsm.gd @@ -0,0 +1,100 @@ +class_name TestFSM +extends GdUnitTestSuite + +var _fsm : FSM + +func before_test(): + _fsm = FSM.new() + +func test_fsm_initialization(): + # Check initial state of the FSM. + assert_bool(_fsm.is_locked()).is_false() + assert_bool(_fsm.is_running()).is_false() + + # Register a state. + var state := FSMState.new() + var state_name := "Start" + _fsm.register_state(state_name, state) + + # Check if the state was registered. + var registered_state = _fsm.get_state(state_name) + assert_object(registered_state).is_equal(state) + + # Set the starting state. + _fsm.set_starting_state(state_name) + assert_str(_fsm.get_starting_state_name()).is_equal(state_name) + assert_object(_fsm.get_starting_state()).is_equal(state) + +func test_fsm_cannot_lock(): + _fsm.lock() + # FSM cannot be locked if a starting state has not been set. + assert_bool(_fsm.is_locked()).is_false() + +func test_fsm_cannot_start(): + _fsm.start() + # FSM cannot be started if it is not locked. + assert_bool(_fsm.is_running()).is_false() + +func test_fsm_locked_behaviour(): + var start_state := FSMState.new() + var start_state_name := "Start" + _fsm.register_state(start_state_name, start_state) + _fsm.set_starting_state(start_state_name) + + var new_state := FSMState.new() + var new_state_name := "New state" + _fsm.register_state(new_state_name, new_state) + + var start_to_new_event := "Start to New" + _fsm.add_transition(start_state_name, start_to_new_event, new_state_name) + + _fsm.lock() + assert_bool(_fsm.is_locked()).is_true() + + # States cannot be registered while the FSM is locked. + var another_state := FSMState.new() + var another_state_name := "Another State" + _fsm.register_state(another_state_name, another_state) + assert_object(_fsm.get_state(another_state_name)).is_null() + + # Running behaviour. + + _fsm.start() + assert_bool(_fsm.is_running()).is_true() + assert_str(_fsm.get_current_state_name()).is_equal(start_state_name) + assert_object(_fsm.get_current_state()).is_equal(start_state) + + # Change state through an event. + _fsm.process_event(start_to_new_event) + assert_str(_fsm.get_current_state_name()).is_equal(new_state_name) + assert_object(_fsm.get_current_state()).is_equal(new_state) + + # Change state manually. + _fsm.change_state(start_state_name) + assert_str(_fsm.get_current_state_name()).is_equal(start_state_name) + assert_object(_fsm.get_current_state()).is_equal(start_state) + + _fsm.pause() + assert_bool(_fsm.is_running()).is_false() + + _fsm.play() + assert_bool(_fsm.is_running()).is_true() + + _fsm.stop() + assert_bool(_fsm.is_running()).is_false() + assert_str(_fsm.get_current_state_name()).is_empty() + assert_object(_fsm.get_current_state()).is_null() + + _fsm.start() + assert_bool(_fsm.is_running()).is_true() + + _fsm.reset() + assert_bool(_fsm.is_running()).is_false() + assert_str(_fsm.get_current_state_name()).is_empty() + assert_object(_fsm.get_current_state()).is_null() + + _fsm.unlock() + assert_bool(_fsm.is_locked()).is_false() + +func after_test(): + pass diff --git a/demo/test/test_state.gd b/demo/test/test_state.gd new file mode 100644 index 0000000..7351e9d --- /dev/null +++ b/demo/test/test_state.gd @@ -0,0 +1,55 @@ +class_name TestState +extends GdUnitTestSuite + +var _state : FSMState + +var _entered := false +var _processed := false +var _exited := false + +func before_test(): + _state = FSMState.new() + +func test_state_construction(): + assert_int(_state.on_enter.get_connections().size()).is_equal(0) + assert_int(_state.on_process.get_connections().size()).is_equal(0) + assert_int(_state.on_exit.get_connections().size()).is_equal(0) + + # Add callbacks. + _state.on_enter.connect(_set_entered_true) + _state.on_process.connect(_set_processed_true) + _state.on_exit.connect(_set_exited_true) + + assert_int(_state.on_enter.get_connections().size()).is_equal(1) + assert_int(_state.on_process.get_connections().size()).is_equal(1) + assert_int(_state.on_exit.get_connections().size()).is_equal(1) + + # Call callbacks. + _state.on_enter.emit() + _state.on_process.emit() + _state.on_exit.emit() + + assert_bool(_entered).is_true() + assert_bool(_processed).is_true() + assert_bool(_exited).is_true() + + # Remove callbacks. + _state.on_enter.disconnect(_set_entered_true) + _state.on_process.disconnect(_set_processed_true) + _state.on_exit.disconnect(_set_exited_true) + + assert_int(_state.on_enter.get_connections().size()).is_equal(0) + assert_int(_state.on_process.get_connections().size()).is_equal(0) + assert_int(_state.on_exit.get_connections().size()).is_equal(0) + +func after_test(): + pass + +func _set_entered_true(): + _entered = true + +func _set_processed_true(): + _processed = true + +func _set_exited_true(): + _exited = true