From 51907a1f01779ab5e6b56e4863acc7ee5fe4c882 Mon Sep 17 00:00:00 2001 From: Minimata Date: Mon, 26 Jan 2026 08:41:48 +0100 Subject: [PATCH] trying to fix Export --- Movement tests.csproj | 10 + addons/gdUnit4/LICENSE | 21 - addons/gdUnit4/bin/GdUnitCmdTool.gd | 21 - addons/gdUnit4/bin/GdUnitCmdTool.gd.uid | 1 - addons/gdUnit4/bin/GdUnitCopyLog.gd | 167 --- addons/gdUnit4/bin/GdUnitCopyLog.gd.uid | 1 - addons/gdUnit4/plugin.cfg | 7 - addons/gdUnit4/plugin.gd | 110 -- addons/gdUnit4/plugin.gd.uid | 1 - addons/gdUnit4/runtest.cmd | 62 - addons/gdUnit4/runtest.sh | 62 - addons/gdUnit4/src/Comparator.gd | 12 - addons/gdUnit4/src/Comparator.gd.uid | 1 - addons/gdUnit4/src/Fuzzers.gd | 80 -- addons/gdUnit4/src/Fuzzers.gd.uid | 1 - addons/gdUnit4/src/GdUnitArrayAssert.gd | 122 -- addons/gdUnit4/src/GdUnitArrayAssert.gd.uid | 1 - addons/gdUnit4/src/GdUnitAssert.gd | 47 - addons/gdUnit4/src/GdUnitAssert.gd.uid | 1 - addons/gdUnit4/src/GdUnitAwaiter.gd | 72 - addons/gdUnit4/src/GdUnitAwaiter.gd.uid | 1 - addons/gdUnit4/src/GdUnitBoolAssert.gd | 35 - addons/gdUnit4/src/GdUnitBoolAssert.gd.uid | 1 - addons/gdUnit4/src/GdUnitConstants.gd | 10 - addons/gdUnit4/src/GdUnitConstants.gd.uid | 1 - addons/gdUnit4/src/GdUnitDictionaryAssert.gd | 79 -- .../gdUnit4/src/GdUnitDictionaryAssert.gd.uid | 1 - addons/gdUnit4/src/GdUnitFailureAssert.gd | 52 - addons/gdUnit4/src/GdUnitFailureAssert.gd.uid | 1 - addons/gdUnit4/src/GdUnitFileAssert.gd | 38 - addons/gdUnit4/src/GdUnitFileAssert.gd.uid | 1 - addons/gdUnit4/src/GdUnitFloatAssert.gd | 75 - addons/gdUnit4/src/GdUnitFloatAssert.gd.uid | 1 - addons/gdUnit4/src/GdUnitFuncAssert.gd | 42 - addons/gdUnit4/src/GdUnitFuncAssert.gd.uid | 1 - addons/gdUnit4/src/GdUnitGodotErrorAssert.gd | 59 - .../gdUnit4/src/GdUnitGodotErrorAssert.gd.uid | 1 - addons/gdUnit4/src/GdUnitIntAssert.gd | 79 -- addons/gdUnit4/src/GdUnitIntAssert.gd.uid | 1 - addons/gdUnit4/src/GdUnitObjectAssert.gd | 51 - addons/gdUnit4/src/GdUnitObjectAssert.gd.uid | 1 - addons/gdUnit4/src/GdUnitResultAssert.gd | 51 - addons/gdUnit4/src/GdUnitResultAssert.gd.uid | 1 - addons/gdUnit4/src/GdUnitSceneRunner.gd | 325 ----- addons/gdUnit4/src/GdUnitSceneRunner.gd.uid | 1 - addons/gdUnit4/src/GdUnitSignalAssert.gd | 46 - addons/gdUnit4/src/GdUnitSignalAssert.gd.uid | 1 - addons/gdUnit4/src/GdUnitStringAssert.gd | 71 - addons/gdUnit4/src/GdUnitStringAssert.gd.uid | 1 - addons/gdUnit4/src/GdUnitTestSuite.gd | 691 --------- addons/gdUnit4/src/GdUnitTestSuite.gd.uid | 1 - addons/gdUnit4/src/GdUnitTuple.gd | 28 - addons/gdUnit4/src/GdUnitTuple.gd.uid | 1 - addons/gdUnit4/src/GdUnitValueExtractor.gd | 9 - .../gdUnit4/src/GdUnitValueExtractor.gd.uid | 1 - addons/gdUnit4/src/GdUnitVectorAssert.gd | 55 - addons/gdUnit4/src/GdUnitVectorAssert.gd.uid | 1 - .../src/asserts/CallBackValueProvider.gd | 25 - .../src/asserts/CallBackValueProvider.gd.uid | 1 - .../src/asserts/DefaultValueProvider.gd | 13 - .../src/asserts/DefaultValueProvider.gd.uid | 1 - .../gdUnit4/src/asserts/GdAssertMessages.gd | 692 --------- .../src/asserts/GdAssertMessages.gd.uid | 1 - addons/gdUnit4/src/asserts/GdAssertReports.gd | 54 - .../src/asserts/GdAssertReports.gd.uid | 1 - .../src/asserts/GdUnitArrayAssertImpl.gd | 436 ------ .../src/asserts/GdUnitArrayAssertImpl.gd.uid | 1 - .../gdUnit4/src/asserts/GdUnitAssertImpl.gd | 80 -- .../src/asserts/GdUnitAssertImpl.gd.uid | 1 - .../gdUnit4/src/asserts/GdUnitAssertions.gd | 68 - .../src/asserts/GdUnitAssertions.gd.uid | 1 - .../src/asserts/GdUnitBoolAssertImpl.gd | 87 -- .../src/asserts/GdUnitBoolAssertImpl.gd.uid | 1 - .../src/asserts/GdUnitDictionaryAssertImpl.gd | 207 --- .../asserts/GdUnitDictionaryAssertImpl.gd.uid | 1 - .../src/asserts/GdUnitFailureAssertImpl.gd | 136 -- .../asserts/GdUnitFailureAssertImpl.gd.uid | 1 - .../src/asserts/GdUnitFileAssertImpl.gd | 116 -- .../src/asserts/GdUnitFileAssertImpl.gd.uid | 1 - .../src/asserts/GdUnitFloatAssertImpl.gd | 159 --- .../src/asserts/GdUnitFloatAssertImpl.gd.uid | 1 - .../src/asserts/GdUnitFuncAssertImpl.gd | 177 --- .../src/asserts/GdUnitFuncAssertImpl.gd.uid | 1 - .../src/asserts/GdUnitGodotErrorAssertImpl.gd | 141 -- .../asserts/GdUnitGodotErrorAssertImpl.gd.uid | 1 - .../src/asserts/GdUnitIntAssertImpl.gd | 166 --- .../src/asserts/GdUnitIntAssertImpl.gd.uid | 1 - .../src/asserts/GdUnitObjectAssertImpl.gd | 166 --- .../src/asserts/GdUnitObjectAssertImpl.gd.uid | 1 - .../src/asserts/GdUnitResultAssertImpl.gd | 128 -- .../src/asserts/GdUnitResultAssertImpl.gd.uid | 1 - .../src/asserts/GdUnitSignalAssertImpl.gd | 143 -- .../src/asserts/GdUnitSignalAssertImpl.gd.uid | 1 - .../src/asserts/GdUnitStringAssertImpl.gd | 208 --- .../src/asserts/GdUnitStringAssertImpl.gd.uid | 1 - .../src/asserts/GdUnitVectorAssertImpl.gd | 187 --- .../src/asserts/GdUnitVectorAssertImpl.gd.uid | 1 - addons/gdUnit4/src/asserts/ValueProvider.gd | 10 - .../gdUnit4/src/asserts/ValueProvider.gd.uid | 1 - addons/gdUnit4/src/cmd/CmdArgumentParser.gd | 62 - .../gdUnit4/src/cmd/CmdArgumentParser.gd.uid | 1 - addons/gdUnit4/src/cmd/CmdCommand.gd | 27 - addons/gdUnit4/src/cmd/CmdCommand.gd.uid | 1 - addons/gdUnit4/src/cmd/CmdCommandHandler.gd | 136 -- .../gdUnit4/src/cmd/CmdCommandHandler.gd.uid | 1 - addons/gdUnit4/src/cmd/CmdOption.gd | 61 - addons/gdUnit4/src/cmd/CmdOption.gd.uid | 1 - addons/gdUnit4/src/cmd/CmdOptions.gd | 31 - addons/gdUnit4/src/cmd/CmdOptions.gd.uid | 1 - addons/gdUnit4/src/core/GdArrayTools.gd | 127 -- addons/gdUnit4/src/core/GdArrayTools.gd.uid | 1 - addons/gdUnit4/src/core/GdDiffTool.gd | 224 --- addons/gdUnit4/src/core/GdDiffTool.gd.uid | 1 - addons/gdUnit4/src/core/GdObjects.gd | 726 ---------- addons/gdUnit4/src/core/GdObjects.gd.uid | 1 - addons/gdUnit4/src/core/GdUnit4Version.gd | 65 - addons/gdUnit4/src/core/GdUnit4Version.gd.uid | 1 - addons/gdUnit4/src/core/GdUnitFileAccess.gd | 232 --- .../gdUnit4/src/core/GdUnitFileAccess.gd.uid | 1 - addons/gdUnit4/src/core/GdUnitProperty.gd | 81 -- addons/gdUnit4/src/core/GdUnitProperty.gd.uid | 1 - addons/gdUnit4/src/core/GdUnitResult.gd | 109 -- addons/gdUnit4/src/core/GdUnitResult.gd.uid | 1 - addons/gdUnit4/src/core/GdUnitRunnerConfig.gd | 126 -- .../src/core/GdUnitRunnerConfig.gd.uid | 1 - .../gdUnit4/src/core/GdUnitSceneRunnerImpl.gd | 622 -------- .../src/core/GdUnitSceneRunnerImpl.gd.uid | 1 - addons/gdUnit4/src/core/GdUnitSettings.gd | 435 ------ addons/gdUnit4/src/core/GdUnitSettings.gd.uid | 1 - .../gdUnit4/src/core/GdUnitSignalAwaiter.gd | 81 -- .../src/core/GdUnitSignalAwaiter.gd.uid | 1 - .../gdUnit4/src/core/GdUnitSignalCollector.gd | 129 -- .../src/core/GdUnitSignalCollector.gd.uid | 1 - addons/gdUnit4/src/core/GdUnitSignals.gd | 118 -- addons/gdUnit4/src/core/GdUnitSignals.gd.uid | 1 - addons/gdUnit4/src/core/GdUnitSingleton.gd | 56 - .../gdUnit4/src/core/GdUnitSingleton.gd.uid | 1 - .../src/core/GdUnitTestResourceLoader.gd | 97 -- .../src/core/GdUnitTestResourceLoader.gd.uid | 1 - .../src/core/GdUnitTestSuiteBuilder.gd | 20 - .../src/core/GdUnitTestSuiteBuilder.gd.uid | 1 - .../src/core/GdUnitTestSuiteScanner.gd | 404 ------ .../src/core/GdUnitTestSuiteScanner.gd.uid | 1 - addons/gdUnit4/src/core/GdUnitTools.gd | 144 -- addons/gdUnit4/src/core/GdUnitTools.gd.uid | 1 - .../gdUnit4/src/core/GodotVersionFixures.gd | 11 - .../src/core/GodotVersionFixures.gd.uid | 1 - addons/gdUnit4/src/core/LocalTime.gd | 114 -- addons/gdUnit4/src/core/LocalTime.gd.uid | 1 - addons/gdUnit4/src/core/_TestCase.gd | 243 ---- addons/gdUnit4/src/core/_TestCase.gd.uid | 1 - .../gdUnit4/src/core/assets/touch-button.png | 3 - .../src/core/assets/touch-button.png.import | 40 - .../src/core/attributes/TestCaseAttribute.gd | 76 - .../core/attributes/TestCaseAttribute.gd.uid | 1 - .../gdUnit4/src/core/command/GdUnitCommand.gd | 41 - .../src/core/command/GdUnitCommand.gd.uid | 1 - .../src/core/command/GdUnitCommandHandler.gd | 408 ------ .../core/command/GdUnitCommandHandler.gd.uid | 1 - .../src/core/command/GdUnitShortcut.gd | 52 - .../src/core/command/GdUnitShortcut.gd.uid | 1 - .../src/core/command/GdUnitShortcutAction.gd | 40 - .../core/command/GdUnitShortcutAction.gd.uid | 1 - .../gdUnit4/src/core/discovery/GdUnitGUID.gd | 46 - .../src/core/discovery/GdUnitGUID.gd.uid | 1 - .../src/core/discovery/GdUnitTestCase.gd | 125 -- .../src/core/discovery/GdUnitTestCase.gd.uid | 1 - .../core/discovery/GdUnitTestDiscoverGuard.gd | 323 ----- .../discovery/GdUnitTestDiscoverGuard.gd.uid | 1 - .../core/discovery/GdUnitTestDiscoverSink.gd | 13 - .../discovery/GdUnitTestDiscoverSink.gd.uid | 1 - .../core/discovery/GdUnitTestDiscoverer.gd | 171 --- .../discovery/GdUnitTestDiscoverer.gd.uid | 1 - addons/gdUnit4/src/core/event/GdUnitEvent.gd | 206 --- .../gdUnit4/src/core/event/GdUnitEvent.gd.uid | 1 - .../gdUnit4/src/core/event/GdUnitEventInit.gd | 6 - .../src/core/event/GdUnitEventInit.gd.uid | 1 - .../gdUnit4/src/core/event/GdUnitEventStop.gd | 6 - .../src/core/event/GdUnitEventStop.gd.uid | 1 - .../core/event/GdUnitEventTestDiscoverEnd.gd | 19 - .../event/GdUnitEventTestDiscoverEnd.gd.uid | 1 - .../event/GdUnitEventTestDiscoverStart.gd | 6 - .../event/GdUnitEventTestDiscoverStart.gd.uid | 1 - .../src/core/event/GdUnitSessionClose.gd | 6 - .../src/core/event/GdUnitSessionClose.gd.uid | 1 - .../src/core/event/GdUnitSessionStart.gd | 6 - .../src/core/event/GdUnitSessionStart.gd.uid | 1 - .../core/execution/GdUnitExecutionContext.gd | 269 ---- .../execution/GdUnitExecutionContext.gd.uid | 1 - .../core/execution/GdUnitMemoryObserver.gd | 135 -- .../execution/GdUnitMemoryObserver.gd.uid | 1 - .../execution/GdUnitTestReportCollector.gd | 62 - .../GdUnitTestReportCollector.gd.uid | 1 - .../core/execution/GdUnitTestSuiteExecutor.gd | 48 - .../execution/GdUnitTestSuiteExecutor.gd.uid | 1 - .../stages/GdUnitTestCaseAfterStage.gd | 22 - .../stages/GdUnitTestCaseAfterStage.gd.uid | 1 - .../stages/GdUnitTestCaseBeforeStage.gd | 19 - .../stages/GdUnitTestCaseBeforeStage.gd.uid | 1 - .../stages/GdUnitTestCaseExecutionStage.gd | 37 - .../GdUnitTestCaseExecutionStage.gd.uid | 1 - .../stages/GdUnitTestSuiteAfterStage.gd | 29 - .../stages/GdUnitTestSuiteAfterStage.gd.uid | 1 - .../stages/GdUnitTestSuiteBeforeStage.gd | 14 - .../stages/GdUnitTestSuiteBeforeStage.gd.uid | 1 - .../stages/GdUnitTestSuiteExecutionStage.gd | 147 -- .../GdUnitTestSuiteExecutionStage.gd.uid | 1 - .../execution/stages/IGdUnitExecutionStage.gd | 39 - .../stages/IGdUnitExecutionStage.gd.uid | 1 - .../GdUnitTestCaseFuzzedExecutionStage.gd | 52 - .../GdUnitTestCaseFuzzedExecutionStage.gd.uid | 1 - .../fuzzed/GdUnitTestCaseFuzzedTestStage.gd | 55 - .../GdUnitTestCaseFuzzedTestStage.gd.uid | 1 - .../GdUnitTestCaseSingleExecutionStage.gd | 53 - .../GdUnitTestCaseSingleExecutionStage.gd.uid | 1 - .../single/GdUnitTestCaseSingleTestStage.gd | 11 - .../GdUnitTestCaseSingleTestStage.gd.uid | 1 - .../GdUnitBaseReporterTestSessionHook.gd | 78 -- .../GdUnitBaseReporterTestSessionHook.gd.uid | 1 - .../GdUnitHtmlReporterTestSessionHook.gd | 9 - .../GdUnitHtmlReporterTestSessionHook.gd.uid | 1 - .../src/core/hooks/GdUnitTestSessionHook.gd | 111 -- .../core/hooks/GdUnitTestSessionHook.gd.uid | 1 - .../hooks/GdUnitTestSessionHookService.gd | 191 --- .../hooks/GdUnitTestSessionHookService.gd.uid | 1 - .../hooks/GdUnitXMLReporterTestSessionHook.gd | 11 - .../GdUnitXMLReporterTestSessionHook.gd.uid | 1 - .../src/core/parse/GdClassDescriptor.gd | 25 - .../src/core/parse/GdClassDescriptor.gd.uid | 1 - .../src/core/parse/GdDefaultValueDecoder.gd | 290 ---- .../core/parse/GdDefaultValueDecoder.gd.uid | 1 - .../src/core/parse/GdFunctionArgument.gd | 208 --- .../src/core/parse/GdFunctionArgument.gd.uid | 1 - .../src/core/parse/GdFunctionDescriptor.gd | 286 ---- .../core/parse/GdFunctionDescriptor.gd.uid | 1 - .../parse/GdFunctionParameterSetResolver.gd | 188 --- .../GdFunctionParameterSetResolver.gd.uid | 1 - .../gdUnit4/src/core/parse/GdScriptParser.gd | 764 ---------- .../src/core/parse/GdScriptParser.gd.uid | 1 - .../src/core/parse/GdUnitExpressionRunner.gd | 74 - .../core/parse/GdUnitExpressionRunner.gd.uid | 1 - .../parse/GdUnitTestParameterSetResolver.gd | 163 --- .../GdUnitTestParameterSetResolver.gd.uid | 1 - .../gdUnit4/src/core/report/GdUnitReport.gd | 74 - .../src/core/report/GdUnitReport.gd.uid | 1 - .../src/core/runners/GdUnitTestCIRunner.gd | 470 ------- .../core/runners/GdUnitTestCIRunner.gd.uid | 1 - .../src/core/runners/GdUnitTestRunner.gd | 87 -- .../src/core/runners/GdUnitTestRunner.gd.uid | 1 - .../src/core/runners/GdUnitTestRunner.tscn | 34 - .../src/core/runners/GdUnitTestSession.gd | 169 --- .../src/core/runners/GdUnitTestSession.gd.uid | 1 - .../core/runners/GdUnitTestSessionRunner.gd | 180 --- .../runners/GdUnitTestSessionRunner.gd.uid | 1 - .../GdUnitTestSuiteDefaultTemplate.gd | 36 - .../GdUnitTestSuiteDefaultTemplate.gd.uid | 1 - .../test_suite/GdUnitTestSuiteTemplate.gd | 144 -- .../test_suite/GdUnitTestSuiteTemplate.gd.uid | 1 - .../src/core/thread/GdUnitThreadContext.gd | 66 - .../core/thread/GdUnitThreadContext.gd.uid | 1 - .../src/core/thread/GdUnitThreadManager.gd | 64 - .../core/thread/GdUnitThreadManager.gd.uid | 1 - .../core/writers/GdUnitCSIMessageWriter.gd | 227 --- .../writers/GdUnitCSIMessageWriter.gd.uid | 1 - .../src/core/writers/GdUnitMessageWriter.gd | 214 --- .../core/writers/GdUnitMessageWriter.gd.uid | 1 - .../writers/GdUnitRichTextMessageWriter.gd | 115 -- .../GdUnitRichTextMessageWriter.gd.uid | 1 - addons/gdUnit4/src/dotnet/GdUnit4CSharpApi.cs | 235 ---- .../src/dotnet/GdUnit4CSharpApi.cs.uid | 1 - .../src/dotnet/GdUnit4CSharpApiLoader.gd | 114 -- .../src/dotnet/GdUnit4CSharpApiLoader.gd.uid | 1 - addons/gdUnit4/src/doubler/CallableDoubler.gd | 156 --- .../src/doubler/CallableDoubler.gd.uid | 1 - .../gdUnit4/src/doubler/GdFunctionDoubler.gd | 4 - .../src/doubler/GdFunctionDoubler.gd.uid | 1 - .../gdUnit4/src/doubler/GdUnitClassDoubler.gd | 119 -- .../src/doubler/GdUnitClassDoubler.gd.uid | 1 - .../doubler/GdUnitFunctionDoublerBuilder.gd | 336 ----- .../GdUnitFunctionDoublerBuilder.gd.uid | 1 - .../src/doubler/GdUnitMockFunctionDoubler.gd | 10 - .../doubler/GdUnitMockFunctionDoubler.gd.uid | 1 - .../src/doubler/GdUnitObjectInteractions.gd | 53 - .../doubler/GdUnitObjectInteractions.gd.uid | 1 - .../GdUnitObjectInteractionsVerifier.gd | 84 -- .../GdUnitObjectInteractionsVerifier.gd.uid | 1 - .../src/doubler/GdUnitSpyFunctionDoubler.gd | 8 - .../doubler/GdUnitSpyFunctionDoubler.gd.uid | 1 - .../extractors/GdUnitFuncValueExtractor.gd | 73 - .../GdUnitFuncValueExtractor.gd.uid | 1 - addons/gdUnit4/src/fuzzers/BoolFuzzer.gd | 24 - addons/gdUnit4/src/fuzzers/BoolFuzzer.gd.uid | 1 - addons/gdUnit4/src/fuzzers/FloatFuzzer.gd | 37 - addons/gdUnit4/src/fuzzers/FloatFuzzer.gd.uid | 1 - addons/gdUnit4/src/fuzzers/Fuzzer.gd | 80 -- addons/gdUnit4/src/fuzzers/Fuzzer.gd.uid | 1 - addons/gdUnit4/src/fuzzers/IntFuzzer.gd | 77 - addons/gdUnit4/src/fuzzers/IntFuzzer.gd.uid | 1 - addons/gdUnit4/src/fuzzers/StringFuzzer.gd | 112 -- .../gdUnit4/src/fuzzers/StringFuzzer.gd.uid | 1 - addons/gdUnit4/src/fuzzers/Vector2Fuzzer.gd | 45 - .../gdUnit4/src/fuzzers/Vector2Fuzzer.gd.uid | 1 - addons/gdUnit4/src/fuzzers/Vector3Fuzzer.gd | 48 - .../gdUnit4/src/fuzzers/Vector3Fuzzer.gd.uid | 1 - .../src/matchers/AnyArgumentMatcher.gd | 11 - .../src/matchers/AnyArgumentMatcher.gd.uid | 1 - .../matchers/AnyBuildInTypeArgumentMatcher.gd | 50 - .../AnyBuildInTypeArgumentMatcher.gd.uid | 1 - .../src/matchers/AnyClazzArgumentMatcher.gd | 32 - .../matchers/AnyClazzArgumentMatcher.gd.uid | 1 - .../src/matchers/ChainedArgumentMatcher.gd | 22 - .../matchers/ChainedArgumentMatcher.gd.uid | 1 - .../src/matchers/EqualsArgumentMatcher.gd | 22 - .../src/matchers/EqualsArgumentMatcher.gd.uid | 1 - .../src/matchers/GdUnitArgumentMatcher.gd | 13 - .../src/matchers/GdUnitArgumentMatcher.gd.uid | 1 - .../src/matchers/GdUnitArgumentMatchers.gd | 42 - .../matchers/GdUnitArgumentMatchers.gd.uid | 1 - addons/gdUnit4/src/mocking/GdUnitMock.gd | 45 - addons/gdUnit4/src/mocking/GdUnitMock.gd.uid | 1 - .../gdUnit4/src/mocking/GdUnitMockBuilder.gd | 186 --- .../src/mocking/GdUnitMockBuilder.gd.uid | 1 - addons/gdUnit4/src/mocking/GdUnitMockImpl.gd | 143 -- .../gdUnit4/src/mocking/GdUnitMockImpl.gd.uid | 1 - addons/gdUnit4/src/monitor/ErrorLogEntry.gd | 72 - .../gdUnit4/src/monitor/ErrorLogEntry.gd.uid | 1 - addons/gdUnit4/src/monitor/GdUnitMonitor.gd | 24 - .../gdUnit4/src/monitor/GdUnitMonitor.gd.uid | 1 - .../src/monitor/GdUnitOrphanNodesMonitor.gd | 27 - .../monitor/GdUnitOrphanNodesMonitor.gd.uid | 1 - .../src/monitor/GodotGdErrorMonitor.gd | 103 -- .../src/monitor/GodotGdErrorMonitor.gd.uid | 1 - addons/gdUnit4/src/network/GdUnitServer.gd | 42 - .../gdUnit4/src/network/GdUnitServer.gd.uid | 1 - addons/gdUnit4/src/network/GdUnitServer.tscn | 10 - .../src/network/GdUnitServerConstants.gd | 6 - .../src/network/GdUnitServerConstants.gd.uid | 1 - addons/gdUnit4/src/network/GdUnitTask.gd | 25 - addons/gdUnit4/src/network/GdUnitTask.gd.uid | 1 - addons/gdUnit4/src/network/GdUnitTcpClient.gd | 124 -- .../src/network/GdUnitTcpClient.gd.uid | 1 - addons/gdUnit4/src/network/GdUnitTcpNode.gd | 73 - .../gdUnit4/src/network/GdUnitTcpNode.gd.uid | 1 - addons/gdUnit4/src/network/GdUnitTcpServer.gd | 129 -- .../src/network/GdUnitTcpServer.gd.uid | 1 - addons/gdUnit4/src/network/rpc/RPC.gd | 37 - addons/gdUnit4/src/network/rpc/RPC.gd.uid | 1 - .../src/network/rpc/RPCClientConnect.gd | 13 - .../src/network/rpc/RPCClientConnect.gd.uid | 1 - .../src/network/rpc/RPCClientDisconnect.gd | 13 - .../network/rpc/RPCClientDisconnect.gd.uid | 1 - .../gdUnit4/src/network/rpc/RPCGdUnitEvent.gd | 14 - .../src/network/rpc/RPCGdUnitEvent.gd.uid | 1 - addons/gdUnit4/src/network/rpc/RPCMessage.gd | 18 - .../gdUnit4/src/network/rpc/RPCMessage.gd.uid | 1 - .../src/reporters/GdUnitReportSummary.gd | 202 --- .../src/reporters/GdUnitReportSummary.gd.uid | 1 - .../src/reporters/GdUnitReportWriter.gd | 12 - .../src/reporters/GdUnitReportWriter.gd.uid | 1 - .../src/reporters/GdUnitTestCaseReport.gd | 47 - .../src/reporters/GdUnitTestCaseReport.gd.uid | 1 - .../src/reporters/GdUnitTestReporter.gd | 112 -- .../src/reporters/GdUnitTestReporter.gd.uid | 1 - .../src/reporters/GdUnitTestSuiteReport.gd | 96 -- .../reporters/GdUnitTestSuiteReport.gd.uid | 1 - .../console/GdUnitConsoleTestReporter.gd | 234 ---- .../console/GdUnitConsoleTestReporter.gd.uid | 1 - .../src/reporters/html/GdUnitByPathReport.gd | 60 - .../reporters/html/GdUnitByPathReport.gd.uid | 1 - .../src/reporters/html/GdUnitHtmlPatterns.gd | 199 --- .../reporters/html/GdUnitHtmlPatterns.gd.uid | 1 - .../reporters/html/GdUnitHtmlReportWriter.gd | 72 - .../html/GdUnitHtmlReportWriter.gd.uid | 1 - .../src/reporters/html/template/.gdignore | 0 .../html/template/css/breadcrumb.css | 66 - .../src/reporters/html/template/css/logo.png | 3 - .../reporters/html/template/css/styles.css | 475 ------- .../html/template/folder_report.html | 122 -- .../src/reporters/html/template/index.html | 164 --- .../reporters/html/template/suite_report.html | 177 --- .../src/reporters/xml/JUnitXmlReportWriter.gd | 143 -- .../reporters/xml/JUnitXmlReportWriter.gd.uid | 1 - .../gdUnit4/src/reporters/xml/XmlElement.gd | 69 - .../src/reporters/xml/XmlElement.gd.uid | 1 - addons/gdUnit4/src/spy/GdUnitSpyBuilder.gd | 154 -- .../gdUnit4/src/spy/GdUnitSpyBuilder.gd.uid | 1 - addons/gdUnit4/src/spy/GdUnitSpyImpl.gd | 46 - addons/gdUnit4/src/spy/GdUnitSpyImpl.gd.uid | 1 - addons/gdUnit4/src/ui/GdUnitConsole.gd | 91 -- addons/gdUnit4/src/ui/GdUnitConsole.gd.uid | 1 - addons/gdUnit4/src/ui/GdUnitConsole.tscn | 64 - addons/gdUnit4/src/ui/GdUnitFonts.gd | 36 - addons/gdUnit4/src/ui/GdUnitFonts.gd.uid | 1 - addons/gdUnit4/src/ui/GdUnitInspector.gd | 31 - addons/gdUnit4/src/ui/GdUnitInspector.gd.uid | 1 - addons/gdUnit4/src/ui/GdUnitInspector.tscn | 71 - .../src/ui/GdUnitInspectorTreeConstants.gd | 31 - .../ui/GdUnitInspectorTreeConstants.gd.uid | 1 - addons/gdUnit4/src/ui/GdUnitUiTools.gd | 151 -- addons/gdUnit4/src/ui/GdUnitUiTools.gd.uid | 1 - addons/gdUnit4/src/ui/ScriptEditorControls.gd | 100 -- .../src/ui/ScriptEditorControls.gd.uid | 1 - .../EditorFileSystemContextMenuHandler.gd | 79 -- .../EditorFileSystemContextMenuHandler.gd.uid | 1 - .../EditorFileSystemContextMenuHandlerV44.gdx | 47 - .../src/ui/menu/GdUnitContextMenuItem.gd | 69 - .../src/ui/menu/GdUnitContextMenuItem.gd.uid | 1 - .../ui/menu/ScriptEditorContextMenuHandler.gd | 81 -- .../ScriptEditorContextMenuHandler.gd.uid | 1 - .../ScriptEditorContextMenuHandlerV44.gdx | 33 - .../gdUnit4/src/ui/parts/InspectorMonitor.gd | 54 - .../src/ui/parts/InspectorMonitor.gd.uid | 1 - .../src/ui/parts/InspectorMonitor.tscn | 94 -- .../src/ui/parts/InspectorProgressBar.gd | 49 - .../src/ui/parts/InspectorProgressBar.gd.uid | 1 - .../src/ui/parts/InspectorProgressBar.tscn | 33 - .../src/ui/parts/InspectorStatusBar.gd | 216 --- .../src/ui/parts/InspectorStatusBar.gd.uid | 1 - .../src/ui/parts/InspectorStatusBar.tscn | 477 ------- .../gdUnit4/src/ui/parts/InspectorToolBar.gd | 130 -- .../src/ui/parts/InspectorToolBar.gd.uid | 1 - .../src/ui/parts/InspectorToolBar.tscn | 212 --- .../src/ui/parts/InspectorTreeMainPanel.gd | 1245 ----------------- .../ui/parts/InspectorTreeMainPanel.gd.uid | 1 - .../src/ui/parts/InspectorTreePanel.tscn | 273 ---- .../src/ui/settings/GdUnitInputCapture.gd | 56 - .../src/ui/settings/GdUnitInputCapture.gd.uid | 1 - .../src/ui/settings/GdUnitInputCapture.tscn | 36 - .../src/ui/settings/GdUnitSettingsDialog.gd | 327 ----- .../ui/settings/GdUnitSettingsDialog.gd.uid | 1 - .../src/ui/settings/GdUnitSettingsDialog.tscn | 349 ----- .../src/ui/settings/GdUnitSettingsTabHooks.gd | 255 ---- .../ui/settings/GdUnitSettingsTabHooks.gd.uid | 1 - .../ui/settings/GdUnitSettingsTabHooks.tscn | 148 -- addons/gdUnit4/src/ui/settings/logo.png | 3 - .../gdUnit4/src/ui/settings/logo.png.import | 40 - .../src/ui/templates/TestSuiteTemplate.gd | 129 -- .../src/ui/templates/TestSuiteTemplate.gd.uid | 1 - .../src/ui/templates/TestSuiteTemplate.tscn | 127 -- addons/gdUnit4/src/update/GdMarkDownReader.gd | 405 ------ .../src/update/GdMarkDownReader.gd.uid | 1 - addons/gdUnit4/src/update/GdUnitPatch.gd | 20 - addons/gdUnit4/src/update/GdUnitPatch.gd.uid | 1 - addons/gdUnit4/src/update/GdUnitPatcher.gd | 75 - .../gdUnit4/src/update/GdUnitPatcher.gd.uid | 1 - addons/gdUnit4/src/update/GdUnitUpdate.gd | 305 ---- addons/gdUnit4/src/update/GdUnitUpdate.gd.uid | 1 - addons/gdUnit4/src/update/GdUnitUpdate.tscn | 100 -- .../gdUnit4/src/update/GdUnitUpdateClient.gd | 98 -- .../src/update/GdUnitUpdateClient.gd.uid | 1 - .../gdUnit4/src/update/GdUnitUpdateNotify.gd | 206 --- .../src/update/GdUnitUpdateNotify.gd.uid | 1 - .../src/update/GdUnitUpdateNotify.tscn | 97 -- .../src/update/assets/border_bottom.png | 3 - .../update/assets/border_bottom.png.import | 40 - .../gdUnit4/src/update/assets/border_top.png | 3 - .../src/update/assets/border_top.png.import | 40 - addons/gdUnit4/src/update/assets/dot1.png | 3 - .../gdUnit4/src/update/assets/dot1.png.import | 40 - addons/gdUnit4/src/update/assets/dot2.png | 3 - .../gdUnit4/src/update/assets/dot2.png.import | 40 - addons/gdUnit4/src/update/assets/embedded.png | 3 - .../src/update/assets/embedded.png.import | 40 - .../src/update/assets/horizontal-line2.png | 3 - .../update/assets/horizontal-line2.png.import | 40 - tests/ExampleTest.cs | 56 +- 466 files changed, 38 insertions(+), 29625 deletions(-) delete mode 100644 addons/gdUnit4/LICENSE delete mode 100644 addons/gdUnit4/bin/GdUnitCmdTool.gd delete mode 100644 addons/gdUnit4/bin/GdUnitCmdTool.gd.uid delete mode 100644 addons/gdUnit4/bin/GdUnitCopyLog.gd delete mode 100644 addons/gdUnit4/bin/GdUnitCopyLog.gd.uid delete mode 100644 addons/gdUnit4/plugin.cfg delete mode 100644 addons/gdUnit4/plugin.gd delete mode 100644 addons/gdUnit4/plugin.gd.uid delete mode 100644 addons/gdUnit4/runtest.cmd delete mode 100644 addons/gdUnit4/runtest.sh delete mode 100644 addons/gdUnit4/src/Comparator.gd delete mode 100644 addons/gdUnit4/src/Comparator.gd.uid delete mode 100644 addons/gdUnit4/src/Fuzzers.gd delete mode 100644 addons/gdUnit4/src/Fuzzers.gd.uid delete mode 100644 addons/gdUnit4/src/GdUnitArrayAssert.gd delete mode 100644 addons/gdUnit4/src/GdUnitArrayAssert.gd.uid delete mode 100644 addons/gdUnit4/src/GdUnitAssert.gd delete mode 100644 addons/gdUnit4/src/GdUnitAssert.gd.uid delete mode 100644 addons/gdUnit4/src/GdUnitAwaiter.gd delete mode 100644 addons/gdUnit4/src/GdUnitAwaiter.gd.uid delete mode 100644 addons/gdUnit4/src/GdUnitBoolAssert.gd delete mode 100644 addons/gdUnit4/src/GdUnitBoolAssert.gd.uid delete mode 100644 addons/gdUnit4/src/GdUnitConstants.gd delete mode 100644 addons/gdUnit4/src/GdUnitConstants.gd.uid delete mode 100644 addons/gdUnit4/src/GdUnitDictionaryAssert.gd delete mode 100644 addons/gdUnit4/src/GdUnitDictionaryAssert.gd.uid delete mode 100644 addons/gdUnit4/src/GdUnitFailureAssert.gd delete mode 100644 addons/gdUnit4/src/GdUnitFailureAssert.gd.uid delete mode 100644 addons/gdUnit4/src/GdUnitFileAssert.gd delete mode 100644 addons/gdUnit4/src/GdUnitFileAssert.gd.uid delete mode 100644 addons/gdUnit4/src/GdUnitFloatAssert.gd delete mode 100644 addons/gdUnit4/src/GdUnitFloatAssert.gd.uid delete mode 100644 addons/gdUnit4/src/GdUnitFuncAssert.gd delete mode 100644 addons/gdUnit4/src/GdUnitFuncAssert.gd.uid delete mode 100644 addons/gdUnit4/src/GdUnitGodotErrorAssert.gd delete mode 100644 addons/gdUnit4/src/GdUnitGodotErrorAssert.gd.uid delete mode 100644 addons/gdUnit4/src/GdUnitIntAssert.gd delete mode 100644 addons/gdUnit4/src/GdUnitIntAssert.gd.uid delete mode 100644 addons/gdUnit4/src/GdUnitObjectAssert.gd delete mode 100644 addons/gdUnit4/src/GdUnitObjectAssert.gd.uid delete mode 100644 addons/gdUnit4/src/GdUnitResultAssert.gd delete mode 100644 addons/gdUnit4/src/GdUnitResultAssert.gd.uid delete mode 100644 addons/gdUnit4/src/GdUnitSceneRunner.gd delete mode 100644 addons/gdUnit4/src/GdUnitSceneRunner.gd.uid delete mode 100644 addons/gdUnit4/src/GdUnitSignalAssert.gd delete mode 100644 addons/gdUnit4/src/GdUnitSignalAssert.gd.uid delete mode 100644 addons/gdUnit4/src/GdUnitStringAssert.gd delete mode 100644 addons/gdUnit4/src/GdUnitStringAssert.gd.uid delete mode 100644 addons/gdUnit4/src/GdUnitTestSuite.gd delete mode 100644 addons/gdUnit4/src/GdUnitTestSuite.gd.uid delete mode 100644 addons/gdUnit4/src/GdUnitTuple.gd delete mode 100644 addons/gdUnit4/src/GdUnitTuple.gd.uid delete mode 100644 addons/gdUnit4/src/GdUnitValueExtractor.gd delete mode 100644 addons/gdUnit4/src/GdUnitValueExtractor.gd.uid delete mode 100644 addons/gdUnit4/src/GdUnitVectorAssert.gd delete mode 100644 addons/gdUnit4/src/GdUnitVectorAssert.gd.uid delete mode 100644 addons/gdUnit4/src/asserts/CallBackValueProvider.gd delete mode 100644 addons/gdUnit4/src/asserts/CallBackValueProvider.gd.uid delete mode 100644 addons/gdUnit4/src/asserts/DefaultValueProvider.gd delete mode 100644 addons/gdUnit4/src/asserts/DefaultValueProvider.gd.uid delete mode 100644 addons/gdUnit4/src/asserts/GdAssertMessages.gd delete mode 100644 addons/gdUnit4/src/asserts/GdAssertMessages.gd.uid delete mode 100644 addons/gdUnit4/src/asserts/GdAssertReports.gd delete mode 100644 addons/gdUnit4/src/asserts/GdAssertReports.gd.uid delete mode 100644 addons/gdUnit4/src/asserts/GdUnitArrayAssertImpl.gd delete mode 100644 addons/gdUnit4/src/asserts/GdUnitArrayAssertImpl.gd.uid delete mode 100644 addons/gdUnit4/src/asserts/GdUnitAssertImpl.gd delete mode 100644 addons/gdUnit4/src/asserts/GdUnitAssertImpl.gd.uid delete mode 100644 addons/gdUnit4/src/asserts/GdUnitAssertions.gd delete mode 100644 addons/gdUnit4/src/asserts/GdUnitAssertions.gd.uid delete mode 100644 addons/gdUnit4/src/asserts/GdUnitBoolAssertImpl.gd delete mode 100644 addons/gdUnit4/src/asserts/GdUnitBoolAssertImpl.gd.uid delete mode 100644 addons/gdUnit4/src/asserts/GdUnitDictionaryAssertImpl.gd delete mode 100644 addons/gdUnit4/src/asserts/GdUnitDictionaryAssertImpl.gd.uid delete mode 100644 addons/gdUnit4/src/asserts/GdUnitFailureAssertImpl.gd delete mode 100644 addons/gdUnit4/src/asserts/GdUnitFailureAssertImpl.gd.uid delete mode 100644 addons/gdUnit4/src/asserts/GdUnitFileAssertImpl.gd delete mode 100644 addons/gdUnit4/src/asserts/GdUnitFileAssertImpl.gd.uid delete mode 100644 addons/gdUnit4/src/asserts/GdUnitFloatAssertImpl.gd delete mode 100644 addons/gdUnit4/src/asserts/GdUnitFloatAssertImpl.gd.uid delete mode 100644 addons/gdUnit4/src/asserts/GdUnitFuncAssertImpl.gd delete mode 100644 addons/gdUnit4/src/asserts/GdUnitFuncAssertImpl.gd.uid delete mode 100644 addons/gdUnit4/src/asserts/GdUnitGodotErrorAssertImpl.gd delete mode 100644 addons/gdUnit4/src/asserts/GdUnitGodotErrorAssertImpl.gd.uid delete mode 100644 addons/gdUnit4/src/asserts/GdUnitIntAssertImpl.gd delete mode 100644 addons/gdUnit4/src/asserts/GdUnitIntAssertImpl.gd.uid delete mode 100644 addons/gdUnit4/src/asserts/GdUnitObjectAssertImpl.gd delete mode 100644 addons/gdUnit4/src/asserts/GdUnitObjectAssertImpl.gd.uid delete mode 100644 addons/gdUnit4/src/asserts/GdUnitResultAssertImpl.gd delete mode 100644 addons/gdUnit4/src/asserts/GdUnitResultAssertImpl.gd.uid delete mode 100644 addons/gdUnit4/src/asserts/GdUnitSignalAssertImpl.gd delete mode 100644 addons/gdUnit4/src/asserts/GdUnitSignalAssertImpl.gd.uid delete mode 100644 addons/gdUnit4/src/asserts/GdUnitStringAssertImpl.gd delete mode 100644 addons/gdUnit4/src/asserts/GdUnitStringAssertImpl.gd.uid delete mode 100644 addons/gdUnit4/src/asserts/GdUnitVectorAssertImpl.gd delete mode 100644 addons/gdUnit4/src/asserts/GdUnitVectorAssertImpl.gd.uid delete mode 100644 addons/gdUnit4/src/asserts/ValueProvider.gd delete mode 100644 addons/gdUnit4/src/asserts/ValueProvider.gd.uid delete mode 100644 addons/gdUnit4/src/cmd/CmdArgumentParser.gd delete mode 100644 addons/gdUnit4/src/cmd/CmdArgumentParser.gd.uid delete mode 100644 addons/gdUnit4/src/cmd/CmdCommand.gd delete mode 100644 addons/gdUnit4/src/cmd/CmdCommand.gd.uid delete mode 100644 addons/gdUnit4/src/cmd/CmdCommandHandler.gd delete mode 100644 addons/gdUnit4/src/cmd/CmdCommandHandler.gd.uid delete mode 100644 addons/gdUnit4/src/cmd/CmdOption.gd delete mode 100644 addons/gdUnit4/src/cmd/CmdOption.gd.uid delete mode 100644 addons/gdUnit4/src/cmd/CmdOptions.gd delete mode 100644 addons/gdUnit4/src/cmd/CmdOptions.gd.uid delete mode 100644 addons/gdUnit4/src/core/GdArrayTools.gd delete mode 100644 addons/gdUnit4/src/core/GdArrayTools.gd.uid delete mode 100644 addons/gdUnit4/src/core/GdDiffTool.gd delete mode 100644 addons/gdUnit4/src/core/GdDiffTool.gd.uid delete mode 100644 addons/gdUnit4/src/core/GdObjects.gd delete mode 100644 addons/gdUnit4/src/core/GdObjects.gd.uid delete mode 100644 addons/gdUnit4/src/core/GdUnit4Version.gd delete mode 100644 addons/gdUnit4/src/core/GdUnit4Version.gd.uid delete mode 100644 addons/gdUnit4/src/core/GdUnitFileAccess.gd delete mode 100644 addons/gdUnit4/src/core/GdUnitFileAccess.gd.uid delete mode 100644 addons/gdUnit4/src/core/GdUnitProperty.gd delete mode 100644 addons/gdUnit4/src/core/GdUnitProperty.gd.uid delete mode 100644 addons/gdUnit4/src/core/GdUnitResult.gd delete mode 100644 addons/gdUnit4/src/core/GdUnitResult.gd.uid delete mode 100644 addons/gdUnit4/src/core/GdUnitRunnerConfig.gd delete mode 100644 addons/gdUnit4/src/core/GdUnitRunnerConfig.gd.uid delete mode 100644 addons/gdUnit4/src/core/GdUnitSceneRunnerImpl.gd delete mode 100644 addons/gdUnit4/src/core/GdUnitSceneRunnerImpl.gd.uid delete mode 100644 addons/gdUnit4/src/core/GdUnitSettings.gd delete mode 100644 addons/gdUnit4/src/core/GdUnitSettings.gd.uid delete mode 100644 addons/gdUnit4/src/core/GdUnitSignalAwaiter.gd delete mode 100644 addons/gdUnit4/src/core/GdUnitSignalAwaiter.gd.uid delete mode 100644 addons/gdUnit4/src/core/GdUnitSignalCollector.gd delete mode 100644 addons/gdUnit4/src/core/GdUnitSignalCollector.gd.uid delete mode 100644 addons/gdUnit4/src/core/GdUnitSignals.gd delete mode 100644 addons/gdUnit4/src/core/GdUnitSignals.gd.uid delete mode 100644 addons/gdUnit4/src/core/GdUnitSingleton.gd delete mode 100644 addons/gdUnit4/src/core/GdUnitSingleton.gd.uid delete mode 100644 addons/gdUnit4/src/core/GdUnitTestResourceLoader.gd delete mode 100644 addons/gdUnit4/src/core/GdUnitTestResourceLoader.gd.uid delete mode 100644 addons/gdUnit4/src/core/GdUnitTestSuiteBuilder.gd delete mode 100644 addons/gdUnit4/src/core/GdUnitTestSuiteBuilder.gd.uid delete mode 100644 addons/gdUnit4/src/core/GdUnitTestSuiteScanner.gd delete mode 100644 addons/gdUnit4/src/core/GdUnitTestSuiteScanner.gd.uid delete mode 100644 addons/gdUnit4/src/core/GdUnitTools.gd delete mode 100644 addons/gdUnit4/src/core/GdUnitTools.gd.uid delete mode 100644 addons/gdUnit4/src/core/GodotVersionFixures.gd delete mode 100644 addons/gdUnit4/src/core/GodotVersionFixures.gd.uid delete mode 100644 addons/gdUnit4/src/core/LocalTime.gd delete mode 100644 addons/gdUnit4/src/core/LocalTime.gd.uid delete mode 100644 addons/gdUnit4/src/core/_TestCase.gd delete mode 100644 addons/gdUnit4/src/core/_TestCase.gd.uid delete mode 100644 addons/gdUnit4/src/core/assets/touch-button.png delete mode 100644 addons/gdUnit4/src/core/assets/touch-button.png.import delete mode 100644 addons/gdUnit4/src/core/attributes/TestCaseAttribute.gd delete mode 100644 addons/gdUnit4/src/core/attributes/TestCaseAttribute.gd.uid delete mode 100644 addons/gdUnit4/src/core/command/GdUnitCommand.gd delete mode 100644 addons/gdUnit4/src/core/command/GdUnitCommand.gd.uid delete mode 100644 addons/gdUnit4/src/core/command/GdUnitCommandHandler.gd delete mode 100644 addons/gdUnit4/src/core/command/GdUnitCommandHandler.gd.uid delete mode 100644 addons/gdUnit4/src/core/command/GdUnitShortcut.gd delete mode 100644 addons/gdUnit4/src/core/command/GdUnitShortcut.gd.uid delete mode 100644 addons/gdUnit4/src/core/command/GdUnitShortcutAction.gd delete mode 100644 addons/gdUnit4/src/core/command/GdUnitShortcutAction.gd.uid delete mode 100644 addons/gdUnit4/src/core/discovery/GdUnitGUID.gd delete mode 100644 addons/gdUnit4/src/core/discovery/GdUnitGUID.gd.uid delete mode 100644 addons/gdUnit4/src/core/discovery/GdUnitTestCase.gd delete mode 100644 addons/gdUnit4/src/core/discovery/GdUnitTestCase.gd.uid delete mode 100644 addons/gdUnit4/src/core/discovery/GdUnitTestDiscoverGuard.gd delete mode 100644 addons/gdUnit4/src/core/discovery/GdUnitTestDiscoverGuard.gd.uid delete mode 100644 addons/gdUnit4/src/core/discovery/GdUnitTestDiscoverSink.gd delete mode 100644 addons/gdUnit4/src/core/discovery/GdUnitTestDiscoverSink.gd.uid delete mode 100644 addons/gdUnit4/src/core/discovery/GdUnitTestDiscoverer.gd delete mode 100644 addons/gdUnit4/src/core/discovery/GdUnitTestDiscoverer.gd.uid delete mode 100644 addons/gdUnit4/src/core/event/GdUnitEvent.gd delete mode 100644 addons/gdUnit4/src/core/event/GdUnitEvent.gd.uid delete mode 100644 addons/gdUnit4/src/core/event/GdUnitEventInit.gd delete mode 100644 addons/gdUnit4/src/core/event/GdUnitEventInit.gd.uid delete mode 100644 addons/gdUnit4/src/core/event/GdUnitEventStop.gd delete mode 100644 addons/gdUnit4/src/core/event/GdUnitEventStop.gd.uid delete mode 100644 addons/gdUnit4/src/core/event/GdUnitEventTestDiscoverEnd.gd delete mode 100644 addons/gdUnit4/src/core/event/GdUnitEventTestDiscoverEnd.gd.uid delete mode 100644 addons/gdUnit4/src/core/event/GdUnitEventTestDiscoverStart.gd delete mode 100644 addons/gdUnit4/src/core/event/GdUnitEventTestDiscoverStart.gd.uid delete mode 100644 addons/gdUnit4/src/core/event/GdUnitSessionClose.gd delete mode 100644 addons/gdUnit4/src/core/event/GdUnitSessionClose.gd.uid delete mode 100644 addons/gdUnit4/src/core/event/GdUnitSessionStart.gd delete mode 100644 addons/gdUnit4/src/core/event/GdUnitSessionStart.gd.uid delete mode 100644 addons/gdUnit4/src/core/execution/GdUnitExecutionContext.gd delete mode 100644 addons/gdUnit4/src/core/execution/GdUnitExecutionContext.gd.uid delete mode 100644 addons/gdUnit4/src/core/execution/GdUnitMemoryObserver.gd delete mode 100644 addons/gdUnit4/src/core/execution/GdUnitMemoryObserver.gd.uid delete mode 100644 addons/gdUnit4/src/core/execution/GdUnitTestReportCollector.gd delete mode 100644 addons/gdUnit4/src/core/execution/GdUnitTestReportCollector.gd.uid delete mode 100644 addons/gdUnit4/src/core/execution/GdUnitTestSuiteExecutor.gd delete mode 100644 addons/gdUnit4/src/core/execution/GdUnitTestSuiteExecutor.gd.uid delete mode 100644 addons/gdUnit4/src/core/execution/stages/GdUnitTestCaseAfterStage.gd delete mode 100644 addons/gdUnit4/src/core/execution/stages/GdUnitTestCaseAfterStage.gd.uid delete mode 100644 addons/gdUnit4/src/core/execution/stages/GdUnitTestCaseBeforeStage.gd delete mode 100644 addons/gdUnit4/src/core/execution/stages/GdUnitTestCaseBeforeStage.gd.uid delete mode 100644 addons/gdUnit4/src/core/execution/stages/GdUnitTestCaseExecutionStage.gd delete mode 100644 addons/gdUnit4/src/core/execution/stages/GdUnitTestCaseExecutionStage.gd.uid delete mode 100644 addons/gdUnit4/src/core/execution/stages/GdUnitTestSuiteAfterStage.gd delete mode 100644 addons/gdUnit4/src/core/execution/stages/GdUnitTestSuiteAfterStage.gd.uid delete mode 100644 addons/gdUnit4/src/core/execution/stages/GdUnitTestSuiteBeforeStage.gd delete mode 100644 addons/gdUnit4/src/core/execution/stages/GdUnitTestSuiteBeforeStage.gd.uid delete mode 100644 addons/gdUnit4/src/core/execution/stages/GdUnitTestSuiteExecutionStage.gd delete mode 100644 addons/gdUnit4/src/core/execution/stages/GdUnitTestSuiteExecutionStage.gd.uid delete mode 100644 addons/gdUnit4/src/core/execution/stages/IGdUnitExecutionStage.gd delete mode 100644 addons/gdUnit4/src/core/execution/stages/IGdUnitExecutionStage.gd.uid delete mode 100644 addons/gdUnit4/src/core/execution/stages/fuzzed/GdUnitTestCaseFuzzedExecutionStage.gd delete mode 100644 addons/gdUnit4/src/core/execution/stages/fuzzed/GdUnitTestCaseFuzzedExecutionStage.gd.uid delete mode 100644 addons/gdUnit4/src/core/execution/stages/fuzzed/GdUnitTestCaseFuzzedTestStage.gd delete mode 100644 addons/gdUnit4/src/core/execution/stages/fuzzed/GdUnitTestCaseFuzzedTestStage.gd.uid delete mode 100644 addons/gdUnit4/src/core/execution/stages/single/GdUnitTestCaseSingleExecutionStage.gd delete mode 100644 addons/gdUnit4/src/core/execution/stages/single/GdUnitTestCaseSingleExecutionStage.gd.uid delete mode 100644 addons/gdUnit4/src/core/execution/stages/single/GdUnitTestCaseSingleTestStage.gd delete mode 100644 addons/gdUnit4/src/core/execution/stages/single/GdUnitTestCaseSingleTestStage.gd.uid delete mode 100644 addons/gdUnit4/src/core/hooks/GdUnitBaseReporterTestSessionHook.gd delete mode 100644 addons/gdUnit4/src/core/hooks/GdUnitBaseReporterTestSessionHook.gd.uid delete mode 100644 addons/gdUnit4/src/core/hooks/GdUnitHtmlReporterTestSessionHook.gd delete mode 100644 addons/gdUnit4/src/core/hooks/GdUnitHtmlReporterTestSessionHook.gd.uid delete mode 100644 addons/gdUnit4/src/core/hooks/GdUnitTestSessionHook.gd delete mode 100644 addons/gdUnit4/src/core/hooks/GdUnitTestSessionHook.gd.uid delete mode 100644 addons/gdUnit4/src/core/hooks/GdUnitTestSessionHookService.gd delete mode 100644 addons/gdUnit4/src/core/hooks/GdUnitTestSessionHookService.gd.uid delete mode 100644 addons/gdUnit4/src/core/hooks/GdUnitXMLReporterTestSessionHook.gd delete mode 100644 addons/gdUnit4/src/core/hooks/GdUnitXMLReporterTestSessionHook.gd.uid delete mode 100644 addons/gdUnit4/src/core/parse/GdClassDescriptor.gd delete mode 100644 addons/gdUnit4/src/core/parse/GdClassDescriptor.gd.uid delete mode 100644 addons/gdUnit4/src/core/parse/GdDefaultValueDecoder.gd delete mode 100644 addons/gdUnit4/src/core/parse/GdDefaultValueDecoder.gd.uid delete mode 100644 addons/gdUnit4/src/core/parse/GdFunctionArgument.gd delete mode 100644 addons/gdUnit4/src/core/parse/GdFunctionArgument.gd.uid delete mode 100644 addons/gdUnit4/src/core/parse/GdFunctionDescriptor.gd delete mode 100644 addons/gdUnit4/src/core/parse/GdFunctionDescriptor.gd.uid delete mode 100644 addons/gdUnit4/src/core/parse/GdFunctionParameterSetResolver.gd delete mode 100644 addons/gdUnit4/src/core/parse/GdFunctionParameterSetResolver.gd.uid delete mode 100644 addons/gdUnit4/src/core/parse/GdScriptParser.gd delete mode 100644 addons/gdUnit4/src/core/parse/GdScriptParser.gd.uid delete mode 100644 addons/gdUnit4/src/core/parse/GdUnitExpressionRunner.gd delete mode 100644 addons/gdUnit4/src/core/parse/GdUnitExpressionRunner.gd.uid delete mode 100644 addons/gdUnit4/src/core/parse/GdUnitTestParameterSetResolver.gd delete mode 100644 addons/gdUnit4/src/core/parse/GdUnitTestParameterSetResolver.gd.uid delete mode 100644 addons/gdUnit4/src/core/report/GdUnitReport.gd delete mode 100644 addons/gdUnit4/src/core/report/GdUnitReport.gd.uid delete mode 100644 addons/gdUnit4/src/core/runners/GdUnitTestCIRunner.gd delete mode 100644 addons/gdUnit4/src/core/runners/GdUnitTestCIRunner.gd.uid delete mode 100644 addons/gdUnit4/src/core/runners/GdUnitTestRunner.gd delete mode 100644 addons/gdUnit4/src/core/runners/GdUnitTestRunner.gd.uid delete mode 100644 addons/gdUnit4/src/core/runners/GdUnitTestRunner.tscn delete mode 100644 addons/gdUnit4/src/core/runners/GdUnitTestSession.gd delete mode 100644 addons/gdUnit4/src/core/runners/GdUnitTestSession.gd.uid delete mode 100644 addons/gdUnit4/src/core/runners/GdUnitTestSessionRunner.gd delete mode 100644 addons/gdUnit4/src/core/runners/GdUnitTestSessionRunner.gd.uid delete mode 100644 addons/gdUnit4/src/core/templates/test_suite/GdUnitTestSuiteDefaultTemplate.gd delete mode 100644 addons/gdUnit4/src/core/templates/test_suite/GdUnitTestSuiteDefaultTemplate.gd.uid delete mode 100644 addons/gdUnit4/src/core/templates/test_suite/GdUnitTestSuiteTemplate.gd delete mode 100644 addons/gdUnit4/src/core/templates/test_suite/GdUnitTestSuiteTemplate.gd.uid delete mode 100644 addons/gdUnit4/src/core/thread/GdUnitThreadContext.gd delete mode 100644 addons/gdUnit4/src/core/thread/GdUnitThreadContext.gd.uid delete mode 100644 addons/gdUnit4/src/core/thread/GdUnitThreadManager.gd delete mode 100644 addons/gdUnit4/src/core/thread/GdUnitThreadManager.gd.uid delete mode 100644 addons/gdUnit4/src/core/writers/GdUnitCSIMessageWriter.gd delete mode 100644 addons/gdUnit4/src/core/writers/GdUnitCSIMessageWriter.gd.uid delete mode 100644 addons/gdUnit4/src/core/writers/GdUnitMessageWriter.gd delete mode 100644 addons/gdUnit4/src/core/writers/GdUnitMessageWriter.gd.uid delete mode 100644 addons/gdUnit4/src/core/writers/GdUnitRichTextMessageWriter.gd delete mode 100644 addons/gdUnit4/src/core/writers/GdUnitRichTextMessageWriter.gd.uid delete mode 100644 addons/gdUnit4/src/dotnet/GdUnit4CSharpApi.cs delete mode 100644 addons/gdUnit4/src/dotnet/GdUnit4CSharpApi.cs.uid delete mode 100644 addons/gdUnit4/src/dotnet/GdUnit4CSharpApiLoader.gd delete mode 100644 addons/gdUnit4/src/dotnet/GdUnit4CSharpApiLoader.gd.uid delete mode 100644 addons/gdUnit4/src/doubler/CallableDoubler.gd delete mode 100644 addons/gdUnit4/src/doubler/CallableDoubler.gd.uid delete mode 100644 addons/gdUnit4/src/doubler/GdFunctionDoubler.gd delete mode 100644 addons/gdUnit4/src/doubler/GdFunctionDoubler.gd.uid delete mode 100644 addons/gdUnit4/src/doubler/GdUnitClassDoubler.gd delete mode 100644 addons/gdUnit4/src/doubler/GdUnitClassDoubler.gd.uid delete mode 100644 addons/gdUnit4/src/doubler/GdUnitFunctionDoublerBuilder.gd delete mode 100644 addons/gdUnit4/src/doubler/GdUnitFunctionDoublerBuilder.gd.uid delete mode 100644 addons/gdUnit4/src/doubler/GdUnitMockFunctionDoubler.gd delete mode 100644 addons/gdUnit4/src/doubler/GdUnitMockFunctionDoubler.gd.uid delete mode 100644 addons/gdUnit4/src/doubler/GdUnitObjectInteractions.gd delete mode 100644 addons/gdUnit4/src/doubler/GdUnitObjectInteractions.gd.uid delete mode 100644 addons/gdUnit4/src/doubler/GdUnitObjectInteractionsVerifier.gd delete mode 100644 addons/gdUnit4/src/doubler/GdUnitObjectInteractionsVerifier.gd.uid delete mode 100644 addons/gdUnit4/src/doubler/GdUnitSpyFunctionDoubler.gd delete mode 100644 addons/gdUnit4/src/doubler/GdUnitSpyFunctionDoubler.gd.uid delete mode 100644 addons/gdUnit4/src/extractors/GdUnitFuncValueExtractor.gd delete mode 100644 addons/gdUnit4/src/extractors/GdUnitFuncValueExtractor.gd.uid delete mode 100644 addons/gdUnit4/src/fuzzers/BoolFuzzer.gd delete mode 100644 addons/gdUnit4/src/fuzzers/BoolFuzzer.gd.uid delete mode 100644 addons/gdUnit4/src/fuzzers/FloatFuzzer.gd delete mode 100644 addons/gdUnit4/src/fuzzers/FloatFuzzer.gd.uid delete mode 100644 addons/gdUnit4/src/fuzzers/Fuzzer.gd delete mode 100644 addons/gdUnit4/src/fuzzers/Fuzzer.gd.uid delete mode 100644 addons/gdUnit4/src/fuzzers/IntFuzzer.gd delete mode 100644 addons/gdUnit4/src/fuzzers/IntFuzzer.gd.uid delete mode 100644 addons/gdUnit4/src/fuzzers/StringFuzzer.gd delete mode 100644 addons/gdUnit4/src/fuzzers/StringFuzzer.gd.uid delete mode 100644 addons/gdUnit4/src/fuzzers/Vector2Fuzzer.gd delete mode 100644 addons/gdUnit4/src/fuzzers/Vector2Fuzzer.gd.uid delete mode 100644 addons/gdUnit4/src/fuzzers/Vector3Fuzzer.gd delete mode 100644 addons/gdUnit4/src/fuzzers/Vector3Fuzzer.gd.uid delete mode 100644 addons/gdUnit4/src/matchers/AnyArgumentMatcher.gd delete mode 100644 addons/gdUnit4/src/matchers/AnyArgumentMatcher.gd.uid delete mode 100644 addons/gdUnit4/src/matchers/AnyBuildInTypeArgumentMatcher.gd delete mode 100644 addons/gdUnit4/src/matchers/AnyBuildInTypeArgumentMatcher.gd.uid delete mode 100644 addons/gdUnit4/src/matchers/AnyClazzArgumentMatcher.gd delete mode 100644 addons/gdUnit4/src/matchers/AnyClazzArgumentMatcher.gd.uid delete mode 100644 addons/gdUnit4/src/matchers/ChainedArgumentMatcher.gd delete mode 100644 addons/gdUnit4/src/matchers/ChainedArgumentMatcher.gd.uid delete mode 100644 addons/gdUnit4/src/matchers/EqualsArgumentMatcher.gd delete mode 100644 addons/gdUnit4/src/matchers/EqualsArgumentMatcher.gd.uid delete mode 100644 addons/gdUnit4/src/matchers/GdUnitArgumentMatcher.gd delete mode 100644 addons/gdUnit4/src/matchers/GdUnitArgumentMatcher.gd.uid delete mode 100644 addons/gdUnit4/src/matchers/GdUnitArgumentMatchers.gd delete mode 100644 addons/gdUnit4/src/matchers/GdUnitArgumentMatchers.gd.uid delete mode 100644 addons/gdUnit4/src/mocking/GdUnitMock.gd delete mode 100644 addons/gdUnit4/src/mocking/GdUnitMock.gd.uid delete mode 100644 addons/gdUnit4/src/mocking/GdUnitMockBuilder.gd delete mode 100644 addons/gdUnit4/src/mocking/GdUnitMockBuilder.gd.uid delete mode 100644 addons/gdUnit4/src/mocking/GdUnitMockImpl.gd delete mode 100644 addons/gdUnit4/src/mocking/GdUnitMockImpl.gd.uid delete mode 100644 addons/gdUnit4/src/monitor/ErrorLogEntry.gd delete mode 100644 addons/gdUnit4/src/monitor/ErrorLogEntry.gd.uid delete mode 100644 addons/gdUnit4/src/monitor/GdUnitMonitor.gd delete mode 100644 addons/gdUnit4/src/monitor/GdUnitMonitor.gd.uid delete mode 100644 addons/gdUnit4/src/monitor/GdUnitOrphanNodesMonitor.gd delete mode 100644 addons/gdUnit4/src/monitor/GdUnitOrphanNodesMonitor.gd.uid delete mode 100644 addons/gdUnit4/src/monitor/GodotGdErrorMonitor.gd delete mode 100644 addons/gdUnit4/src/monitor/GodotGdErrorMonitor.gd.uid delete mode 100644 addons/gdUnit4/src/network/GdUnitServer.gd delete mode 100644 addons/gdUnit4/src/network/GdUnitServer.gd.uid delete mode 100644 addons/gdUnit4/src/network/GdUnitServer.tscn delete mode 100644 addons/gdUnit4/src/network/GdUnitServerConstants.gd delete mode 100644 addons/gdUnit4/src/network/GdUnitServerConstants.gd.uid delete mode 100644 addons/gdUnit4/src/network/GdUnitTask.gd delete mode 100644 addons/gdUnit4/src/network/GdUnitTask.gd.uid delete mode 100644 addons/gdUnit4/src/network/GdUnitTcpClient.gd delete mode 100644 addons/gdUnit4/src/network/GdUnitTcpClient.gd.uid delete mode 100644 addons/gdUnit4/src/network/GdUnitTcpNode.gd delete mode 100644 addons/gdUnit4/src/network/GdUnitTcpNode.gd.uid delete mode 100644 addons/gdUnit4/src/network/GdUnitTcpServer.gd delete mode 100644 addons/gdUnit4/src/network/GdUnitTcpServer.gd.uid delete mode 100644 addons/gdUnit4/src/network/rpc/RPC.gd delete mode 100644 addons/gdUnit4/src/network/rpc/RPC.gd.uid delete mode 100644 addons/gdUnit4/src/network/rpc/RPCClientConnect.gd delete mode 100644 addons/gdUnit4/src/network/rpc/RPCClientConnect.gd.uid delete mode 100644 addons/gdUnit4/src/network/rpc/RPCClientDisconnect.gd delete mode 100644 addons/gdUnit4/src/network/rpc/RPCClientDisconnect.gd.uid delete mode 100644 addons/gdUnit4/src/network/rpc/RPCGdUnitEvent.gd delete mode 100644 addons/gdUnit4/src/network/rpc/RPCGdUnitEvent.gd.uid delete mode 100644 addons/gdUnit4/src/network/rpc/RPCMessage.gd delete mode 100644 addons/gdUnit4/src/network/rpc/RPCMessage.gd.uid delete mode 100644 addons/gdUnit4/src/reporters/GdUnitReportSummary.gd delete mode 100644 addons/gdUnit4/src/reporters/GdUnitReportSummary.gd.uid delete mode 100644 addons/gdUnit4/src/reporters/GdUnitReportWriter.gd delete mode 100644 addons/gdUnit4/src/reporters/GdUnitReportWriter.gd.uid delete mode 100644 addons/gdUnit4/src/reporters/GdUnitTestCaseReport.gd delete mode 100644 addons/gdUnit4/src/reporters/GdUnitTestCaseReport.gd.uid delete mode 100644 addons/gdUnit4/src/reporters/GdUnitTestReporter.gd delete mode 100644 addons/gdUnit4/src/reporters/GdUnitTestReporter.gd.uid delete mode 100644 addons/gdUnit4/src/reporters/GdUnitTestSuiteReport.gd delete mode 100644 addons/gdUnit4/src/reporters/GdUnitTestSuiteReport.gd.uid delete mode 100644 addons/gdUnit4/src/reporters/console/GdUnitConsoleTestReporter.gd delete mode 100644 addons/gdUnit4/src/reporters/console/GdUnitConsoleTestReporter.gd.uid delete mode 100644 addons/gdUnit4/src/reporters/html/GdUnitByPathReport.gd delete mode 100644 addons/gdUnit4/src/reporters/html/GdUnitByPathReport.gd.uid delete mode 100644 addons/gdUnit4/src/reporters/html/GdUnitHtmlPatterns.gd delete mode 100644 addons/gdUnit4/src/reporters/html/GdUnitHtmlPatterns.gd.uid delete mode 100644 addons/gdUnit4/src/reporters/html/GdUnitHtmlReportWriter.gd delete mode 100644 addons/gdUnit4/src/reporters/html/GdUnitHtmlReportWriter.gd.uid delete mode 100644 addons/gdUnit4/src/reporters/html/template/.gdignore delete mode 100644 addons/gdUnit4/src/reporters/html/template/css/breadcrumb.css delete mode 100644 addons/gdUnit4/src/reporters/html/template/css/logo.png delete mode 100644 addons/gdUnit4/src/reporters/html/template/css/styles.css delete mode 100644 addons/gdUnit4/src/reporters/html/template/folder_report.html delete mode 100644 addons/gdUnit4/src/reporters/html/template/index.html delete mode 100644 addons/gdUnit4/src/reporters/html/template/suite_report.html delete mode 100644 addons/gdUnit4/src/reporters/xml/JUnitXmlReportWriter.gd delete mode 100644 addons/gdUnit4/src/reporters/xml/JUnitXmlReportWriter.gd.uid delete mode 100644 addons/gdUnit4/src/reporters/xml/XmlElement.gd delete mode 100644 addons/gdUnit4/src/reporters/xml/XmlElement.gd.uid delete mode 100644 addons/gdUnit4/src/spy/GdUnitSpyBuilder.gd delete mode 100644 addons/gdUnit4/src/spy/GdUnitSpyBuilder.gd.uid delete mode 100644 addons/gdUnit4/src/spy/GdUnitSpyImpl.gd delete mode 100644 addons/gdUnit4/src/spy/GdUnitSpyImpl.gd.uid delete mode 100644 addons/gdUnit4/src/ui/GdUnitConsole.gd delete mode 100644 addons/gdUnit4/src/ui/GdUnitConsole.gd.uid delete mode 100644 addons/gdUnit4/src/ui/GdUnitConsole.tscn delete mode 100644 addons/gdUnit4/src/ui/GdUnitFonts.gd delete mode 100644 addons/gdUnit4/src/ui/GdUnitFonts.gd.uid delete mode 100644 addons/gdUnit4/src/ui/GdUnitInspector.gd delete mode 100644 addons/gdUnit4/src/ui/GdUnitInspector.gd.uid delete mode 100644 addons/gdUnit4/src/ui/GdUnitInspector.tscn delete mode 100644 addons/gdUnit4/src/ui/GdUnitInspectorTreeConstants.gd delete mode 100644 addons/gdUnit4/src/ui/GdUnitInspectorTreeConstants.gd.uid delete mode 100644 addons/gdUnit4/src/ui/GdUnitUiTools.gd delete mode 100644 addons/gdUnit4/src/ui/GdUnitUiTools.gd.uid delete mode 100644 addons/gdUnit4/src/ui/ScriptEditorControls.gd delete mode 100644 addons/gdUnit4/src/ui/ScriptEditorControls.gd.uid delete mode 100644 addons/gdUnit4/src/ui/menu/EditorFileSystemContextMenuHandler.gd delete mode 100644 addons/gdUnit4/src/ui/menu/EditorFileSystemContextMenuHandler.gd.uid delete mode 100644 addons/gdUnit4/src/ui/menu/EditorFileSystemContextMenuHandlerV44.gdx delete mode 100644 addons/gdUnit4/src/ui/menu/GdUnitContextMenuItem.gd delete mode 100644 addons/gdUnit4/src/ui/menu/GdUnitContextMenuItem.gd.uid delete mode 100644 addons/gdUnit4/src/ui/menu/ScriptEditorContextMenuHandler.gd delete mode 100644 addons/gdUnit4/src/ui/menu/ScriptEditorContextMenuHandler.gd.uid delete mode 100644 addons/gdUnit4/src/ui/menu/ScriptEditorContextMenuHandlerV44.gdx delete mode 100644 addons/gdUnit4/src/ui/parts/InspectorMonitor.gd delete mode 100644 addons/gdUnit4/src/ui/parts/InspectorMonitor.gd.uid delete mode 100644 addons/gdUnit4/src/ui/parts/InspectorMonitor.tscn delete mode 100644 addons/gdUnit4/src/ui/parts/InspectorProgressBar.gd delete mode 100644 addons/gdUnit4/src/ui/parts/InspectorProgressBar.gd.uid delete mode 100644 addons/gdUnit4/src/ui/parts/InspectorProgressBar.tscn delete mode 100644 addons/gdUnit4/src/ui/parts/InspectorStatusBar.gd delete mode 100644 addons/gdUnit4/src/ui/parts/InspectorStatusBar.gd.uid delete mode 100644 addons/gdUnit4/src/ui/parts/InspectorStatusBar.tscn delete mode 100644 addons/gdUnit4/src/ui/parts/InspectorToolBar.gd delete mode 100644 addons/gdUnit4/src/ui/parts/InspectorToolBar.gd.uid delete mode 100644 addons/gdUnit4/src/ui/parts/InspectorToolBar.tscn delete mode 100644 addons/gdUnit4/src/ui/parts/InspectorTreeMainPanel.gd delete mode 100644 addons/gdUnit4/src/ui/parts/InspectorTreeMainPanel.gd.uid delete mode 100644 addons/gdUnit4/src/ui/parts/InspectorTreePanel.tscn delete mode 100644 addons/gdUnit4/src/ui/settings/GdUnitInputCapture.gd delete mode 100644 addons/gdUnit4/src/ui/settings/GdUnitInputCapture.gd.uid delete mode 100644 addons/gdUnit4/src/ui/settings/GdUnitInputCapture.tscn delete mode 100644 addons/gdUnit4/src/ui/settings/GdUnitSettingsDialog.gd delete mode 100644 addons/gdUnit4/src/ui/settings/GdUnitSettingsDialog.gd.uid delete mode 100644 addons/gdUnit4/src/ui/settings/GdUnitSettingsDialog.tscn delete mode 100644 addons/gdUnit4/src/ui/settings/GdUnitSettingsTabHooks.gd delete mode 100644 addons/gdUnit4/src/ui/settings/GdUnitSettingsTabHooks.gd.uid delete mode 100644 addons/gdUnit4/src/ui/settings/GdUnitSettingsTabHooks.tscn delete mode 100644 addons/gdUnit4/src/ui/settings/logo.png delete mode 100644 addons/gdUnit4/src/ui/settings/logo.png.import delete mode 100644 addons/gdUnit4/src/ui/templates/TestSuiteTemplate.gd delete mode 100644 addons/gdUnit4/src/ui/templates/TestSuiteTemplate.gd.uid delete mode 100644 addons/gdUnit4/src/ui/templates/TestSuiteTemplate.tscn delete mode 100644 addons/gdUnit4/src/update/GdMarkDownReader.gd delete mode 100644 addons/gdUnit4/src/update/GdMarkDownReader.gd.uid delete mode 100644 addons/gdUnit4/src/update/GdUnitPatch.gd delete mode 100644 addons/gdUnit4/src/update/GdUnitPatch.gd.uid delete mode 100644 addons/gdUnit4/src/update/GdUnitPatcher.gd delete mode 100644 addons/gdUnit4/src/update/GdUnitPatcher.gd.uid delete mode 100644 addons/gdUnit4/src/update/GdUnitUpdate.gd delete mode 100644 addons/gdUnit4/src/update/GdUnitUpdate.gd.uid delete mode 100644 addons/gdUnit4/src/update/GdUnitUpdate.tscn delete mode 100644 addons/gdUnit4/src/update/GdUnitUpdateClient.gd delete mode 100644 addons/gdUnit4/src/update/GdUnitUpdateClient.gd.uid delete mode 100644 addons/gdUnit4/src/update/GdUnitUpdateNotify.gd delete mode 100644 addons/gdUnit4/src/update/GdUnitUpdateNotify.gd.uid delete mode 100644 addons/gdUnit4/src/update/GdUnitUpdateNotify.tscn delete mode 100644 addons/gdUnit4/src/update/assets/border_bottom.png delete mode 100644 addons/gdUnit4/src/update/assets/border_bottom.png.import delete mode 100644 addons/gdUnit4/src/update/assets/border_top.png delete mode 100644 addons/gdUnit4/src/update/assets/border_top.png.import delete mode 100644 addons/gdUnit4/src/update/assets/dot1.png delete mode 100644 addons/gdUnit4/src/update/assets/dot1.png.import delete mode 100644 addons/gdUnit4/src/update/assets/dot2.png delete mode 100644 addons/gdUnit4/src/update/assets/dot2.png.import delete mode 100644 addons/gdUnit4/src/update/assets/embedded.png delete mode 100644 addons/gdUnit4/src/update/assets/embedded.png.import delete mode 100644 addons/gdUnit4/src/update/assets/horizontal-line2.png delete mode 100644 addons/gdUnit4/src/update/assets/horizontal-line2.png.import diff --git a/Movement tests.csproj b/Movement tests.csproj index e6ba5da8..680b232c 100644 --- a/Movement tests.csproj +++ b/Movement tests.csproj @@ -129,4 +129,14 @@ + + + + + + + none + runtime; build; native; contentfiles; analyzers; buildtransitive + + \ No newline at end of file diff --git a/addons/gdUnit4/LICENSE b/addons/gdUnit4/LICENSE deleted file mode 100644 index 8c60d132..00000000 --- a/addons/gdUnit4/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2023 Mike Schulze - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/addons/gdUnit4/bin/GdUnitCmdTool.gd b/addons/gdUnit4/bin/GdUnitCmdTool.gd deleted file mode 100644 index cae9138b..00000000 --- a/addons/gdUnit4/bin/GdUnitCmdTool.gd +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env -S godot -s -extends SceneTree - - -var _cli_runner: GdUnitTestCIRunner - - -func _initialize() -> void: - DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_MINIMIZED) - _cli_runner = GdUnitTestCIRunner.new() - root.add_child(_cli_runner) - - -# do not use print statements on _finalize it results in random crashes -func _finalize() -> void: - queue_delete(_cli_runner) - if OS.is_stdout_verbose(): - prints("Finallize ..") - prints("-Orphan nodes report-----------------------") - Window.print_orphan_nodes() - prints("Finallize .. done") diff --git a/addons/gdUnit4/bin/GdUnitCmdTool.gd.uid b/addons/gdUnit4/bin/GdUnitCmdTool.gd.uid deleted file mode 100644 index 9e751a61..00000000 --- a/addons/gdUnit4/bin/GdUnitCmdTool.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://do2c2faoehm61 diff --git a/addons/gdUnit4/bin/GdUnitCopyLog.gd b/addons/gdUnit4/bin/GdUnitCopyLog.gd deleted file mode 100644 index 8b228051..00000000 --- a/addons/gdUnit4/bin/GdUnitCopyLog.gd +++ /dev/null @@ -1,167 +0,0 @@ -#!/usr/bin/env -S godot -s -extends MainLoop - -const GdUnitTools := preload("res://addons/gdUnit4/src/core/GdUnitTools.gd") - -# gdlint: disable=max-line-length -const LOG_FRAME_TEMPLATE = """ - - - - - - Godot Logging - - - - -
-${content} -
- - -""" - -const NO_LOG_MESSAGE = """ -

No logging available!

-
-

In order for logging to take place, you must activate the Activate file logging option in the project settings.

-

You can enable the logging under: -Project Settings > Debug > File Logging > Enable File Logging in the project settings.

-""" - -#warning-ignore-all:return_value_discarded -var _cmd_options := CmdOptions.new([ - CmdOption.new( - "-rd, --report-directory", - "-rd ", - "Specifies the output directory in which the reports are to be written. The default is res://reports/.", - TYPE_STRING, - true - ) - ]) - - -var _report_root_path: String -var _current_report_path: String -var _debug_cmd_args := PackedStringArray() - - -func _init() -> void: - set_report_directory(GdUnitFileAccess.current_dir() + "reports") - set_current_report_path() - - -func _process(_delta: float) -> bool: - # check if reports exists - if not reports_available(): - prints("no reports found") - return true - - # only process if godot logging is enabled - if not GdUnitSettings.is_log_enabled(): - write_report(NO_LOG_MESSAGE, "") - return true - - # parse possible custom report path, - var cmd_parser := CmdArgumentParser.new(_cmd_options, "GdUnitCmdTool.gd") - # ignore erros and exit quitly - if cmd_parser.parse(get_cmdline_args(), true).is_error(): - return true - CmdCommandHandler.new(_cmd_options).register_cb("-rd", set_report_directory) - - var godot_log_file := scan_latest_godot_log() - var result := read_log_file_content(godot_log_file) - if result.is_error(): - write_report(result.error_message(), godot_log_file) - return true - write_report(result.value_as_string(), godot_log_file) - return true - - -func set_current_report_path() -> void: - # scan for latest report directory - var iteration := GdUnitFileAccess.find_last_path_index( - _report_root_path, GdUnitConstants.REPORT_DIR_PREFIX - ) - _current_report_path = "%s/%s%d" % [_report_root_path, GdUnitConstants.REPORT_DIR_PREFIX, iteration] - - -func set_report_directory(path: String) -> void: - _report_root_path = path - - -func get_log_report_html() -> String: - return _current_report_path + "/godot_report_log.html" - - -func reports_available() -> bool: - return DirAccess.dir_exists_absolute(_report_root_path) - - -func scan_latest_godot_log() -> String: - var path := GdUnitSettings.get_log_path().get_base_dir() - var files_sorted := Array() - for file in GdUnitFileAccess.scan_dir(path): - var file_name := "%s/%s" % [path, file] - files_sorted.append(file_name) - # sort by name, the name contains the timestamp so we sort at the end by timestamp - files_sorted.sort() - return files_sorted.back() - - -func read_log_file_content(log_file: String) -> GdUnitResult: - var file := FileAccess.open(log_file, FileAccess.READ) - if file == null: - return GdUnitResult.error( - "Can't find log file '%s'. Error: %s" - % [log_file, error_string(FileAccess.get_open_error())] - ) - var content := "
" + file.get_as_text()
-	# patch out console format codes
-	for color_index in range(0, 256):
-		var to_replace := "[38;5;%dm" % color_index
-		content = content.replace(to_replace, "")
-	content += "
" - content = content\ - .replace("", "")\ - .replace(GdUnitCSIMessageWriter.CSI_BOLD, "")\ - .replace(GdUnitCSIMessageWriter.CSI_ITALIC, "")\ - .replace(GdUnitCSIMessageWriter.CSI_UNDERLINE, "") - return GdUnitResult.success(content) - - -func write_report(content: String, godot_log_file: String) -> GdUnitResult: - var file := FileAccess.open(get_log_report_html(), FileAccess.WRITE) - if file == null: - return GdUnitResult.error( - "Can't open to write '%s'. Error: %s" - % [get_log_report_html(), error_string(FileAccess.get_open_error())] - ) - var report_html := LOG_FRAME_TEMPLATE.replace("${content}", content) - file.store_string(report_html) - _update_index_html(godot_log_file) - return GdUnitResult.success(file) - - -func _update_index_html(godot_log_file: String) -> void: - var index_path := "%s/index.html" % _current_report_path - var index_file := FileAccess.open(index_path, FileAccess.READ_WRITE) - if index_file == null: - push_error( - "Can't add log path '%s' to `%s`. Error: %s" - % [godot_log_file, index_path, error_string(FileAccess.get_open_error())] - ) - return - var content := index_file.get_as_text()\ - .replace("${log_report}", get_log_report_html())\ - .replace("${godot_log_file}", godot_log_file) - # overide it - index_file.seek(0) - index_file.store_string(content) - - -func get_cmdline_args() -> PackedStringArray: - if _debug_cmd_args.is_empty(): - return OS.get_cmdline_args() - return _debug_cmd_args diff --git a/addons/gdUnit4/bin/GdUnitCopyLog.gd.uid b/addons/gdUnit4/bin/GdUnitCopyLog.gd.uid deleted file mode 100644 index d5b381ef..00000000 --- a/addons/gdUnit4/bin/GdUnitCopyLog.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bretpek2ehht4 diff --git a/addons/gdUnit4/plugin.cfg b/addons/gdUnit4/plugin.cfg deleted file mode 100644 index ca818277..00000000 --- a/addons/gdUnit4/plugin.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[plugin] - -name="gdUnit4" -description="Unit Testing Framework for Godot Scripts" -author="Mike Schulze" -version="6.0.3" -script="plugin.gd" diff --git a/addons/gdUnit4/plugin.gd b/addons/gdUnit4/plugin.gd deleted file mode 100644 index 822c4d56..00000000 --- a/addons/gdUnit4/plugin.gd +++ /dev/null @@ -1,110 +0,0 @@ -@tool -extends EditorPlugin - -# We need to define manually the slot id's, to be downwards compatible -const CONTEXT_SLOT_FILESYSTEM: int = 1 # EditorContextMenuPlugin.CONTEXT_SLOT_FILESYSTEM -const CONTEXT_SLOT_SCRIPT_EDITOR: int = 2 # EditorContextMenuPlugin.CONTEXT_SLOT_SCRIPT_EDITOR - -var _gd_inspector: Control -var _gd_console: Control -var _gd_filesystem_context_menu: Variant -var _gd_scripteditor_context_menu: Variant - - -func _enter_tree() -> void: - - var inferred_declaration: int = ProjectSettings.get_setting("debug/gdscript/warnings/inferred_declaration") - var exclude_addons: bool = ProjectSettings.get_setting("debug/gdscript/warnings/exclude_addons") - if !exclude_addons and inferred_declaration != 0: - printerr("GdUnit4: 'inferred_declaration' is set to Warning/Error!") - printerr("GdUnit4 is not 'inferred_declaration' save, you have to excluded addons (debug/gdscript/warnings/exclude_addons)") - printerr("Loading GdUnit4 Plugin failed.") - return - - if check_running_in_test_env(): - @warning_ignore("return_value_discarded") - GdUnitCSIMessageWriter.new().prints_warning("It was recognized that GdUnit4 is running in a test environment, therefore the GdUnit4 plugin will not be executed!") - return - - if Engine.get_version_info().hex < 0x40500: - prints("This GdUnit4 plugin version '%s' requires Godot version '4.5' or higher to run." % GdUnit4Version.current()) - return - GdUnitSettings.setup() - # Install the GdUnit Inspector - _gd_inspector = (load("res://addons/gdUnit4/src/ui/GdUnitInspector.tscn") as PackedScene).instantiate() - _add_context_menus() - add_control_to_dock(EditorPlugin.DOCK_SLOT_LEFT_UR, _gd_inspector) - # Install the GdUnit Console - _gd_console = (load("res://addons/gdUnit4/src/ui/GdUnitConsole.tscn") as PackedScene).instantiate() - var control: Control = add_control_to_bottom_panel(_gd_console, "gdUnitConsole") - @warning_ignore("unsafe_method_access") - await _gd_console.setup_update_notification(control) - if GdUnit4CSharpApiLoader.is_api_loaded(): - prints("GdUnit4Net version '%s' loaded." % GdUnit4CSharpApiLoader.version()) - else: - prints("No GdUnit4Net found.") - # Connect to be notified for script changes to be able to discover new tests - GdUnitTestDiscoverGuard.instance() - @warning_ignore("return_value_discarded") - resource_saved.connect(_on_resource_saved) - prints("Loading GdUnit4 Plugin success") - - -func _exit_tree() -> void: - if check_running_in_test_env(): - return - if is_instance_valid(_gd_inspector): - remove_control_from_docks(_gd_inspector) - _gd_inspector.free() - _remove_context_menus() - if is_instance_valid(_gd_console): - remove_control_from_bottom_panel(_gd_console) - _gd_console.free() - var gdUnitTools: GDScript = load("res://addons/gdUnit4/src/core/GdUnitTools.gd") - @warning_ignore("unsafe_method_access") - gdUnitTools.dispose_all(true) - prints("Unload GdUnit4 Plugin success") - - -func check_running_in_test_env() -> bool: - var args: PackedStringArray = OS.get_cmdline_args() - args.append_array(OS.get_cmdline_user_args()) - return DisplayServer.get_name() == "headless" or args.has("--selftest") or args.has("--add") or args.has("-a") or args.has("--quit-after") or args.has("--import") - - -func _add_context_menus() -> void: - if Engine.get_version_info().hex >= 0x40400: - # With Godot 4.4 we have to use the 'add_context_menu_plugin' to register editor context menus - _gd_filesystem_context_menu = _preload_gdx_script("res://addons/gdUnit4/src/ui/menu/EditorFileSystemContextMenuHandlerV44.gdx") - call_deferred("add_context_menu_plugin", CONTEXT_SLOT_FILESYSTEM, _gd_filesystem_context_menu) - # the CONTEXT_SLOT_SCRIPT_EDITOR is adding to the script panel instead of script editor see https://github.com/godotengine/godot/pull/100556 - #_gd_scripteditor_context_menu = _preload("res://addons/gdUnit4/src/ui/menu/ScriptEditorContextMenuHandlerV44.gdx") - #call_deferred("add_context_menu_plugin", CONTEXT_SLOT_SCRIPT_EDITOR, _gd_scripteditor_context_menu) - # so we use the old hacky way to add the context menu - _gd_inspector.add_child(preload("res://addons/gdUnit4/src/ui/menu/ScriptEditorContextMenuHandler.gd").new()) - else: - # TODO Delete it if the minimum requirement for the plugin is set to Godot 4.4. - _gd_inspector.add_child(preload("res://addons/gdUnit4/src/ui/menu/EditorFileSystemContextMenuHandler.gd").new()) - _gd_inspector.add_child(preload("res://addons/gdUnit4/src/ui/menu/ScriptEditorContextMenuHandler.gd").new()) - - -func _remove_context_menus() -> void: - if is_instance_valid(_gd_filesystem_context_menu): - call_deferred("remove_context_menu_plugin", _gd_filesystem_context_menu) - if is_instance_valid(_gd_scripteditor_context_menu): - call_deferred("remove_context_menu_plugin", _gd_scripteditor_context_menu) - - -func _preload_gdx_script(script_path: String) -> Variant: - var script: GDScript = GDScript.new() - script.source_code = GdUnitFileAccess.resource_as_string(script_path) - script.take_over_path(script_path) - var err :Error = script.reload() - if err != OK: - push_error("Can't create context menu %s, error: %s" % [script_path, error_string(err)]) - return script.new() - - -func _on_resource_saved(resource: Resource) -> void: - if resource is Script: - await GdUnitTestDiscoverGuard.instance().discover(resource as Script) diff --git a/addons/gdUnit4/plugin.gd.uid b/addons/gdUnit4/plugin.gd.uid deleted file mode 100644 index 5e8143a9..00000000 --- a/addons/gdUnit4/plugin.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bc4fimf6ynr5d diff --git a/addons/gdUnit4/runtest.cmd b/addons/gdUnit4/runtest.cmd deleted file mode 100644 index ad5da4d9..00000000 --- a/addons/gdUnit4/runtest.cmd +++ /dev/null @@ -1,62 +0,0 @@ -@echo off -setlocal enabledelayedexpansion - -:: Initialize variables -set "godot_binary=" -set "filtered_args=" - -:: Process all arguments -set "i=0" -:parse_args -if "%~1"=="" goto end_parse_args - -if "%~1"=="--godot_binary" ( - set "godot_binary=%~2" - shift - shift -) else ( - set "filtered_args=!filtered_args! %~1" - shift -) -goto parse_args -:end_parse_args - -:: If --godot_binary wasn't provided, fallback to environment variable -if "!godot_binary!"=="" ( - set "godot_binary=%GODOT_BIN%" -) - -:: Check if we have a godot_binary value from any source -if "!godot_binary!"=="" ( - echo Godot binary path is not specified. - echo Please either: - echo - Set the environment variable: set GODOT_BIN=C:\path\to\godot.exe - echo - Or use the --godot_binary argument: --godot_binary C:\path\to\godot.exe - exit /b 1 -) - -:: Check if the Godot binary exists -if not exist "!godot_binary!" ( - echo Error: The specified Godot binary '!godot_binary!' does not exist. - exit /b 1 -) - -:: Get Godot version and check if it's a mono build -for /f "tokens=*" %%i in ('"!godot_binary!" --version') do set GODOT_VERSION=%%i -echo !GODOT_VERSION! | findstr /I "mono" >nul -if !errorlevel! equ 0 ( - echo Godot .NET detected - echo Compiling c# classes ... Please Wait - dotnet build --debug - echo done !errorlevel! -) - -:: Run the tests with the filtered arguments -"!godot_binary!" --path . -s -d res://addons/gdUnit4/bin/GdUnitCmdTool.gd !filtered_args! -set exit_code=%ERRORLEVEL% -echo Run tests ends with %exit_code% - -:: Run the copy log command -"!godot_binary!" --headless --path . --quiet -s res://addons/gdUnit4/bin/GdUnitCopyLog.gd !filtered_args! > nul -set exit_code2=%ERRORLEVEL% -exit /b %exit_code% diff --git a/addons/gdUnit4/runtest.sh b/addons/gdUnit4/runtest.sh deleted file mode 100644 index f0269efb..00000000 --- a/addons/gdUnit4/runtest.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash - -# Check for command-line argument -godot_binary="" -filtered_args="" - -# Process all arguments with a more compatible approach -while [ $# -gt 0 ]; do - if [ "$1" = "--godot_binary" ] && [ $# -gt 1 ]; then - # Get the next argument as the value - godot_binary="$2" - shift 2 - else - # Keep non-godot_binary arguments for passing to Godot - filtered_args="$filtered_args $1" - shift - fi -done - -# If --godot_binary wasn't provided, fallback to environment variable -if [ -z "$godot_binary" ]; then - godot_binary="$GODOT_BIN" -fi - -# Check if we have a godot_binary value from any source -if [ -z "$godot_binary" ]; then - echo "Godot binary path is not specified." - echo "Please either:" - echo " - Set the environment variable: export GODOT_BIN=/path/to/godot" - echo " - Or use the --godot_binary argument: --godot_binary /path/to/godot" - exit 1 -fi - -# Check if the Godot binary exists and is executable -if [ ! -f "$godot_binary" ]; then - echo "Error: The specified Godot binary '$godot_binary' does not exist." - exit 1 -fi - -if [ ! -x "$godot_binary" ]; then - echo "Error: The specified Godot binary '$godot_binary' is not executable." - exit 1 -fi - -# Get Godot version and check if it's a .NET build -GODOT_VERSION=$("$godot_binary" --version) -if echo "$GODOT_VERSION" | grep -i "mono" > /dev/null; then - echo "Godot .NET detected" - echo "Compiling c# classes ... Please Wait" - dotnet build --debug - echo "done $?" -fi - -# Run the tests with the filtered arguments -"$godot_binary" --path . -s -d res://addons/gdUnit4/bin/GdUnitCmdTool.gd $filtered_args -exit_code=$? -echo "Run tests ends with $exit_code" - -# Run the copy log command -"$godot_binary" --headless --path . --quiet -s res://addons/gdUnit4/bin/GdUnitCopyLog.gd $filtered_args > /dev/null -exit_code2=$? -exit $exit_code diff --git a/addons/gdUnit4/src/Comparator.gd b/addons/gdUnit4/src/Comparator.gd deleted file mode 100644 index 096088a6..00000000 --- a/addons/gdUnit4/src/Comparator.gd +++ /dev/null @@ -1,12 +0,0 @@ -class_name Comparator -extends Resource - -enum { - EQUAL, - LESS_THAN, - LESS_EQUAL, - GREATER_THAN, - GREATER_EQUAL, - BETWEEN_EQUAL, - NOT_BETWEEN_EQUAL, -} diff --git a/addons/gdUnit4/src/Comparator.gd.uid b/addons/gdUnit4/src/Comparator.gd.uid deleted file mode 100644 index 73ac82a9..00000000 --- a/addons/gdUnit4/src/Comparator.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://buiskkw1yyuw3 diff --git a/addons/gdUnit4/src/Fuzzers.gd b/addons/gdUnit4/src/Fuzzers.gd deleted file mode 100644 index c8689df3..00000000 --- a/addons/gdUnit4/src/Fuzzers.gd +++ /dev/null @@ -1,80 +0,0 @@ -## Factory class providing convenient static methods to create various fuzzer instances.[br] -## -## Fuzzers is a utility class that simplifies the creation of different fuzzer types -## for testing purposes. It provides static factory methods that create pre-configured -## fuzzers with sensible defaults, making it easier to set up fuzz testing in your -## test suites without manually instantiating each fuzzer type.[br] -## -## This class acts as a central access point for all fuzzer types, improving code -## readability and reducing boilerplate in test cases.[br] -## -## @tutorial(Fuzzing Testing): https://en.wikipedia.org/wiki/Fuzzing -class_name Fuzzers -extends Resource - - -## Generates random strings with length between [param min_length] and -## [param max_length] (inclusive), using characters from [param charset]. -## See [StringFuzzer] for detailed documentation and examples. -static func rand_str(min_length: int, max_length: int, charset := StringFuzzer.DEFAULT_CHARSET) -> StringFuzzer: - return StringFuzzer.new(min_length, max_length, charset) - - -## Creates a [BoolFuzzer] for generating random boolean values.[br] -## -## See [BoolFuzzer] for detailed documentation and examples. -static func boolean() -> BoolFuzzer: - return BoolFuzzer.new() - - -## Creates an [IntFuzzer] for generating random integers within a range.[br] -## -## Generates random integers between [param from] and [param to] (inclusive) -## using [constant IntFuzzer.NORMAL] mode. -## See [IntFuzzer] for detailed documentation and examples. -static func rangei(from: int, to: int) -> IntFuzzer: - return IntFuzzer.new(from, to) - - -## Creates a [FloatFuzzer] for generating random floats within a range.[br] -## -## Generates random float values between [param from] and [param to] (inclusive). -## See [FloatFuzzer] for detailed documentation and examples. -static func rangef(from: float, to: float) -> FloatFuzzer: - return FloatFuzzer.new(from, to) - - -## Creates a [Vector2Fuzzer] for generating random 2D vectors within a range.[br] -## -## Generates random Vector2 values where each component is bounded by -## [param from] and [param to] (inclusive). -## See [Vector2Fuzzer] for detailed documentation and examples. -static func rangev2(from: Vector2, to: Vector2) -> Vector2Fuzzer: - return Vector2Fuzzer.new(from, to) - - -## Creates a [Vector3Fuzzer] for generating random 3D vectors within a range.[br] -## -## Generates random Vector3 values where each component is bounded by -## [param from] and [param to] (inclusive). -## See [Vector3Fuzzer] for detailed documentation and examples. -static func rangev3(from: Vector3, to: Vector3) -> Vector3Fuzzer: - return Vector3Fuzzer.new(from, to) - - -## Creates an [IntFuzzer] that generates only even integers.[br] -## -## Generates random even integers between [param from] and [param to] (inclusive) -## using [constant IntFuzzer.EVEN] mode. -## See [IntFuzzer] for detailed documentation about even number generation. -static func eveni(from: int, to: int) -> IntFuzzer: - return IntFuzzer.new(from, to, IntFuzzer.EVEN) - - -## Creates an [IntFuzzer] that generates only odd integers.[br] -## -## Generates random odd integers between [param from] and [param to] (inclusive) -## using [constant IntFuzzer.ODD] mode. -## See [IntFuzzer] for detailed documentation about odd number generation. -static func oddi(from: int, to: int) -> IntFuzzer: - return IntFuzzer.new(from, to, IntFuzzer.ODD) diff --git a/addons/gdUnit4/src/Fuzzers.gd.uid b/addons/gdUnit4/src/Fuzzers.gd.uid deleted file mode 100644 index 1d752c61..00000000 --- a/addons/gdUnit4/src/Fuzzers.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://drfioswpw8u2u diff --git a/addons/gdUnit4/src/GdUnitArrayAssert.gd b/addons/gdUnit4/src/GdUnitArrayAssert.gd deleted file mode 100644 index eeb7ca6b..00000000 --- a/addons/gdUnit4/src/GdUnitArrayAssert.gd +++ /dev/null @@ -1,122 +0,0 @@ -## An Assertion Tool to verify array values -@abstract class_name GdUnitArrayAssert -extends GdUnitAssert - - -## Verifies that the current value is null. -@abstract func is_null() -> GdUnitArrayAssert - - -## Verifies that the current value is not null. -@abstract func is_not_null() -> GdUnitArrayAssert - - -## Verifies that the current Array is equal to the given one. -@abstract func is_equal(...expected: Array) -> GdUnitArrayAssert - - -## Verifies that the current Array is equal to the given one, ignoring case considerations. -@abstract func is_equal_ignoring_case(...expected: Array) -> GdUnitArrayAssert - - -## Verifies that the current Array is not equal to the given one. -@abstract func is_not_equal(...expected: Array) -> GdUnitArrayAssert - - -## Verifies that the current Array is not equal to the given one, ignoring case considerations. -@abstract func is_not_equal_ignoring_case(...expected: Array) -> GdUnitArrayAssert - - -## Overrides the default failure message by given custom message. -@abstract func override_failure_message(message: String) -> GdUnitArrayAssert - - -## Appends a custom message to the failure message. -@abstract func append_failure_message(message: String) -> GdUnitArrayAssert - - -## Verifies that the current Array is empty, it has a size of 0. -@abstract func is_empty() -> GdUnitArrayAssert - - -## Verifies that the current Array is not empty, it has a size of minimum 1. -@abstract func is_not_empty() -> GdUnitArrayAssert - - -## Verifies that the current Array is the same. [br] -## Compares the current by object reference equals -@abstract func is_same(expected: Variant) -> GdUnitArrayAssert - - -## Verifies that the current Array is NOT the same. [br] -## Compares the current by object reference equals -@abstract func is_not_same(expected: Variant) -> GdUnitArrayAssert - - -## Verifies that the current Array has a size of given value. -@abstract func has_size(expectd: int) -> GdUnitArrayAssert - - -## Verifies that the current Array contains the given values, in any order.[br] -## The values are compared by deep parameter comparision, for object reference compare you have to use [method contains_same] -@abstract func contains(...expected: Array) -> GdUnitArrayAssert - - -## Verifies that the current Array contains exactly only the given values and nothing else, in same order.[br] -## The values are compared by deep parameter comparision, for object reference compare you have to use [method contains_same_exactly] -@abstract func contains_exactly(...expected: Array) -> GdUnitArrayAssert - - -## Verifies that the current Array contains exactly only the given values and nothing else, in any order.[br] -## The values are compared by deep parameter comparision, for object reference compare you have to use [method contains_same_exactly_in_any_order] -@abstract func contains_exactly_in_any_order(...expected: Array) -> GdUnitArrayAssert - - -## Verifies that the current Array contains the given values, in any order.[br] -## The values are compared by object reference, for deep parameter comparision use [method contains] -@abstract func contains_same(...expected: Array) -> GdUnitArrayAssert - - -## Verifies that the current Array contains exactly only the given values and nothing else, in same order.[br] -## The values are compared by object reference, for deep parameter comparision use [method contains_exactly] -@abstract func contains_same_exactly(...expected: Array) -> GdUnitArrayAssert - - -## Verifies that the current Array contains exactly only the given values and nothing else, in any order.[br] -## The values are compared by object reference, for deep parameter comparision use [method contains_exactly_in_any_order] -@abstract func contains_same_exactly_in_any_order(...expected: Array) -> GdUnitArrayAssert - - -## Verifies that the current Array do NOT contains the given values, in any order.[br] -## The values are compared by deep parameter comparision, for object reference compare you have to use [method not_contains_same] -## [b]Example:[/b] -## [codeblock] -## # will succeed -## assert_array([1, 2, 3, 4, 5]).not_contains(6) -## # will fail -## assert_array([1, 2, 3, 4, 5]).not_contains(2, 6) -## [/codeblock] -@abstract func not_contains(...expected: Array) -> GdUnitArrayAssert - - -## Verifies that the current Array do NOT contains the given values, in any order.[br] -## The values are compared by object reference, for deep parameter comparision use [method not_contains] -## [b]Example:[/b] -## [codeblock] -## # will succeed -## assert_array([1, 2, 3, 4, 5]).not_contains(6) -## # will fail -## assert_array([1, 2, 3, 4, 5]).not_contains(2, 6) -## [/codeblock] -@abstract func not_contains_same(...expected: Array) -> GdUnitArrayAssert - - -## Extracts all values by given function name and optional arguments into a new ArrayAssert. -## If the elements not accessible by `func_name` the value is converted to `"n.a"`, expecting null values -@abstract func extract(func_name: String, ...func_args: Array) -> GdUnitArrayAssert - - -## Extracts all values by given extractor's into a new ArrayAssert. -## If the elements not extractable than the value is converted to `"n.a"`, expecting null values -## -- The argument type is Array[GdUnitValueExtractor] -@abstract func extractv(...extractors: Array) -> GdUnitArrayAssert diff --git a/addons/gdUnit4/src/GdUnitArrayAssert.gd.uid b/addons/gdUnit4/src/GdUnitArrayAssert.gd.uid deleted file mode 100644 index bf8d079e..00000000 --- a/addons/gdUnit4/src/GdUnitArrayAssert.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://byeulsiqvaugq diff --git a/addons/gdUnit4/src/GdUnitAssert.gd b/addons/gdUnit4/src/GdUnitAssert.gd deleted file mode 100644 index 41382d9f..00000000 --- a/addons/gdUnit4/src/GdUnitAssert.gd +++ /dev/null @@ -1,47 +0,0 @@ -## Base interface of all GdUnit asserts -@abstract class_name GdUnitAssert -extends RefCounted - - -## Verifies that the current value is null. -@abstract func is_null() -> GdUnitAssert - - -## Verifies that the current value is not null. -@abstract func is_not_null() -> GdUnitAssert - - -## Verifies that the current value is equal to expected one. -@abstract func is_equal(expected: Variant) -> GdUnitAssert - - -## Verifies that the current value is not equal to expected one. -@abstract func is_not_equal(expected: Variant) -> GdUnitAssert - - -## Overrides the default failure message by given custom message.[br] -## This function allows you to replace the automatically generated failure message with a more specific -## or user-friendly message that better describes the test failure context.[br] -## Usage: -## [codeblock] -## # Override with custom context-specific message -## func test_player_inventory(): -## assert_that(player.get_item_count("sword"))\ -## .override_failure_message("Player should have exactly one sword")\ -## .is_equal(1) -## [/codeblock] -@abstract func override_failure_message(message: String) -> GdUnitAssert - - -## Appends a custom message to the failure message.[br] -## This can be used to add additional information to the generated failure message -## while keeping the original assertion details for better debugging context.[br] -## Usage: -## [codeblock] -## # Add context to existing failure message -## func test_player_health(): -## assert_that(player.health)\ -## .append_failure_message("Player was damaged by: %s" % last_damage_source)\ -## .is_greater(0) -## [/codeblock] -@abstract func append_failure_message(message: String) -> GdUnitAssert diff --git a/addons/gdUnit4/src/GdUnitAssert.gd.uid b/addons/gdUnit4/src/GdUnitAssert.gd.uid deleted file mode 100644 index aa0a9cf2..00000000 --- a/addons/gdUnit4/src/GdUnitAssert.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bmy2nu4w22wia diff --git a/addons/gdUnit4/src/GdUnitAwaiter.gd b/addons/gdUnit4/src/GdUnitAwaiter.gd deleted file mode 100644 index 51385e88..00000000 --- a/addons/gdUnit4/src/GdUnitAwaiter.gd +++ /dev/null @@ -1,72 +0,0 @@ -class_name GdUnitAwaiter -extends RefCounted - - -# Waits for a specified signal in an interval of 50ms sent from the , and terminates with an error after the specified timeout has elapsed. -# source: the object from which the signal is emitted -# signal_name: signal name -# args: the expected signal arguments as an array -# timeout: the timeout in ms, default is set to 2000ms -func await_signal_on(source :Object, signal_name :String, args :Array = [], timeout_millis :int = 2000) -> Variant: - # fail fast if the given source instance invalid - var assert_that := GdUnitAssertImpl.new(signal_name) - var line_number := GdUnitAssertions.get_line_number() - if not is_instance_valid(source): - @warning_ignore("return_value_discarded") - assert_that.report_error(GdAssertMessages.error_await_signal_on_invalid_instance(source, signal_name, args), line_number) - return await (Engine.get_main_loop() as SceneTree).process_frame - # fail fast if the given source instance invalid - if not is_instance_valid(source): - @warning_ignore("return_value_discarded") - assert_that.report_error(GdAssertMessages.error_await_signal_on_invalid_instance(source, signal_name, args), line_number) - return await await_idle_frame() - var awaiter := GdUnitSignalAwaiter.new(timeout_millis) - var value :Variant = await awaiter.on_signal(source, signal_name, args) - if awaiter.is_interrupted(): - var failure := "await_signal_on(%s, %s) timed out after %sms" % [signal_name, args, timeout_millis] - @warning_ignore("return_value_discarded") - assert_that.report_error(failure, line_number) - return value - - -# Waits for a specified signal sent from the between idle frames and aborts with an error after the specified timeout has elapsed -# source: the object from which the signal is emitted -# signal_name: signal name -# args: the expected signal arguments as an array -# timeout: the timeout in ms, default is set to 2000ms -func await_signal_idle_frames(source :Object, signal_name :String, args :Array = [], timeout_millis :int = 2000) -> Variant: - var line_number := GdUnitAssertions.get_line_number() - # fail fast if the given source instance invalid - if not is_instance_valid(source): - @warning_ignore("return_value_discarded") - GdUnitAssertImpl.new(signal_name)\ - .report_error(GdAssertMessages.error_await_signal_on_invalid_instance(source, signal_name, args), line_number) - return await await_idle_frame() - var awaiter := GdUnitSignalAwaiter.new(timeout_millis, true) - var value :Variant = await awaiter.on_signal(source, signal_name, args) - if awaiter.is_interrupted(): - var failure := "await_signal_idle_frames(%s, %s) timed out after %sms" % [signal_name, args, timeout_millis] - @warning_ignore("return_value_discarded") - GdUnitAssertImpl.new(signal_name).report_error(failure, line_number) - return value - - -# Waits for for a given amount of milliseconds -# example: -# # waits for 100ms -# await GdUnitAwaiter.await_millis(myNode, 100).completed -# use this waiter and not `await get_tree().create_timer().timeout to prevent errors when a test case is timed out -func await_millis(milliSec :int) -> void: - var timer :Timer = Timer.new() - timer.set_name("gdunit_await_millis_timer_%d" % timer.get_instance_id()) - (Engine.get_main_loop() as SceneTree).root.add_child(timer) - timer.add_to_group("GdUnitTimers") - timer.set_one_shot(true) - timer.start(milliSec / 1000.0) - await timer.timeout - timer.queue_free() - - -# Waits until the next idle frame -func await_idle_frame() -> void: - await (Engine.get_main_loop() as SceneTree).process_frame diff --git a/addons/gdUnit4/src/GdUnitAwaiter.gd.uid b/addons/gdUnit4/src/GdUnitAwaiter.gd.uid deleted file mode 100644 index 5eda3099..00000000 --- a/addons/gdUnit4/src/GdUnitAwaiter.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c1jp2le4lldby diff --git a/addons/gdUnit4/src/GdUnitBoolAssert.gd b/addons/gdUnit4/src/GdUnitBoolAssert.gd deleted file mode 100644 index 714f8fc5..00000000 --- a/addons/gdUnit4/src/GdUnitBoolAssert.gd +++ /dev/null @@ -1,35 +0,0 @@ -## An Assertion Tool to verify boolean values -@abstract class_name GdUnitBoolAssert -extends GdUnitAssert - - -## Verifies that the current value is null. -@abstract func is_null() -> GdUnitBoolAssert - - -## Verifies that the current value is not null. -@abstract func is_not_null() -> GdUnitBoolAssert - - -## Verifies that the current value is equal to the given one. -@abstract func is_equal(expected: Variant) -> GdUnitBoolAssert - - -## Verifies that the current value is not equal to the given one. -@abstract func is_not_equal(expected: Variant) -> GdUnitBoolAssert - - -## Overrides the default failure message by given custom message. -@abstract func override_failure_message(message: String) -> GdUnitBoolAssert - - -## Appends a custom message to the failure message. -@abstract func append_failure_message(message: String) -> GdUnitBoolAssert - - -## Verifies that the current value is true. -@abstract func is_true() -> GdUnitBoolAssert - - -## Verifies that the current value is false. -@abstract func is_false() -> GdUnitBoolAssert diff --git a/addons/gdUnit4/src/GdUnitBoolAssert.gd.uid b/addons/gdUnit4/src/GdUnitBoolAssert.gd.uid deleted file mode 100644 index 7e402923..00000000 --- a/addons/gdUnit4/src/GdUnitBoolAssert.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bftfpffmfb1il diff --git a/addons/gdUnit4/src/GdUnitConstants.gd b/addons/gdUnit4/src/GdUnitConstants.gd deleted file mode 100644 index e43c75ab..00000000 --- a/addons/gdUnit4/src/GdUnitConstants.gd +++ /dev/null @@ -1,10 +0,0 @@ -class_name GdUnitConstants -extends RefCounted - -const NO_ARG :Variant = "<--null-->" - -const EXPECT_ASSERT_REPORT_FAILURES := "expect_assert_report_failures" - -## The maximum number of report history files to store -const DEFAULT_REPORT_HISTORY_COUNT = 20 -const REPORT_DIR_PREFIX = "report_" diff --git a/addons/gdUnit4/src/GdUnitConstants.gd.uid b/addons/gdUnit4/src/GdUnitConstants.gd.uid deleted file mode 100644 index bee2c812..00000000 --- a/addons/gdUnit4/src/GdUnitConstants.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dkap7kpfh2bhg diff --git a/addons/gdUnit4/src/GdUnitDictionaryAssert.gd b/addons/gdUnit4/src/GdUnitDictionaryAssert.gd deleted file mode 100644 index 45cc62a4..00000000 --- a/addons/gdUnit4/src/GdUnitDictionaryAssert.gd +++ /dev/null @@ -1,79 +0,0 @@ -## An Assertion Tool to verify dictionary -@abstract class_name GdUnitDictionaryAssert -extends GdUnitAssert - - -## Verifies that the current value is null. -@abstract func is_null() -> GdUnitDictionaryAssert - - -## Verifies that the current value is not null. -@abstract func is_not_null() -> GdUnitDictionaryAssert - - -## Verifies that the current dictionary is equal to the given one, ignoring order. -@abstract func is_equal(expected: Variant) -> GdUnitDictionaryAssert - - -## Verifies that the current dictionary is not equal to the given one, ignoring order. -@abstract func is_not_equal(expected: Variant) -> GdUnitDictionaryAssert - - -## Overrides the default failure message by given custom message. -@abstract func override_failure_message(message: String) -> GdUnitDictionaryAssert - - -## Appends a custom message to the failure message. -@abstract func append_failure_message(message: String) -> GdUnitDictionaryAssert - - -## Verifies that the current dictionary is empty, it has a size of 0. -@abstract func is_empty() -> GdUnitDictionaryAssert - - -## Verifies that the current dictionary is not empty, it has a size of minimum 1. -@abstract func is_not_empty() -> GdUnitDictionaryAssert - - -## Verifies that the current dictionary is the same. [br] -## Compares the current by object reference equals -@abstract func is_same(expected: Variant) -> GdUnitDictionaryAssert - - -## Verifies that the current dictionary is NOT the same. [br] -## Compares the current by object reference equals -@abstract func is_not_same(expected: Variant) -> GdUnitDictionaryAssert - - -## Verifies that the current dictionary has a size of given value. -@abstract func has_size(expected: int) -> GdUnitDictionaryAssert - - -## Verifies that the current dictionary contains the given key(s).[br] -## The keys are compared by deep parameter comparision, for object reference compare you have to use [method contains_same_keys] -@abstract func contains_keys(...expected: Array) -> GdUnitDictionaryAssert - - -## Verifies that the current dictionary contains the given key and value.[br] -## The key and value are compared by deep parameter comparision, for object reference compare you have to use [method contains_same_key_value] -@abstract func contains_key_value(key: Variant, value: Variant) -> GdUnitDictionaryAssert - - -## Verifies that the current dictionary not contains the given key(s).[br] -## The keys are compared by deep parameter comparision, for object reference compare you have to use [method not_contains_same_keys] -@abstract func not_contains_keys(...expected: Array) -> GdUnitDictionaryAssert - - -## Verifies that the current dictionary contains the given key(s).[br] -## The keys are compared by object reference, for deep parameter comparision use [method contains_keys] -@abstract func contains_same_keys(expected: Array) -> GdUnitDictionaryAssert - - -## Verifies that the current dictionary contains the given key and value.[br] -## The key and value are compared by object reference, for deep parameter comparision use [method contains_key_value] -@abstract func contains_same_key_value(key: Variant, value: Variant) -> GdUnitDictionaryAssert - - -## Verifies that the current dictionary not contains the given key(s). -## The keys are compared by object reference, for deep parameter comparision use [method not_contains_keys] -@abstract func not_contains_same_keys(...expected: Array) -> GdUnitDictionaryAssert diff --git a/addons/gdUnit4/src/GdUnitDictionaryAssert.gd.uid b/addons/gdUnit4/src/GdUnitDictionaryAssert.gd.uid deleted file mode 100644 index 45ba6f27..00000000 --- a/addons/gdUnit4/src/GdUnitDictionaryAssert.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://8s1lymhdvlpu diff --git a/addons/gdUnit4/src/GdUnitFailureAssert.gd b/addons/gdUnit4/src/GdUnitFailureAssert.gd deleted file mode 100644 index 6fec1910..00000000 --- a/addons/gdUnit4/src/GdUnitFailureAssert.gd +++ /dev/null @@ -1,52 +0,0 @@ -## An assertion tool to verify GDUnit asserts. -## This assert is for internal use only, to verify that failed asserts work as expected. -@abstract class_name GdUnitFailureAssert -extends GdUnitAssert - - -## Verifies that the current value is null. -@abstract func is_null() -> GdUnitFailureAssert - - -## Verifies that the current value is not null. -@abstract func is_not_null() -> GdUnitFailureAssert - - -## Verifies that the current value is equal to the given one. -@abstract func is_equal(expected: Variant) -> GdUnitFailureAssert - - -## Verifies that the current value is not equal to expected one. -@abstract func is_not_equal(expected: Variant) -> GdUnitFailureAssert - - -## Overrides the default failure message by given custom message. -@abstract func override_failure_message(message: String) -> GdUnitFailureAssert - - -## Appends a custom message to the failure message. -@abstract func append_failure_message(message: String) -> GdUnitFailureAssert - - -## Verifies if the executed assert was successful -@abstract func is_success() -> GdUnitFailureAssert - - -## Verifies if the executed assert has failed -@abstract func is_failed() -> GdUnitFailureAssert - - -## Verifies the failure line is equal to expected one. -@abstract func has_line(expected: int) -> GdUnitFailureAssert - - -## Verifies the failure message is equal to expected one. -@abstract func has_message(expected: String) -> GdUnitFailureAssert - - -## Verifies that the failure message starts with the expected message. -@abstract func starts_with_message(expected: String) -> GdUnitFailureAssert - - -## Verifies that the failure message contains the expected message. -@abstract func contains_message(expected: String) -> GdUnitFailureAssert diff --git a/addons/gdUnit4/src/GdUnitFailureAssert.gd.uid b/addons/gdUnit4/src/GdUnitFailureAssert.gd.uid deleted file mode 100644 index 204f1438..00000000 --- a/addons/gdUnit4/src/GdUnitFailureAssert.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://x54vf4fue301 diff --git a/addons/gdUnit4/src/GdUnitFileAssert.gd b/addons/gdUnit4/src/GdUnitFileAssert.gd deleted file mode 100644 index 771da906..00000000 --- a/addons/gdUnit4/src/GdUnitFileAssert.gd +++ /dev/null @@ -1,38 +0,0 @@ -@abstract class_name GdUnitFileAssert -extends GdUnitAssert - - -## Verifies that the current value is null. -@abstract func is_null() -> GdUnitFileAssert - - -## Verifies that the current value is not null. -@abstract func is_not_null() -> GdUnitFileAssert - - -## Verifies that the current value is equal to the given one. -@abstract func is_equal(expected: Variant) -> GdUnitFileAssert - - -## Verifies that the current value is not equal to expected one. -@abstract func is_not_equal(expected: Variant) -> GdUnitFileAssert - - -## Overrides the default failure message by given custom message. -@abstract func override_failure_message(message: String) -> GdUnitFileAssert - - -## Appends a custom message to the failure message. -@abstract func append_failure_message(message: String) -> GdUnitFileAssert - - -@abstract func is_file() -> GdUnitFileAssert - - -@abstract func exists() -> GdUnitFileAssert - - -@abstract func is_script() -> GdUnitFileAssert - - -@abstract func contains_exactly(expected_rows :Array) -> GdUnitFileAssert diff --git a/addons/gdUnit4/src/GdUnitFileAssert.gd.uid b/addons/gdUnit4/src/GdUnitFileAssert.gd.uid deleted file mode 100644 index d79b837d..00000000 --- a/addons/gdUnit4/src/GdUnitFileAssert.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://vt1hx0i6pg4h diff --git a/addons/gdUnit4/src/GdUnitFloatAssert.gd b/addons/gdUnit4/src/GdUnitFloatAssert.gd deleted file mode 100644 index 2695ab0e..00000000 --- a/addons/gdUnit4/src/GdUnitFloatAssert.gd +++ /dev/null @@ -1,75 +0,0 @@ -## An Assertion Tool to verify float values -@abstract class_name GdUnitFloatAssert -extends GdUnitAssert - - -## Verifies that the current value is null. -@abstract func is_null() -> GdUnitFloatAssert - - -## Verifies that the current value is not null. -@abstract func is_not_null() -> GdUnitFloatAssert - - -## Verifies that the current value is equal to the given one. -@abstract func is_equal(expected: Variant) -> GdUnitFloatAssert - - -## Verifies that the current value is not equal to expected one. -@abstract func is_not_equal(expected: Variant) -> GdUnitFloatAssert - - -## Verifies that the current and expected value are approximately equal. -@abstract func is_equal_approx(expected: float, approx: float) -> GdUnitFloatAssert - - -## Overrides the default failure message by given custom message. -@abstract func override_failure_message(message: String) -> GdUnitFloatAssert - - -## Appends a custom message to the failure message. -@abstract func append_failure_message(message: String) -> GdUnitFloatAssert - - -## Verifies that the current value is less than the given one. -@abstract func is_less(expected: float) -> GdUnitFloatAssert - - -## Verifies that the current value is less than or equal the given one. -@abstract func is_less_equal(expected: float) -> GdUnitFloatAssert - - -## Verifies that the current value is greater than the given one. -@abstract func is_greater(expected: float) -> GdUnitFloatAssert - - -## Verifies that the current value is greater than or equal the given one. -@abstract func is_greater_equal(expected: float) -> GdUnitFloatAssert - - -## Verifies that the current value is negative. -@abstract func is_negative() -> GdUnitFloatAssert - - -## Verifies that the current value is not negative. -@abstract func is_not_negative() -> GdUnitFloatAssert - - -## Verifies that the current value is equal to zero. -@abstract func is_zero() -> GdUnitFloatAssert - - -## Verifies that the current value is not equal to zero. -@abstract func is_not_zero() -> GdUnitFloatAssert - - -## Verifies that the current value is in the given set of values. -@abstract func is_in(expected: Array) -> GdUnitFloatAssert - - -## Verifies that the current value is not in the given set of values. -@abstract func is_not_in(expected: Array) -> GdUnitFloatAssert - - -## Verifies that the current value is between the given boundaries (inclusive). -@abstract func is_between(from: float, to: float) -> GdUnitFloatAssert diff --git a/addons/gdUnit4/src/GdUnitFloatAssert.gd.uid b/addons/gdUnit4/src/GdUnitFloatAssert.gd.uid deleted file mode 100644 index 4f3ff1e4..00000000 --- a/addons/gdUnit4/src/GdUnitFloatAssert.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://l487wamffax1 diff --git a/addons/gdUnit4/src/GdUnitFuncAssert.gd b/addons/gdUnit4/src/GdUnitFuncAssert.gd deleted file mode 100644 index e8a49c51..00000000 --- a/addons/gdUnit4/src/GdUnitFuncAssert.gd +++ /dev/null @@ -1,42 +0,0 @@ -## An Assertion Tool to verify function callback values -@abstract class_name GdUnitFuncAssert -extends GdUnitAssert - - -## Verifies that the current value is null. -@abstract func is_null() -> GdUnitFuncAssert - - -## Verifies that the current value is not null. -@abstract func is_not_null() -> GdUnitFuncAssert - - -## Verifies that the current value is equal to the given one. -@abstract func is_equal(expected: Variant) -> GdUnitFuncAssert - - -## Verifies that the current value is not equal to expected one. -@abstract func is_not_equal(expected: Variant) -> GdUnitFuncAssert - - -## Overrides the default failure message by given custom message. -@abstract func override_failure_message(message: String) -> GdUnitFuncAssert - - -## Appends a custom message to the failure message. -@abstract func append_failure_message(message: String) -> GdUnitFuncAssert - - -## Verifies that the current value is true. -@abstract func is_true() -> GdUnitFuncAssert - - -## Verifies that the current value is false. -@abstract func is_false() -> GdUnitFuncAssert - - -## Sets the timeout in ms to wait the function returnd the expected value, if the time over a failure is emitted.[br] -## e.g.[br] -## do wait until 5s the function `is_state` is returns 10 [br] -## [code]assert_func(instance, "is_state").wait_until(5000).is_equal(10)[/code] -@abstract func wait_until(timeout: int) -> GdUnitFuncAssert diff --git a/addons/gdUnit4/src/GdUnitFuncAssert.gd.uid b/addons/gdUnit4/src/GdUnitFuncAssert.gd.uid deleted file mode 100644 index f8c037d4..00000000 --- a/addons/gdUnit4/src/GdUnitFuncAssert.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bvvptcdhi1g14 diff --git a/addons/gdUnit4/src/GdUnitGodotErrorAssert.gd b/addons/gdUnit4/src/GdUnitGodotErrorAssert.gd deleted file mode 100644 index 01711f9a..00000000 --- a/addons/gdUnit4/src/GdUnitGodotErrorAssert.gd +++ /dev/null @@ -1,59 +0,0 @@ -## An assertion tool to verify for Godot runtime errors like assert() and push notifications like push_error(). -@abstract class_name GdUnitGodotErrorAssert -extends GdUnitAssert - - -## Verifies that the current value is null. -@abstract func is_null() -> GdUnitGodotErrorAssert - - -## Verifies that the current value is not null. -@abstract func is_not_null() -> GdUnitGodotErrorAssert - - -## Verifies that the current value is equal to the given one. -@abstract func is_equal(expected: Variant) -> GdUnitGodotErrorAssert - - -## Verifies that the current value is not equal to expected one. -@abstract func is_not_equal(expected: Variant) -> GdUnitGodotErrorAssert - - -## Overrides the default failure message by given custom message. -@abstract func override_failure_message(message: String) -> GdUnitGodotErrorAssert - - -## Appends a custom message to the failure message. -@abstract func append_failure_message(message: String) -> GdUnitGodotErrorAssert - - -## Verifies if the executed code runs without any runtime errors -## Usage: -## [codeblock] -## await assert_error().is_success() -## [/codeblock] -@abstract func is_success() -> GdUnitGodotErrorAssert - - -## Verifies if the executed code runs into a runtime error -## Usage: -## [codeblock] -## await assert_error().is_runtime_error() -## [/codeblock] -@abstract func is_runtime_error(expected_error: Variant) -> GdUnitGodotErrorAssert - - -## Verifies if the executed code has a push_warning() used -## Usage: -## [codeblock] -## await assert_error().is_push_warning() -## [/codeblock] -@abstract func is_push_warning(expected_warning: Variant) -> GdUnitGodotErrorAssert - - -## Verifies if the executed code has a push_error() used -## Usage: -## [codeblock] -## await assert_error().is_push_error() -## [/codeblock] -@abstract func is_push_error(expected_error: Variant) -> GdUnitGodotErrorAssert diff --git a/addons/gdUnit4/src/GdUnitGodotErrorAssert.gd.uid b/addons/gdUnit4/src/GdUnitGodotErrorAssert.gd.uid deleted file mode 100644 index bdad5847..00000000 --- a/addons/gdUnit4/src/GdUnitGodotErrorAssert.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bwkv3a1hhdt88 diff --git a/addons/gdUnit4/src/GdUnitIntAssert.gd b/addons/gdUnit4/src/GdUnitIntAssert.gd deleted file mode 100644 index 05eb9223..00000000 --- a/addons/gdUnit4/src/GdUnitIntAssert.gd +++ /dev/null @@ -1,79 +0,0 @@ -## An Assertion Tool to verify integer values -@abstract class_name GdUnitIntAssert -extends GdUnitAssert - - -## Verifies that the current value is null. -@abstract func is_null() -> GdUnitIntAssert - - -## Verifies that the current value is not null. -@abstract func is_not_null() -> GdUnitIntAssert - - -## Verifies that the current value is equal to the given one. -@abstract func is_equal(expected: Variant) -> GdUnitIntAssert - - -## Verifies that the current value is not equal to expected one. -@abstract func is_not_equal(expected: Variant) -> GdUnitIntAssert - - -## Overrides the default failure message by given custom message. -@abstract func override_failure_message(message: String) -> GdUnitIntAssert - - -## Appends a custom message to the failure message. -@abstract func append_failure_message(message: String) -> GdUnitIntAssert - - -## Verifies that the current value is less than the given one. -@abstract func is_less(expected: int) -> GdUnitIntAssert - - -## Verifies that the current value is less than or equal the given one. -@abstract func is_less_equal(expected: int) -> GdUnitIntAssert - - -## Verifies that the current value is greater than the given one. -@abstract func is_greater(expected: int) -> GdUnitIntAssert - - -## Verifies that the current value is greater than or equal the given one. -@abstract func is_greater_equal(expected: int) -> GdUnitIntAssert - - -## Verifies that the current value is even. -@abstract func is_even() -> GdUnitIntAssert - - -## Verifies that the current value is odd. -@abstract func is_odd() -> GdUnitIntAssert - - -## Verifies that the current value is negative. -@abstract func is_negative() -> GdUnitIntAssert - - -## Verifies that the current value is not negative. -@abstract func is_not_negative() -> GdUnitIntAssert - - -## Verifies that the current value is equal to zero. -@abstract func is_zero() -> GdUnitIntAssert - - -## Verifies that the current value is not equal to zero. -@abstract func is_not_zero() -> GdUnitIntAssert - - -## Verifies that the current value is in the given set of values. -@abstract func is_in(expected: Array) -> GdUnitIntAssert - - -## Verifies that the current value is not in the given set of values. -@abstract func is_not_in(expected: Array) -> GdUnitIntAssert - - -## Verifies that the current value is between the given boundaries (inclusive). -@abstract func is_between(from: int, to: int) -> GdUnitIntAssert diff --git a/addons/gdUnit4/src/GdUnitIntAssert.gd.uid b/addons/gdUnit4/src/GdUnitIntAssert.gd.uid deleted file mode 100644 index 968a7b3d..00000000 --- a/addons/gdUnit4/src/GdUnitIntAssert.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ghuy35olsym1 diff --git a/addons/gdUnit4/src/GdUnitObjectAssert.gd b/addons/gdUnit4/src/GdUnitObjectAssert.gd deleted file mode 100644 index 9d7e76ea..00000000 --- a/addons/gdUnit4/src/GdUnitObjectAssert.gd +++ /dev/null @@ -1,51 +0,0 @@ -## An Assertion Tool to verify Object values -@abstract class_name GdUnitObjectAssert -extends GdUnitAssert - - -## Verifies that the current value is null. -@abstract func is_null() -> GdUnitObjectAssert - - -## Verifies that the current value is not null. -@abstract func is_not_null() -> GdUnitObjectAssert - - -## Verifies that the current value is equal to the given one. -@abstract func is_equal(expected: Variant) -> GdUnitObjectAssert - - -## Verifies that the current value is not equal to expected one. -@abstract func is_not_equal(expected: Variant) -> GdUnitObjectAssert - - -## Overrides the default failure message by given custom message. -@abstract func override_failure_message(message: String) -> GdUnitObjectAssert - - -## Appends a custom message to the failure message. -@abstract func append_failure_message(message: String) -> GdUnitObjectAssert - - -## Verifies that the current object is the same as the given one. -@abstract func is_same(expected: Variant) -> GdUnitObjectAssert - - -## Verifies that the current object is not the same as the given one. -@abstract func is_not_same(expected: Variant) -> GdUnitObjectAssert - - -## Verifies that the current object is an instance of the given type. -@abstract func is_instanceof(type: Variant) -> GdUnitObjectAssert - - -## Verifies that the current object is not an instance of the given type. -@abstract func is_not_instanceof(type: Variant) -> GdUnitObjectAssert - - -## Checks whether the current object inherits from the specified type. -@abstract func is_inheriting(type: Variant) -> GdUnitObjectAssert - - -## Checks whether the current object does NOT inherit from the specified type. -@abstract func is_not_inheriting(type: Variant) -> GdUnitObjectAssert diff --git a/addons/gdUnit4/src/GdUnitObjectAssert.gd.uid b/addons/gdUnit4/src/GdUnitObjectAssert.gd.uid deleted file mode 100644 index 1ace27e5..00000000 --- a/addons/gdUnit4/src/GdUnitObjectAssert.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dmunl8xg53sym diff --git a/addons/gdUnit4/src/GdUnitResultAssert.gd b/addons/gdUnit4/src/GdUnitResultAssert.gd deleted file mode 100644 index 01eb8800..00000000 --- a/addons/gdUnit4/src/GdUnitResultAssert.gd +++ /dev/null @@ -1,51 +0,0 @@ -## An Assertion Tool to verify Results -@abstract class_name GdUnitResultAssert -extends GdUnitAssert - - -## Verifies that the current value is null. -@abstract func is_null() -> GdUnitResultAssert - - -## Verifies that the current value is not null. -@abstract func is_not_null() -> GdUnitResultAssert - - -## Verifies that the current value is equal to the given one. -@abstract func is_equal(expected: Variant) -> GdUnitResultAssert - - -## Verifies that the current value is not equal to expected one. -@abstract func is_not_equal(expected: Variant) -> GdUnitResultAssert - - -## Overrides the default failure message by given custom message. -@abstract func override_failure_message(message: String) -> GdUnitResultAssert - - -## Appends a custom message to the failure message. -@abstract func append_failure_message(message: String) -> GdUnitResultAssert - - -## Verifies that the result is ends up with empty -@abstract func is_empty() -> GdUnitResultAssert - - -## Verifies that the result is ends up with success -@abstract func is_success() -> GdUnitResultAssert - - -## Verifies that the result is ends up with warning -@abstract func is_warning() -> GdUnitResultAssert - - -## Verifies that the result is ends up with error -@abstract func is_error() -> GdUnitResultAssert - - -## Verifies that the result contains the given message -@abstract func contains_message(expected: String) -> GdUnitResultAssert - - -## Verifies that the result contains the given value -@abstract func is_value(expected: Variant) -> GdUnitResultAssert diff --git a/addons/gdUnit4/src/GdUnitResultAssert.gd.uid b/addons/gdUnit4/src/GdUnitResultAssert.gd.uid deleted file mode 100644 index 1ac97d4a..00000000 --- a/addons/gdUnit4/src/GdUnitResultAssert.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b4n45twg8y2ar diff --git a/addons/gdUnit4/src/GdUnitSceneRunner.gd b/addons/gdUnit4/src/GdUnitSceneRunner.gd deleted file mode 100644 index 6b11918d..00000000 --- a/addons/gdUnit4/src/GdUnitSceneRunner.gd +++ /dev/null @@ -1,325 +0,0 @@ -## The Scene Runner is a tool used for simulating interactions on a scene. -## With this tool, you can simulate input events such as keyboard or mouse input and/or simulate scene processing over a certain number of frames. -## This tool is typically used for integration testing a scene. -@abstract class_name GdUnitSceneRunner -extends RefCounted - - -## Simulates that an action has been pressed.[br] -## [member action] : the action e.g. [code]"ui_up"[/code][br] -## [member event_index] : [url=https://docs.godotengine.org/en/4.4/classes/class_inputeventaction.html#class-inputeventaction-property-event-index]default=-1[/url][br] -@abstract func simulate_action_pressed(action: String, event_index := -1) -> GdUnitSceneRunner - - -## Simulates that an action is pressed.[br] -## [member action] : the action e.g. [code]"ui_up"[/code][br] -## [member event_index] : [url=https://docs.godotengine.org/en/4.4/classes/class_inputeventaction.html#class-inputeventaction-property-event-index]default=-1[/url][br] -@abstract func simulate_action_press(action: String, event_index := -1) -> GdUnitSceneRunner - - -## Simulates that an action has been released.[br] -## [member action] : the action e.g. [code]"ui_up"[/code][br] -## [member event_index] : [url=https://docs.godotengine.org/en/4.4/classes/class_inputeventaction.html#class-inputeventaction-property-event-index]default=-1[/url][br] -@abstract func simulate_action_release(action: String, event_index := -1) -> GdUnitSceneRunner - - -## Simulates that a key has been pressed.[br] -## [member key_code] : the key code e.g. [constant KEY_ENTER][br] -## [member shift_pressed] : false by default set to true if simmulate shift is press[br] -## [member ctrl_pressed] : false by default set to true if simmulate control is press[br] -## [codeblock] -## func test_key_presssed(): -## var runner = scene_runner("res://scenes/simple_scene.tscn") -## await runner.simulate_key_pressed(KEY_SPACE) -## [/codeblock] -@abstract func simulate_key_pressed(key_code: int, shift_pressed := false, ctrl_pressed := false) -> GdUnitSceneRunner - - -## Simulates that a key is pressed.[br] -## [member key_code] : the key code e.g. [constant KEY_ENTER][br] -## [member shift_pressed] : false by default set to true if simmulate shift is press[br] -## [member ctrl_pressed] : false by default set to true if simmulate control is press[br] -@abstract func simulate_key_press(key_code: int, shift_pressed := false, ctrl_pressed := false) -> GdUnitSceneRunner - - -## Simulates that a key has been released.[br] -## [member key_code] : the key code e.g. [constant KEY_ENTER][br] -## [member shift_pressed] : false by default set to true if simmulate shift is press[br] -## [member ctrl_pressed] : false by default set to true if simmulate control is press[br] -@abstract func simulate_key_release(key_code: int, shift_pressed := false, ctrl_pressed := false) -> GdUnitSceneRunner - - -## Sets the mouse position to the specified vector, provided in pixels and relative to an origin at the upper left corner of the currently focused Window Manager game window.[br] -## [member position] : The absolute position in pixels as Vector2 -@abstract func set_mouse_position(position: Vector2) -> GdUnitSceneRunner - - -## Returns the mouse's position in this Viewport using the coordinate system of this Viewport. -@abstract func get_mouse_position() -> Vector2 - - -## Gets the current global mouse position of the current window -@abstract func get_global_mouse_position() -> Vector2 - - -## Simulates a mouse moved to final position.[br] -## [member position] : The final mouse position -@abstract func simulate_mouse_move(position: Vector2) -> GdUnitSceneRunner - - -## Simulates a mouse move to the relative coordinates (offset).[br] -## [color=yellow]You must use [b]await[/b] to wait until the simulated mouse movement is complete.[/color][br] -## [br] -## [member relative] : The relative position, indicating the mouse position offset.[br] -## [member time] : The time to move the mouse by the relative position in seconds (default is 1 second).[br] -## [member trans_type] : Sets the type of transition used (default is TRANS_LINEAR).[br] -## [codeblock] -## func test_move_mouse(): -## var runner = scene_runner("res://scenes/simple_scene.tscn") -## await runner.simulate_mouse_move_relative(Vector2(100,100)) -## [/codeblock] -@abstract func simulate_mouse_move_relative(relative: Vector2, time: float = 1.0, trans_type: Tween.TransitionType = Tween.TRANS_LINEAR) -> GdUnitSceneRunner - - -## Simulates a mouse move to the absolute coordinates.[br] -## [color=yellow]You must use [b]await[/b] to wait until the simulated mouse movement is complete.[/color][br] -## [br] -## [member position] : The final position of the mouse.[br] -## [member time] : The time to move the mouse to the final position in seconds (default is 1 second).[br] -## [member trans_type] : Sets the type of transition used (default is TRANS_LINEAR).[br] -## [codeblock] -## func test_move_mouse(): -## var runner = scene_runner("res://scenes/simple_scene.tscn") -## await runner.simulate_mouse_move_absolute(Vector2(100,100)) -## [/codeblock] -@abstract func simulate_mouse_move_absolute(position: Vector2, time: float = 1.0, trans_type: Tween.TransitionType = Tween.TRANS_LINEAR) -> GdUnitSceneRunner - - -## Simulates a mouse button pressed.[br] -## [member button_index] : The mouse button identifier, one of the [enum MouseButton] or button wheel constants. -## [member double_click] : Set to true to simulate a double-click -@abstract func simulate_mouse_button_pressed(button_index: MouseButton, double_click := false) -> GdUnitSceneRunner - - -## Simulates a mouse button press (holding)[br] -## [member button_index] : The mouse button identifier, one of the [enum MouseButton] or button wheel constants. -## [member double_click] : Set to true to simulate a double-click -@abstract func simulate_mouse_button_press(button_index: MouseButton, double_click := false) -> GdUnitSceneRunner - - -## Simulates a mouse button released.[br] -## [member button_index] : The mouse button identifier, one of the [enum MouseButton] or button wheel constants. -@abstract func simulate_mouse_button_release(button_index: MouseButton) -> GdUnitSceneRunner - - -## Simulates a screen touch is pressed.[br] -## [member index] : The touch index in the case of a multi-touch event.[br] -## [member position] : The position to touch the screen.[br] -## [member double_tap] : If true, the touch's state is a double tab. -@abstract func simulate_screen_touch_pressed(index: int, position: Vector2, double_tap := false) -> GdUnitSceneRunner - - -## Simulates a screen touch press without releasing it immediately, effectively simulating a "hold" action.[br] -## [member index] : The touch index in the case of a multi-touch event.[br] -## [member position] : The position to touch the screen.[br] -## [member double_tap] : If true, the touch's state is a double tab. -@abstract func simulate_screen_touch_press(index: int, position: Vector2, double_tap := false) -> GdUnitSceneRunner - - -## Simulates a screen touch is released.[br] -## [member index] : The touch index in the case of a multi-touch event.[br] -## [member double_tap] : If true, the touch's state is a double tab. -@abstract func simulate_screen_touch_release(index: int, double_tap := false) -> GdUnitSceneRunner - - -## Simulates a touch drag and drop event to a relative position.[br] -## [color=yellow]You must use [b]await[/b] to wait until the simulated drag&drop is complete.[/color][br] -## [br] -## [member index] : The touch index in the case of a multi-touch event.[br] -## [member relative] : The relative position, indicating the drag&drop position offset.[br] -## [member time] : The time to move to the relative position in seconds (default is 1 second).[br] -## [member trans_type] : Sets the type of transition used (default is TRANS_LINEAR).[br] -## [codeblock] -## func test_touch_drag_drop(): -## var runner = scene_runner("res://scenes/simple_scene.tscn") -## # start drag at position 50,50 -## runner.simulate_screen_touch_drag_begin(1, Vector2(50, 50)) -## # and drop it at final at 150,50 relative (50,50 + 100,0) -## await runner.simulate_screen_touch_drag_relative(1, Vector2(100,0)) -## [/codeblock] -@abstract func simulate_screen_touch_drag_relative(index: int, relative: Vector2, time: float = 1.0, trans_type: Tween.TransitionType = Tween.TRANS_LINEAR) -> GdUnitSceneRunner - - -## Simulates a touch screen drop to the absolute coordinates (offset).[br] -## [color=yellow]You must use [b]await[/b] to wait until the simulated drop is complete.[/color][br] -## [br] -## [member index] : The touch index in the case of a multi-touch event.[br] -## [member position] : The final position, indicating the drop position.[br] -## [member time] : The time to move to the final position in seconds (default is 1 second).[br] -## [member trans_type] : Sets the type of transition used (default is TRANS_LINEAR).[br] -## [codeblock] -## func test_touch_drag_drop(): -## var runner = scene_runner("res://scenes/simple_scene.tscn") -## # start drag at position 50,50 -## runner.simulate_screen_touch_drag_begin(1, Vector2(50, 50)) -## # and drop it at 100,50 -## await runner.simulate_screen_touch_drag_absolute(1, Vector2(100,50)) -## [/codeblock] -@abstract func simulate_screen_touch_drag_absolute(index: int, position: Vector2, time: float = 1.0, trans_type: Tween.TransitionType = Tween.TRANS_LINEAR) -> GdUnitSceneRunner - - -## Simulates a complete drag and drop event from one position to another.[br] -## This is ideal for testing complex drag-and-drop scenarios that require a specific start and end position.[br] -## [color=yellow]You must use [b]await[/b] to wait until the simulated drop is complete.[/color][br] -## [br] -## [member index] : The touch index in the case of a multi-touch event.[br] -## [member position] : The drag start position, indicating the drag position.[br] -## [member drop_position] : The drop position, indicating the drop position.[br] -## [member time] : The time to move to the final position in seconds (default is 1 second).[br] -## [member trans_type] : Sets the type of transition used (default is TRANS_LINEAR).[br] -## [codeblock] -## func test_touch_drag_drop(): -## var runner = scene_runner("res://scenes/simple_scene.tscn") -## # start drag at position 50,50 and drop it at 100,50 -## await runner.simulate_screen_touch_drag_drop(1, Vector2(50, 50), Vector2(100,50)) -## [/codeblock] -@abstract func simulate_screen_touch_drag_drop(index: int, position: Vector2, drop_position: Vector2, time: float = 1.0, trans_type: Tween.TransitionType = Tween.TRANS_LINEAR) -> GdUnitSceneRunner - - -## Simulates a touch screen drag event to given position.[br] -## [member index] : The touch index in the case of a multi-touch event.[br] -## [member position] : The drag start position, indicating the drag position.[br] -@abstract func simulate_screen_touch_drag(index: int, position: Vector2) -> GdUnitSceneRunner - - -## Returns the actual position of the touchscreen drag position by given index. -## [member index] : The touch index in the case of a multi-touch event.[br] -@abstract func get_screen_touch_drag_position(index: int) -> Vector2 - - -## Sets how fast or slow the scene simulation is processed (clock ticks versus the real).[br] -## It defaults to 1.0. A value of 2.0 means the game moves twice as fast as real life, -## whilst a value of 0.5 means the game moves at half the regular speed. -## [member time_factor] : A float representing the simulation speed.[br] -## - Default is 1.0, meaning the simulation runs at normal speed.[br] -## - A value of 2.0 means the simulation runs twice as fast as real time.[br] -## - A value of 0.5 means the simulation runs at half the regular speed.[br] -@abstract func set_time_factor(time_factor: float = 1.0) -> GdUnitSceneRunner - - -## Simulates scene processing for a certain number of frames.[br] -## [member frames] : amount of frames to process[br] -## [member delta_milli] : the time delta between a frame in milliseconds -@abstract func simulate_frames(frames: int, delta_milli: int = -1) -> GdUnitSceneRunner - - -## Simulates scene processing until the given signal is emitted by the scene.[br] -## [member signal_name] : the signal to stop the simulation[br] -## [member args] : optional signal arguments to be matched for stop[br] -@abstract func simulate_until_signal(signal_name: String, ...args: Array) -> GdUnitSceneRunner - - -## Simulates scene processing until the given signal is emitted by the given object.[br] -## [member source] : the object that should emit the signal[br] -## [member signal_name] : the signal to stop the simulation[br] -## [member args] : optional signal arguments to be matched for stop -@abstract func simulate_until_object_signal(source: Object, signal_name: String, ...args: Array) -> GdUnitSceneRunner - - -## Waits for all input events to be processed by flushing any buffered input events -## and then awaiting a full cycle of both the process and physics frames.[br] -## [br] -## This is typically used to ensure that any simulated or queued inputs are fully -## processed before proceeding with the next steps in the scene.[br] -## It's essential for reliable input simulation or when synchronizing logic based -## on inputs.[br] -## -## Usage Example: -## [codeblock] -## await await_input_processed() # Ensure all inputs are processed before continuing -## [/codeblock] -@abstract func await_input_processed() -> void - - -## The await_func function pauses execution until a specified function in the scene returns a value.[br] -## It returns a [GdUnitFuncAssert], which provides a suite of assertion methods to verify the returned value.[br] -## [member func_name] : The name of the function to wait for.[br] -## [member args] : Optional function arguments -## [br] -## Usage Example: -## [codeblock] -## # Waits for 'calculate_score' function and verifies the result is equal to 100. -## await_func("calculate_score").is_equal(100) -## [/codeblock] -@abstract func await_func(func_name: String, ...args: Array) -> GdUnitFuncAssert - - -## The await_func_on function extends the functionality of await_func by allowing you to specify a source node within the scene.[br] -## It waits for a specified function on that node to return a value and returns a [GdUnitFuncAssert] object for assertions.[br] -## [member source] : The object where implements the function.[br] -## [member func_name] : The name of the function to wait for.[br] -## [member args] : optional function arguments -## [br] -## Usage Example: -## [codeblock] -## # Waits for 'calculate_score' function and verifies the result is equal to 100. -## var my_instance := ScoreCalculator.new() -## await_func(my_instance, "calculate_score").is_equal(100) -## [/codeblock] -@abstract func await_func_on(source: Object, func_name: String, ...args: Array) -> GdUnitFuncAssert - - -## Waits for the specified signal to be emitted by the scene. If the signal is not emitted within the given timeout, the operation fails.[br] -## [member signal_name] : The name of the signal to wait for[br] -## [member args] : The signal arguments as an array[br] -## [member timeout] : The maximum duration (in milliseconds) to wait for the signal to be emitted before failing -@abstract func await_signal(signal_name: String, args := [], timeout := 2000 ) -> void - - -## Waits for the specified signal to be emitted by a particular source node. If the signal is not emitted within the given timeout, the operation fails.[br] -## [member source] : the object from which the signal is emitted[br] -## [member signal_name] : The name of the signal to wait for[br] -## [member args] : The signal arguments as an array[br] -## [member timeout] : tThe maximum duration (in milliseconds) to wait for the signal to be emitted before failing -@abstract func await_signal_on(source: Object, signal_name: String, args := [], timeout := 2000 ) -> void - - -## Restores the scene window to a windowed mode and brings it to the foreground.[br] -## This ensures that the scene is visible and active during testing, making it easier to observe and interact with. -@abstract func move_window_to_foreground() -> GdUnitSceneRunner - - -## Minimizes the scene window to a windowed mode and brings it to the background.[br] -## This ensures that the scene is hidden during testing. -@abstract func move_window_to_background() -> GdUnitSceneRunner - - -## Return the current value of the property with the name .[br] -## [member name] : name of property[br] -## [member return] : the value of the property -@abstract func get_property(name: String) -> Variant - - -## Set the value of the property with the name .[br] -## [member name] : name of property[br] -## [member value] : value of property[br] -## [member return] : true|false depending on valid property name. -@abstract func set_property(name: String, value: Variant) -> bool - - -## executes the function specified by in the scene and returns the result.[br] -## [member name] : the name of the function to execute[br] -## [member args] : optional function arguments[br] -## [member return] : the function result -@abstract func invoke(name: String, ...args: Array) -> Variant - - -## Searches for the specified node with the name in the current scene and returns it, otherwise null.[br] -## [member name] : the name of the node to find[br] -## [member recursive] : enables/disables seraching recursive[br] -## [member return] : the node if find otherwise null -@abstract func find_child(name: String, recursive: bool = true, owned: bool = false) -> Node - - -## Access to current running scene -@abstract func scene() -> Node diff --git a/addons/gdUnit4/src/GdUnitSceneRunner.gd.uid b/addons/gdUnit4/src/GdUnitSceneRunner.gd.uid deleted file mode 100644 index a3745db0..00000000 --- a/addons/gdUnit4/src/GdUnitSceneRunner.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dn20c5e8kb3q3 diff --git a/addons/gdUnit4/src/GdUnitSignalAssert.gd b/addons/gdUnit4/src/GdUnitSignalAssert.gd deleted file mode 100644 index bb975e89..00000000 --- a/addons/gdUnit4/src/GdUnitSignalAssert.gd +++ /dev/null @@ -1,46 +0,0 @@ -## An Assertion Tool to verify for emitted signals until a waiting time -@abstract class_name GdUnitSignalAssert -extends GdUnitAssert - - -## Verifies that the current value is null. -@abstract func is_null() -> GdUnitSignalAssert - - -## Verifies that the current value is not null. -@abstract func is_not_null() -> GdUnitSignalAssert - - -## Verifies that the current value is equal to the given one. -@abstract func is_equal(expected: Variant) -> GdUnitSignalAssert - - -## Verifies that the current value is not equal to expected one. -@abstract func is_not_equal(expected: Variant) -> GdUnitSignalAssert - - -## Overrides the default failure message by given custom message. -@abstract func override_failure_message(message: String) -> GdUnitSignalAssert - - -## Appends a custom message to the failure message. -@abstract func append_failure_message(message: String) -> GdUnitSignalAssert - - -## Verifies that given signal is emitted until waiting time -@abstract func is_emitted(name: String, args := []) -> GdUnitSignalAssert - - -## Verifies that given signal is NOT emitted until waiting time -@abstract func is_not_emitted(name: String, args := []) -> GdUnitSignalAssert - - -## Verifies the signal exists checked the emitter -@abstract func is_signal_exists(name: String) -> GdUnitSignalAssert - - -## Sets the assert signal timeout in ms, if the time over a failure is reported.[br] -## e.g.[br] -## do wait until 5s the instance has emitted the signal `signal_a`[br] -## [code]assert_signal(instance).wait_until(5000).is_emitted("signal_a")[/code] -@abstract func wait_until(timeout: int) -> GdUnitSignalAssert diff --git a/addons/gdUnit4/src/GdUnitSignalAssert.gd.uid b/addons/gdUnit4/src/GdUnitSignalAssert.gd.uid deleted file mode 100644 index 1674748f..00000000 --- a/addons/gdUnit4/src/GdUnitSignalAssert.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://572nse6u4l86 diff --git a/addons/gdUnit4/src/GdUnitStringAssert.gd b/addons/gdUnit4/src/GdUnitStringAssert.gd deleted file mode 100644 index 2de698bd..00000000 --- a/addons/gdUnit4/src/GdUnitStringAssert.gd +++ /dev/null @@ -1,71 +0,0 @@ -## An Assertion Tool to verify String values -@abstract class_name GdUnitStringAssert -extends GdUnitAssert - - -## Verifies that the current value is null. -@abstract func is_null() -> GdUnitStringAssert - - -## Verifies that the current value is not null. -@abstract func is_not_null() -> GdUnitStringAssert - - -## Verifies that the current value is equal to the given one. -@abstract func is_equal(expected: Variant) -> GdUnitStringAssert - - -## Verifies that the current String is equal to the given one, ignoring case considerations. -@abstract func is_equal_ignoring_case(expected: Variant) -> GdUnitStringAssert - - -## Verifies that the current value is not equal to expected one. -@abstract func is_not_equal(expected: Variant) -> GdUnitStringAssert - - -## Verifies that the current String is not equal to the given one, ignoring case considerations. -@abstract func is_not_equal_ignoring_case(expected: Variant) -> GdUnitStringAssert - - -## Overrides the default failure message by given custom message. -@abstract func override_failure_message(message: String) -> GdUnitStringAssert - - -## Appends a custom message to the failure message. -@abstract func append_failure_message(message: String) -> GdUnitStringAssert - - -## Verifies that the current String is empty, it has a length of 0. -@abstract func is_empty() -> GdUnitStringAssert - - -## Verifies that the current String is not empty, it has a length of minimum 1. -@abstract func is_not_empty() -> GdUnitStringAssert - - -## Verifies that the current String contains the given String. -@abstract func contains(expected: String) -> GdUnitStringAssert - - -## Verifies that the current String does not contain the given String. -@abstract func not_contains(expected: String) -> GdUnitStringAssert - - -## Verifies that the current String does not contain the given String, ignoring case considerations. -@abstract func contains_ignoring_case(expected: String) -> GdUnitStringAssert - - -## Verifies that the current String does not contain the given String, ignoring case considerations. -@abstract func not_contains_ignoring_case(expected: String) -> GdUnitStringAssert - - -## Verifies that the current String starts with the given prefix. -@abstract func starts_with(expected: String) -> GdUnitStringAssert - - -## Verifies that the current String ends with the given suffix. -@abstract func ends_with(expected: String) -> GdUnitStringAssert - - -## Verifies that the current String has the expected length by used comparator. -@abstract func has_length(length: int, comparator: int = Comparator.EQUAL) -> GdUnitStringAssert diff --git a/addons/gdUnit4/src/GdUnitStringAssert.gd.uid b/addons/gdUnit4/src/GdUnitStringAssert.gd.uid deleted file mode 100644 index 0d26dde3..00000000 --- a/addons/gdUnit4/src/GdUnitStringAssert.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ip241g801xri diff --git a/addons/gdUnit4/src/GdUnitTestSuite.gd b/addons/gdUnit4/src/GdUnitTestSuite.gd deleted file mode 100644 index 48cde7ac..00000000 --- a/addons/gdUnit4/src/GdUnitTestSuite.gd +++ /dev/null @@ -1,691 +0,0 @@ -## The main class for all GdUnit test suites[br] -## This class is the main class to implement your unit tests[br] -## You have to extend and implement your test cases as described[br] -## e.g MyTests.gd [br] -## [codeblock] -## extends GdUnitTestSuite -## # testcase -## func test_case_a(): -## assert_that("value").is_equal("value") -## [/codeblock] -## @tutorial: https://mikeschulze.github.io/gdUnit4/faq/test-suite/ - -@icon("res://addons/gdUnit4/src/ui/settings/logo.png") -class_name GdUnitTestSuite -extends Node - -const NO_ARG :Variant = GdUnitConstants.NO_ARG - -### internal runtime variables that must not be overwritten!!! -@warning_ignore("unused_private_class_variable") -var __is_skipped := false -@warning_ignore("unused_private_class_variable") -var __skip_reason :String = "Unknow." -var __active_test_case :String -var __awaiter := __gdunit_awaiter() - - -### We now load all used asserts and tool scripts into the cache according to the principle of "lazy loading" -### in order to noticeably reduce the loading time of the test suite. -# We go this hard way to increase the loading performance to avoid reparsing all the used scripts -# for more detailed info -> https://github.com/godotengine/godot/issues/67400 -func __lazy_load(script_path :String) -> GDScript: - return GdUnitAssertions.__lazy_load(script_path) - - -func __gdunit_assert() -> GDScript: - return __lazy_load("res://addons/gdUnit4/src/asserts/GdUnitAssertImpl.gd") - - -func __gdunit_tools() -> GDScript: - return __lazy_load("res://addons/gdUnit4/src/core/GdUnitTools.gd") - - -func __gdunit_file_access() -> GDScript: - return __lazy_load("res://addons/gdUnit4/src/core/GdUnitFileAccess.gd") - - -func __gdunit_awaiter() -> Object: - return __lazy_load("res://addons/gdUnit4/src/GdUnitAwaiter.gd").new() - - -func __gdunit_argument_matchers() -> GDScript: - return __lazy_load("res://addons/gdUnit4/src/matchers/GdUnitArgumentMatchers.gd") - - -func __gdunit_object_interactions() -> GDScript: - return __lazy_load("res://addons/gdUnit4/src/doubler/GdUnitObjectInteractions.gd") - - -## This function is called before a test suite starts[br] -## You can overwrite to prepare test data or initalizize necessary variables -func before() -> void: - pass - - -## This function is called at least when a test suite is finished[br] -## You can overwrite to cleanup data created during test running -func after() -> void: - pass - - -## This function is called before a test case starts[br] -## You can overwrite to prepare test case specific data -func before_test() -> void: - pass - - -## This function is called after the test case is finished[br] -## You can overwrite to cleanup your test case specific data -func after_test() -> void: - pass - - -func is_failure(_expected_failure :String = NO_ARG) -> bool: - return Engine.get_meta("GD_TEST_FAILURE") if Engine.has_meta("GD_TEST_FAILURE") else false - - -func set_active_test_case(test_case :String) -> void: - __active_test_case = test_case - - -# === Tools ==================================================================== -# Mapps Godot error number to a readable error message. See at ERROR -# https://docs.godotengine.org/de/stable/classes/class_@globalscope.html#enum-globalscope-error -func error_as_string(error_number :int) -> String: - return error_string(error_number) - - -## A litle helper to auto freeing your created objects after test execution -func auto_free(obj :Variant) -> Variant: - var execution_context := GdUnitThreadManager.get_current_context().get_execution_context() - - assert(execution_context != null, "INTERNAL ERROR: The current execution_context is null! Please report this as bug.") - return execution_context.register_auto_free(obj) - - -@warning_ignore("native_method_override") -func add_child(node :Node, force_readable_name := false, internal := Node.INTERNAL_MODE_DISABLED) -> void: - super.add_child(node, force_readable_name, internal) - var execution_context := GdUnitThreadManager.get_current_context().get_execution_context() - if execution_context != null: - execution_context.orphan_monitor_start() - - -## Discard the error message triggered by a timeout (interruption).[br] -## By default, an interrupted test is reported as an error.[br] -## This function allows you to change the message to Success when an interrupted error is reported. -func discard_error_interupted_by_timeout() -> void: - @warning_ignore("unsafe_method_access") - __gdunit_tools().register_expect_interupted_by_timeout(self, __active_test_case) - - -## Creates a new directory under the temporary directory *user://tmp*[br] -## Useful for storing data during test execution. [br] -## The directory is automatically deleted after test suite execution -func create_temp_dir(relative_path :String) -> String: - @warning_ignore("unsafe_method_access") - return __gdunit_file_access().create_temp_dir(relative_path) - - -## Deletes the temporary base directory[br] -## Is called automatically after each execution of the test suite -func clean_temp_dir() -> void: - @warning_ignore("unsafe_method_access") - __gdunit_file_access().clear_tmp() - - -## Creates a new file under the temporary directory *user://tmp* + [br] -## with given name and given file (default = File.WRITE)[br] -## If success the returned File is automatically closed after the execution of the test suite -func create_temp_file(relative_path :String, file_name :String, mode := FileAccess.WRITE) -> FileAccess: - @warning_ignore("unsafe_method_access") - return __gdunit_file_access().create_temp_file(relative_path, file_name, mode) - - -## Reads a resource by given path into a PackedStringArray. -func resource_as_array(resource_path :String) -> PackedStringArray: - @warning_ignore("unsafe_method_access") - return __gdunit_file_access().resource_as_array(resource_path) - - -## Reads a resource by given path and returned the content as String. -func resource_as_string(resource_path :String) -> String: - @warning_ignore("unsafe_method_access") - return __gdunit_file_access().resource_as_string(resource_path) - - -## Reads a resource by given path and return Variand translated by str_to_var -func resource_as_var(resource_path :String) -> Variant: - @warning_ignore("unsafe_method_access", "unsafe_cast") - return str_to_var(__gdunit_file_access().resource_as_string(resource_path) as String) - - -## Waits for given signal to be emitted by until a specified timeout to fail[br] -## source: the object from which the signal is emitted[br] -## signal_name: signal name[br] -## args: the expected signal arguments as an array[br] -## timeout: the timeout in ms, default is set to 2000ms -func await_signal_on(source :Object, signal_name :String, args :Array = [], timeout :int = 2000) -> Variant: - @warning_ignore("unsafe_method_access") - return await __awaiter.await_signal_on(source, signal_name, args, timeout) - - -## Waits until the next idle frame -func await_idle_frame() -> void: - @warning_ignore("unsafe_method_access") - await __awaiter.await_idle_frame() - - -## Waits for a given amount of milliseconds[br] -## example:[br] -## [codeblock] -## # waits for 100ms -## await await_millis(myNode, 100).completed -## [/codeblock][br] -## use this waiter and not `await get_tree().create_timer().timeout to prevent errors when a test case is timed out -func await_millis(timeout :int) -> void: - @warning_ignore("unsafe_method_access") - await __awaiter.await_millis(timeout) - - -## Creates a new scene runner to allow simulate interactions checked a scene.[br] -## The runner will manage the scene instance and release after the runner is released[br] -## example:[br] -## [codeblock] -## # creates a runner by using a instanciated scene -## var scene = load("res://foo/my_scne.tscn").instantiate() -## var runner := scene_runner(scene) -## -## # or simply creates a runner by using the scene resource path -## var runner := scene_runner("res://foo/my_scne.tscn") -## [/codeblock] -func scene_runner(scene :Variant, verbose := false) -> GdUnitSceneRunner: - return auto_free(__lazy_load("res://addons/gdUnit4/src/core/GdUnitSceneRunnerImpl.gd").new(scene, verbose)) - - -# === Mocking & Spy =========================================================== - -## do return a default value for primitive types or null -const RETURN_DEFAULTS = GdUnitMock.RETURN_DEFAULTS -## do call the real implementation -const CALL_REAL_FUNC = GdUnitMock.CALL_REAL_FUNC -## do return a default value for primitive types and a fully mocked value for Object types -## builds full deep mocked object -const RETURN_DEEP_STUB = GdUnitMock.RETURN_DEEP_STUB - - -## Creates a mock for given class name -func mock(clazz :Variant, mock_mode := RETURN_DEFAULTS) -> Variant: - @warning_ignore("unsafe_method_access") - return __lazy_load("res://addons/gdUnit4/src/mocking/GdUnitMockBuilder.gd").build(clazz, mock_mode) - - -## Creates a spy checked given object instance -func spy(instance :Variant) -> Variant: - @warning_ignore("unsafe_method_access") - return __lazy_load("res://addons/gdUnit4/src/spy/GdUnitSpyBuilder.gd").build(instance) - - -## Configures a return value for the specified function and used arguments.[br] -## [b]Example: -## [codeblock] -## # overrides the return value of myMock.is_selected() to false -## do_return(false).on(myMock).is_selected() -## [/codeblock] -func do_return(value :Variant) -> GdUnitMock: - return GdUnitMock.new(value) - - -## Verifies certain behavior happened at least once or exact number of times -func verify(obj :Variant, times := 1) -> Variant: - @warning_ignore("unsafe_method_access") - return __gdunit_object_interactions().verify(obj, times) - - -## Verifies no interactions is happen checked this mock or spy -func verify_no_interactions(obj :Variant) -> GdUnitAssert: - @warning_ignore("unsafe_method_access") - return __gdunit_object_interactions().verify_no_interactions(obj) - - -## Verifies the given mock or spy has any unverified interaction. -func verify_no_more_interactions(obj :Variant) -> GdUnitAssert: - @warning_ignore("unsafe_method_access") - return __gdunit_object_interactions().verify_no_more_interactions(obj) - - -## Resets the saved function call counters checked a mock or spy -func reset(obj :Variant) -> void: - @warning_ignore("unsafe_method_access") - __gdunit_object_interactions().reset(obj) - - -## Starts monitoring the specified source to collect all transmitted signals.[br] -## The collected signals can then be checked with 'assert_signal'.[br] -## By default, the specified source is automatically released when the test ends. -## You can control this behavior by setting auto_free to false if you do not want the source to be automatically freed.[br] -## Usage: -## [codeblock] -## var emitter := monitor_signals(MyEmitter.new()) -## # call the function to send the signal -## emitter.do_it() -## # verify the signial is emitted -## await assert_signal(emitter).is_emitted('my_signal') -## [/codeblock] -func monitor_signals(source :Object, _auto_free := true) -> Object: - @warning_ignore("unsafe_method_access") - __lazy_load("res://addons/gdUnit4/src/core/thread/GdUnitThreadManager.gd")\ - .get_current_context()\ - .get_signal_collector()\ - .register_emitter(source, true) # force recreate to start with a fresh monitoring - return auto_free(source) if _auto_free else source - - -# === Argument matchers ======================================================== -## Argument matcher to match any argument -func any() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().any() - - -## Argument matcher to match any boolean value -func any_bool() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_BOOL) - - -## Argument matcher to match any integer value -func any_int() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_INT) - - -## Argument matcher to match any float value -func any_float() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_FLOAT) - - -## Argument matcher to match any String value -func any_string() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_STRING) - - -## Argument matcher to match any Color value -func any_color() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_COLOR) - - -## Argument matcher to match any Vector typed value -func any_vector() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_types([ - TYPE_VECTOR2, - TYPE_VECTOR2I, - TYPE_VECTOR3, - TYPE_VECTOR3I, - TYPE_VECTOR4, - TYPE_VECTOR4I, - ]) - - -## Argument matcher to match any Vector2 value -func any_vector2() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_VECTOR2) - - -## Argument matcher to match any Vector2i value -func any_vector2i() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_VECTOR2I) - - -## Argument matcher to match any Vector3 value -func any_vector3() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_VECTOR3) - - -## Argument matcher to match any Vector3i value -func any_vector3i() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_VECTOR3I) - - -## Argument matcher to match any Vector4 value -func any_vector4() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_VECTOR4) - - -## Argument matcher to match any Vector4i value -func any_vector4i() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_VECTOR4I) - - -## Argument matcher to match any Rect2 value -func any_rect2() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_RECT2) - - -## Argument matcher to match any Plane value -func any_plane() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_PLANE) - - -## Argument matcher to match any Quaternion value -func any_quat() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_QUATERNION) - - -## Argument matcher to match any AABB value -func any_aabb() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_AABB) - - -## Argument matcher to match any Basis value -func any_basis() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_BASIS) - - -## Argument matcher to match any Transform2D value -func any_transform_2d() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_TRANSFORM2D) - - -## Argument matcher to match any Transform3D value -func any_transform_3d() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_TRANSFORM3D) - - -## Argument matcher to match any NodePath value -func any_node_path() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_NODE_PATH) - - -## Argument matcher to match any RID value -func any_rid() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_RID) - - -## Argument matcher to match any Object value -func any_object() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_OBJECT) - - -## Argument matcher to match any Dictionary value -func any_dictionary() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_DICTIONARY) - - -## Argument matcher to match any Array value -func any_array() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_ARRAY) - - -## Argument matcher to match any PackedByteArray value -func any_packed_byte_array() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_PACKED_BYTE_ARRAY) - - -## Argument matcher to match any PackedInt32Array value -func any_packed_int32_array() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_PACKED_INT32_ARRAY) - - -## Argument matcher to match any PackedInt64Array value -func any_packed_int64_array() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_PACKED_INT64_ARRAY) - - -## Argument matcher to match any PackedFloat32Array value -func any_packed_float32_array() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_PACKED_FLOAT32_ARRAY) - - -## Argument matcher to match any PackedFloat64Array value -func any_packed_float64_array() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_PACKED_FLOAT64_ARRAY) - - -## Argument matcher to match any PackedStringArray value -func any_packed_string_array() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_PACKED_STRING_ARRAY) - - -## Argument matcher to match any PackedVector2Array value -func any_packed_vector2_array() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_PACKED_VECTOR2_ARRAY) - - -## Argument matcher to match any PackedVector3Array value -func any_packed_vector3_array() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_PACKED_VECTOR3_ARRAY) - - -## Argument matcher to match any PackedColorArray value -func any_packed_color_array() -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().by_type(TYPE_PACKED_COLOR_ARRAY) - - -## Argument matcher to match any instance of given class -func any_class(clazz :Object) -> GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - return __gdunit_argument_matchers().any_class(clazz) - - -# === value extract utils ====================================================== -## Builds an extractor by given function name and optional arguments -func extr(func_name :String, args := Array()) -> GdUnitValueExtractor: - return __lazy_load("res://addons/gdUnit4/src/extractors/GdUnitFuncValueExtractor.gd").new(func_name, args) - - -## Constructs a tuple by given arguments -func tuple(arg0 :Variant, - arg1 :Variant=NO_ARG, - arg2 :Variant=NO_ARG, - arg3 :Variant=NO_ARG, - arg4 :Variant=NO_ARG, - arg5 :Variant=NO_ARG, - arg6 :Variant=NO_ARG, - arg7 :Variant=NO_ARG, - arg8 :Variant=NO_ARG, - arg9 :Variant=NO_ARG) -> GdUnitTuple: - return GdUnitTuple.new(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) - - -# === Asserts ================================================================== - -## The common assertion tool to verify values. -## It checks the given value by type to fit to the best assert -func assert_that(current :Variant) -> GdUnitAssert: - match typeof(current): - TYPE_BOOL: - return assert_bool(current) - TYPE_INT: - return assert_int(current) - TYPE_FLOAT: - return assert_float(current) - TYPE_STRING: - return assert_str(current) - TYPE_VECTOR2, TYPE_VECTOR2I, TYPE_VECTOR3, TYPE_VECTOR3I, TYPE_VECTOR4, TYPE_VECTOR4I: - return assert_vector(current, false) - TYPE_DICTIONARY: - return assert_dict(current) - TYPE_ARRAY, TYPE_PACKED_BYTE_ARRAY, TYPE_PACKED_INT32_ARRAY, TYPE_PACKED_INT64_ARRAY,\ - TYPE_PACKED_FLOAT32_ARRAY, TYPE_PACKED_FLOAT64_ARRAY, TYPE_PACKED_STRING_ARRAY,\ - TYPE_PACKED_VECTOR2_ARRAY, TYPE_PACKED_VECTOR3_ARRAY, TYPE_PACKED_COLOR_ARRAY: - return assert_array(current, false) - TYPE_OBJECT, TYPE_NIL: - return assert_object(current) - _: - return __gdunit_assert().new(current) - - -## An assertion tool to verify boolean values. -func assert_bool(current :Variant) -> GdUnitBoolAssert: - return __lazy_load("res://addons/gdUnit4/src/asserts/GdUnitBoolAssertImpl.gd").new(current) - - -## An assertion tool to verify String values. -func assert_str(current :Variant) -> GdUnitStringAssert: - return __lazy_load("res://addons/gdUnit4/src/asserts/GdUnitStringAssertImpl.gd").new(current) - - -## An assertion tool to verify integer values. -func assert_int(current :Variant) -> GdUnitIntAssert: - return __lazy_load("res://addons/gdUnit4/src/asserts/GdUnitIntAssertImpl.gd").new(current) - - -## An assertion tool to verify float values. -func assert_float(current :Variant) -> GdUnitFloatAssert: - return __lazy_load("res://addons/gdUnit4/src/asserts/GdUnitFloatAssertImpl.gd").new(current) - - -## An assertion tool to verify Vector values.[br] -## This assertion supports all vector types.[br] -## Usage: -## [codeblock] -## assert_vector(Vector2(1.2, 1.000001)).is_equal(Vector2(1.2, 1.000001)) -## [/codeblock] -func assert_vector(current :Variant, type_check := true) -> GdUnitVectorAssert: - return __lazy_load("res://addons/gdUnit4/src/asserts/GdUnitVectorAssertImpl.gd").new(current, type_check) - - -## An assertion tool to verify arrays. -func assert_array(current :Variant, type_check := true) -> GdUnitArrayAssert: - return __lazy_load("res://addons/gdUnit4/src/asserts/GdUnitArrayAssertImpl.gd").new(current, type_check) - - -## An assertion tool to verify dictionaries. -func assert_dict(current :Variant) -> GdUnitDictionaryAssert: - return __lazy_load("res://addons/gdUnit4/src/asserts/GdUnitDictionaryAssertImpl.gd").new(current) - - -## An assertion tool to verify FileAccess. -func assert_file(current :Variant) -> GdUnitFileAssert: - return __lazy_load("res://addons/gdUnit4/src/asserts/GdUnitFileAssertImpl.gd").new(current) - - -## An assertion tool to verify Objects. -func assert_object(current :Variant) -> GdUnitObjectAssert: - return __lazy_load("res://addons/gdUnit4/src/asserts/GdUnitObjectAssertImpl.gd").new(current) - - -func assert_result(current :Variant) -> GdUnitResultAssert: - return __lazy_load("res://addons/gdUnit4/src/asserts/GdUnitResultAssertImpl.gd").new(current) - - -## An assertion tool that waits until a certain time for an expected function return value -func assert_func(instance :Object, func_name :String, args := Array()) -> GdUnitFuncAssert: - return __lazy_load("res://addons/gdUnit4/src/asserts/GdUnitFuncAssertImpl.gd").new(instance, func_name, args) - - -## An assertion tool to verify for emitted signals until a certain time. -func assert_signal(instance :Object) -> GdUnitSignalAssert: - return __lazy_load("res://addons/gdUnit4/src/asserts/GdUnitSignalAssertImpl.gd").new(instance) - - -## An assertion tool to test for failing assertions.[br] -## This assert is only designed for internal use to verify failing asserts working as expected.[br] -## Usage: -## [codeblock] -## assert_failure(func(): assert_bool(true).is_not_equal(true)) \ -## .has_message("Expecting:\n 'true'\n not equal to\n 'true'") -## [/codeblock] -func assert_failure(assertion :Callable) -> GdUnitFailureAssert: - @warning_ignore("unsafe_method_access") - return __lazy_load("res://addons/gdUnit4/src/asserts/GdUnitFailureAssertImpl.gd").new().execute(assertion) - - -## An assertion tool to test for failing assertions.[br] -## This assert is only designed for internal use to verify failing asserts working as expected.[br] -## Usage: -## [codeblock] -## await assert_failure_await(func(): assert_bool(true).is_not_equal(true)) \ -## .has_message("Expecting:\n 'true'\n not equal to\n 'true'") -## [/codeblock] -func assert_failure_await(assertion :Callable) -> GdUnitFailureAssert: - @warning_ignore("unsafe_method_access") - return await __lazy_load("res://addons/gdUnit4/src/asserts/GdUnitFailureAssertImpl.gd").new().execute_and_await(assertion) - - -## An assertion tool to verify Godot errors.[br] -## You can use to verify certain Godot errors like failing assertions, push_error, push_warn.[br] -## Usage: -## [codeblock] -## # tests no error occurred during execution of the code -## await assert_error(func (): return 0 )\ -## .is_success() -## -## # tests a push_error('test error') occured during execution of the code -## await assert_error(func (): push_error('test error') )\ -## .is_push_error('test error') -## [/codeblock] -func assert_error(current :Callable) -> GdUnitGodotErrorAssert: - return __lazy_load("res://addons/gdUnit4/src/asserts/GdUnitGodotErrorAssertImpl.gd").new(current) - - -## Explicitly fails the current test indicating that the feature is not yet implemented.[br] -## This function is useful during development when you want to write test cases before implementing the actual functionality.[br] -## It provides a clear indication that the test failure is expected because the feature is still under development.[br] -## Usage: -## [codeblock] -## # Test for a feature that will be implemented later -## func test_advanced_ai_behavior(): -## assert_not_yet_implemented() -## -## [/codeblock] -func assert_not_yet_implemented() -> void: - @warning_ignore("unsafe_method_access") - __gdunit_assert().new(null).do_fail() - - -## Explicitly fails the current test with a custom error message.[br] -## This function reports an error but does not terminate test execution automatically.[br] -## You must use 'return' after calling fail() to stop the test since GDScript has no exception support.[br] -## Useful for complex conditional testing scenarios where standard assertions are insufficient.[br] -## Usage: -## [codeblock] -## # Fail test when conditions are not met -## if !custom_check(player): -## fail("Player should be alive but has %d health" % player.health) -## return -## -## # Continue with test if conditions pass -## assert_that(player.health).is_greater(0) -## [/codeblock] -func fail(message: String) -> void: - @warning_ignore("unsafe_method_access") - __gdunit_assert().new(null).report_error(message) - - -# --- internal stuff do not override!!! -func ResourcePath() -> String: - return get_script().resource_path diff --git a/addons/gdUnit4/src/GdUnitTestSuite.gd.uid b/addons/gdUnit4/src/GdUnitTestSuite.gd.uid deleted file mode 100644 index 2dc80ed3..00000000 --- a/addons/gdUnit4/src/GdUnitTestSuite.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cgbfa4cflb5nl diff --git a/addons/gdUnit4/src/GdUnitTuple.gd b/addons/gdUnit4/src/GdUnitTuple.gd deleted file mode 100644 index 6c910023..00000000 --- a/addons/gdUnit4/src/GdUnitTuple.gd +++ /dev/null @@ -1,28 +0,0 @@ -## A tuple implementation to hold two or many values -class_name GdUnitTuple -extends RefCounted - -const NO_ARG :Variant = GdUnitConstants.NO_ARG - -var __values :Array = Array() - - -func _init(arg0:Variant, - arg1 :Variant=NO_ARG, - arg2 :Variant=NO_ARG, - arg3 :Variant=NO_ARG, - arg4 :Variant=NO_ARG, - arg5 :Variant=NO_ARG, - arg6 :Variant=NO_ARG, - arg7 :Variant=NO_ARG, - arg8 :Variant=NO_ARG, - arg9 :Variant=NO_ARG) -> void: - __values = GdArrayTools.filter_value([arg0,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9], NO_ARG) - - -func values() -> Array: - return __values - - -func _to_string() -> String: - return "tuple(%s)" % str(__values) diff --git a/addons/gdUnit4/src/GdUnitTuple.gd.uid b/addons/gdUnit4/src/GdUnitTuple.gd.uid deleted file mode 100644 index 0a8b36ec..00000000 --- a/addons/gdUnit4/src/GdUnitTuple.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://mjqw2uww51fk diff --git a/addons/gdUnit4/src/GdUnitValueExtractor.gd b/addons/gdUnit4/src/GdUnitValueExtractor.gd deleted file mode 100644 index 1a344454..00000000 --- a/addons/gdUnit4/src/GdUnitValueExtractor.gd +++ /dev/null @@ -1,9 +0,0 @@ -## This is the base interface for value extraction -class_name GdUnitValueExtractor -extends RefCounted - - -## Extracts a value by given implementation -func extract_value(value :Variant) -> Variant: - push_error("Uninplemented func 'extract_value'") - return value diff --git a/addons/gdUnit4/src/GdUnitValueExtractor.gd.uid b/addons/gdUnit4/src/GdUnitValueExtractor.gd.uid deleted file mode 100644 index 40cc1111..00000000 --- a/addons/gdUnit4/src/GdUnitValueExtractor.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://2dylh01qtb66 diff --git a/addons/gdUnit4/src/GdUnitVectorAssert.gd b/addons/gdUnit4/src/GdUnitVectorAssert.gd deleted file mode 100644 index c186cba2..00000000 --- a/addons/gdUnit4/src/GdUnitVectorAssert.gd +++ /dev/null @@ -1,55 +0,0 @@ -## An Assertion Tool to verify Vector values -@abstract class_name GdUnitVectorAssert -extends GdUnitAssert - - -## Verifies that the current value is null. -@abstract func is_null() -> GdUnitVectorAssert - - -## Verifies that the current value is not null. -@abstract func is_not_null() -> GdUnitVectorAssert - - -## Verifies that the current value is equal to the given one. -@abstract func is_equal(expected: Variant) -> GdUnitVectorAssert - - -## Verifies that the current value is not equal to expected one. -@abstract func is_not_equal(expected: Variant) -> GdUnitVectorAssert - - -## Verifies that the current and expected value are approximately equal. -@abstract func is_equal_approx(expected: Variant, approx: Variant) -> GdUnitVectorAssert - - -## Overrides the default failure message by given custom message. -@abstract func override_failure_message(message: String) -> GdUnitVectorAssert - - -## Appends a custom message to the failure message. -@abstract func append_failure_message(message: String) -> GdUnitVectorAssert - - -## Verifies that the current value is less than the given one. -@abstract func is_less(expected: Variant) -> GdUnitVectorAssert - - -## Verifies that the current value is less than or equal the given one. -@abstract func is_less_equal(expected: Variant) -> GdUnitVectorAssert - - -## Verifies that the current value is greater than the given one. -@abstract func is_greater(expected: Variant) -> GdUnitVectorAssert - - -## Verifies that the current value is greater than or equal the given one. -@abstract func is_greater_equal(expected: Variant) -> GdUnitVectorAssert - - -## Verifies that the current value is between the given boundaries (inclusive). -@abstract func is_between(from: Variant, to: Variant) -> GdUnitVectorAssert - - -## Verifies that the current value is not between the given boundaries (inclusive). -@abstract func is_not_between(from: Variant, to: Variant) -> GdUnitVectorAssert diff --git a/addons/gdUnit4/src/GdUnitVectorAssert.gd.uid b/addons/gdUnit4/src/GdUnitVectorAssert.gd.uid deleted file mode 100644 index a1926b28..00000000 --- a/addons/gdUnit4/src/GdUnitVectorAssert.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bcx6bgypklb3e diff --git a/addons/gdUnit4/src/asserts/CallBackValueProvider.gd b/addons/gdUnit4/src/asserts/CallBackValueProvider.gd deleted file mode 100644 index 6be4b3ee..00000000 --- a/addons/gdUnit4/src/asserts/CallBackValueProvider.gd +++ /dev/null @@ -1,25 +0,0 @@ -# a value provider unsing a callback to get `next` value from a certain function -class_name CallBackValueProvider -extends ValueProvider - -var _cb :Callable -var _args :Array - - -func _init(instance :Object, func_name :String, args :Array = Array(), force_error := true) -> void: - _cb = Callable(instance, func_name); - _args = args - if force_error and not _cb.is_valid(): - push_error("Can't find function '%s' checked instance %s" % [func_name, instance]) - - -func get_value() -> Variant: - if not _cb.is_valid(): - return null - if _args.is_empty(): - return await _cb.call() - return await _cb.callv(_args) - - -func dispose() -> void: - _cb = Callable() diff --git a/addons/gdUnit4/src/asserts/CallBackValueProvider.gd.uid b/addons/gdUnit4/src/asserts/CallBackValueProvider.gd.uid deleted file mode 100644 index 50e1e8a7..00000000 --- a/addons/gdUnit4/src/asserts/CallBackValueProvider.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://r43u2usutiss diff --git a/addons/gdUnit4/src/asserts/DefaultValueProvider.gd b/addons/gdUnit4/src/asserts/DefaultValueProvider.gd deleted file mode 100644 index 2f828fa2..00000000 --- a/addons/gdUnit4/src/asserts/DefaultValueProvider.gd +++ /dev/null @@ -1,13 +0,0 @@ -# default value provider, simple returns the initial value -class_name DefaultValueProvider -extends ValueProvider - -var _value: Variant - - -func _init(value: Variant) -> void: - _value = value - - -func get_value() -> Variant: - return _value diff --git a/addons/gdUnit4/src/asserts/DefaultValueProvider.gd.uid b/addons/gdUnit4/src/asserts/DefaultValueProvider.gd.uid deleted file mode 100644 index cd08d1f8..00000000 --- a/addons/gdUnit4/src/asserts/DefaultValueProvider.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://coauynw7rnsij diff --git a/addons/gdUnit4/src/asserts/GdAssertMessages.gd b/addons/gdUnit4/src/asserts/GdAssertMessages.gd deleted file mode 100644 index f9bc7aa5..00000000 --- a/addons/gdUnit4/src/asserts/GdAssertMessages.gd +++ /dev/null @@ -1,692 +0,0 @@ -class_name GdAssertMessages -extends Resource - -const WARN_COLOR = "#EFF883" -const ERROR_COLOR = "#CD5C5C" -const VALUE_COLOR = "#1E90FF" -const SUB_COLOR := Color(1, 0, 0, .15) -const ADD_COLOR := Color(0, 1, 0, .15) - - -# Dictionary of control characters and their readable representations -const CONTROL_CHARS = { - "\n": "", # Line Feed - "\r": "", # Carriage Return - "\t": "", # Tab - "\b": "", # Backspace - "\f": "", # Form Feed - "\v": "", # Vertical Tab - "\a": "", # Bell - "": "" # Escape -} - - -static func format_dict(value :Variant) -> String: - if not value is Dictionary: - return str(value) - - var dict_value: Dictionary = value - if dict_value.is_empty(): - return "{ }" - var as_rows := var_to_str(value).split("\n") - for index in range( 1, as_rows.size()-1): - as_rows[index] = " " + as_rows[index] - as_rows[-1] = " " + as_rows[-1] - return "\n".join(as_rows) - - -# improved version of InputEvent as text -static func input_event_as_text(event :InputEvent) -> String: - var text := "" - if event is InputEventKey: - var key_event := event as InputEventKey - text += "InputEventKey : key='%s', pressed=%s, keycode=%d, physical_keycode=%s" % [ - event.as_text(), key_event.pressed, key_event.keycode, key_event.physical_keycode] - else: - text += event.as_text() - if event is InputEventMouse: - var mouse_event := event as InputEventMouse - text += ", global_position %s" % mouse_event.global_position - if event is InputEventWithModifiers: - var mouse_event := event as InputEventWithModifiers - text += ", shift=%s, alt=%s, control=%s, meta=%s, command=%s" % [ - mouse_event.shift_pressed, - mouse_event.alt_pressed, - mouse_event.ctrl_pressed, - mouse_event.meta_pressed, - mouse_event.command_or_control_autoremap] - return text - - -static func _colored_string_div(characters: String) -> String: - return colored_array_div(characters.to_utf32_buffer().to_int32_array()) - - -static func colored_array_div(characters: PackedInt32Array) -> String: - if characters.is_empty(): - return "" - var result := PackedInt32Array() - var index := 0 - var missing_chars := PackedInt32Array() - var additional_chars := PackedInt32Array() - - while index < characters.size(): - var character := characters[index] - match character: - GdDiffTool.DIV_ADD: - index += 1 - @warning_ignore("return_value_discarded") - additional_chars.append(characters[index]) - GdDiffTool.DIV_SUB: - index += 1 - @warning_ignore("return_value_discarded") - missing_chars.append(characters[index]) - _: - if not missing_chars.is_empty(): - result.append_array(format_chars(missing_chars, SUB_COLOR)) - missing_chars = PackedInt32Array() - if not additional_chars.is_empty(): - result.append_array(format_chars(additional_chars, ADD_COLOR)) - additional_chars = PackedInt32Array() - @warning_ignore("return_value_discarded") - result.append(character) - index += 1 - - result.append_array(format_chars(missing_chars, SUB_COLOR)) - result.append_array(format_chars(additional_chars, ADD_COLOR)) - return result.to_byte_array().get_string_from_utf32() - - -static func _typed_value(value :Variant) -> String: - return GdDefaultValueDecoder.decode(value) - - -static func _warning(error :String) -> String: - return "[color=%s]%s[/color]" % [WARN_COLOR, error] - - -static func _error(error :String) -> String: - return "[color=%s]%s[/color]" % [ERROR_COLOR, error] - - -static func _nerror(number :Variant) -> String: - match typeof(number): - TYPE_INT: - return "[color=%s]%d[/color]" % [ERROR_COLOR, number] - TYPE_FLOAT: - return "[color=%s]%f[/color]" % [ERROR_COLOR, number] - _: - return "[color=%s]%s[/color]" % [ERROR_COLOR, str(number)] - - -static func _colored_value(value :Variant) -> String: - match typeof(value): - TYPE_STRING, TYPE_STRING_NAME: - return "'[color=%s]%s[/color]'" % [VALUE_COLOR, _colored_string_div(str(value))] - TYPE_INT: - return "'[color=%s]%d[/color]'" % [VALUE_COLOR, value] - TYPE_FLOAT: - return "'[color=%s]%s[/color]'" % [VALUE_COLOR, _typed_value(value)] - TYPE_COLOR: - return "'[color=%s]%s[/color]'" % [VALUE_COLOR, _typed_value(value)] - TYPE_OBJECT: - if value == null: - return "'[color=%s][/color]'" % [VALUE_COLOR] - if value is InputEvent: - var ie: InputEvent = value - return "[color=%s]<%s>[/color]" % [VALUE_COLOR, input_event_as_text(ie)] - var obj_value: Object = value - if obj_value.has_method("_to_string"): - return "[color=%s]<%s>[/color]" % [VALUE_COLOR, str(value)] - return "[color=%s]<%s>[/color]" % [VALUE_COLOR, obj_value.get_class()] - TYPE_DICTIONARY: - return "'[color=%s]%s[/color]'" % [VALUE_COLOR, format_dict(value)] - _: - if GdArrayTools.is_array_type(value): - return "'[color=%s]%s[/color]'" % [VALUE_COLOR, _typed_value(value)] - return "'[color=%s]%s[/color]'" % [VALUE_COLOR, value] - - - -static func _index_report_as_table(index_reports :Array) -> String: - var table := "[table=3]$cells[/table]" - var header := "[cell][right][b]$text[/b][/right]\t[/cell]" - var cell := "[cell][right]$text[/right]\t[/cell]" - var cells := header.replace("$text", "Index") + header.replace("$text", "Current") + header.replace("$text", "Expected") - for report :Variant in index_reports: - var index :String = str(report["index"]) - var current :String = str(report["current"]) - var expected :String = str(report["expected"]) - cells += cell.replace("$text", index) + cell.replace("$text", current) + cell.replace("$text", expected) - return table.replace("$cells", cells) - - -static func orphan_detected_on_suite_setup(count :int) -> String: - return "%s\n Detected <%d> orphan nodes during test suite setup stage! [b]Check before() and after()![/b]" % [ - _warning("WARNING:"), count] - - -static func orphan_detected_on_test_setup(count :int) -> String: - return "%s\n Detected <%d> orphan nodes during test setup! [b]Check before_test() and after_test()![/b]" % [ - _warning("WARNING:"), count] - - -static func orphan_detected_on_test(count :int) -> String: - return "%s\n Detected <%d> orphan nodes during test execution!" % [ - _warning("WARNING:"), count] - - -static func fuzzer_interuped(iterations: int, error: String) -> String: - return "%s %s %s\n %s" % [ - _error("Found an error after"), - _colored_value(iterations + 1), - _error("test iterations"), - error] - - -static func test_timeout(timeout :int) -> String: - return "%s\n %s" % [_error("Timeout !"), _colored_value("Test timed out after %s" % LocalTime.elapsed(timeout))] - - -# gdlint:disable = mixed-tabs-and-spaces -static func test_suite_skipped(hint :String, skip_count :int) -> String: - return """ - %s - Skipped %s tests - Reason: %s - """.dedent().trim_prefix("\n")\ - % [_error("The Entire test-suite is skipped!"), _colored_value(skip_count), _colored_value(hint)] - - -static func test_skipped(hint :String) -> String: - return """ - %s - Reason: %s - """.dedent().trim_prefix("\n")\ - % [_error("This test is skipped!"), _colored_value(hint)] - - -static func error_not_implemented() -> String: - return _error("Test not implemented!") - - -static func error_is_null(current :Variant) -> String: - return "%s %s but was %s" % [_error("Expecting:"), _colored_value(null), _colored_value(current)] - - -static func error_is_not_null() -> String: - return "%s %s" % [_error("Expecting: not to be"), _colored_value(null)] - - -static func error_equal(current :Variant, expected :Variant, index_reports :Array = []) -> String: - var report := """ - %s - %s - but was - %s""".dedent().trim_prefix("\n") % [_error("Expecting:"), _colored_value(expected), _colored_value(current)] - if not index_reports.is_empty(): - report += "\n\n%s\n%s" % [_error("Differences found:"), _index_report_as_table(index_reports)] - return report - - -static func error_not_equal(current :Variant, expected :Variant) -> String: - return "%s\n %s\n not equal to\n %s" % [_error("Expecting:"), _colored_value(expected), _colored_value(current)] - - -static func error_not_equal_case_insensetiv(current :Variant, expected :Variant) -> String: - return "%s\n %s\n not equal to (case insensitiv)\n %s" % [ - _error("Expecting:"), _colored_value(expected), _colored_value(current)] - - -static func error_is_empty(current :Variant) -> String: - return "%s\n must be empty but was\n %s" % [_error("Expecting:"), _colored_value(current)] - - -static func error_is_not_empty() -> String: - return "%s\n must not be empty" % [_error("Expecting:")] - - -static func error_is_same(current :Variant, expected :Variant) -> String: - return "%s\n %s\n to refer to the same object\n %s" % [_error("Expecting:"), _colored_value(expected), _colored_value(current)] - - -@warning_ignore("unused_parameter") -static func error_not_same(_current :Variant, expected :Variant) -> String: - return "%s\n %s" % [_error("Expecting not same:"), _colored_value(expected)] - - -static func error_not_same_error(current :Variant, expected :Variant) -> String: - return "%s\n %s\n but was\n %s" % [_error("Expecting error message:"), _colored_value(expected), _colored_value(current)] - - -static func error_is_instanceof(current: GdUnitResult, expected :GdUnitResult) -> String: - return "%s\n %s\n But it was %s" % [_error("Expected instance of:"),\ - _colored_value(expected.or_else(null)), _colored_value(current.or_else(null))] - - -# -- Boolean Assert specific messages ----------------------------------------------------- -static func error_is_true(current :Variant) -> String: - return "%s %s but is %s" % [_error("Expecting:"), _colored_value(true), _colored_value(current)] - - -static func error_is_false(current :Variant) -> String: - return "%s %s but is %s" % [_error("Expecting:"), _colored_value(false), _colored_value(current)] - - -# - Integer/Float Assert specific messages ----------------------------------------------------- - -static func error_is_even(current :Variant) -> String: - return "%s\n %s must be even" % [_error("Expecting:"), _colored_value(current)] - - -static func error_is_odd(current :Variant) -> String: - return "%s\n %s must be odd" % [_error("Expecting:"), _colored_value(current)] - - -static func error_is_negative(current :Variant) -> String: - return "%s\n %s be negative" % [_error("Expecting:"), _colored_value(current)] - - -static func error_is_not_negative(current :Variant) -> String: - return "%s\n %s be not negative" % [_error("Expecting:"), _colored_value(current)] - - -static func error_is_zero(current :Variant) -> String: - return "%s\n equal to 0 but is %s" % [_error("Expecting:"), _colored_value(current)] - - -static func error_is_not_zero() -> String: - return "%s\n not equal to 0" % [_error("Expecting:")] - - -static func error_is_wrong_type(current_type :Variant.Type, expected_type :Variant.Type) -> String: - return "%s\n Expecting type %s but is %s" % [ - _error("Unexpected type comparison:"), - _colored_value(GdObjects.type_as_string(current_type)), - _colored_value(GdObjects.type_as_string(expected_type))] - - -static func error_is_value(operation :int, current :Variant, expected :Variant, expected2 :Variant = null) -> String: - match operation: - Comparator.EQUAL: - return "%s\n %s but was '%s'" % [_error("Expecting:"), _colored_value(expected), _nerror(current)] - Comparator.LESS_THAN: - return "%s\n %s but was '%s'" % [_error("Expecting to be less than:"), _colored_value(expected), _nerror(current)] - Comparator.LESS_EQUAL: - return "%s\n %s but was '%s'" % [_error("Expecting to be less than or equal:"), _colored_value(expected), _nerror(current)] - Comparator.GREATER_THAN: - return "%s\n %s but was '%s'" % [_error("Expecting to be greater than:"), _colored_value(expected), _nerror(current)] - Comparator.GREATER_EQUAL: - return "%s\n %s but was '%s'" % [_error("Expecting to be greater than or equal:"), _colored_value(expected), _nerror(current)] - Comparator.BETWEEN_EQUAL: - return "%s\n %s\n in range between\n %s <> %s" % [ - _error("Expecting:"), _colored_value(current), _colored_value(expected), _colored_value(expected2)] - Comparator.NOT_BETWEEN_EQUAL: - return "%s\n %s\n not in range between\n %s <> %s" % [ - _error("Expecting:"), _colored_value(current), _colored_value(expected), _colored_value(expected2)] - return "TODO create expected message" - - -static func error_is_in(current :Variant, expected :Array) -> String: - return "%s\n %s\n is in\n %s" % [_error("Expecting:"), _colored_value(current), _colored_value(str(expected))] - - -static func error_is_not_in(current :Variant, expected :Array) -> String: - return "%s\n %s\n is not in\n %s" % [_error("Expecting:"), _colored_value(current), _colored_value(str(expected))] - - -# - StringAssert --------------------------------------------------------------------------------- -static func error_equal_ignoring_case(current :Variant, expected :Variant) -> String: - return "%s\n %s\n but was\n %s (ignoring case)" % [_error("Expecting:"), _colored_value(expected), _colored_value(current)] - - -static func error_contains(current :Variant, expected :Variant) -> String: - return "%s\n %s\n do contains\n %s" % [_error("Expecting:"), _colored_value(current), _colored_value(expected)] - - -static func error_not_contains(current :Variant, expected :Variant) -> String: - return "%s\n %s\n not do contain\n %s" % [_error("Expecting:"), _colored_value(current), _colored_value(expected)] - - -static func error_contains_ignoring_case(current :Variant, expected :Variant) -> String: - return "%s\n %s\n contains\n %s\n (ignoring case)" % [_error("Expecting:"), _colored_value(current), _colored_value(expected)] - - -static func error_not_contains_ignoring_case(current :Variant, expected :Variant) -> String: - return "%s\n %s\n not do contains\n %s\n (ignoring case)" % [_error("Expecting:"), _colored_value(current), _colored_value(expected)] - - -static func error_starts_with(current :Variant, expected :Variant) -> String: - return "%s\n %s\n to start with\n %s" % [_error("Expecting:"), _colored_value(current), _colored_value(expected)] - - -static func error_ends_with(current :Variant, expected :Variant) -> String: - return "%s\n %s\n to end with\n %s" % [_error("Expecting:"), _colored_value(current), _colored_value(expected)] - - -static func error_has_length(current :Variant, expected: int, compare_operator :int) -> String: - @warning_ignore("unsafe_method_access") - var current_length :Variant = current.length() if current != null else null - match compare_operator: - Comparator.EQUAL: - return "%s\n %s but was '%s' in\n %s" % [ - _error("Expecting size:"), _colored_value(expected), _nerror(current_length), _colored_value(current)] - Comparator.LESS_THAN: - return "%s\n %s but was '%s' in\n %s" % [ - _error("Expecting size to be less than:"), _colored_value(expected), _nerror(current_length), _colored_value(current)] - Comparator.LESS_EQUAL: - return "%s\n %s but was '%s' in\n %s" % [ - _error("Expecting size to be less than or equal:"), _colored_value(expected), - _nerror(current_length), _colored_value(current)] - Comparator.GREATER_THAN: - return "%s\n %s but was '%s' in\n %s" % [ - _error("Expecting size to be greater than:"), _colored_value(expected), - _nerror(current_length), _colored_value(current)] - Comparator.GREATER_EQUAL: - return "%s\n %s but was '%s' in\n %s" % [ - _error("Expecting size to be greater than or equal:"), _colored_value(expected), - _nerror(current_length), _colored_value(current)] - return "TODO create expected message" - - -# - ArrayAssert specific messgaes --------------------------------------------------- - -static func error_arr_contains(current: Variant, expected: Variant, not_expect: Variant, not_found: Variant, by_reference: bool) -> String: - var failure_message := "Expecting contains SAME elements:" if by_reference else "Expecting contains elements:" - var error := "%s\n %s\n do contains (in any order)\n %s" % [ - _error(failure_message), _colored_value(current), _colored_value(expected)] - if not is_empty(not_expect): - error += "\nbut some elements where not expected:\n %s" % _colored_value(not_expect) - if not is_empty(not_found): - var prefix := "but" if is_empty(not_expect) else "and" - error += "\n%s could not find elements:\n %s" % [prefix, _colored_value(not_found)] - return error - - -static func error_arr_contains_exactly( - current: Variant, - expected: Variant, - not_expect: Variant, - not_found: Variant, compare_mode: GdObjects.COMPARE_MODE) -> String: - var failure_message := ( - "Expecting contains exactly elements:" if compare_mode == GdObjects.COMPARE_MODE.PARAMETER_DEEP_TEST - else "Expecting contains SAME exactly elements:" - ) - if is_empty(not_expect) and is_empty(not_found): - var arr_current: Array = current - var arr_expected: Array = expected - var diff := _find_first_diff(arr_current, arr_expected) - return "%s\n %s\n do contains (in same order)\n %s\n but has different order %s" % [ - _error(failure_message), _colored_value(current), _colored_value(expected), diff] - - var error := "%s\n %s\n do contains (in same order)\n %s" % [ - _error(failure_message), _colored_value(current), _colored_value(expected)] - if not is_empty(not_expect): - error += "\nbut some elements where not expected:\n %s" % _colored_value(not_expect) - if not is_empty(not_found): - var prefix := "but" if is_empty(not_expect) else "and" - error += "\n%s could not find elements:\n %s" % [prefix, _colored_value(not_found)] - return error - - -static func error_arr_contains_exactly_in_any_order( - current: Variant, - expected: Variant, - not_expect: Variant, - not_found: Variant, - compare_mode: GdObjects.COMPARE_MODE) -> String: - - var failure_message := ( - "Expecting contains exactly elements:" if compare_mode == GdObjects.COMPARE_MODE.PARAMETER_DEEP_TEST - else "Expecting contains SAME exactly elements:" - ) - var error := "%s\n %s\n do contains exactly (in any order)\n %s" % [ - _error(failure_message), _colored_value(current), _colored_value(expected)] - if not is_empty(not_expect): - error += "\nbut some elements where not expected:\n %s" % _colored_value(not_expect) - if not is_empty(not_found): - var prefix := "but" if is_empty(not_expect) else "and" - error += "\n%s could not find elements:\n %s" % [prefix, _colored_value(not_found)] - return error - - -static func error_arr_not_contains(current: Variant, expected: Variant, found: Variant, compare_mode: GdObjects.COMPARE_MODE) -> String: - var failure_message := "Expecting:" if compare_mode == GdObjects.COMPARE_MODE.PARAMETER_DEEP_TEST else "Expecting SAME:" - var error := "%s\n %s\n do not contains\n %s" % [ - _error(failure_message), _colored_value(current), _colored_value(expected)] - if not is_empty(found): - error += "\n but found elements:\n %s" % _colored_value(found) - return error - - -# - DictionaryAssert specific messages ---------------------------------------------- -static func error_contains_keys(current :Array, expected :Array, keys_not_found :Array, compare_mode :GdObjects.COMPARE_MODE) -> String: - var failure := ( - "Expecting contains keys:" if compare_mode == GdObjects.COMPARE_MODE.PARAMETER_DEEP_TEST - else "Expecting contains SAME keys:" - ) - return "%s\n %s\n to contains:\n %s\n but can't find key's:\n %s" % [ - _error(failure), _colored_value(current), _colored_value(expected), _colored_value(keys_not_found)] - - -static func error_not_contains_keys(current :Array, expected :Array, keys_not_found :Array, compare_mode :GdObjects.COMPARE_MODE) -> String: - var failure := ( - "Expecting NOT contains keys:" if compare_mode == GdObjects.COMPARE_MODE.PARAMETER_DEEP_TEST - else "Expecting NOT contains SAME keys" - ) - return "%s\n %s\n do not contains:\n %s\n but contains key's:\n %s" % [ - _error(failure), _colored_value(current), _colored_value(expected), _colored_value(keys_not_found)] - - -static func error_contains_key_value(key :Variant, value :Variant, current_value :Variant, compare_mode :GdObjects.COMPARE_MODE) -> String: - var failure := ( - "Expecting contains key and value:" if compare_mode == GdObjects.COMPARE_MODE.PARAMETER_DEEP_TEST - else "Expecting contains SAME key and value:" - ) - return "%s\n %s : %s\n but contains\n %s : %s" % [ - _error(failure), _colored_value(key), _colored_value(value), _colored_value(key), _colored_value(current_value)] - - -# - ResultAssert specific errors ---------------------------------------------------- -static func error_result_is_empty(current :GdUnitResult) -> String: - return _result_error_message(current, GdUnitResult.EMPTY) - - -static func error_result_is_success(current :GdUnitResult) -> String: - return _result_error_message(current, GdUnitResult.SUCCESS) - - -static func error_result_is_warning(current :GdUnitResult) -> String: - return _result_error_message(current, GdUnitResult.WARN) - - -static func error_result_is_error(current :GdUnitResult) -> String: - return _result_error_message(current, GdUnitResult.ERROR) - - -static func error_result_has_message(current :String, expected :String) -> String: - return "%s\n %s\n but was\n %s." % [_error("Expecting:"), _colored_value(expected), _colored_value(current)] - - -static func error_result_has_message_on_success(expected :String) -> String: - return "%s\n %s\n but the GdUnitResult is a success." % [_error("Expecting:"), _colored_value(expected)] - - -static func error_result_is_value(current :Variant, expected :Variant) -> String: - return "%s\n %s\n but was\n %s." % [_error("Expecting to contain same value:"), _colored_value(expected), _colored_value(current)] - - -static func _result_error_message(current :GdUnitResult, expected_type :int) -> String: - if current == null: - return _error("Expecting the result must be a %s but was ." % result_type(expected_type)) - if current.is_success(): - return _error("Expecting the result must be a %s but was SUCCESS." % result_type(expected_type)) - var error := "Expecting the result must be a %s but was %s:" % [result_type(expected_type), result_type(current._state)] - return "%s\n %s" % [_error(error), _colored_value(result_message(current))] - - -static func error_interrupted(func_name :String, expected :Variant, elapsed :String) -> String: - func_name = humanized(func_name) - if expected == null: - return "%s %s but timed out after %s" % [_error("Expected:"), func_name, elapsed] - return "%s %s %s but timed out after %s" % [_error("Expected:"), func_name, _colored_value(expected), elapsed] - - -static func error_wait_signal(signal_name :String, args :Array, elapsed :String) -> String: - if args.is_empty(): - return "%s %s but timed out after %s" % [ - _error("Expecting emit signal:"), _colored_value(signal_name + "()"), elapsed] - return "%s %s but timed out after %s" % [ - _error("Expecting emit signal:"), _colored_value(signal_name + "(" + str(args) + ")"), elapsed] - - -static func error_signal_emitted(signal_name :String, args :Array, elapsed :String) -> String: - if args.is_empty(): - return "%s %s but is emitted after %s" % [ - _error("Expecting do not emit signal:"), _colored_value(signal_name + "()"), elapsed] - return "%s %s but is emitted after %s" % [ - _error("Expecting do not emit signal:"), _colored_value(signal_name + "(" + str(args) + ")"), elapsed] - - -static func error_await_signal_on_invalid_instance(source :Variant, signal_name :String, args :Array) -> String: - return "%s\n await_signal_on(%s, %s, %s)" % [ - _error("Invalid source! Can't await on signal:"), _colored_value(source), signal_name, args] - - -static func result_type(type :int) -> String: - match type: - GdUnitResult.SUCCESS: return "SUCCESS" - GdUnitResult.WARN: return "WARNING" - GdUnitResult.ERROR: return "ERROR" - GdUnitResult.EMPTY: return "EMPTY" - return "UNKNOWN" - - -static func result_message(result :GdUnitResult) -> String: - match result._state: - GdUnitResult.SUCCESS: return "" - GdUnitResult.WARN: return result.warn_message() - GdUnitResult.ERROR: return result.error_message() - GdUnitResult.EMPTY: return "" - return "UNKNOWN" -# ----------------------------------------------------------------------------------- - -# - Spy|Mock specific errors ---------------------------------------------------- -static func error_no_more_interactions(summary :Dictionary) -> String: - var interactions := PackedStringArray() - for args :Array in summary.keys(): - var times :int = summary[args] - @warning_ignore("return_value_discarded") - interactions.append(_format_arguments(args, times)) - return "%s\n%s\n%s" % [_error("Expecting no more interactions!"), _error("But found interactions on:"), "\n".join(interactions)] - - -static func error_validate_interactions(current_interactions: Dictionary, expected_interactions: Dictionary) -> String: - var collected_interactions := PackedStringArray() - for args: Array in current_interactions.keys(): - var times: int = current_interactions[args] - @warning_ignore("return_value_discarded") - collected_interactions.append(_format_arguments(args, times)) - - var arguments: Array = expected_interactions.keys()[0] - var interactions: int = expected_interactions.values()[0] - var expected_interaction := _format_arguments(arguments, interactions) - return "%s\n%s\n%s\n%s" % [ - _error("Expecting interaction on:"), expected_interaction, _error("But found interactions on:"), "\n".join(collected_interactions)] - - -static func _format_arguments(args :Array, times :int) -> String: - var fname :String = args[0] - var fargs := args.slice(1) as Array - var typed_args := _to_typed_args(fargs) - var fsignature := _colored_value("%s(%s)" % [fname, ", ".join(typed_args)]) - return " %s %d time's" % [fsignature, times] - - -static func _to_typed_args(args :Array) -> PackedStringArray: - var typed := PackedStringArray() - for arg :Variant in args: - @warning_ignore("return_value_discarded") - typed.append(_format_arg(arg) + " :" + GdObjects.type_as_string(typeof(arg))) - return typed - - -static func _format_arg(arg :Variant) -> String: - if arg is InputEvent: - var ie: InputEvent = arg - return input_event_as_text(ie) - return str(arg) - - -static func _find_first_diff(left :Array, right :Array) -> String: - for index in left.size(): - var l :Variant = left[index] - var r :Variant = "" if index >= right.size() else right[index] - if not GdObjects.equals(l, r): - return "at position %s\n '%s' vs '%s'" % [_colored_value(index), _typed_value(l), _typed_value(r)] - return "" - - -static func error_has_size(current :Variant, expected: int) -> String: - @warning_ignore("unsafe_method_access") - var current_size :Variant = null if current == null else current.size() - return "%s\n %s\n but was\n %s" % [_error("Expecting size:"), _colored_value(expected), _colored_value(current_size)] - - -static func error_contains_exactly(current: Array, expected: Array) -> String: - return "%s\n %s\n but was\n %s" % [_error("Expecting exactly equal:"), _colored_value(expected), _colored_value(current)] - - -static func format_chars(characters: PackedInt32Array, type: Color) -> PackedInt32Array: - if characters.size() == 0:# or characters[0] == 10: - return characters - - # Replace each control character with its readable form - var formatted_text := characters.to_byte_array().get_string_from_utf32() - for control_char: String in CONTROL_CHARS: - var replace_text: String = CONTROL_CHARS[control_char] - formatted_text = formatted_text.replace(control_char, replace_text) - - # Handle special ASCII control characters (0x00-0x1F, 0x7F) - var ascii_text := "" - for i in formatted_text.length(): - var character := formatted_text[i] - var code := character.unicode_at(0) - if code < 0x20 and not CONTROL_CHARS.has(character): # Control characters not handled above - ascii_text += "<0x%02X>" % code - elif code == 0x7F: # DEL character - ascii_text += "" - else: - ascii_text += character - - var message := "[bgcolor=#%s][color=white]%s[/color][/bgcolor]" % [ - type.to_html(), - ascii_text - ] - - var result := PackedInt32Array() - result.append_array(message.to_utf32_buffer().to_int32_array()) - return result - - -static func format_invalid(value :String) -> String: - return "[bgcolor=#%s][color=with]%s[/color][/bgcolor]" % [SUB_COLOR.to_html(), value] - - -static func humanized(value :String) -> String: - return value.replace("_", " ") - - -static func build_failure_message(failure :String, additional_failure_message: String, custom_failure_message: String) -> String: - var message := failure if custom_failure_message.is_empty() else custom_failure_message - if additional_failure_message.is_empty(): - return message - return """ - %s - [color=LIME_GREEN][b]Additional info:[/b][/color] - %s""".dedent().trim_prefix("\n") % [message, additional_failure_message] - - -static func is_empty(value: Variant) -> bool: - var arry_value: Array = value - return arry_value != null and arry_value.is_empty() diff --git a/addons/gdUnit4/src/asserts/GdAssertMessages.gd.uid b/addons/gdUnit4/src/asserts/GdAssertMessages.gd.uid deleted file mode 100644 index ea0b25ef..00000000 --- a/addons/gdUnit4/src/asserts/GdAssertMessages.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://vl7cfc01g5wl diff --git a/addons/gdUnit4/src/asserts/GdAssertReports.gd b/addons/gdUnit4/src/asserts/GdAssertReports.gd deleted file mode 100644 index 06b72edb..00000000 --- a/addons/gdUnit4/src/asserts/GdAssertReports.gd +++ /dev/null @@ -1,54 +0,0 @@ -class_name GdAssertReports -extends RefCounted - -const LAST_ERROR = "last_assert_error_message" -const LAST_ERROR_LINE = "last_assert_error_line" - - -static func report_success() -> void: - GdUnitSignals.instance().gdunit_set_test_failed.emit(false) - GdAssertReports.set_last_error_line_number(-1) - Engine.remove_meta(LAST_ERROR) - - -static func report_warning(message :String, line_number :int) -> void: - GdUnitSignals.instance().gdunit_set_test_failed.emit(false) - send_report(GdUnitReport.new().create(GdUnitReport.WARN, line_number, message)) - - -static func report_error(message:String, line_number :int) -> void: - GdUnitSignals.instance().gdunit_set_test_failed.emit(true) - GdAssertReports.set_last_error_line_number(line_number) - Engine.set_meta(LAST_ERROR, message) - # if we expect to fail we handle as success test - if _do_expect_assert_failing(): - return - send_report(GdUnitReport.new().create(GdUnitReport.FAILURE, line_number, message)) - - -static func reset_last_error_line_number() -> void: - Engine.remove_meta(LAST_ERROR_LINE) - - -static func set_last_error_line_number(line_number :int) -> void: - Engine.set_meta(LAST_ERROR_LINE, line_number) - - -static func get_last_error_line_number() -> int: - if Engine.has_meta(LAST_ERROR_LINE): - return Engine.get_meta(LAST_ERROR_LINE) - return -1 - - -static func _do_expect_assert_failing() -> bool: - if Engine.has_meta(GdUnitConstants.EXPECT_ASSERT_REPORT_FAILURES): - return Engine.get_meta(GdUnitConstants.EXPECT_ASSERT_REPORT_FAILURES) - return false - - -static func current_failure() -> String: - return Engine.get_meta(LAST_ERROR) - - -static func send_report(report :GdUnitReport) -> void: - GdUnitThreadManager.get_current_context().get_execution_context().add_report(report) diff --git a/addons/gdUnit4/src/asserts/GdAssertReports.gd.uid b/addons/gdUnit4/src/asserts/GdAssertReports.gd.uid deleted file mode 100644 index e1b6b858..00000000 --- a/addons/gdUnit4/src/asserts/GdAssertReports.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://brxvavm3ml0om diff --git a/addons/gdUnit4/src/asserts/GdUnitArrayAssertImpl.gd b/addons/gdUnit4/src/asserts/GdUnitArrayAssertImpl.gd deleted file mode 100644 index 730b5da9..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitArrayAssertImpl.gd +++ /dev/null @@ -1,436 +0,0 @@ -class_name GdUnitArrayAssertImpl -extends GdUnitArrayAssert - - -var _base: GdUnitAssertImpl -var _current_value_provider: ValueProvider -var _type_check: bool - - -func _init(current: Variant, type_check := true) -> void: - _type_check = type_check - _current_value_provider = DefaultValueProvider.new(current) - _base = GdUnitAssertImpl.new(current) - # save the actual assert instance on the current thread context - GdUnitThreadManager.get_current_context().set_assert(self) - if not _validate_value_type(current): - @warning_ignore("return_value_discarded") - report_error("GdUnitArrayAssert inital error, unexpected type <%s>" % GdObjects.typeof_as_string(current)) - - -func _notification(event: int) -> void: - if event == NOTIFICATION_PREDELETE: - if _base != null: - _base.notification(event) - _base = null - - -func report_success() -> GdUnitArrayAssert: - @warning_ignore("return_value_discarded") - _base.report_success() - return self - - -func report_error(error: String) -> GdUnitArrayAssert: - @warning_ignore("return_value_discarded") - _base.report_error(error) - return self - - -func failure_message() -> String: - return _base.failure_message() - - -func override_failure_message(message: String) -> GdUnitArrayAssert: - @warning_ignore("return_value_discarded") - _base.override_failure_message(message) - return self - - -func append_failure_message(message: String) -> GdUnitArrayAssert: - @warning_ignore("return_value_discarded") - _base.append_failure_message(message) - return self - - -func _validate_value_type(value: Variant) -> bool: - return value == null or GdArrayTools.is_array_type(value) - - -func get_current_value() -> Variant: - return _current_value_provider.get_value() - - -func max_length(left: Variant, right: Variant) -> int: - var ls := str(left).length() - var rs := str(right).length() - return rs if ls < rs else ls - - -# gdlint: disable=function-name -func _toPackedStringArray(value: Variant) -> PackedStringArray: - if GdArrayTools.is_array_type(value): - @warning_ignore("unsafe_cast") - return PackedStringArray(value as Array) - return PackedStringArray([str(value)]) - - -func _array_equals_div(current: Variant, expected: Variant, case_sensitive: bool = false) -> Array[Array]: - var current_value := _toPackedStringArray(current) - var expected_value := _toPackedStringArray(expected) - var index_report := Array() - for index in current_value.size(): - var c := current_value[index] - if index < expected_value.size(): - var e := expected_value[index] - if not GdObjects.equals(c, e, case_sensitive): - var length := max_length(c, e) - current_value[index] = GdAssertMessages.format_invalid(c.lpad(length)) - expected_value[index] = e.lpad(length) - index_report.push_back({"index": index, "current": c, "expected": e}) - else: - current_value[index] = GdAssertMessages.format_invalid(c) - index_report.push_back({"index": index, "current": c, "expected": ""}) - - for index in range(current_value.size(), expected_value.size()): - var value := expected_value[index] - expected_value[index] = GdAssertMessages.format_invalid(value) - index_report.push_back({"index": index, "current": "", "expected": value}) - return [current_value, expected_value, index_report] - - -func _array_div(compare_mode: GdObjects.COMPARE_MODE, left: Array[Variant], right: Array[Variant], _same_order := false) -> Array[Variant]: - var not_expect := left.duplicate(true) - var not_found := right.duplicate(true) - for index_c in left.size(): - var c: Variant = left[index_c] - for index_e in right.size(): - var e: Variant = right[index_e] - if GdObjects.equals(c, e, false, compare_mode): - GdArrayTools.erase_value(not_expect, e) - GdArrayTools.erase_value(not_found, c) - break - return [not_expect, not_found] - - -func _contains(expected: Array, compare_mode: GdObjects.COMPARE_MODE) -> GdUnitArrayAssert: - var by_reference := compare_mode == GdObjects.COMPARE_MODE.OBJECT_REFERENCE - var current_value: Variant = get_current_value() - var expected_value: Variant = _extract_variadic_value(expected) - if not _validate_value_type(expected_value): - return report_error("ERROR: expected value: <%s>\n is not a Array Type!" % GdObjects.typeof_as_string(expected_value)) - - if current_value == null: - return report_error(GdAssertMessages.error_arr_contains(current_value, expected_value, [], expected_value, by_reference)) - @warning_ignore("unsafe_cast") - var diffs := _array_div(compare_mode, current_value as Array[Variant], expected_value as Array[Variant]) - #var not_expect := diffs[0] as Array - var not_found: Array = diffs[1] - if not not_found.is_empty(): - return report_error(GdAssertMessages.error_arr_contains(current_value, expected_value, [], not_found, by_reference)) - return report_success() - - -func _contains_exactly(expected: Array, compare_mode: GdObjects.COMPARE_MODE) -> GdUnitArrayAssert: - var current_value: Variant = get_current_value() - var expected_value: Variant = _extract_variadic_value(expected) - if not _validate_value_type(expected_value): - return report_error("ERROR: expected value: <%s>\n is not a Array Type!" % GdObjects.typeof_as_string(expected_value)) - - if current_value == null: - return report_error(GdAssertMessages.error_arr_contains_exactly(null, expected_value, [], expected_value, compare_mode)) - # has same content in same order - if _is_equal(current_value, expected_value, false, compare_mode): - return report_success() - # check has same elements but in different order - if _is_equals_sorted(current_value, expected_value, false, compare_mode): - return report_error(GdAssertMessages.error_arr_contains_exactly(current_value, expected_value, [], [], compare_mode)) - # find the difference - @warning_ignore("unsafe_cast") - var diffs := _array_div(compare_mode, - current_value as Array[Variant], - expected_value as Array[Variant], - GdObjects.COMPARE_MODE.PARAMETER_DEEP_TEST) - var not_expect: Array[Variant] = diffs[0] - var not_found: Array[Variant] = diffs[1] - return report_error(GdAssertMessages.error_arr_contains_exactly(current_value, expected_value, not_expect, not_found, compare_mode)) - - -func _contains_exactly_in_any_order(expected: Array, compare_mode: GdObjects.COMPARE_MODE) -> GdUnitArrayAssert: - var current_value: Variant = get_current_value() - var expected_value: Variant = _extract_variadic_value(expected) - if not _validate_value_type(expected_value): - return report_error("ERROR: expected value: <%s>\n is not a Array Type!" % GdObjects.typeof_as_string(expected_value)) - - if current_value == null: - return report_error(GdAssertMessages.error_arr_contains_exactly_in_any_order(current_value, expected_value, [], - expected_value, compare_mode)) - # find the difference - @warning_ignore("unsafe_cast") - var diffs := _array_div(compare_mode, current_value as Array[Variant], expected_value as Array[Variant], false) - var not_expect: Array[Variant] = diffs[0] - var not_found: Array[Variant] = diffs[1] - if not_expect.is_empty() and not_found.is_empty(): - return report_success() - return report_error(GdAssertMessages.error_arr_contains_exactly_in_any_order(current_value, expected_value, not_expect, - not_found, compare_mode)) - - -func _not_contains(expected: Array, compare_mode: GdObjects.COMPARE_MODE) -> GdUnitArrayAssert: - var current_value: Variant = get_current_value() - var expected_value: Variant = _extract_variadic_value(expected) - if not _validate_value_type(expected_value): - return report_error("ERROR: expected value: <%s>\n is not a Array Type!" % GdObjects.typeof_as_string(expected_value)) - if current_value == null: - return report_error(GdAssertMessages.error_arr_contains_exactly_in_any_order(current_value, expected_value, [], - expected_value, compare_mode)) - @warning_ignore("unsafe_cast") - var diffs := _array_div(compare_mode, current_value as Array[Variant], expected_value as Array[Variant]) - var found: Array[Variant] = diffs[0] - @warning_ignore("unsafe_cast") - if found.size() == (current_value as Array).size(): - return report_success() - @warning_ignore("unsafe_cast") - var diffs2 := _array_div(compare_mode, expected_value as Array[Variant], diffs[1] as Array[Variant]) - return report_error(GdAssertMessages.error_arr_not_contains(current_value, expected_value, diffs2[0], compare_mode)) - - -func is_null() -> GdUnitArrayAssert: - @warning_ignore("return_value_discarded") - _base.is_null() - return self - - -func is_not_null() -> GdUnitArrayAssert: - @warning_ignore("return_value_discarded") - _base.is_not_null() - return self - - -func is_equal(...expected: Array) -> GdUnitArrayAssert: - var current_value: Variant = get_current_value() - var expected_value: Variant= _extract_variadic_value(expected) - if not _validate_value_type(expected_value): - return report_error("ERROR: expected value: <%s>\n is not a Array Type!" % GdObjects.typeof_as_string(expected_value)) - if current_value == null and expected_value != null: - return report_error(GdAssertMessages.error_equal(null, expected_value)) - - if not _is_equal(current_value, expected_value): - var diff := _array_equals_div(current_value, expected_value) - var expected_as_list := GdArrayTools.as_string(diff[0], false) - var current_as_list := GdArrayTools.as_string(diff[1], false) - var index_report: Array = diff[2] - return report_error(GdAssertMessages.error_equal(expected_as_list, current_as_list, index_report)) - return report_success() - - -# Verifies that the current Array is equal to the given one, ignoring case considerations. -func is_equal_ignoring_case(...expected: Array) -> GdUnitArrayAssert: - var current_value: Variant = get_current_value() - var expected_value: Variant = _extract_variadic_value(expected) - if not _validate_value_type(expected_value): - return report_error("ERROR: expected value: <%s>\n is not a Array Type!" % GdObjects.typeof_as_string(expected_value)) - if current_value == null and expected_value != null: - @warning_ignore("unsafe_cast") - return report_error(GdAssertMessages.error_equal(null, GdArrayTools.as_string(expected_value))) - - if not _is_equal(current_value, expected_value, true): - @warning_ignore("unsafe_cast") - var diff := _array_equals_div(current_value, expected_value, true) - var expected_as_list := GdArrayTools.as_string(diff[0]) - var current_as_list := GdArrayTools.as_string(diff[1]) - var index_report: Array = diff[2] - return report_error(GdAssertMessages.error_equal(expected_as_list, current_as_list, index_report)) - return report_success() - - -func is_not_equal(...expected: Array) -> GdUnitArrayAssert: - var current_value: Variant = get_current_value() - var expected_value: Variant = _extract_variadic_value(expected) - if not _validate_value_type(expected_value): - return report_error("ERROR: expected value: <%s>\n is not a Array Type!" % GdObjects.typeof_as_string(expected_value)) - - if _is_equal(current_value, expected_value): - return report_error(GdAssertMessages.error_not_equal(current_value, expected_value)) - return report_success() - - -func is_not_equal_ignoring_case(...expected: Array) -> GdUnitArrayAssert: - var current_value: Variant = get_current_value() - var expected_value: Variant = _extract_variadic_value(expected) - if not _validate_value_type(expected_value): - return report_error("ERROR: expected value: <%s>\n is not a Array Type!" % GdObjects.typeof_as_string(expected_value)) - - if _is_equal(current_value, expected_value, true): - @warning_ignore("unsafe_cast") - var c := GdArrayTools.as_string(current_value as Array) - @warning_ignore("unsafe_cast") - var e := GdArrayTools.as_string(expected_value) - return report_error(GdAssertMessages.error_not_equal_case_insensetiv(c, e)) - return report_success() - - -func is_empty() -> GdUnitArrayAssert: - var current_value: Variant = get_current_value() - @warning_ignore("unsafe_cast") - if current_value == null or (current_value as Array).size() > 0: - return report_error(GdAssertMessages.error_is_empty(current_value)) - return report_success() - - -func is_not_empty() -> GdUnitArrayAssert: - var current_value: Variant = get_current_value() - @warning_ignore("unsafe_cast") - if current_value != null and (current_value as Array).size() == 0: - return report_error(GdAssertMessages.error_is_not_empty()) - return report_success() - - -@warning_ignore("unused_parameter", "shadowed_global_identifier") -func is_same(expected: Variant) -> GdUnitArrayAssert: - if not _validate_value_type(expected): - return report_error("ERROR: expected value: <%s>\n is not a Array Type!" % GdObjects.typeof_as_string(expected)) - var current: Variant = get_current_value() - if not is_same(current, expected): - @warning_ignore("return_value_discarded") - report_error(GdAssertMessages.error_is_same(current, expected)) - return self - - -func is_not_same(expected: Variant) -> GdUnitArrayAssert: - if not _validate_value_type(expected): - return report_error("ERROR: expected value: <%s>\n is not a Array Type!" % GdObjects.typeof_as_string(expected)) - var current: Variant = get_current_value() - if is_same(current, expected): - @warning_ignore("return_value_discarded") - report_error(GdAssertMessages.error_not_same(current, expected)) - return self - - -func has_size(expected: int) -> GdUnitArrayAssert: - var current_value: Variant = get_current_value() - @warning_ignore("unsafe_cast") - if current_value == null or (current_value as Array).size() != expected: - return report_error(GdAssertMessages.error_has_size(current_value, expected)) - return report_success() - - -func contains(...expected: Array) -> GdUnitArrayAssert: - return _contains(expected, GdObjects.COMPARE_MODE.PARAMETER_DEEP_TEST) - - -func contains_exactly(...expected: Array) -> GdUnitArrayAssert: - return _contains_exactly(expected, GdObjects.COMPARE_MODE.PARAMETER_DEEP_TEST) - - -func contains_exactly_in_any_order(...expected: Array) -> GdUnitArrayAssert: - return _contains_exactly_in_any_order(expected, GdObjects.COMPARE_MODE.PARAMETER_DEEP_TEST) - - -func contains_same(...expected: Array) -> GdUnitArrayAssert: - return _contains(expected, GdObjects.COMPARE_MODE.OBJECT_REFERENCE) - - -func contains_same_exactly(...expected: Array) -> GdUnitArrayAssert: - return _contains_exactly(expected, GdObjects.COMPARE_MODE.OBJECT_REFERENCE) - - -func contains_same_exactly_in_any_order(...expected: Array) -> GdUnitArrayAssert: - return _contains_exactly_in_any_order(expected, GdObjects.COMPARE_MODE.OBJECT_REFERENCE) - - -func not_contains(...expected: Array) -> GdUnitArrayAssert: - return _not_contains(expected, GdObjects.COMPARE_MODE.PARAMETER_DEEP_TEST) - - -func not_contains_same(...expected: Array) -> GdUnitArrayAssert: - return _not_contains(expected, GdObjects.COMPARE_MODE.OBJECT_REFERENCE) - - -func is_instanceof(expected: Variant) -> GdUnitAssert: - @warning_ignore("unsafe_method_access") - _base.is_instanceof(expected) - return self - - -func extract(func_name: String, ...func_args: Array) -> GdUnitArrayAssert: - var extracted_elements := Array() - var args: Array = _extract_variadic_value(func_args) - var extractor := GdUnitFuncValueExtractor.new(func_name, args) - var current: Variant = get_current_value() - if current == null: - _current_value_provider = DefaultValueProvider.new(null) - else: - for element: Variant in current: - extracted_elements.append(extractor.extract_value(element)) - _current_value_provider = DefaultValueProvider.new(extracted_elements) - return self - - -func extractv(...extractors: Array) -> GdUnitArrayAssert: - var extracted_elements := Array() - var current: Variant = get_current_value() - if current == null: - _current_value_provider = DefaultValueProvider.new(null) - else: - for element: Variant in current: - var ev: Array[Variant] = [ - GdUnitTuple.NO_ARG, - GdUnitTuple.NO_ARG, - GdUnitTuple.NO_ARG, - GdUnitTuple.NO_ARG, - GdUnitTuple.NO_ARG, - GdUnitTuple.NO_ARG, - GdUnitTuple.NO_ARG, - GdUnitTuple.NO_ARG, - GdUnitTuple.NO_ARG, - GdUnitTuple.NO_ARG - ] - - for index: int in extractors.size(): - var extractor: GdUnitValueExtractor = extractors[index] - ev[index] = extractor.extract_value(element) - if extractors.size() > 1: - extracted_elements.append(GdUnitTuple.new(ev[0], ev[1], ev[2], ev[3], ev[4], ev[5], ev[6], ev[7], ev[8], ev[9])) - else: - extracted_elements.append(ev[0]) - _current_value_provider = DefaultValueProvider.new(extracted_elements) - return self - - -## Small helper to support the old expected arguments as single array and variadic arguments -func _extract_variadic_value(values: Variant) -> Variant: - @warning_ignore("unsafe_method_access") - if values != null and values.size() == 1 and GdArrayTools.is_array_type(values[0]): - return values[0] - return values - - -@warning_ignore("incompatible_ternary") -func _is_equal( - left: Variant, - right: Variant, - case_sensitive := false, - compare_mode := GdObjects.COMPARE_MODE.PARAMETER_DEEP_TEST) -> bool: - - @warning_ignore("unsafe_cast") - return GdObjects.equals( - (left as Array) if GdArrayTools.is_array_type(left) else left, - (right as Array) if GdArrayTools.is_array_type(right) else right, - case_sensitive, - compare_mode - ) - - -func _is_equals_sorted( - left: Variant, - right: Variant, - case_sensitive := false, - compare_mode := GdObjects.COMPARE_MODE.PARAMETER_DEEP_TEST) -> bool: - - @warning_ignore("unsafe_cast") - return GdObjects.equals_sorted( - left as Array, - right as Array, - case_sensitive, - compare_mode) diff --git a/addons/gdUnit4/src/asserts/GdUnitArrayAssertImpl.gd.uid b/addons/gdUnit4/src/asserts/GdUnitArrayAssertImpl.gd.uid deleted file mode 100644 index e49cbab9..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitArrayAssertImpl.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bx7cehfdh2x4w diff --git a/addons/gdUnit4/src/asserts/GdUnitAssertImpl.gd b/addons/gdUnit4/src/asserts/GdUnitAssertImpl.gd deleted file mode 100644 index 9f578c4d..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitAssertImpl.gd +++ /dev/null @@ -1,80 +0,0 @@ -class_name GdUnitAssertImpl -extends GdUnitAssert - - -var _current :Variant -var _current_failure_message :String = "" -var _custom_failure_message :String = "" -var _additional_failure_message: String = "" - - -func _init(current :Variant) -> void: - _current = current - # save the actual assert instance on the current thread context - GdUnitThreadManager.get_current_context().set_assert(self) - GdAssertReports.reset_last_error_line_number() - - - -func failure_message() -> String: - return _current_failure_message - - -func current_value() -> Variant: - return _current - - -func report_success() -> GdUnitAssert: - GdAssertReports.report_success() - return self - - -func report_error(failure :String, failure_line_number: int = -1) -> GdUnitAssert: - var line_number := failure_line_number if failure_line_number != -1 else GdUnitAssertions.get_line_number() - GdAssertReports.set_last_error_line_number(line_number) - _current_failure_message = GdAssertMessages.build_failure_message(failure, _additional_failure_message, _custom_failure_message) - GdAssertReports.report_error(_current_failure_message, line_number) - Engine.set_meta("GD_TEST_FAILURE", true) - return self - - -func do_fail() -> GdUnitAssert: - return report_error(GdAssertMessages.error_not_implemented()) - - -func override_failure_message(message: String) -> GdUnitAssert: - _custom_failure_message = message - return self - - -func append_failure_message(message: String) -> GdUnitAssert: - _additional_failure_message = message - return self - - -func is_null() -> GdUnitAssert: - var current :Variant = current_value() - if current != null: - return report_error(GdAssertMessages.error_is_null(current)) - return report_success() - - -func is_not_null() -> GdUnitAssert: - var current :Variant = current_value() - if current == null: - return report_error(GdAssertMessages.error_is_not_null()) - return report_success() - - -func is_equal(expected: Variant) -> GdUnitAssert: - var current: Variant = current_value() - if not GdObjects.equals(current, expected): - return report_error(GdAssertMessages.error_equal(current, expected)) - return report_success() - - -func is_not_equal(expected: Variant) -> GdUnitAssert: - var current: Variant = current_value() - if GdObjects.equals(current, expected): - return report_error(GdAssertMessages.error_not_equal(current, expected)) - return report_success() diff --git a/addons/gdUnit4/src/asserts/GdUnitAssertImpl.gd.uid b/addons/gdUnit4/src/asserts/GdUnitAssertImpl.gd.uid deleted file mode 100644 index e60fa2ed..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitAssertImpl.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cq38mcld2thyl diff --git a/addons/gdUnit4/src/asserts/GdUnitAssertions.gd b/addons/gdUnit4/src/asserts/GdUnitAssertions.gd deleted file mode 100644 index a5b53c17..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitAssertions.gd +++ /dev/null @@ -1,68 +0,0 @@ -# Preloads all GdUnit assertions -class_name GdUnitAssertions -extends RefCounted - - -@warning_ignore("return_value_discarded") -func _init() -> void: - # preload all gdunit assertions to speedup testsuite loading time - # gdlint:disable=private-method-call - @warning_ignore_start("return_value_discarded") - GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitAssertImpl.gd") - GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitBoolAssertImpl.gd") - GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitStringAssertImpl.gd") - GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitIntAssertImpl.gd") - GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitFloatAssertImpl.gd") - GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitVectorAssertImpl.gd") - GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitArrayAssertImpl.gd") - GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitDictionaryAssertImpl.gd") - GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitFileAssertImpl.gd") - GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitObjectAssertImpl.gd") - GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitResultAssertImpl.gd") - GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitFuncAssertImpl.gd") - GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitSignalAssertImpl.gd") - GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitFailureAssertImpl.gd") - GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitGodotErrorAssertImpl.gd") - @warning_ignore_restore("return_value_discarded") - - -### We now load all used asserts and tool scripts into the cache according to the principle of "lazy loading" -### in order to noticeably reduce the loading time of the test suite. -# We go this hard way to increase the loading performance to avoid reparsing all the used scripts -# for more detailed info -> https://github.com/godotengine/godot/issues/67400 -# gdlint:disable=function-name -static func __lazy_load(script_path :String) -> GDScript: - return ResourceLoader.load(script_path, "GDScript", ResourceLoader.CACHE_MODE_REUSE) - - -static func validate_value_type(value :Variant, type :Variant.Type) -> bool: - return value == null or typeof(value) == type - - -# Scans the current stack trace for the root cause to extract the line number -static func get_line_number() -> int: - var stack_trace := get_stack() - if stack_trace == null or stack_trace.is_empty(): - return -1 - for index in stack_trace.size(): - var stack_info :Dictionary = stack_trace[index] - var function :String = stack_info.get("function") - # we catch helper asserts to skip over to return the correct line number - if function.begins_with("assert_"): - continue - if function.begins_with("test_"): - return stack_info.get("line") - var source :String = stack_info.get("source") - if source.is_empty() \ - or source.begins_with("user://") \ - or source.ends_with("GdUnitAssert.gd") \ - or source.ends_with("GdUnitAssertions.gd") \ - or source.ends_with("AssertImpl.gd") \ - or source.ends_with("GdUnitTestSuite.gd") \ - or source.ends_with("GdUnitSceneRunnerImpl.gd") \ - or source.ends_with("GdUnitObjectInteractions.gd") \ - or source.ends_with("GdUnitObjectInteractionsVerifier.gd") \ - or source.ends_with("GdUnitAwaiter.gd"): - continue - return stack_info.get("line") - return -1 diff --git a/addons/gdUnit4/src/asserts/GdUnitAssertions.gd.uid b/addons/gdUnit4/src/asserts/GdUnitAssertions.gd.uid deleted file mode 100644 index a8600308..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitAssertions.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://61d7pdgldg0r diff --git a/addons/gdUnit4/src/asserts/GdUnitBoolAssertImpl.gd b/addons/gdUnit4/src/asserts/GdUnitBoolAssertImpl.gd deleted file mode 100644 index 2fc0ce43..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitBoolAssertImpl.gd +++ /dev/null @@ -1,87 +0,0 @@ -extends GdUnitBoolAssert - -var _base: GdUnitAssertImpl - - -func _init(current :Variant) -> void: - _base = GdUnitAssertImpl.new(current) - # save the actual assert instance on the current thread context - GdUnitThreadManager.get_current_context().set_assert(self) - if not GdUnitAssertions.validate_value_type(current, TYPE_BOOL): - @warning_ignore("return_value_discarded") - report_error("GdUnitBoolAssert inital error, unexpected type <%s>" % GdObjects.typeof_as_string(current)) - - -func _notification(event :int) -> void: - if event == NOTIFICATION_PREDELETE: - if _base != null: - _base.notification(event) - _base = null - - -func current_value() -> Variant: - return _base.current_value() - - -func report_success() -> GdUnitBoolAssert: - @warning_ignore("return_value_discarded") - _base.report_success() - return self - - -func report_error(error :String) -> GdUnitBoolAssert: - @warning_ignore("return_value_discarded") - _base.report_error(error) - return self - - -func failure_message() -> String: - return _base.failure_message() - - -func override_failure_message(message: String) -> GdUnitBoolAssert: - @warning_ignore("return_value_discarded") - _base.override_failure_message(message) - return self - - -func append_failure_message(message: String) -> GdUnitBoolAssert: - @warning_ignore("return_value_discarded") - _base.append_failure_message(message) - return self - - -func is_null() -> GdUnitBoolAssert: - @warning_ignore("return_value_discarded") - _base.is_null() - return self - - -func is_not_null() -> GdUnitBoolAssert: - @warning_ignore("return_value_discarded") - _base.is_not_null() - return self - - -func is_equal(expected: Variant) -> GdUnitBoolAssert: - @warning_ignore("return_value_discarded") - _base.is_equal(expected) - return self - - -func is_not_equal(expected: Variant) -> GdUnitBoolAssert: - @warning_ignore("return_value_discarded") - _base.is_not_equal(expected) - return self - - -func is_true() -> GdUnitBoolAssert: - if current_value() != true: - return report_error(GdAssertMessages.error_is_true(current_value())) - return report_success() - - -func is_false() -> GdUnitBoolAssert: - if current_value() == true || current_value() == null: - return report_error(GdAssertMessages.error_is_false(current_value())) - return report_success() diff --git a/addons/gdUnit4/src/asserts/GdUnitBoolAssertImpl.gd.uid b/addons/gdUnit4/src/asserts/GdUnitBoolAssertImpl.gd.uid deleted file mode 100644 index 76e9a3a0..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitBoolAssertImpl.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cxndss6mdq7de diff --git a/addons/gdUnit4/src/asserts/GdUnitDictionaryAssertImpl.gd b/addons/gdUnit4/src/asserts/GdUnitDictionaryAssertImpl.gd deleted file mode 100644 index c57bbc23..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitDictionaryAssertImpl.gd +++ /dev/null @@ -1,207 +0,0 @@ -extends GdUnitDictionaryAssert - -var _base: GdUnitAssertImpl - - -func _init(current :Variant) -> void: - _base = GdUnitAssertImpl.new(current) - # save the actual assert instance on the current thread context - GdUnitThreadManager.get_current_context().set_assert(self) - if not GdUnitAssertions.validate_value_type(current, TYPE_DICTIONARY): - @warning_ignore("return_value_discarded") - report_error("GdUnitDictionaryAssert inital error, unexpected type <%s>" % GdObjects.typeof_as_string(current)) - - -func _notification(event :int) -> void: - if event == NOTIFICATION_PREDELETE: - if _base != null: - _base.notification(event) - _base = null - - -func report_success() -> GdUnitDictionaryAssert: - @warning_ignore("return_value_discarded") - _base.report_success() - return self - - -func report_error(error :String) -> GdUnitDictionaryAssert: - @warning_ignore("return_value_discarded") - _base.report_error(error) - return self - - -func failure_message() -> String: - return _base.failure_message() - - -func override_failure_message(message: String) -> GdUnitDictionaryAssert: - @warning_ignore("return_value_discarded") - _base.override_failure_message(message) - return self - - -func append_failure_message(message: String) -> GdUnitDictionaryAssert: - @warning_ignore("return_value_discarded") - _base.append_failure_message(message) - return self - - -func current_value() -> Variant: - return _base.current_value() - - -func is_null() -> GdUnitDictionaryAssert: - @warning_ignore("return_value_discarded") - _base.is_null() - return self - - -func is_not_null() -> GdUnitDictionaryAssert: - @warning_ignore("return_value_discarded") - _base.is_not_null() - return self - - -func is_equal(expected: Variant) -> GdUnitDictionaryAssert: - var current :Variant = current_value() - if current == null: - return report_error(GdAssertMessages.error_equal(null, GdAssertMessages.format_dict(expected))) - if not GdObjects.equals(current, expected): - var c := GdAssertMessages.format_dict(current) - var e := GdAssertMessages.format_dict(expected) - return report_error(GdAssertMessages.error_equal(c, e)) - return report_success() - - -func is_not_equal(expected: Variant) -> GdUnitDictionaryAssert: - var current: Variant = current_value() - if GdObjects.equals(current, expected): - return report_error(GdAssertMessages.error_not_equal(current, expected)) - return report_success() - - -@warning_ignore("unused_parameter", "shadowed_global_identifier") -func is_same(expected :Variant) -> GdUnitDictionaryAssert: - var current :Variant = current_value() - if current == null: - return report_error(GdAssertMessages.error_equal(null, GdAssertMessages.format_dict(expected))) - if not is_same(current, expected): - var c := GdAssertMessages.format_dict(current) - var e := GdAssertMessages.format_dict(expected) - return report_error(GdAssertMessages.error_is_same(c, e)) - return report_success() - - -@warning_ignore("unused_parameter", "shadowed_global_identifier") -func is_not_same(expected :Variant) -> GdUnitDictionaryAssert: - var current :Variant = current_value() - if is_same(current, expected): - return report_error(GdAssertMessages.error_not_same(current, expected)) - return report_success() - - -func is_empty() -> GdUnitDictionaryAssert: - var current :Variant = current_value() - @warning_ignore("unsafe_cast") - if current == null or not (current as Dictionary).is_empty(): - return report_error(GdAssertMessages.error_is_empty(current)) - return report_success() - - -func is_not_empty() -> GdUnitDictionaryAssert: - var current :Variant = current_value() - @warning_ignore("unsafe_cast") - if current == null or (current as Dictionary).is_empty(): - return report_error(GdAssertMessages.error_is_not_empty()) - return report_success() - - -func has_size(expected: int) -> GdUnitDictionaryAssert: - var current :Variant = current_value() - if current == null: - return report_error(GdAssertMessages.error_is_not_null()) - @warning_ignore("unsafe_cast") - if (current as Dictionary).size() != expected: - return report_error(GdAssertMessages.error_has_size(current, expected)) - return report_success() - - -func _contains_keys(expected: Array, compare_mode: GdObjects.COMPARE_MODE) -> GdUnitDictionaryAssert: - var current :Variant = current_value() - var expected_value: Array = _extract_variadic_value(expected) - if current == null: - return report_error(GdAssertMessages.error_is_not_null()) - # find expected keys - @warning_ignore("unsafe_cast") - var keys_not_found :Array = expected_value.filter(_filter_by_key.bind((current as Dictionary).keys(), compare_mode)) - if not keys_not_found.is_empty(): - @warning_ignore("unsafe_cast") - return report_error(GdAssertMessages.error_contains_keys((current as Dictionary).keys() as Array, expected_value, - keys_not_found, compare_mode)) - return report_success() - - -func _contains_key_value(key :Variant, value :Variant, compare_mode :GdObjects.COMPARE_MODE) -> GdUnitDictionaryAssert: - var current :Variant = current_value() - var expected := [key] - if current == null: - return report_error(GdAssertMessages.error_is_not_null()) - var dict_current: Dictionary = current - var keys_not_found :Array = expected.filter(_filter_by_key.bind(dict_current.keys(), compare_mode)) - if not keys_not_found.is_empty(): - return report_error(GdAssertMessages.error_contains_keys(dict_current.keys() as Array, expected, keys_not_found, compare_mode)) - if not GdObjects.equals(dict_current[key], value, false, compare_mode): - return report_error(GdAssertMessages.error_contains_key_value(key, value, dict_current[key], compare_mode)) - return report_success() - - -func _not_contains_keys(expected: Array, compare_mode: GdObjects.COMPARE_MODE) -> GdUnitDictionaryAssert: - var current :Variant = current_value() - var expected_value: Array = _extract_variadic_value(expected) - if current == null: - return report_error(GdAssertMessages.error_is_not_null()) - var dict_current: Dictionary = current - var keys_found :Array = dict_current.keys().filter(_filter_by_key.bind(expected_value, compare_mode, true)) - if not keys_found.is_empty(): - return report_error(GdAssertMessages.error_not_contains_keys(dict_current.keys() as Array, expected_value, keys_found, compare_mode)) - return report_success() - - -func contains_keys(...expected: Array) -> GdUnitDictionaryAssert: - return _contains_keys(expected, GdObjects.COMPARE_MODE.PARAMETER_DEEP_TEST) - - -func contains_key_value(key :Variant, value :Variant) -> GdUnitDictionaryAssert: - return _contains_key_value(key, value, GdObjects.COMPARE_MODE.PARAMETER_DEEP_TEST) - - -func not_contains_keys(...expected: Array) -> GdUnitDictionaryAssert: - return _not_contains_keys(expected, GdObjects.COMPARE_MODE.PARAMETER_DEEP_TEST) - - -func contains_same_keys(expected :Array) -> GdUnitDictionaryAssert: - return _contains_keys(expected, GdObjects.COMPARE_MODE.OBJECT_REFERENCE) - - -func contains_same_key_value(key :Variant, value :Variant) -> GdUnitDictionaryAssert: - return _contains_key_value(key, value, GdObjects.COMPARE_MODE.OBJECT_REFERENCE) - - -func not_contains_same_keys(...expected: Array) -> GdUnitDictionaryAssert: - return _not_contains_keys(expected, GdObjects.COMPARE_MODE.OBJECT_REFERENCE) - - -func _filter_by_key(element :Variant, values :Array, compare_mode :GdObjects.COMPARE_MODE, is_not :bool = false) -> bool: - for key :Variant in values: - if GdObjects.equals(key, element, false, compare_mode): - return is_not - return !is_not - - -## Small helper to support the old expected arguments as single array and variadic arguments -func _extract_variadic_value(values: Variant) -> Variant: - @warning_ignore("unsafe_method_access") - if values != null and values.size() == 1 and GdArrayTools.is_array_type(values[0]): - return values[0] - return values diff --git a/addons/gdUnit4/src/asserts/GdUnitDictionaryAssertImpl.gd.uid b/addons/gdUnit4/src/asserts/GdUnitDictionaryAssertImpl.gd.uid deleted file mode 100644 index 10a744ef..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitDictionaryAssertImpl.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dqrp7csbeyvon diff --git a/addons/gdUnit4/src/asserts/GdUnitFailureAssertImpl.gd b/addons/gdUnit4/src/asserts/GdUnitFailureAssertImpl.gd deleted file mode 100644 index 198624c6..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitFailureAssertImpl.gd +++ /dev/null @@ -1,136 +0,0 @@ -extends GdUnitFailureAssert - -const GdUnitTools := preload("res://addons/gdUnit4/src/core/GdUnitTools.gd") - -var _is_failed := false -var _failure_message: String -var _current_failure_message := "" -var _custom_failure_message := "" -var _additional_failure_message := "" - - -func _set_do_expect_fail(enabled :bool = true) -> void: - Engine.set_meta(GdUnitConstants.EXPECT_ASSERT_REPORT_FAILURES, enabled) - - -func execute_and_await(assertion :Callable, do_await := true) -> GdUnitFailureAssert: - # do not report any failure from the original assertion we want to test - _set_do_expect_fail(true) - var thread_context := GdUnitThreadManager.get_current_context() - thread_context.set_assert(null) - @warning_ignore("return_value_discarded") - GdUnitSignals.instance().gdunit_set_test_failed.connect(_on_test_failed) - # execute the given assertion as callable - if do_await: - await assertion.call() - else: - assertion.call() - _set_do_expect_fail(false) - # get the assert instance from current tread context - var current_assert := thread_context.get_assert() - if not is_instance_of(current_assert, GdUnitAssert): - _is_failed = true - _failure_message = "Invalid Callable! It must be a callable of 'GdUnitAssert'" - return self - @warning_ignore("unsafe_method_access") - _failure_message = current_assert.failure_message() - return self - - -func execute(assertion :Callable) -> GdUnitFailureAssert: - @warning_ignore("return_value_discarded") - execute_and_await(assertion, false) - return self - - -func _on_test_failed(value :bool) -> void: - _is_failed = value - - -func is_equal(_expected: Variant) -> GdUnitFailureAssert: - return _report_error("Not implemented") - - -func is_not_equal(_expected: Variant) -> GdUnitFailureAssert: - return _report_error("Not implemented") - - -func is_null() -> GdUnitFailureAssert: - return _report_error("Not implemented") - - -func is_not_null() -> GdUnitFailureAssert: - return _report_error("Not implemented") - - -func override_failure_message(message: String) -> GdUnitFailureAssert: - _custom_failure_message = message - return self - - -func append_failure_message(message: String) -> GdUnitFailureAssert: - _additional_failure_message = message - return self - - -func is_success() -> GdUnitFailureAssert: - if _is_failed: - return _report_error("Expect: assertion ends successfully.") - return self - - -func is_failed() -> GdUnitFailureAssert: - if not _is_failed: - return _report_error("Expect: assertion fails.") - return self - - -func has_line(expected :int) -> GdUnitFailureAssert: - var current := GdAssertReports.get_last_error_line_number() - if current != expected: - return _report_error("Expect: to failed on line '%d'\n but was '%d'." % [expected, current]) - return self - - -func has_message(expected :String) -> GdUnitFailureAssert: - @warning_ignore("return_value_discarded") - is_failed() - var expected_error := GdUnitTools.normalize_text(GdUnitTools.richtext_normalize(expected)) - var current_error := GdUnitTools.normalize_text(GdUnitTools.richtext_normalize(_failure_message)) - if current_error != expected_error: - var diffs := GdDiffTool.string_diff(current_error, expected_error) - var current := GdAssertMessages.colored_array_div(diffs[1]) - return _report_error(GdAssertMessages.error_not_same_error(current, expected_error)) - return self - - -func contains_message(expected :String) -> GdUnitFailureAssert: - var expected_error := GdUnitTools.normalize_text(expected) - var current_error := GdUnitTools.normalize_text(GdUnitTools.richtext_normalize(_failure_message)) - if not current_error.contains(expected_error): - var diffs := GdDiffTool.string_diff(current_error, expected_error) - var current := GdAssertMessages.colored_array_div(diffs[1]) - return _report_error(GdAssertMessages.error_not_same_error(current, expected_error)) - return self - - -func starts_with_message(expected :String) -> GdUnitFailureAssert: - var expected_error := GdUnitTools.normalize_text(expected) - var current_error := GdUnitTools.normalize_text(GdUnitTools.richtext_normalize(_failure_message)) - if current_error.find(expected_error) != 0: - var diffs := GdDiffTool.string_diff(current_error, expected_error) - var current := GdAssertMessages.colored_array_div(diffs[1]) - return _report_error(GdAssertMessages.error_not_same_error(current, expected_error)) - return self - - -func _report_error(error_message :String, failure_line_number: int = -1) -> GdUnitAssert: - var line_number := failure_line_number if failure_line_number != -1 else GdUnitAssertions.get_line_number() - _current_failure_message = GdAssertMessages.build_failure_message(error_message, _additional_failure_message, _custom_failure_message) - GdAssertReports.report_error(_current_failure_message, line_number) - return self - - -func _report_success() -> GdUnitFailureAssert: - GdAssertReports.report_success() - return self diff --git a/addons/gdUnit4/src/asserts/GdUnitFailureAssertImpl.gd.uid b/addons/gdUnit4/src/asserts/GdUnitFailureAssertImpl.gd.uid deleted file mode 100644 index 61645532..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitFailureAssertImpl.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cbrj7dsr235i0 diff --git a/addons/gdUnit4/src/asserts/GdUnitFileAssertImpl.gd b/addons/gdUnit4/src/asserts/GdUnitFileAssertImpl.gd deleted file mode 100644 index c4f9570e..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitFileAssertImpl.gd +++ /dev/null @@ -1,116 +0,0 @@ -extends GdUnitFileAssert - -const GdUnitTools := preload("res://addons/gdUnit4/src/core/GdUnitTools.gd") - -var _base: GdUnitAssertImpl - - -func _init(current :Variant) -> void: - _base = GdUnitAssertImpl.new(current) - # save the actual assert instance on the current thread context - GdUnitThreadManager.get_current_context().set_assert(self) - if not GdUnitAssertions.validate_value_type(current, TYPE_STRING): - @warning_ignore("return_value_discarded") - report_error("GdUnitFileAssert inital error, unexpected type <%s>" % GdObjects.typeof_as_string(current)) - - -func _notification(event :int) -> void: - if event == NOTIFICATION_PREDELETE: - if _base != null: - _base.notification(event) - _base = null - - -func current_value() -> String: - return _base.current_value() - - -func report_success() -> GdUnitFileAssert: - @warning_ignore("return_value_discarded") - _base.report_success() - return self - - -func report_error(error :String) -> GdUnitFileAssert: - @warning_ignore("return_value_discarded") - _base.report_error(error) - return self - - -func failure_message() -> String: - return _base.failure_message() - - -func override_failure_message(message: String) -> GdUnitFileAssert: - @warning_ignore("return_value_discarded") - _base.override_failure_message(message) - return self - - -func append_failure_message(message: String) -> GdUnitFileAssert: - @warning_ignore("return_value_discarded") - _base.append_failure_message(message) - return self - - -func is_null() -> GdUnitFileAssert: - @warning_ignore("return_value_discarded") - _base.is_null() - return self - - -func is_not_null() -> GdUnitFileAssert: - @warning_ignore("return_value_discarded") - _base.is_not_null() - return self - - -func is_equal(expected: Variant) -> GdUnitFileAssert: - @warning_ignore("return_value_discarded") - _base.is_equal(expected) - return self - - -func is_not_equal(expected: Variant) -> GdUnitFileAssert: - @warning_ignore("return_value_discarded") - _base.is_not_equal(expected) - return self - - -func is_file() -> GdUnitFileAssert: - var current := current_value() - if FileAccess.open(current, FileAccess.READ) == null: - return report_error("Is not a file '%s', error code %s" % [current, FileAccess.get_open_error()]) - return report_success() - - -func exists() -> GdUnitFileAssert: - var current := current_value() - if not FileAccess.file_exists(current): - return report_error("The file '%s' not exists" %current) - return report_success() - - -func is_script() -> GdUnitFileAssert: - var current := current_value() - if FileAccess.open(current, FileAccess.READ) == null: - return report_error("Can't acces the file '%s'! Error code %s" % [current, FileAccess.get_open_error()]) - - var script := load(current) - if not script is GDScript: - return report_error("The file '%s' is not a GdScript" % current) - return report_success() - - -func contains_exactly(expected_rows: Array) -> GdUnitFileAssert: - var current := current_value() - if FileAccess.open(current, FileAccess.READ) == null: - return report_error("Can't acces the file '%s'! Error code %s" % [current, FileAccess.get_open_error()]) - - var script: GDScript = load(current) - if script is GDScript: - var source_code := GdScriptParser.to_unix_format(script.source_code) - var rows := Array(source_code.split("\n")) - @warning_ignore("return_value_discarded") - GdUnitArrayAssertImpl.new(rows).contains_exactly(expected_rows) - return self diff --git a/addons/gdUnit4/src/asserts/GdUnitFileAssertImpl.gd.uid b/addons/gdUnit4/src/asserts/GdUnitFileAssertImpl.gd.uid deleted file mode 100644 index 7141b12b..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitFileAssertImpl.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://2s6h0titid8y diff --git a/addons/gdUnit4/src/asserts/GdUnitFloatAssertImpl.gd b/addons/gdUnit4/src/asserts/GdUnitFloatAssertImpl.gd deleted file mode 100644 index 83d7e05e..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitFloatAssertImpl.gd +++ /dev/null @@ -1,159 +0,0 @@ -extends GdUnitFloatAssert - -var _base: GdUnitAssertImpl - - -func _init(current :Variant) -> void: - _base = GdUnitAssertImpl.new(current) - # save the actual assert instance on the current thread context - GdUnitThreadManager.get_current_context().set_assert(self) - if not GdUnitAssertions.validate_value_type(current, TYPE_FLOAT): - @warning_ignore("return_value_discarded") - report_error("GdUnitFloatAssert inital error, unexpected type <%s>" % GdObjects.typeof_as_string(current)) - - -func _notification(event :int) -> void: - if event == NOTIFICATION_PREDELETE: - if _base != null: - _base.notification(event) - _base = null - - -func current_value() -> Variant: - return _base.current_value() - - -func report_success() -> GdUnitFloatAssert: - @warning_ignore("return_value_discarded") - _base.report_success() - return self - - -func report_error(error :String) -> GdUnitFloatAssert: - @warning_ignore("return_value_discarded") - _base.report_error(error) - return self - - -func failure_message() -> String: - return _base.failure_message() - - -func override_failure_message(message: String) -> GdUnitFloatAssert: - @warning_ignore("return_value_discarded") - _base.override_failure_message(message) - return self - - -func append_failure_message(message: String) -> GdUnitFloatAssert: - @warning_ignore("return_value_discarded") - _base.append_failure_message(message) - return self - - -func is_null() -> GdUnitFloatAssert: - @warning_ignore("return_value_discarded") - _base.is_null() - return self - - -func is_not_null() -> GdUnitFloatAssert: - @warning_ignore("return_value_discarded") - _base.is_not_null() - return self - - -func is_equal(expected: Variant) -> GdUnitFloatAssert: - @warning_ignore("return_value_discarded") - _base.is_equal(expected) - return self - - -func is_not_equal(expected: Variant) -> GdUnitFloatAssert: - @warning_ignore("return_value_discarded") - _base.is_not_equal(expected) - return self - - -@warning_ignore("shadowed_global_identifier") -func is_equal_approx(expected :float, approx :float) -> GdUnitFloatAssert: - return is_between(expected-approx, expected+approx) - - -func is_less(expected :float) -> GdUnitFloatAssert: - var current :Variant = current_value() - if current == null or current >= expected: - return report_error(GdAssertMessages.error_is_value(Comparator.LESS_THAN, current, expected)) - return report_success() - - -func is_less_equal(expected :float) -> GdUnitFloatAssert: - var current :Variant = current_value() - if current == null or current > expected: - return report_error(GdAssertMessages.error_is_value(Comparator.LESS_EQUAL, current, expected)) - return report_success() - - -func is_greater(expected :float) -> GdUnitFloatAssert: - var current :Variant = current_value() - if current == null or current <= expected: - return report_error(GdAssertMessages.error_is_value(Comparator.GREATER_THAN, current, expected)) - return report_success() - - -func is_greater_equal(expected :float) -> GdUnitFloatAssert: - var current :Variant = current_value() - if current == null or current < expected: - return report_error(GdAssertMessages.error_is_value(Comparator.GREATER_EQUAL, current, expected)) - return report_success() - - -func is_negative() -> GdUnitFloatAssert: - var current :Variant = current_value() - if current == null or current >= 0.0: - return report_error(GdAssertMessages.error_is_negative(current)) - return report_success() - - -func is_not_negative() -> GdUnitFloatAssert: - var current :Variant = current_value() - if current == null or current < 0.0: - return report_error(GdAssertMessages.error_is_not_negative(current)) - return report_success() - - -func is_zero() -> GdUnitFloatAssert: - var current :Variant = current_value() - @warning_ignore("unsafe_cast") - if current == null or not is_equal_approx(0.00000000, current as float): - return report_error(GdAssertMessages.error_is_zero(current)) - return report_success() - - -func is_not_zero() -> GdUnitFloatAssert: - var current :Variant = current_value() - @warning_ignore("unsafe_cast") - if current == null or is_equal_approx(0.00000000, current as float): - return report_error(GdAssertMessages.error_is_not_zero()) - return report_success() - - -func is_in(expected :Array) -> GdUnitFloatAssert: - var current :Variant = current_value() - if not expected.has(current): - return report_error(GdAssertMessages.error_is_in(current, expected)) - return report_success() - - -func is_not_in(expected :Array) -> GdUnitFloatAssert: - var current :Variant = current_value() - if expected.has(current): - return report_error(GdAssertMessages.error_is_not_in(current, expected)) - return report_success() - - -func is_between(from :float, to :float) -> GdUnitFloatAssert: - var current :Variant = current_value() - if current == null or current < from or current > to: - return report_error(GdAssertMessages.error_is_value(Comparator.BETWEEN_EQUAL, current, from, to)) - return report_success() diff --git a/addons/gdUnit4/src/asserts/GdUnitFloatAssertImpl.gd.uid b/addons/gdUnit4/src/asserts/GdUnitFloatAssertImpl.gd.uid deleted file mode 100644 index a5add1a5..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitFloatAssertImpl.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dvce6xeybbh1i diff --git a/addons/gdUnit4/src/asserts/GdUnitFuncAssertImpl.gd b/addons/gdUnit4/src/asserts/GdUnitFuncAssertImpl.gd deleted file mode 100644 index c38acf08..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitFuncAssertImpl.gd +++ /dev/null @@ -1,177 +0,0 @@ -extends GdUnitFuncAssert - - -const GdUnitTools := preload("res://addons/gdUnit4/src/core/GdUnitTools.gd") -const DEFAULT_TIMEOUT := 2000 - - -var _current_value_provider :ValueProvider -var _current_failure_message :String = "" -var _custom_failure_message :String = "" -var _additional_failure_message: String = "" -var _line_number := -1 -var _timeout := DEFAULT_TIMEOUT -var _interrupted := false -var _sleep_timer :Timer = null - - -func _init(instance :Object, func_name :String, args := Array()) -> void: - _line_number = GdUnitAssertions.get_line_number() - GdAssertReports.reset_last_error_line_number() - # save the actual assert instance on the current thread context - GdUnitThreadManager.get_current_context().set_assert(self) - # verify at first the function name exists - if not instance.has_method(func_name): - @warning_ignore("return_value_discarded") - report_error("The function '%s' do not exists checked instance '%s'." % [func_name, instance]) - _interrupted = true - else: - _current_value_provider = CallBackValueProvider.new(instance, func_name, args) - - -func _notification(what :int) -> void: - if what == NOTIFICATION_PREDELETE: - _interrupted = true - var main_node :Node = (Engine.get_main_loop() as SceneTree).root - if is_instance_valid(_current_value_provider): - _current_value_provider.dispose() - _current_value_provider = null - if is_instance_valid(_sleep_timer): - _sleep_timer.set_wait_time(0.0001) - _sleep_timer.stop() - main_node.remove_child(_sleep_timer) - _sleep_timer.free() - _sleep_timer = null - - -func report_success() -> GdUnitFuncAssert: - GdAssertReports.report_success() - return self - - -func report_error(failure :String) -> GdUnitFuncAssert: - _current_failure_message = GdAssertMessages.build_failure_message(failure, _additional_failure_message, _custom_failure_message) - GdAssertReports.report_error(_current_failure_message, _line_number) - return self - - -func failure_message() -> String: - return _current_failure_message - - -func override_failure_message(message: String) -> GdUnitFuncAssert: - _custom_failure_message = message - return self - - -func append_failure_message(message: String) -> GdUnitFuncAssert: - _additional_failure_message = message - return self - - -func wait_until(timeout := 2000) -> GdUnitFuncAssert: - if timeout <= 0: - push_warning("Invalid timeout param, alloed timeouts must be grater than 0. Use default timeout instead") - _timeout = DEFAULT_TIMEOUT - else: - _timeout = timeout - return self - - -func is_null() -> GdUnitFuncAssert: - await _validate_callback(cb_is_null) - return self - - -func is_not_null() -> GdUnitFuncAssert: - await _validate_callback(cb_is_not_null) - return self - - -func is_false() -> GdUnitFuncAssert: - await _validate_callback(cb_is_false) - return self - - -func is_true() -> GdUnitFuncAssert: - await _validate_callback(cb_is_true) - return self - - -func is_equal(expected: Variant) -> GdUnitFuncAssert: - await _validate_callback(cb_is_equal, expected) - return self - - -func is_not_equal(expected: Variant) -> GdUnitFuncAssert: - await _validate_callback(cb_is_not_equal, expected) - return self - - -# we need actually to define this Callable as functions otherwise we results into leaked scripts here -# this is actually a Godot bug and needs this kind of workaround -func cb_is_null(c :Variant, _e :Variant) -> bool: return c == null -func cb_is_not_null(c :Variant, _e :Variant) -> bool: return c != null -func cb_is_false(c :Variant, _e :Variant) -> bool: return c == false -func cb_is_true(c :Variant, _e :Variant) -> bool: return c == true -func cb_is_equal(c :Variant, e :Variant) -> bool: return GdObjects.equals(c,e) -func cb_is_not_equal(c :Variant, e :Variant) -> bool: return not GdObjects.equals(c, e) - - -func do_interrupt() -> void: - _interrupted = true - - -func _validate_callback(predicate :Callable, expected :Variant = null) -> void: - if _interrupted: - return - GdUnitMemoryObserver.guard_instance(self) - var time_scale := Engine.get_time_scale() - var timer := Timer.new() - timer.set_name("gdunit_funcassert_interrupt_timer_%d" % timer.get_instance_id()) - var scene_tree := Engine.get_main_loop() as SceneTree - scene_tree.root.add_child(timer) - timer.add_to_group("GdUnitTimers") - @warning_ignore("return_value_discarded") - timer.timeout.connect(do_interrupt, CONNECT_DEFERRED) - timer.set_one_shot(true) - timer.start((_timeout/1000.0)*time_scale) - _sleep_timer = Timer.new() - _sleep_timer.set_name("gdunit_funcassert_sleep_timer_%d" % _sleep_timer.get_instance_id() ) - scene_tree.root.add_child(_sleep_timer) - - while true: - var current :Variant = await next_current_value() - # is interupted or predicate success - if _interrupted or predicate.call(current, expected): - break - if is_instance_valid(_sleep_timer): - _sleep_timer.start(0.05) - await _sleep_timer.timeout - - _sleep_timer.stop() - await scene_tree.process_frame - if _interrupted: - # https://github.com/godotengine/godot/issues/73052 - #var predicate_name = predicate.get_method() - var predicate_name :String = str(predicate).split('::')[1] - @warning_ignore("return_value_discarded") - report_error(GdAssertMessages.error_interrupted( - predicate_name.strip_edges().trim_prefix("cb_"), - expected, - LocalTime.elapsed(_timeout) - ) - ) - else: - @warning_ignore("return_value_discarded") - report_success() - _sleep_timer.free() - timer.free() - GdUnitMemoryObserver.unguard_instance(self) - - -func next_current_value() -> Variant: - @warning_ignore("redundant_await") - if is_instance_valid(_current_value_provider): - return await _current_value_provider.get_value() - return "invalid value" diff --git a/addons/gdUnit4/src/asserts/GdUnitFuncAssertImpl.gd.uid b/addons/gdUnit4/src/asserts/GdUnitFuncAssertImpl.gd.uid deleted file mode 100644 index dbde7c4f..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitFuncAssertImpl.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c2jdw0vv5nldq diff --git a/addons/gdUnit4/src/asserts/GdUnitGodotErrorAssertImpl.gd b/addons/gdUnit4/src/asserts/GdUnitGodotErrorAssertImpl.gd deleted file mode 100644 index fc010db3..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitGodotErrorAssertImpl.gd +++ /dev/null @@ -1,141 +0,0 @@ -extends GdUnitGodotErrorAssert - -var _current_failure_message := "" -var _custom_failure_message := "" -var _additional_failure_message := "" -var _callable: Callable - - -func _init(callable: Callable) -> void: - # save the actual assert instance on the current thread context - GdUnitThreadManager.get_current_context().set_assert(self) - GdAssertReports.reset_last_error_line_number() - _callable = callable - - -func _execute() -> Array[ErrorLogEntry]: - # execute the given code and monitor for runtime errors - if _callable == null or not _callable.is_valid(): - @warning_ignore("return_value_discarded") - _report_error("Invalid Callable '%s'" % _callable) - else: - await _callable.call() - return await _error_monitor().scan(true) - - -func _error_monitor() -> GodotGdErrorMonitor: - return GdUnitThreadManager.get_current_context().get_execution_context().error_monitor - - -func failure_message() -> String: - return _current_failure_message - - -func _report_success() -> GdUnitAssert: - GdAssertReports.report_success() - return self - - -func _report_error(error_message: String, failure_line_number: int = -1) -> GdUnitAssert: - var line_number := failure_line_number if failure_line_number != -1 else GdUnitAssertions.get_line_number() - _current_failure_message = GdAssertMessages.build_failure_message(error_message, _additional_failure_message, _custom_failure_message) - GdAssertReports.report_error(_current_failure_message, line_number) - return self - - -func _has_log_entry(log_entries: Array[ErrorLogEntry], type: ErrorLogEntry.TYPE, error: Variant) -> bool: - for entry in log_entries: - if entry._type == type and GdObjects.equals(entry._message, error): - # Erase the log entry we already handled it by this assertion, otherwise it will report at twice - _error_monitor().erase_log_entry(entry) - return true - return false - - -func _to_list(log_entries: Array[ErrorLogEntry]) -> String: - if log_entries.is_empty(): - return "no errors" - if log_entries.size() == 1: - return log_entries[0]._message - var value := "" - for entry in log_entries: - value += "'%s'\n" % entry._message - return value - - -func is_null() -> GdUnitGodotErrorAssert: - return _report_error("Not implemented") - - -func is_not_null() -> GdUnitGodotErrorAssert: - return _report_error("Not implemented") - - -func is_equal(_expected: Variant) -> GdUnitGodotErrorAssert: - return _report_error("Not implemented") - - -func is_not_equal(_expected: Variant) -> GdUnitGodotErrorAssert: - return _report_error("Not implemented") - - -func override_failure_message(message: String) -> GdUnitGodotErrorAssert: - _custom_failure_message = message - return self - - -func append_failure_message(message: String) -> GdUnitGodotErrorAssert: - _additional_failure_message = message - return self - - -func is_success() -> GdUnitGodotErrorAssert: - var log_entries := await _execute() - if log_entries.is_empty(): - return _report_success() - return _report_error(""" - Expecting: no error's are ocured. - but found: '%s' - """.dedent().trim_prefix("\n") % _to_list(log_entries)) - - -func is_runtime_error(expected_error: Variant) -> GdUnitGodotErrorAssert: - var result := GdUnitArgumentMatchers.is_variant_string_matching(expected_error) - if result.is_error(): - return _report_error(result.error_message()) - var log_entries := await _execute() - if _has_log_entry(log_entries, ErrorLogEntry.TYPE.SCRIPT_ERROR, expected_error): - return _report_success() - return _report_error(""" - Expecting: a runtime error is triggered. - message: '%s' - found: %s - """.dedent().trim_prefix("\n") % [expected_error, _to_list(log_entries)]) - - -func is_push_warning(expected_warning: Variant) -> GdUnitGodotErrorAssert: - var result := GdUnitArgumentMatchers.is_variant_string_matching(expected_warning) - if result.is_error(): - return _report_error(result.error_message()) - var log_entries := await _execute() - if _has_log_entry(log_entries, ErrorLogEntry.TYPE.PUSH_WARNING, expected_warning): - return _report_success() - return _report_error(""" - Expecting: push_warning() is called. - message: '%s' - found: %s - """.dedent().trim_prefix("\n") % [expected_warning, _to_list(log_entries)]) - - -func is_push_error(expected_error: Variant) -> GdUnitGodotErrorAssert: - var result := GdUnitArgumentMatchers.is_variant_string_matching(expected_error) - if result.is_error(): - return _report_error(result.error_message()) - var log_entries := await _execute() - if _has_log_entry(log_entries, ErrorLogEntry.TYPE.PUSH_ERROR, expected_error): - return _report_success() - return _report_error(""" - Expecting: push_error() is called. - message: '%s' - found: %s - """.dedent().trim_prefix("\n") % [expected_error, _to_list(log_entries)]) diff --git a/addons/gdUnit4/src/asserts/GdUnitGodotErrorAssertImpl.gd.uid b/addons/gdUnit4/src/asserts/GdUnitGodotErrorAssertImpl.gd.uid deleted file mode 100644 index 6da674e1..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitGodotErrorAssertImpl.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cyi6ooahncq7q diff --git a/addons/gdUnit4/src/asserts/GdUnitIntAssertImpl.gd b/addons/gdUnit4/src/asserts/GdUnitIntAssertImpl.gd deleted file mode 100644 index bdee249e..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitIntAssertImpl.gd +++ /dev/null @@ -1,166 +0,0 @@ -extends GdUnitIntAssert - -var _base: GdUnitAssertImpl - - -func _init(current :Variant) -> void: - _base = GdUnitAssertImpl.new(current) - # save the actual assert instance on the current thread context - GdUnitThreadManager.get_current_context().set_assert(self) - if not GdUnitAssertions.validate_value_type(current, TYPE_INT): - @warning_ignore("return_value_discarded") - report_error("GdUnitIntAssert inital error, unexpected type <%s>" % GdObjects.typeof_as_string(current)) - - -func _notification(event :int) -> void: - if event == NOTIFICATION_PREDELETE: - if _base != null: - _base.notification(event) - _base = null - - -func current_value() -> Variant: - return _base.current_value() - - -func report_success() -> GdUnitIntAssert: - @warning_ignore("return_value_discarded") - _base.report_success() - return self - - -func report_error(error :String) -> GdUnitIntAssert: - @warning_ignore("return_value_discarded") - _base.report_error(error) - return self - - -func failure_message() -> String: - return _base.failure_message() - - -func override_failure_message(message: String) -> GdUnitIntAssert: - @warning_ignore("return_value_discarded") - _base.override_failure_message(message) - return self - - -func append_failure_message(message: String) -> GdUnitIntAssert: - @warning_ignore("return_value_discarded") - _base.append_failure_message(message) - return self - - -func is_null() -> GdUnitIntAssert: - @warning_ignore("return_value_discarded") - _base.is_null() - return self - - -func is_not_null() -> GdUnitIntAssert: - @warning_ignore("return_value_discarded") - _base.is_not_null() - return self - - -func is_equal(expected: Variant) -> GdUnitIntAssert: - @warning_ignore("return_value_discarded") - _base.is_equal(expected) - return self - - -func is_not_equal(expected: Variant) -> GdUnitIntAssert: - @warning_ignore("return_value_discarded") - _base.is_not_equal(expected) - return self - - -func is_less(expected :int) -> GdUnitIntAssert: - var current :Variant = current_value() - if current == null or current >= expected: - return report_error(GdAssertMessages.error_is_value(Comparator.LESS_THAN, current, expected)) - return report_success() - - -func is_less_equal(expected :int) -> GdUnitIntAssert: - var current :Variant = current_value() - if current == null or current > expected: - return report_error(GdAssertMessages.error_is_value(Comparator.LESS_EQUAL, current, expected)) - return report_success() - - -func is_greater(expected :int) -> GdUnitIntAssert: - var current :Variant = current_value() - if current == null or current <= expected: - return report_error(GdAssertMessages.error_is_value(Comparator.GREATER_THAN, current, expected)) - return report_success() - - -func is_greater_equal(expected :int) -> GdUnitIntAssert: - var current :Variant = current_value() - if current == null or current < expected: - return report_error(GdAssertMessages.error_is_value(Comparator.GREATER_EQUAL, current, expected)) - return report_success() - - -func is_even() -> GdUnitIntAssert: - var current :Variant = current_value() - if current == null or current % 2 != 0: - return report_error(GdAssertMessages.error_is_even(current)) - return report_success() - - -func is_odd() -> GdUnitIntAssert: - var current :Variant = current_value() - if current == null or current % 2 == 0: - return report_error(GdAssertMessages.error_is_odd(current)) - return report_success() - - -func is_negative() -> GdUnitIntAssert: - var current :Variant = current_value() - if current == null or current >= 0: - return report_error(GdAssertMessages.error_is_negative(current)) - return report_success() - - -func is_not_negative() -> GdUnitIntAssert: - var current :Variant = current_value() - if current == null or current < 0: - return report_error(GdAssertMessages.error_is_not_negative(current)) - return report_success() - - -func is_zero() -> GdUnitIntAssert: - var current :Variant = current_value() - if current != 0: - return report_error(GdAssertMessages.error_is_zero(current)) - return report_success() - - -func is_not_zero() -> GdUnitIntAssert: - var current :Variant= current_value() - if current == 0: - return report_error(GdAssertMessages.error_is_not_zero()) - return report_success() - - -func is_in(expected :Array) -> GdUnitIntAssert: - var current :Variant = current_value() - if not expected.has(current): - return report_error(GdAssertMessages.error_is_in(current, expected)) - return report_success() - - -func is_not_in(expected :Array) -> GdUnitIntAssert: - var current :Variant = current_value() - if expected.has(current): - return report_error(GdAssertMessages.error_is_not_in(current, expected)) - return report_success() - - -func is_between(from :int, to :int) -> GdUnitIntAssert: - var current :Variant = current_value() - if current == null or current < from or current > to: - return report_error(GdAssertMessages.error_is_value(Comparator.BETWEEN_EQUAL, current, from, to)) - return report_success() diff --git a/addons/gdUnit4/src/asserts/GdUnitIntAssertImpl.gd.uid b/addons/gdUnit4/src/asserts/GdUnitIntAssertImpl.gd.uid deleted file mode 100644 index 2424b41a..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitIntAssertImpl.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://j4mpmwm2hw61 diff --git a/addons/gdUnit4/src/asserts/GdUnitObjectAssertImpl.gd b/addons/gdUnit4/src/asserts/GdUnitObjectAssertImpl.gd deleted file mode 100644 index 955e1ef3..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitObjectAssertImpl.gd +++ /dev/null @@ -1,166 +0,0 @@ -extends GdUnitObjectAssert - -var _base: GdUnitAssertImpl - - -func _init(current: Variant) -> void: - _base = GdUnitAssertImpl.new(current) - # save the actual assert instance on the current thread context - GdUnitThreadManager.get_current_context().set_assert(self) - if (current != null - and (GdUnitAssertions.validate_value_type(current, TYPE_BOOL) - or GdUnitAssertions.validate_value_type(current, TYPE_INT) - or GdUnitAssertions.validate_value_type(current, TYPE_FLOAT) - or GdUnitAssertions.validate_value_type(current, TYPE_STRING))): - @warning_ignore("return_value_discarded") - report_error("GdUnitObjectAssert inital error, unexpected type <%s>" % GdObjects.typeof_as_string(current)) - - -func _notification(event: int) -> void: - if event == NOTIFICATION_PREDELETE: - if _base != null: - _base.notification(event) - _base = null - - -func current_value() -> Variant: - return _base.current_value() - - -func report_success() -> GdUnitObjectAssert: - @warning_ignore("return_value_discarded") - _base.report_success() - return self - - -func report_error(error: String) -> GdUnitObjectAssert: - @warning_ignore("return_value_discarded") - _base.report_error(error) - return self - - -func failure_message() -> String: - return _base.failure_message() - - -func override_failure_message(message: String) -> GdUnitObjectAssert: - @warning_ignore("return_value_discarded") - _base.override_failure_message(message) - return self - - -func append_failure_message(message: String) -> GdUnitObjectAssert: - @warning_ignore("return_value_discarded") - _base.append_failure_message(message) - return self - - -func is_equal(expected: Variant) -> GdUnitObjectAssert: - @warning_ignore("return_value_discarded") - _base.is_equal(expected) - return self - - -func is_not_equal(expected: Variant) -> GdUnitObjectAssert: - @warning_ignore("return_value_discarded") - _base.is_not_equal(expected) - return self - - -func is_null() -> GdUnitObjectAssert: - @warning_ignore("return_value_discarded") - _base.is_null() - return self - - -func is_not_null() -> GdUnitObjectAssert: - @warning_ignore("return_value_discarded") - _base.is_not_null() - return self - - -@warning_ignore("shadowed_global_identifier") -func is_same(expected: Variant) -> GdUnitObjectAssert: - var current: Variant = current_value() - if not is_same(current, expected): - return report_error(GdAssertMessages.error_is_same(current, expected)) - return report_success() - - -func is_not_same(expected: Variant) -> GdUnitObjectAssert: - var current: Variant = current_value() - if is_same(current, expected): - return report_error(GdAssertMessages.error_not_same(current, expected)) - return report_success() - - -func is_instanceof(type: Variant) -> GdUnitObjectAssert: - var current: Variant = current_value() - if current == null or not is_instance_of(current, type): - var result_expected := GdObjects.extract_class_name(type) - var result_current := GdObjects.extract_class_name(current) - return report_error(GdAssertMessages.error_is_instanceof(result_current, result_expected)) - return report_success() - - -func is_not_instanceof(type: Variant) -> GdUnitObjectAssert: - var current: Variant = current_value() - if is_instance_of(current, type): - var result := GdObjects.extract_class_name(type) - if result.is_success(): - return report_error("Expected not be a instance of <%s>" % str(result.value())) - - push_error("Internal ERROR: %s" % result.error_message()) - return self - return report_success() - - -## Checks whether the current object inherits from the specified type. -func is_inheriting(type: Variant) -> GdUnitObjectAssert: - var current: Variant = current_value() - if not is_instance_of(current, TYPE_OBJECT): - return report_error("Expected '%s' to inherit from at least Object." % str(current)) - var result := _inherits(current, type) - if result.is_success(): - return report_success() - return report_error(result.error_message()) - - -## Checks whether the current object does NOT inherit from the specified type. -func is_not_inheriting(type: Variant) -> GdUnitObjectAssert: - var current: Variant = current_value() - if not is_instance_of(current, TYPE_OBJECT): - return report_error("Expected '%s' to inherit from at least Object." % str(current)) - var result := _inherits(current, type) - if result.is_success(): - return report_error("Expected type to not inherit from <%s>" % _extract_class_type(type)) - return report_success() - - -func _inherits(current: Variant, type: Variant) -> GdUnitResult: - var type_as_string := _extract_class_type(type) - if type_as_string == "Object": - return GdUnitResult.success("") - - var obj: Object = current - for p in obj.get_property_list(): - var clazz_name :String = p["name"] - if p["usage"] == PROPERTY_USAGE_CATEGORY and clazz_name == p["hint_string"] and clazz_name == type_as_string: - return GdUnitResult.success("") - var script: Script = obj.get_script() - if script != null: - while script != null: - var result := GdObjects.extract_class_name(script) - if result.is_success() and result.value() == type_as_string: - return GdUnitResult.success("") - script = script.get_base_script() - return GdUnitResult.error("Expected type to inherit from <%s>" % type_as_string) - - -func _extract_class_type(type: Variant) -> String: - if type is String: - return type - var result := GdObjects.extract_class_name(type) - if result.is_error(): - return "" - return result.value() diff --git a/addons/gdUnit4/src/asserts/GdUnitObjectAssertImpl.gd.uid b/addons/gdUnit4/src/asserts/GdUnitObjectAssertImpl.gd.uid deleted file mode 100644 index 5db4c8b3..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitObjectAssertImpl.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bm6qm58a0dacq diff --git a/addons/gdUnit4/src/asserts/GdUnitResultAssertImpl.gd b/addons/gdUnit4/src/asserts/GdUnitResultAssertImpl.gd deleted file mode 100644 index 98a6768f..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitResultAssertImpl.gd +++ /dev/null @@ -1,128 +0,0 @@ -extends GdUnitResultAssert - -var _base: GdUnitAssertImpl - - -func _init(current :Variant) -> void: - _base = GdUnitAssertImpl.new(current) - # save the actual assert instance on the current thread context - GdUnitThreadManager.get_current_context().set_assert(self) - if not validate_value_type(current): - @warning_ignore("return_value_discarded") - report_error("GdUnitResultAssert inital error, unexpected type <%s>" % GdObjects.typeof_as_string(current)) - - -func _notification(event :int) -> void: - if event == NOTIFICATION_PREDELETE: - if _base != null: - _base.notification(event) - _base = null - - -func validate_value_type(value :Variant) -> bool: - return value == null or value is GdUnitResult - - -func current_value() -> GdUnitResult: - return _base.current_value() - - -func report_success() -> GdUnitResultAssert: - @warning_ignore("return_value_discarded") - _base.report_success() - return self - - -func report_error(error :String) -> GdUnitResultAssert: - @warning_ignore("return_value_discarded") - _base.report_error(error) - return self - - -func failure_message() -> String: - return _base.failure_message() - - -func override_failure_message(message: String) -> GdUnitResultAssert: - @warning_ignore("return_value_discarded") - _base.override_failure_message(message) - return self - - -func append_failure_message(message: String) -> GdUnitResultAssert: - @warning_ignore("return_value_discarded") - _base.append_failure_message(message) - return self - - -func is_null() -> GdUnitResultAssert: - @warning_ignore("return_value_discarded") - _base.is_null() - return self - - -func is_not_null() -> GdUnitResultAssert: - @warning_ignore("return_value_discarded") - _base.is_not_null() - return self - - -func is_equal(expected: Variant) -> GdUnitResultAssert: - return is_value(expected) - - -func is_not_equal(expected: Variant) -> GdUnitResultAssert: - var result := current_value() - var value :Variant = null if result == null else result.value() - if GdObjects.equals(value, expected): - return report_error(GdAssertMessages.error_not_equal(value, expected)) - return report_success() - - -func is_empty() -> GdUnitResultAssert: - var result := current_value() - if result == null or not result.is_empty(): - return report_error(GdAssertMessages.error_result_is_empty(result)) - return report_success() - - -func is_success() -> GdUnitResultAssert: - var result := current_value() - if result == null or not result.is_success(): - return report_error(GdAssertMessages.error_result_is_success(result)) - return report_success() - - -func is_warning() -> GdUnitResultAssert: - var result := current_value() - if result == null or not result.is_warn(): - return report_error(GdAssertMessages.error_result_is_warning(result)) - return report_success() - - -func is_error() -> GdUnitResultAssert: - var result := current_value() - if result == null or not result.is_error(): - return report_error(GdAssertMessages.error_result_is_error(result)) - return report_success() - - -func contains_message(expected :String) -> GdUnitResultAssert: - var result := current_value() - if result == null: - return report_error(GdAssertMessages.error_result_has_message("", expected)) - if result.is_success(): - return report_error(GdAssertMessages.error_result_has_message_on_success(expected)) - if result.is_error() and result.error_message() != expected: - return report_error(GdAssertMessages.error_result_has_message(result.error_message(), expected)) - if result.is_warn() and result.warn_message() != expected: - return report_error(GdAssertMessages.error_result_has_message(result.warn_message(), expected)) - return report_success() - - -func is_value(expected: Variant) -> GdUnitResultAssert: - var result := current_value() - var value :Variant = null if result == null else result.value() - if not GdObjects.equals(value, expected): - return report_error(GdAssertMessages.error_result_is_value(value, expected)) - return report_success() diff --git a/addons/gdUnit4/src/asserts/GdUnitResultAssertImpl.gd.uid b/addons/gdUnit4/src/asserts/GdUnitResultAssertImpl.gd.uid deleted file mode 100644 index 6d1ed11d..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitResultAssertImpl.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b0dlq6jyjcvps diff --git a/addons/gdUnit4/src/asserts/GdUnitSignalAssertImpl.gd b/addons/gdUnit4/src/asserts/GdUnitSignalAssertImpl.gd deleted file mode 100644 index 6f5878c8..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitSignalAssertImpl.gd +++ /dev/null @@ -1,143 +0,0 @@ -extends GdUnitSignalAssert - -const DEFAULT_TIMEOUT := 2000 - -var _signal_collector :GdUnitSignalCollector -var _emitter :Object -var _current_failure_message :String = "" -var _custom_failure_message :String = "" -var _additional_failure_message: String = "" -var _line_number := -1 -var _timeout := DEFAULT_TIMEOUT -var _interrupted := false - - -func _init(emitter :Object) -> void: - # save the actual assert instance on the current thread context - var context := GdUnitThreadManager.get_current_context() - context.set_assert(self) - _signal_collector = context.get_signal_collector() - _line_number = GdUnitAssertions.get_line_number() - _emitter = emitter - GdAssertReports.reset_last_error_line_number() - - -func _notification(what :int) -> void: - if what == NOTIFICATION_PREDELETE: - _interrupted = true - if is_instance_valid(_emitter): - _signal_collector.unregister_emitter(_emitter) - _emitter = null - - -func report_success() -> GdUnitAssert: - GdAssertReports.report_success() - return self - - -func report_warning(message :String) -> GdUnitAssert: - GdAssertReports.report_warning(message, GdUnitAssertions.get_line_number()) - return self - - -func report_error(failure :String) -> GdUnitAssert: - _current_failure_message = GdAssertMessages.build_failure_message(failure, _additional_failure_message, _custom_failure_message) - GdAssertReports.report_error(_current_failure_message, _line_number) - return self - - -func failure_message() -> String: - return _current_failure_message - - -func override_failure_message(message: String) -> GdUnitSignalAssert: - _custom_failure_message = message - return self - - -func append_failure_message(message: String) -> GdUnitSignalAssert: - _additional_failure_message = message - return self - - -func wait_until(timeout := 2000) -> GdUnitSignalAssert: - if timeout <= 0: - @warning_ignore("return_value_discarded") - report_warning("Invalid timeout parameter, allowed timeouts must be greater than 0, use default timeout instead!") - _timeout = DEFAULT_TIMEOUT - else: - _timeout = timeout - return self - - -func is_null() -> GdUnitSignalAssert: - if _emitter != null: - return report_error(GdAssertMessages.error_is_null(_emitter)) - return report_success() - - -func is_not_null() -> GdUnitSignalAssert: - if _emitter == null: - return report_error(GdAssertMessages.error_is_not_null()) - return report_success() - - -func is_equal(_expected: Variant) -> GdUnitSignalAssert: - return report_error("Not implemented") - - -func is_not_equal(_expected: Variant) -> GdUnitSignalAssert: - return report_error("Not implemented") - - -# Verifies the signal exists checked the emitter -func is_signal_exists(signal_name :String) -> GdUnitSignalAssert: - if not _emitter.has_signal(signal_name): - @warning_ignore("return_value_discarded") - report_error("The signal '%s' not exists checked object '%s'." % [signal_name, _emitter.get_class()]) - return self - - -# Verifies that given signal is emitted until waiting time -func is_emitted(name :String, args := []) -> GdUnitSignalAssert: - _line_number = GdUnitAssertions.get_line_number() - return await _wail_until_signal(name, args, false) - - -# Verifies that given signal is NOT emitted until waiting time -func is_not_emitted(name :String, args := []) -> GdUnitSignalAssert: - _line_number = GdUnitAssertions.get_line_number() - return await _wail_until_signal(name, args, true) - - -func _wail_until_signal(signal_name :String, expected_args :Array, expect_not_emitted: bool) -> GdUnitSignalAssert: - if _emitter == null: - return report_error("Can't wait for signal checked a NULL object.") - # first verify the signal is defined - if not _emitter.has_signal(signal_name): - return report_error("Can't wait for non-existion signal '%s' checked object '%s'." % [signal_name,_emitter.get_class()]) - _signal_collector.register_emitter(_emitter) - var time_scale := Engine.get_time_scale() - var timer := Timer.new() - (Engine.get_main_loop() as SceneTree).root.add_child(timer) - timer.add_to_group("GdUnitTimers") - timer.set_one_shot(true) - @warning_ignore("return_value_discarded") - timer.timeout.connect(func on_timeout() -> void: _interrupted = true) - timer.start((_timeout/1000.0)*time_scale) - var is_signal_emitted := false - while not _interrupted and not is_signal_emitted: - await (Engine.get_main_loop() as SceneTree).process_frame - if is_instance_valid(_emitter): - is_signal_emitted = _signal_collector.match(_emitter, signal_name, expected_args) - if is_signal_emitted and expect_not_emitted: - @warning_ignore("return_value_discarded") - report_error(GdAssertMessages.error_signal_emitted(signal_name, expected_args, LocalTime.elapsed(int(_timeout-timer.time_left*1000)))) - - if _interrupted and not expect_not_emitted: - @warning_ignore("return_value_discarded") - report_error(GdAssertMessages.error_wait_signal(signal_name, expected_args, LocalTime.elapsed(_timeout))) - timer.free() - if is_instance_valid(_emitter): - _signal_collector.reset_received_signals(_emitter, signal_name, expected_args) - return self diff --git a/addons/gdUnit4/src/asserts/GdUnitSignalAssertImpl.gd.uid b/addons/gdUnit4/src/asserts/GdUnitSignalAssertImpl.gd.uid deleted file mode 100644 index 0feeb0f2..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitSignalAssertImpl.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dlh37yc086vr5 diff --git a/addons/gdUnit4/src/asserts/GdUnitStringAssertImpl.gd b/addons/gdUnit4/src/asserts/GdUnitStringAssertImpl.gd deleted file mode 100644 index cdbcdff8..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitStringAssertImpl.gd +++ /dev/null @@ -1,208 +0,0 @@ -extends GdUnitStringAssert - -var _base: GdUnitAssertImpl - - -func _init(current :Variant) -> void: - _base = GdUnitAssertImpl.new(current) - # save the actual assert instance on the current thread context - GdUnitThreadManager.get_current_context().set_assert(self) - if current != null and typeof(current) != TYPE_STRING and typeof(current) != TYPE_STRING_NAME: - @warning_ignore("return_value_discarded") - report_error("GdUnitStringAssert inital error, unexpected type <%s>" % GdObjects.typeof_as_string(current)) - - -func _notification(event :int) -> void: - if event == NOTIFICATION_PREDELETE: - if _base != null: - _base.notification(event) - _base = null - - -func failure_message() -> String: - return _base.failure_message() - - -func current_value() -> Variant: - return _base.current_value() - - -func report_success() -> GdUnitStringAssert: - @warning_ignore("return_value_discarded") - _base.report_success() - return self - - -func report_error(error :String) -> GdUnitStringAssert: - @warning_ignore("return_value_discarded") - _base.report_error(error) - return self - - -func override_failure_message(message: String) -> GdUnitStringAssert: - @warning_ignore("return_value_discarded") - _base.override_failure_message(message) - return self - - -func append_failure_message(message: String) -> GdUnitStringAssert: - @warning_ignore("return_value_discarded") - _base.append_failure_message(message) - return self - - -func is_null() -> GdUnitStringAssert: - @warning_ignore("return_value_discarded") - _base.is_null() - return self - - -func is_not_null() -> GdUnitStringAssert: - @warning_ignore("return_value_discarded") - _base.is_not_null() - return self - - -func is_equal(expected: Variant) -> GdUnitStringAssert: - return _is_equal(expected, false, GdAssertMessages.error_equal) - - -func is_equal_ignoring_case(expected: Variant) -> GdUnitStringAssert: - return _is_equal(expected, true, GdAssertMessages.error_equal_ignoring_case) - - -@warning_ignore_start("unsafe_call_argument") -func _is_equal(expected: Variant, ignore_case: bool, message_cb: Callable) -> GdUnitStringAssert: - var current: Variant = current_value() - if current == null: - return report_error(message_cb.call(current, expected)) - var cur_value := str(current) - if not GdObjects.equals(cur_value, expected, ignore_case): - var exp_value := str(expected) - if contains_bbcode(cur_value): - # mask user bbcode - # https://docs.godotengine.org/en/4.5/tutorials/ui/bbcode_in_richtextlabel.html#handling-user-input-safely - return report_error(message_cb.call(cur_value.replace("[", "[lb]"), exp_value.replace("[", "[lb]"))) - var diffs := GdDiffTool.string_diff(cur_value, exp_value) - var formatted_current := GdAssertMessages.colored_array_div(diffs[1]) - return report_error(message_cb.call(formatted_current, exp_value)) - return report_success() -@warning_ignore_restore("unsafe_call_argument") - - -func is_not_equal(expected: Variant) -> GdUnitStringAssert: - var current: Variant = current_value() - if GdObjects.equals(current, expected): - return report_error(GdAssertMessages.error_not_equal(current, expected)) - return report_success() - - -func is_not_equal_ignoring_case(expected :Variant) -> GdUnitStringAssert: - var current :Variant = current_value() - if GdObjects.equals(current, expected, true): - return report_error(GdAssertMessages.error_not_equal(current, expected)) - return report_success() - - -func is_empty() -> GdUnitStringAssert: - var current :Variant = current_value() - @warning_ignore("unsafe_cast") - if current == null or not (current as String).is_empty(): - return report_error(GdAssertMessages.error_is_empty(current)) - return report_success() - - -func is_not_empty() -> GdUnitStringAssert: - var current :Variant = current_value() - @warning_ignore("unsafe_cast") - if current == null or (current as String).is_empty(): - return report_error(GdAssertMessages.error_is_not_empty()) - return report_success() - - -func contains(expected :String) -> GdUnitStringAssert: - var current :Variant = current_value() - @warning_ignore("unsafe_cast") - if current == null or (current as String).find(expected) == -1: - return report_error(GdAssertMessages.error_contains(current, expected)) - return report_success() - - -func not_contains(expected :String) -> GdUnitStringAssert: - var current :Variant = current_value() - @warning_ignore("unsafe_cast") - if current != null and (current as String).find(expected) != -1: - return report_error(GdAssertMessages.error_not_contains(current, expected)) - return report_success() - - -func contains_ignoring_case(expected :String) -> GdUnitStringAssert: - var current :Variant = current_value() - @warning_ignore("unsafe_cast") - if current == null or (current as String).findn(expected) == -1: - return report_error(GdAssertMessages.error_contains_ignoring_case(current, expected)) - return report_success() - - -func not_contains_ignoring_case(expected :String) -> GdUnitStringAssert: - var current :Variant = current_value() - @warning_ignore("unsafe_cast") - if current != null and (current as String).findn(expected) != -1: - return report_error(GdAssertMessages.error_not_contains_ignoring_case(current, expected)) - return report_success() - - -func starts_with(expected :String) -> GdUnitStringAssert: - var current :Variant = current_value() - @warning_ignore("unsafe_cast") - if current == null or (current as String).find(expected) != 0: - return report_error(GdAssertMessages.error_starts_with(current, expected)) - return report_success() - - -func ends_with(expected :String) -> GdUnitStringAssert: - var current :Variant = current_value() - if current == null: - return report_error(GdAssertMessages.error_ends_with(current, expected)) - @warning_ignore("unsafe_cast") - var find :int = (current as String).length() - expected.length() - @warning_ignore("unsafe_cast") - if (current as String).rfind(expected) != find: - return report_error(GdAssertMessages.error_ends_with(current, expected)) - return report_success() - - -# gdlint:disable=max-returns -func has_length(expected :int, comparator := Comparator.EQUAL) -> GdUnitStringAssert: - var current :Variant = current_value() - if current == null: - return report_error(GdAssertMessages.error_has_length(current, expected, comparator)) - var str_current: String = current - match comparator: - Comparator.EQUAL: - if str_current.length() != expected: - return report_error(GdAssertMessages.error_has_length(str_current, expected, comparator)) - Comparator.LESS_THAN: - if str_current.length() >= expected: - return report_error(GdAssertMessages.error_has_length(str_current, expected, comparator)) - Comparator.LESS_EQUAL: - if str_current.length() > expected: - return report_error(GdAssertMessages.error_has_length(str_current, expected, comparator)) - Comparator.GREATER_THAN: - if str_current.length() <= expected: - return report_error(GdAssertMessages.error_has_length(str_current, expected, comparator)) - Comparator.GREATER_EQUAL: - if str_current.length() < expected: - return report_error(GdAssertMessages.error_has_length(str_current, expected, comparator)) - _: - return report_error("Comparator '%d' not implemented!" % comparator) - return report_success() - - -func contains_bbcode(value: String) -> bool: - var rtl := RichTextLabel.new() - rtl.bbcode_enabled = true - rtl.parse_bbcode(value) - var has_bbcode := rtl.get_parsed_text() != value - rtl.free() - return has_bbcode diff --git a/addons/gdUnit4/src/asserts/GdUnitStringAssertImpl.gd.uid b/addons/gdUnit4/src/asserts/GdUnitStringAssertImpl.gd.uid deleted file mode 100644 index ba34078a..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitStringAssertImpl.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dxqvilchqqeta diff --git a/addons/gdUnit4/src/asserts/GdUnitVectorAssertImpl.gd b/addons/gdUnit4/src/asserts/GdUnitVectorAssertImpl.gd deleted file mode 100644 index fbc031a4..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitVectorAssertImpl.gd +++ /dev/null @@ -1,187 +0,0 @@ -extends GdUnitVectorAssert - -var _base: GdUnitAssertImpl -var _current_type: int -var _type_check: bool - -func _init(current: Variant, type_check := true) -> void: - _type_check = type_check - _base = GdUnitAssertImpl.new(current) - # save the actual assert instance on the current thread context - GdUnitThreadManager.get_current_context().set_assert(self) - if not _validate_value_type(current): - @warning_ignore("return_value_discarded") - report_error("GdUnitVectorAssert error, the type <%s> is not supported." % GdObjects.typeof_as_string(current)) - _current_type = typeof(current) - - -func _notification(event :int) -> void: - if event == NOTIFICATION_PREDELETE: - if _base != null: - _base.notification(event) - _base = null - - -func _validate_value_type(value :Variant) -> bool: - return ( - value == null - or typeof(value) in [ - TYPE_VECTOR2, - TYPE_VECTOR2I, - TYPE_VECTOR3, - TYPE_VECTOR3I, - TYPE_VECTOR4, - TYPE_VECTOR4I - ] - ) - - -func _validate_is_vector_type(value :Variant) -> bool: - var type := typeof(value) - if type == _current_type or _current_type == TYPE_NIL: - return true - @warning_ignore("return_value_discarded") - report_error(GdAssertMessages.error_is_wrong_type(_current_type, type)) - return false - - -func current_value() -> Variant: - return _base.current_value() - - -func report_success() -> GdUnitVectorAssert: - @warning_ignore("return_value_discarded") - _base.report_success() - return self - - -func report_error(error :String) -> GdUnitVectorAssert: - @warning_ignore("return_value_discarded") - _base.report_error(error) - return self - - -func failure_message() -> String: - return _base.failure_message() - - -func override_failure_message(message: String) -> GdUnitVectorAssert: - @warning_ignore("return_value_discarded") - _base.override_failure_message(message) - return self - - -func append_failure_message(message :String) -> GdUnitVectorAssert: - @warning_ignore("return_value_discarded") - _base.append_failure_message(message) - return self - - -func is_null() -> GdUnitVectorAssert: - @warning_ignore("return_value_discarded") - _base.is_null() - return self - - -func is_not_null() -> GdUnitVectorAssert: - @warning_ignore("return_value_discarded") - _base.is_not_null() - return self - - -func is_equal(expected: Variant) -> GdUnitVectorAssert: - if _type_check and not _validate_is_vector_type(expected): - return self - @warning_ignore("return_value_discarded") - _base.is_equal(expected) - return self - - -func is_not_equal(expected: Variant) -> GdUnitVectorAssert: - if _type_check and not _validate_is_vector_type(expected): - return self - @warning_ignore("return_value_discarded") - _base.is_not_equal(expected) - return self - - -@warning_ignore("shadowed_global_identifier") -func is_equal_approx(expected :Variant, approx :Variant) -> GdUnitVectorAssert: - if not _validate_is_vector_type(expected) or not _validate_is_vector_type(approx): - return self - var current :Variant = current_value() - var from :Variant = expected - approx - var to :Variant = expected + approx - if current == null or (not _is_equal_approx(current, from, to)): - return report_error(GdAssertMessages.error_is_value(Comparator.BETWEEN_EQUAL, current, from, to)) - return report_success() - - -func _is_equal_approx(current :Variant, from :Variant, to :Variant) -> bool: - match typeof(current): - TYPE_VECTOR2, TYPE_VECTOR2I: - return ((current.x >= from.x and current.y >= from.y) - and (current.x <= to.x and current.y <= to.y)) - TYPE_VECTOR3, TYPE_VECTOR3I: - return ((current.x >= from.x and current.y >= from.y and current.z >= from.z) - and (current.x <= to.x and current.y <= to.y and current.z <= to.z)) - TYPE_VECTOR4, TYPE_VECTOR4I: - return ((current.x >= from.x and current.y >= from.y and current.z >= from.z and current.w >= from.w) - and (current.x <= to.x and current.y <= to.y and current.z <= to.z and current.w <= to.w)) - _: - push_error("Missing implementation '_is_equal_approx' for vector type %s" % typeof(current)) - return false - - -func is_less(expected :Variant) -> GdUnitVectorAssert: - if not _validate_is_vector_type(expected): - return self - var current :Variant = current_value() - if current == null or current >= expected: - return report_error(GdAssertMessages.error_is_value(Comparator.LESS_THAN, current, expected)) - return report_success() - - -func is_less_equal(expected :Variant) -> GdUnitVectorAssert: - if not _validate_is_vector_type(expected): - return self - var current :Variant = current_value() - if current == null or current > expected: - return report_error(GdAssertMessages.error_is_value(Comparator.LESS_EQUAL, current, expected)) - return report_success() - - -func is_greater(expected :Variant) -> GdUnitVectorAssert: - if not _validate_is_vector_type(expected): - return self - var current :Variant = current_value() - if current == null or current <= expected: - return report_error(GdAssertMessages.error_is_value(Comparator.GREATER_THAN, current, expected)) - return report_success() - - -func is_greater_equal(expected :Variant) -> GdUnitVectorAssert: - if not _validate_is_vector_type(expected): - return self - var current :Variant = current_value() - if current == null or current < expected: - return report_error(GdAssertMessages.error_is_value(Comparator.GREATER_EQUAL, current, expected)) - return report_success() - - -func is_between(from :Variant, to :Variant) -> GdUnitVectorAssert: - if not _validate_is_vector_type(from) or not _validate_is_vector_type(to): - return self - var current :Variant = current_value() - if current == null or not (current >= from and current <= to): - return report_error(GdAssertMessages.error_is_value(Comparator.BETWEEN_EQUAL, current, from, to)) - return report_success() - - -func is_not_between(from :Variant, to :Variant) -> GdUnitVectorAssert: - if not _validate_is_vector_type(from) or not _validate_is_vector_type(to): - return self - var current :Variant = current_value() - if (current != null and current >= from and current <= to): - return report_error(GdAssertMessages.error_is_value(Comparator.NOT_BETWEEN_EQUAL, current, from, to)) - return report_success() diff --git a/addons/gdUnit4/src/asserts/GdUnitVectorAssertImpl.gd.uid b/addons/gdUnit4/src/asserts/GdUnitVectorAssertImpl.gd.uid deleted file mode 100644 index c0a7e13a..00000000 --- a/addons/gdUnit4/src/asserts/GdUnitVectorAssertImpl.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://r4avfcakvscw diff --git a/addons/gdUnit4/src/asserts/ValueProvider.gd b/addons/gdUnit4/src/asserts/ValueProvider.gd deleted file mode 100644 index be01f70b..00000000 --- a/addons/gdUnit4/src/asserts/ValueProvider.gd +++ /dev/null @@ -1,10 +0,0 @@ -# base interface for assert value provider -class_name ValueProvider -extends RefCounted - -func get_value() -> Variant: - return null - - -func dispose() -> void: - pass diff --git a/addons/gdUnit4/src/asserts/ValueProvider.gd.uid b/addons/gdUnit4/src/asserts/ValueProvider.gd.uid deleted file mode 100644 index a34788ef..00000000 --- a/addons/gdUnit4/src/asserts/ValueProvider.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://8y15b6ts3kss diff --git a/addons/gdUnit4/src/cmd/CmdArgumentParser.gd b/addons/gdUnit4/src/cmd/CmdArgumentParser.gd deleted file mode 100644 index aa023194..00000000 --- a/addons/gdUnit4/src/cmd/CmdArgumentParser.gd +++ /dev/null @@ -1,62 +0,0 @@ -class_name CmdArgumentParser -extends RefCounted - -var _options :CmdOptions -var _tool_name :String -var _parsed_commands :Dictionary = Dictionary() - - -func _init(p_options :CmdOptions, p_tool_name :String) -> void: - _options = p_options - _tool_name = p_tool_name - - -func parse(args :Array, ignore_unknown_cmd := false) -> GdUnitResult: - _parsed_commands.clear() - - # parse until first program argument - while not args.is_empty(): - var arg :String = args.pop_front() - if arg.find(_tool_name) != -1: - break - - if args.is_empty(): - return GdUnitResult.empty() - - # now parse all arguments - while not args.is_empty(): - var cmd :String = args.pop_front() - var option := _options.get_option(cmd) - - if option: - if _parse_cmd_arguments(option, args) == -1: - return GdUnitResult.error("The '%s' command requires an argument!" % option.short_command()) - elif not ignore_unknown_cmd: - return GdUnitResult.error("Unknown '%s' command!" % cmd) - return GdUnitResult.success(_parsed_commands.values()) - - -func options() -> CmdOptions: - return _options - - -func _parse_cmd_arguments(option: CmdOption, args: Array) -> int: - var command_name := option.short_command() - var command: CmdCommand = _parsed_commands.get(command_name, CmdCommand.new(command_name)) - - if option.has_argument(): - if not option.is_argument_optional() and args.is_empty(): - return -1 - if _is_next_value_argument(args): - var value: String = args.pop_front() - command.add_argument(value) - elif not option.is_argument_optional(): - return -1 - _parsed_commands[command_name] = command - return 0 - - -func _is_next_value_argument(args: PackedStringArray) -> bool: - if args.is_empty(): - return false - return _options.get_option(args[0]) == null diff --git a/addons/gdUnit4/src/cmd/CmdArgumentParser.gd.uid b/addons/gdUnit4/src/cmd/CmdArgumentParser.gd.uid deleted file mode 100644 index f0bc4b67..00000000 --- a/addons/gdUnit4/src/cmd/CmdArgumentParser.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://d4hd3vc50jltg diff --git a/addons/gdUnit4/src/cmd/CmdCommand.gd b/addons/gdUnit4/src/cmd/CmdCommand.gd deleted file mode 100644 index 92e8c1fe..00000000 --- a/addons/gdUnit4/src/cmd/CmdCommand.gd +++ /dev/null @@ -1,27 +0,0 @@ -class_name CmdCommand -extends RefCounted - -var _name: String -var _arguments: PackedStringArray - - -func _init(p_name :String, p_arguments := []) -> void: - _name = p_name - _arguments = PackedStringArray(p_arguments) - - -func name() -> String: - return _name - - -func arguments() -> PackedStringArray: - return _arguments - - -func add_argument(arg :String) -> void: - @warning_ignore("return_value_discarded") - _arguments.append(arg) - - -func _to_string() -> String: - return "%s:%s" % [_name, ", ".join(_arguments)] diff --git a/addons/gdUnit4/src/cmd/CmdCommand.gd.uid b/addons/gdUnit4/src/cmd/CmdCommand.gd.uid deleted file mode 100644 index f087f8c7..00000000 --- a/addons/gdUnit4/src/cmd/CmdCommand.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://w4mr1j0k0l diff --git a/addons/gdUnit4/src/cmd/CmdCommandHandler.gd b/addons/gdUnit4/src/cmd/CmdCommandHandler.gd deleted file mode 100644 index 2a7ed553..00000000 --- a/addons/gdUnit4/src/cmd/CmdCommandHandler.gd +++ /dev/null @@ -1,136 +0,0 @@ -class_name CmdCommandHandler -extends RefCounted - -const CB_SINGLE_ARG = 0 -const CB_MULTI_ARGS = 1 -const NO_CB := Callable() - -var _cmd_options :CmdOptions -# holds the command callbacks by key::String and value: [, ]:Array -# Dictionary[String, Array[Callback] -var _command_cbs :Dictionary - - - -func _init(cmd_options: CmdOptions) -> void: - _cmd_options = cmd_options - - -# register a callback function for given command -# cmd_name short name of the command -# fr_arg a funcref to a function with a single argument -func register_cb(cmd_name: String, cb: Callable) -> CmdCommandHandler: - var registered_cb: Array = _command_cbs.get(cmd_name, [NO_CB, NO_CB]) - if registered_cb[CB_SINGLE_ARG]: - push_error("A function for command '%s' is already registered!" % cmd_name) - return self - - if not _validate_cb_signature(cb, TYPE_STRING): - push_error( - ("The callback '%s:%s' for command '%s' has invalid function signature. " - +"The callback signature must be 'func name(value: PackedStringArray)'") - % [cb.get_object().get_class(), cb.get_method(), cmd_name]) - return null - - registered_cb[CB_SINGLE_ARG] = cb - _command_cbs[cmd_name] = registered_cb - return self - - -# register a callback function for given command -# cb a funcref to a function with a variable number of arguments but expects all parameters to be passed via a single Array. -func register_cbv(cmd_name: String, cb: Callable) -> CmdCommandHandler: - var registered_cb: Array = _command_cbs.get(cmd_name, [NO_CB, NO_CB]) - if registered_cb[CB_MULTI_ARGS]: - push_error("A function for command '%s' is already registered!" % cmd_name) - return self - - if not _validate_cb_signature(cb, TYPE_PACKED_STRING_ARRAY): - push_error( - ("The callback '%s:%s' for command '%s' has invalid function signature. " - +"The callback signature must be 'func name(value: PackedStringArray)'") - % [cb.get_object().get_class(), cb.get_method(), cmd_name]) - return null - - registered_cb[CB_MULTI_ARGS] = cb - _command_cbs[cmd_name] = registered_cb - return self - - -func _validate() -> GdUnitResult: - var errors := PackedStringArray() - # Dictionary[StringName, String] - var registered_cbs := Dictionary() - - for cmd_name in _command_cbs.keys() as Array[String]: - var cb: Callable = (_command_cbs[cmd_name][CB_SINGLE_ARG] - if _command_cbs[cmd_name][CB_SINGLE_ARG] - else _command_cbs[cmd_name][CB_MULTI_ARGS]) - if cb != NO_CB and not cb.is_valid(): - @warning_ignore("return_value_discarded") - errors.append("Invalid function reference for command '%s', Check the function reference!" % cmd_name) - if _cmd_options.get_option(cmd_name) == null: - @warning_ignore("return_value_discarded") - errors.append("The command '%s' is unknown, verify your CmdOptions!" % cmd_name) - # verify for multiple registered command callbacks - if cb != NO_CB: - var cb_method := cb.get_method() - if registered_cbs.has(cb_method): - var already_registered_cmd :String = registered_cbs[cb_method] - @warning_ignore("return_value_discarded") - errors.append("The function reference '%s' already registerd for command '%s'!" % [cb_method, already_registered_cmd]) - else: - registered_cbs[cb_method] = cmd_name - if errors.is_empty(): - return GdUnitResult.success(true) - return GdUnitResult.error("\n".join(errors)) - - -func execute(commands: Array[CmdCommand]) -> GdUnitResult: - var result := _validate() - if result.is_error(): - return result - for cmd in commands: - var cmd_name := cmd.name() - if _command_cbs.has(cmd_name): - var cb_s: Callable = _command_cbs.get(cmd_name)[CB_SINGLE_ARG] - var arguments := cmd.arguments() - var cmd_option := _cmd_options.get_option(cmd_name) - - if arguments.is_empty(): - cb_s.call() - elif arguments.size() > 1: - var cb_m: Callable = _command_cbs.get(cmd_name)[CB_MULTI_ARGS] - cb_m.call(arguments) - else: - if cmd_option.type() == TYPE_BOOL: - cb_s.call(true if arguments[0] == "true" else false) - else: - cb_s.call(arguments[0]) - - return GdUnitResult.success(true) - - -func _validate_cb_signature(cb: Callable, arg_type: int) -> bool: - for m in cb.get_object().get_method_list(): - if m["name"] == cb.get_method(): - @warning_ignore("unsafe_cast") - return _validate_func_arguments(m["args"] as Array, arg_type) - return true - - -func _validate_func_arguments(arguments: Array, arg_type: int) -> bool: - # validate we have a single argument - if arguments.size() > 1: - return false - # a cb with no arguments is also valid - if arguments.size() == 0: - return true - # validate argument type - var arg: Dictionary = arguments[0] - @warning_ignore("unsafe_cast") - if arg["usage"] as int == PROPERTY_USAGE_NIL_IS_VARIANT: - return true - if arg["type"] != arg_type: - return false - return true diff --git a/addons/gdUnit4/src/cmd/CmdCommandHandler.gd.uid b/addons/gdUnit4/src/cmd/CmdCommandHandler.gd.uid deleted file mode 100644 index a1a2ddc6..00000000 --- a/addons/gdUnit4/src/cmd/CmdCommandHandler.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ccm3ivfiaf3i7 diff --git a/addons/gdUnit4/src/cmd/CmdOption.gd b/addons/gdUnit4/src/cmd/CmdOption.gd deleted file mode 100644 index a4982de2..00000000 --- a/addons/gdUnit4/src/cmd/CmdOption.gd +++ /dev/null @@ -1,61 +0,0 @@ -class_name CmdOption -extends RefCounted - - -var _commands :PackedStringArray -var _help :String -var _description :String -var _type :int -var _arg_optional :bool = false - - -# constructs a command option by given arguments -# commands : a string with comma separated list of available commands begining with the short form -# help: a help text show howto use -# description: a full description of the command -# type: the argument type -# arg_optional: defines of the argument optional -func _init(p_commands :String, p_help :String, p_description :String, p_type :int = TYPE_NIL, p_arg_optional :bool = false) -> void: - _commands = p_commands.replace(" ", "").replace("\t", "").split(",") - _help = p_help - _description = p_description - _type = p_type - _arg_optional = p_arg_optional - - -func commands() -> PackedStringArray: - return _commands - - -func short_command() -> String: - return _commands[0] - - -func help() -> String: - return _help - - -func description() -> String: - return _description - - -func type() -> int: - return _type - - -func is_argument_optional() -> bool: - return _arg_optional - - -func has_argument() -> bool: - return _type != TYPE_NIL - - -func describe() -> String: - if help().is_empty(): - return " %-32s %s \n" % [commands(), description()] - return " %-32s %s \n %-32s %s\n" % [commands(), description(), "", help()] - - -func _to_string() -> String: - return describe() diff --git a/addons/gdUnit4/src/cmd/CmdOption.gd.uid b/addons/gdUnit4/src/cmd/CmdOption.gd.uid deleted file mode 100644 index 0b077447..00000000 --- a/addons/gdUnit4/src/cmd/CmdOption.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ccnb2ah35atho diff --git a/addons/gdUnit4/src/cmd/CmdOptions.gd b/addons/gdUnit4/src/cmd/CmdOptions.gd deleted file mode 100644 index c6105298..00000000 --- a/addons/gdUnit4/src/cmd/CmdOptions.gd +++ /dev/null @@ -1,31 +0,0 @@ -class_name CmdOptions -extends RefCounted - - -var _default_options :Array[CmdOption] -var _advanced_options :Array[CmdOption] - - -func _init(p_options :Array[CmdOption] = [], p_advanced_options :Array[CmdOption] = []) -> void: - # default help options - _default_options = p_options - _advanced_options = p_advanced_options - - -func default_options() -> Array[CmdOption]: - return _default_options - - -func advanced_options() -> Array[CmdOption]: - return _advanced_options - - -func options() -> Array[CmdOption]: - return default_options() + advanced_options() - - -func get_option(cmd :String) -> CmdOption: - for option in options(): - if Array(option.commands()).has(cmd): - return option - return null diff --git a/addons/gdUnit4/src/cmd/CmdOptions.gd.uid b/addons/gdUnit4/src/cmd/CmdOptions.gd.uid deleted file mode 100644 index 6d1112bf..00000000 --- a/addons/gdUnit4/src/cmd/CmdOptions.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://0p8udx4tdwol diff --git a/addons/gdUnit4/src/core/GdArrayTools.gd b/addons/gdUnit4/src/core/GdArrayTools.gd deleted file mode 100644 index 74f0e175..00000000 --- a/addons/gdUnit4/src/core/GdArrayTools.gd +++ /dev/null @@ -1,127 +0,0 @@ -## Small helper tool to work with Godot Arrays -class_name GdArrayTools -extends RefCounted - - -const max_elements := 32 -const ARRAY_TYPES := [ - TYPE_ARRAY, - TYPE_PACKED_BYTE_ARRAY, - TYPE_PACKED_INT32_ARRAY, - TYPE_PACKED_INT64_ARRAY, - TYPE_PACKED_FLOAT32_ARRAY, - TYPE_PACKED_FLOAT64_ARRAY, - TYPE_PACKED_STRING_ARRAY, - TYPE_PACKED_VECTOR2_ARRAY, - TYPE_PACKED_VECTOR3_ARRAY, - TYPE_PACKED_VECTOR4_ARRAY, - TYPE_PACKED_COLOR_ARRAY -] - - -static func is_array_type(value: Variant) -> bool: - return is_type_array(typeof(value)) - - -static func is_type_array(type :int) -> bool: - return type in ARRAY_TYPES - - -## Filters an array by given value[br] -## If the given value not an array it returns null, will remove all occurence of given value. -static func filter_value(array: Variant, value: Variant) -> Variant: - if not is_array_type(array): - return null - - @warning_ignore("unsafe_method_access") - var filtered_array: Variant = array.duplicate() - @warning_ignore("unsafe_method_access") - var index: int = filtered_array.find(value) - while index != -1: - @warning_ignore("unsafe_method_access") - filtered_array.remove_at(index) - @warning_ignore("unsafe_method_access") - index = filtered_array.find(value) - return filtered_array - - -## Groups an array by a custom key selector -## The function should take an item and return the group key -static func group_by(array: Array, key_selector: Callable) -> Dictionary: - var result := {} - - for item: Variant in array: - var group_key: Variant = key_selector.call(item) - var values: Array = result.get_or_add(group_key, []) - values.append(item) - - return result - - -## Erases a value from given array by using equals(l,r) to find the element to erase -static func erase_value(array :Array, value :Variant) -> void: - for element :Variant in array: - if GdObjects.equals(element, value): - array.erase(element) - - -## Scans for the array build in type on a untyped array[br] -## Returns the buildin type by scan all values and returns the type if all values has the same type. -## If the values has different types TYPE_VARIANT is returend -static func scan_typed(array :Array) -> int: - if array.is_empty(): - return TYPE_NIL - var actual_type := GdObjects.TYPE_VARIANT - for value :Variant in array: - var current_type := typeof(value) - if not actual_type in [GdObjects.TYPE_VARIANT, current_type]: - return GdObjects.TYPE_VARIANT - actual_type = current_type - return actual_type - - -## Converts given array into a string presentation.[br] -## This function is different to the original Godot str() implementation. -## The string presentaion contains fullquallified typed informations. -##[br] -## Examples: -## [codeblock] -## # will result in PackedString(["a", "b"]) -## GdArrayTools.as_string(PackedStringArray("a", "b")) -## # will result in PackedString(["a", "b"]) -## GdArrayTools.as_string(PackedColorArray(Color.RED, COLOR.GREEN)) -## [/codeblock] -static func as_string(elements: Variant, encode_value := true) -> String: - var delemiter := ", " - if elements == null: - return "" - @warning_ignore("unsafe_cast") - if (elements as Array).is_empty(): - return "" - var prefix := _typeof_as_string(elements) if encode_value else "" - var formatted := "" - var index := 0 - for element :Variant in elements: - if max_elements != -1 and index > max_elements: - return prefix + "[" + formatted + delemiter + "...]" - if formatted.length() > 0 : - formatted += delemiter - formatted += GdDefaultValueDecoder.decode(element) if encode_value else str(element) - index += 1 - return prefix + "[" + formatted + "]" - - -static func has_same_content(current: Array, other: Array) -> bool: - if current.size() != other.size(): return false - for element: Variant in current: - if not other.has(element): return false - if current.count(element) != other.count(element): return false - return true - - -static func _typeof_as_string(value :Variant) -> String: - var type := typeof(value) - # for untyped array we retun empty string - if type == TYPE_ARRAY: - return "" - return GdObjects.typeof_as_string(value) diff --git a/addons/gdUnit4/src/core/GdArrayTools.gd.uid b/addons/gdUnit4/src/core/GdArrayTools.gd.uid deleted file mode 100644 index 98d9d57d..00000000 --- a/addons/gdUnit4/src/core/GdArrayTools.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bk60ywsj4ekp7 diff --git a/addons/gdUnit4/src/core/GdDiffTool.gd b/addons/gdUnit4/src/core/GdDiffTool.gd deleted file mode 100644 index 5131df71..00000000 --- a/addons/gdUnit4/src/core/GdDiffTool.gd +++ /dev/null @@ -1,224 +0,0 @@ -# Myers' Diff Algorithm implementation -# Based on "An O(ND) Difference Algorithm and Its Variations" by Eugene W. Myers -class_name GdDiffTool -extends RefCounted - - -const DIV_ADD :int = 214 -const DIV_SUB :int = 215 - - -class Edit: - enum Type { EQUAL, INSERT, DELETE } - var type: Type - var character: int - - func _init(t: Type, chr: int) -> void: - type = t - character = chr - - -# Main entry point - returns [ldiff, rdiff] -static func string_diff(left: Variant, right: Variant) -> Array[PackedInt32Array]: - var lb := PackedInt32Array() if left == null else str(left).to_utf32_buffer().to_int32_array() - var rb := PackedInt32Array() if right == null else str(right).to_utf32_buffer().to_int32_array() - - # Early exit for identical strings - if lb == rb: - return [lb.duplicate(), rb.duplicate()] - - var edits := _myers_diff(lb, rb) - return _edits_to_diff_format(edits) - - -# Core Myers' algorithm -static func _myers_diff(a: PackedInt32Array, b: PackedInt32Array) -> Array[Edit]: - var n := a.size() - var m := b.size() - var max_d := n + m - - # V array stores the furthest reaching x coordinate for each k-line - # We need indices from -max_d to max_d, so we offset by max_d - var v := PackedInt32Array() - v.resize(2 * max_d + 1) - v.fill(-1) - v[max_d + 1] = 0 # k=1 starts at x=0 - - var trace := [] # Store V arrays for each d to backtrack later - - # Find the edit distance - for d in range(0, max_d + 1): - # Store current V for backtracking - trace.append(v.duplicate()) - - for k in range(-d, d + 1, 2): - var k_offset := k + max_d - - # Decide whether to move down or right - var x: int - if k == -d or (k != d and v[k_offset - 1] < v[k_offset + 1]): - x = v[k_offset + 1] # Move down (insert from b) - else: - x = v[k_offset - 1] + 1 # Move right (delete from a) - - var y := x - k - - # Follow diagonal as far as possible (matching characters) - while x < n and y < m and a[x] == b[y]: - x += 1 - y += 1 - - v[k_offset] = x - - # Check if we've reached the end - if x >= n and y >= m: - return _backtrack(a, b, trace, d, max_d) - - # Should never reach here for valid inputs - return [] - - -# Backtrack through the edit graph to build the edit script -static func _backtrack(a: PackedInt32Array, b: PackedInt32Array, trace: Array, d: int, max_d: int) -> Array[Edit]: - var edits: Array[Edit] = [] - var x := a.size() - var y := b.size() - - # Walk backwards through each d value - for depth in range(d, -1, -1): - var v: PackedInt32Array = trace[depth] - var k := x - y - var k_offset := k + max_d - - # Determine previous k - var prev_k: int - if k == -depth or (k != depth and v[k_offset - 1] < v[k_offset + 1]): - prev_k = k + 1 - else: - prev_k = k - 1 - - var prev_k_offset := prev_k + max_d - var prev_x := v[prev_k_offset] - var prev_y := prev_x - prev_k - - # Extract diagonal (equal) characters - while x > prev_x and y > prev_y: - x -= 1 - y -= 1 - #var char_array := PackedInt32Array([a[x]]) - edits.insert(0, Edit.new(Edit.Type.EQUAL, a[x])) - - # Record the edit operation - if depth > 0: - if x == prev_x: - # Insert from b - y -= 1 - #var char_array := PackedInt32Array([b[y]]) - edits.insert(0, Edit.new(Edit.Type.INSERT, b[y])) - else: - # Delete from a - x -= 1 - #var char_array := PackedInt32Array([a[x]]) - edits.insert(0, Edit.new(Edit.Type.DELETE, a[x])) - - return edits - - -# Convert edit script to the DIV_ADD/DIV_SUB format -static func _edits_to_diff_format(edits: Array[Edit]) -> Array[PackedInt32Array]: - var ldiff := PackedInt32Array() - var rdiff := PackedInt32Array() - - for edit in edits: - match edit.type: - Edit.Type.EQUAL: - ldiff.append(edit.character) - rdiff.append(edit.character) - Edit.Type.INSERT: - ldiff.append(DIV_ADD) - ldiff.append(edit.character) - rdiff.append(DIV_SUB) - rdiff.append(edit.character) - Edit.Type.DELETE: - ldiff.append(DIV_SUB) - ldiff.append(edit.character) - rdiff.append(DIV_ADD) - rdiff.append(edit.character) - - return [ldiff, rdiff] - - -# prototype -static func longestCommonSubsequence(text1 :String, text2 :String) -> PackedStringArray: - var text1Words := text1.split(" ") - var text2Words := text2.split(" ") - var text1WordCount := text1Words.size() - var text2WordCount := text2Words.size() - var solutionMatrix := Array() - for i in text1WordCount+1: - var ar := Array() - for n in text2WordCount+1: - ar.append(0) - solutionMatrix.append(ar) - - for i in range(text1WordCount-1, 0, -1): - for j in range(text2WordCount-1, 0, -1): - if text1Words[i] == text2Words[j]: - solutionMatrix[i][j] = solutionMatrix[i + 1][j + 1] + 1; - else: - solutionMatrix[i][j] = max(solutionMatrix[i + 1][j], solutionMatrix[i][j + 1]); - - var i := 0 - var j := 0 - var lcsResultList := PackedStringArray(); - while (i < text1WordCount && j < text2WordCount): - if text1Words[i] == text2Words[j]: - @warning_ignore("return_value_discarded") - lcsResultList.append(text2Words[j]) - i += 1 - j += 1 - else: if (solutionMatrix[i + 1][j] >= solutionMatrix[i][j + 1]): - i += 1 - else: - j += 1 - return lcsResultList - - -static func markTextDifferences(text1 :String, text2 :String, lcsList :PackedStringArray, insertColor :Color, deleteColor:Color) -> String: - var stringBuffer := "" - if text1 == null and lcsList == null: - return stringBuffer - - var text1Words := text1.split(" ") - var text2Words := text2.split(" ") - var i := 0 - var j := 0 - var word1LastIndex := 0 - var word2LastIndex := 0 - for k in lcsList.size(): - while i < text1Words.size() and j < text2Words.size(): - if text1Words[i] == lcsList[k] and text2Words[j] == lcsList[k]: - stringBuffer += "" + lcsList[k] + " " - word1LastIndex = i + 1 - word2LastIndex = j + 1 - i = text1Words.size() - j = text2Words.size() - - else: if text1Words[i] != lcsList[k]: - while i < text1Words.size() and text1Words[i] != lcsList[k]: - stringBuffer += "" + text1Words[i] + " " - i += 1 - else: if text2Words[j] != lcsList[k]: - while j < text2Words.size() and text2Words[j] != lcsList[k]: - stringBuffer += "" + text2Words[j] + " " - j += 1 - i = word1LastIndex - j = word2LastIndex - - while word1LastIndex < text1Words.size(): - stringBuffer += "" + text1Words[word1LastIndex] + " " - word1LastIndex += 1 - while word2LastIndex < text2Words.size(): - stringBuffer += "" + text2Words[word2LastIndex] + " " - word2LastIndex += 1 - return stringBuffer diff --git a/addons/gdUnit4/src/core/GdDiffTool.gd.uid b/addons/gdUnit4/src/core/GdDiffTool.gd.uid deleted file mode 100644 index 89041b66..00000000 --- a/addons/gdUnit4/src/core/GdDiffTool.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b5sli0lem5xca diff --git a/addons/gdUnit4/src/core/GdObjects.gd b/addons/gdUnit4/src/core/GdObjects.gd deleted file mode 100644 index 279e5188..00000000 --- a/addons/gdUnit4/src/core/GdObjects.gd +++ /dev/null @@ -1,726 +0,0 @@ -# This is a helper class to compare two objects by equals -class_name GdObjects -extends Resource - -const GdUnitTools := preload("res://addons/gdUnit4/src/core/GdUnitTools.gd") - - -# introduced with Godot 4.3.beta1 -const TYPE_VOID = 1000 -const TYPE_VARARG = 1001 -const TYPE_VARIANT = 1002 -const TYPE_FUNC = 1003 -const TYPE_FUZZER = 1004 -# missing Godot types -const TYPE_NODE = 2001 -const TYPE_CONTROL = 2002 -const TYPE_CANVAS = 2003 -const TYPE_ENUM = 2004 - - -const TYPE_AS_STRING_MAPPINGS := { - TYPE_NIL: "null", - TYPE_BOOL: "bool", - TYPE_INT: "int", - TYPE_FLOAT: "float", - TYPE_STRING: "String", - TYPE_VECTOR2: "Vector2", - TYPE_VECTOR2I: "Vector2i", - TYPE_RECT2: "Rect2", - TYPE_RECT2I: "Rect2i", - TYPE_VECTOR3: "Vector3", - TYPE_VECTOR3I: "Vector3i", - TYPE_TRANSFORM2D: "Transform2D", - TYPE_VECTOR4: "Vector4", - TYPE_VECTOR4I: "Vector4i", - TYPE_PLANE: "Plane", - TYPE_QUATERNION: "Quaternion", - TYPE_AABB: "AABB", - TYPE_BASIS: "Basis", - TYPE_TRANSFORM3D: "Transform3D", - TYPE_PROJECTION: "Projection", - TYPE_COLOR: "Color", - TYPE_STRING_NAME: "StringName", - TYPE_NODE_PATH: "NodePath", - TYPE_RID: "RID", - TYPE_OBJECT: "Object", - TYPE_CALLABLE: "Callable", - TYPE_SIGNAL: "Signal", - TYPE_DICTIONARY: "Dictionary", - TYPE_ARRAY: "Array", - TYPE_PACKED_BYTE_ARRAY: "PackedByteArray", - TYPE_PACKED_INT32_ARRAY: "PackedInt32Array", - TYPE_PACKED_INT64_ARRAY: "PackedInt64Array", - TYPE_PACKED_FLOAT32_ARRAY: "PackedFloat32Array", - TYPE_PACKED_FLOAT64_ARRAY: "PackedFloat64Array", - TYPE_PACKED_STRING_ARRAY: "PackedStringArray", - TYPE_PACKED_VECTOR2_ARRAY: "PackedVector2Array", - TYPE_PACKED_VECTOR3_ARRAY: "PackedVector3Array", - TYPE_PACKED_VECTOR4_ARRAY: "PackedVector4Array", - TYPE_PACKED_COLOR_ARRAY: "PackedColorArray", - TYPE_VOID: "void", - TYPE_VARARG: "VarArg", - TYPE_FUNC: "Func", - TYPE_FUZZER: "Fuzzer", - TYPE_VARIANT: "Variant" -} - - -class EditorNotifications: - # NOTE: Hardcoding to avoid runtime errors in exported projects when editor - # classes are not available. These values are unlikely to change. - # See: EditorSettings.NOTIFICATION_EDITOR_SETTINGS_CHANGED - const NOTIFICATION_EDITOR_SETTINGS_CHANGED := 10000 - - -const NOTIFICATION_AS_STRING_MAPPINGS := { - TYPE_OBJECT: { - Object.NOTIFICATION_POSTINITIALIZE : "POSTINITIALIZE", - Object.NOTIFICATION_PREDELETE: "PREDELETE", - EditorNotifications.NOTIFICATION_EDITOR_SETTINGS_CHANGED: "EDITOR_SETTINGS_CHANGED", - }, - TYPE_NODE: { - Node.NOTIFICATION_ENTER_TREE : "ENTER_TREE", - Node.NOTIFICATION_EXIT_TREE: "EXIT_TREE", - Node.NOTIFICATION_CHILD_ORDER_CHANGED: "CHILD_ORDER_CHANGED", - Node.NOTIFICATION_READY: "READY", - Node.NOTIFICATION_PAUSED: "PAUSED", - Node.NOTIFICATION_UNPAUSED: "UNPAUSED", - Node.NOTIFICATION_PHYSICS_PROCESS: "PHYSICS_PROCESS", - Node.NOTIFICATION_PROCESS: "PROCESS", - Node.NOTIFICATION_PARENTED: "PARENTED", - Node.NOTIFICATION_UNPARENTED: "UNPARENTED", - Node.NOTIFICATION_SCENE_INSTANTIATED: "INSTANCED", - Node.NOTIFICATION_DRAG_BEGIN: "DRAG_BEGIN", - Node.NOTIFICATION_DRAG_END: "DRAG_END", - Node.NOTIFICATION_PATH_RENAMED: "PATH_CHANGED", - Node.NOTIFICATION_INTERNAL_PROCESS: "INTERNAL_PROCESS", - Node.NOTIFICATION_INTERNAL_PHYSICS_PROCESS: "INTERNAL_PHYSICS_PROCESS", - Node.NOTIFICATION_POST_ENTER_TREE: "POST_ENTER_TREE", - Node.NOTIFICATION_WM_MOUSE_ENTER: "WM_MOUSE_ENTER", - Node.NOTIFICATION_WM_MOUSE_EXIT: "WM_MOUSE_EXIT", - Node.NOTIFICATION_APPLICATION_FOCUS_IN: "WM_FOCUS_IN", - Node.NOTIFICATION_APPLICATION_FOCUS_OUT: "WM_FOCUS_OUT", - #Node.NOTIFICATION_WM_QUIT_REQUEST: "WM_QUIT_REQUEST", - Node.NOTIFICATION_WM_GO_BACK_REQUEST: "WM_GO_BACK_REQUEST", - Node.NOTIFICATION_WM_WINDOW_FOCUS_OUT: "WM_UNFOCUS_REQUEST", - Node.NOTIFICATION_OS_MEMORY_WARNING: "OS_MEMORY_WARNING", - Node.NOTIFICATION_TRANSLATION_CHANGED: "TRANSLATION_CHANGED", - Node.NOTIFICATION_WM_ABOUT: "WM_ABOUT", - Node.NOTIFICATION_CRASH: "CRASH", - Node.NOTIFICATION_OS_IME_UPDATE: "OS_IME_UPDATE", - Node.NOTIFICATION_APPLICATION_RESUMED: "APP_RESUMED", - Node.NOTIFICATION_APPLICATION_PAUSED: "APP_PAUSED", - Node3D.NOTIFICATION_TRANSFORM_CHANGED: "TRANSFORM_CHANGED", - Node3D.NOTIFICATION_ENTER_WORLD: "ENTER_WORLD", - Node3D.NOTIFICATION_EXIT_WORLD: "EXIT_WORLD", - Node3D.NOTIFICATION_VISIBILITY_CHANGED: "VISIBILITY_CHANGED", - Skeleton3D.NOTIFICATION_UPDATE_SKELETON: "UPDATE_SKELETON", - CanvasItem.NOTIFICATION_DRAW: "DRAW", - CanvasItem.NOTIFICATION_VISIBILITY_CHANGED: "VISIBILITY_CHANGED", - CanvasItem.NOTIFICATION_ENTER_CANVAS: "ENTER_CANVAS", - CanvasItem.NOTIFICATION_EXIT_CANVAS: "EXIT_CANVAS", - #Popup.NOTIFICATION_POST_POPUP: "POST_POPUP", - #Popup.NOTIFICATION_POPUP_HIDE: "POPUP_HIDE", - }, - TYPE_CONTROL : { - Object.NOTIFICATION_PREDELETE: "PREDELETE", - Container.NOTIFICATION_SORT_CHILDREN: "SORT_CHILDREN", - Control.NOTIFICATION_RESIZED: "RESIZED", - Control.NOTIFICATION_MOUSE_ENTER: "MOUSE_ENTER", - Control.NOTIFICATION_MOUSE_EXIT: "MOUSE_EXIT", - Control.NOTIFICATION_FOCUS_ENTER: "FOCUS_ENTER", - Control.NOTIFICATION_FOCUS_EXIT: "FOCUS_EXIT", - Control.NOTIFICATION_THEME_CHANGED: "THEME_CHANGED", - #Control.NOTIFICATION_MODAL_CLOSE: "MODAL_CLOSE", - Control.NOTIFICATION_SCROLL_BEGIN: "SCROLL_BEGIN", - Control.NOTIFICATION_SCROLL_END: "SCROLL_END", - } -} - - -enum COMPARE_MODE { - OBJECT_REFERENCE, - PARAMETER_DEEP_TEST -} - - -# prototype of better object to dictionary -static func obj2dict(obj: Object, hashed_objects := Dictionary()) -> Dictionary: - if obj == null: - return {} - var clazz_name := obj.get_class() - var dict := Dictionary() - var clazz_path := "" - - if is_instance_valid(obj) and obj.get_script() != null: - var script: Script = obj.get_script() - # handle build-in scripts - if script.resource_path != null and script.resource_path.contains(".tscn"): - var path_elements := script.resource_path.split(".tscn") - clazz_name = path_elements[0].get_file() - clazz_path = script.resource_path - else: - var d := inst_to_dict(obj) - clazz_path = d["@path"] - if d["@subpath"] != NodePath(""): - clazz_name = d["@subpath"] - dict["@inner_class"] = true - else: - clazz_name = clazz_path.get_file().replace(".gd", "") - dict["@path"] = clazz_path - - for property in obj.get_property_list(): - var property_name :String = property["name"] - var property_type :int = property["type"] - var property_value :Variant = obj.get(property_name) - if property_value is GDScript or property_value is Callable or property_value is RegEx: - continue - if (property["usage"] & PROPERTY_USAGE_SCRIPT_VARIABLE|PROPERTY_USAGE_DEFAULT - and not property["usage"] & PROPERTY_USAGE_CATEGORY - and not property["usage"] == 0): - if property_type == TYPE_OBJECT: - # prevent recursion - if hashed_objects.has(obj): - dict[property_name] = str(property_value) - continue - hashed_objects[obj] = true - @warning_ignore("unsafe_cast") - dict[property_name] = obj2dict(property_value as Object, hashed_objects) - else: - dict[property_name] = property_value - if obj is Node: - var childrens :Array = (obj as Node).get_children() - dict["childrens"] = childrens.map(func (child :Object) -> Dictionary: return obj2dict(child, hashed_objects)) - if obj is TreeItem: - var childrens :Array = (obj as TreeItem).get_children() - dict["childrens"] = childrens.map(func (child :Object) -> Dictionary: return obj2dict(child, hashed_objects)) - - return {"%s" % clazz_name : dict} - - -static func equals(obj_a :Variant, obj_b :Variant, case_sensitive :bool = false, compare_mode :COMPARE_MODE = COMPARE_MODE.PARAMETER_DEEP_TEST) -> bool: - return _equals(obj_a, obj_b, case_sensitive, compare_mode, [], 0) - - -static func equals_sorted(obj_a: Array[Variant], obj_b: Array[Variant], case_sensitive: bool = false, compare_mode: COMPARE_MODE = COMPARE_MODE.PARAMETER_DEEP_TEST) -> bool: - var a: Array[Variant] = obj_a.duplicate() - var b: Array[Variant] = obj_b.duplicate() - a.sort() - b.sort() - return equals(a, b, case_sensitive, compare_mode) - - -static func _equals(obj_a :Variant, obj_b :Variant, case_sensitive :bool, compare_mode :COMPARE_MODE, deep_stack :Array, stack_depth :int ) -> bool: - var type_a := typeof(obj_a) - var type_b := typeof(obj_b) - if stack_depth > 32: - prints("stack_depth", stack_depth, deep_stack) - push_error("GdUnit equals has max stack deep reached!") - return false - - # use argument matcher if requested - if is_instance_valid(obj_a) and obj_a is GdUnitArgumentMatcher: - @warning_ignore("unsafe_cast") - return (obj_a as GdUnitArgumentMatcher).is_match(obj_b) - if is_instance_valid(obj_b) and obj_b is GdUnitArgumentMatcher: - @warning_ignore("unsafe_cast") - return (obj_b as GdUnitArgumentMatcher).is_match(obj_a) - - stack_depth += 1 - # fast fail is different types - if not _is_type_equivalent(type_a, type_b): - return false - # is same instance - if obj_a == obj_b: - return true - # handle null values - if obj_a == null and obj_b != null: - return false - if obj_b == null and obj_a != null: - return false - - match type_a: - TYPE_OBJECT: - if deep_stack.has(obj_a) or deep_stack.has(obj_b): - return true - deep_stack.append(obj_a) - deep_stack.append(obj_b) - if compare_mode == COMPARE_MODE.PARAMETER_DEEP_TEST: - # fail fast - if not is_instance_valid(obj_a) or not is_instance_valid(obj_b): - return false - @warning_ignore("unsafe_method_access") - if obj_a.get_class() != obj_b.get_class(): - return false - @warning_ignore("unsafe_cast") - var a := obj2dict(obj_a as Object) - @warning_ignore("unsafe_cast") - var b := obj2dict(obj_b as Object) - return _equals(a, b, case_sensitive, compare_mode, deep_stack, stack_depth) - return obj_a == obj_b - - TYPE_ARRAY: - @warning_ignore("unsafe_method_access") - if obj_a.size() != obj_b.size(): - return false - @warning_ignore("unsafe_method_access") - for index :int in obj_a.size(): - if not _equals(obj_a[index], obj_b[index], case_sensitive, compare_mode, deep_stack, stack_depth): - return false - return true - - TYPE_DICTIONARY: - @warning_ignore("unsafe_method_access") - if obj_a.size() != obj_b.size(): - return false - @warning_ignore("unsafe_method_access") - for key :Variant in obj_a.keys(): - @warning_ignore("unsafe_method_access") - var value_a :Variant = obj_a[key] if obj_a.has(key) else null - @warning_ignore("unsafe_method_access") - var value_b :Variant = obj_b[key] if obj_b.has(key) else null - if not _equals(value_a, value_b, case_sensitive, compare_mode, deep_stack, stack_depth): - return false - return true - - TYPE_STRING: - if case_sensitive: - @warning_ignore("unsafe_method_access") - return obj_a.to_lower() == obj_b.to_lower() - else: - return obj_a == obj_b - return obj_a == obj_b - - -@warning_ignore("shadowed_variable_base_class") -static func notification_as_string(instance :Variant, notification :int) -> String: - var error := "Unknown notification: '%s' at instance: %s" % [notification, instance] - if instance is Node and NOTIFICATION_AS_STRING_MAPPINGS[TYPE_NODE].has(notification): - return NOTIFICATION_AS_STRING_MAPPINGS[TYPE_NODE].get(notification, error) - if instance is Control and NOTIFICATION_AS_STRING_MAPPINGS[TYPE_CONTROL].has(notification): - return NOTIFICATION_AS_STRING_MAPPINGS[TYPE_CONTROL].get(notification, error) - return NOTIFICATION_AS_STRING_MAPPINGS[TYPE_OBJECT].get(notification, error) - - -static func string_to_type(value :String) -> int: - for type :int in TYPE_AS_STRING_MAPPINGS.keys(): - if TYPE_AS_STRING_MAPPINGS.get(type) == value: - return type - return TYPE_NIL - - -static func to_camel_case(value :String) -> String: - var p := to_pascal_case(value) - if not p.is_empty(): - p[0] = p[0].to_lower() - return p - - -static func to_pascal_case(value :String) -> String: - return value.capitalize().replace(" ", "") - - -@warning_ignore("return_value_discarded") -static func to_snake_case(value :String) -> String: - var result := PackedStringArray() - for ch in value: - var lower_ch := ch.to_lower() - if ch != lower_ch and result.size() > 1: - result.append('_') - result.append(lower_ch) - return ''.join(result) - - -static func is_snake_case(value :String) -> bool: - for ch in value: - if ch == '_': - continue - if ch == ch.to_upper(): - return false - return true - - -static func type_as_string(type :int) -> String: - if type < TYPE_MAX: - return type_string(type) - return TYPE_AS_STRING_MAPPINGS.get(type, "Variant") - - -static func typeof_as_string(value :Variant) -> String: - return TYPE_AS_STRING_MAPPINGS.get(typeof(value), "Unknown type") - - -static func all_types() -> PackedInt32Array: - return PackedInt32Array(TYPE_AS_STRING_MAPPINGS.keys()) - - -static func string_as_typeof(type_name :String) -> int: - var type :Variant = TYPE_AS_STRING_MAPPINGS.find_key(type_name) - return type if type != null else TYPE_VARIANT - - -static func is_primitive_type(value :Variant) -> bool: - return typeof(value) in [TYPE_BOOL, TYPE_STRING, TYPE_STRING_NAME, TYPE_INT, TYPE_FLOAT] - - -static func _is_type_equivalent(type_a :int, type_b :int) -> bool: - # don't test for TYPE_STRING_NAME equivalenz - if type_a == TYPE_STRING_NAME or type_b == TYPE_STRING_NAME: - return true - if GdUnitSettings.is_strict_number_type_compare(): - return type_a == type_b - return ( - (type_a == TYPE_FLOAT and type_b == TYPE_INT) - or (type_a == TYPE_INT and type_b == TYPE_FLOAT) - or type_a == type_b) - - -static func is_engine_type(value :Variant) -> bool: - if value is GDScript or value is ScriptExtension: - return false - var obj: Object = value - if is_instance_valid(obj) and obj.has_method("is_class"): - return obj.is_class("GDScriptNativeClass") - return false - - -static func is_type(value :Variant) -> bool: - # is an build-in type - if typeof(value) != TYPE_OBJECT: - return false - # is a engine class type - if is_engine_type(value): - return true - # is a custom class type - @warning_ignore("unsafe_cast") - if value is GDScript and (value as GDScript).can_instantiate(): - return true - return false - - -static func _is_same(left :Variant, right :Variant) -> bool: - var left_type := -1 if left == null else typeof(left) - var right_type := -1 if right == null else typeof(right) - - # if typ different can't be the same - if left_type != right_type: - return false - if left_type == TYPE_OBJECT and right_type == TYPE_OBJECT: - @warning_ignore("unsafe_cast") - return (left as Object).get_instance_id() == (right as Object).get_instance_id() - return equals(left, right) - - -static func is_object(value :Variant) -> bool: - return typeof(value) == TYPE_OBJECT - - -static func is_script(value :Variant) -> bool: - return is_object(value) and value is Script - - -static func is_native_class(value :Variant) -> bool: - return is_object(value) and is_engine_type(value) - - -static func is_scene(value :Variant) -> bool: - return is_object(value) and value is PackedScene - - -static func is_scene_resource_path(value :Variant) -> bool: - @warning_ignore("unsafe_cast") - return value is String and (value as String).ends_with(".tscn") - - -static func is_singleton(value: Variant) -> bool: - if not is_instance_valid(value) or is_native_class(value): - return false - for name in Engine.get_singleton_list(): - @warning_ignore("unsafe_cast") - if (value as Object).is_class(name): - return true - return false - - -static func is_instance(value :Variant) -> bool: - if not is_instance_valid(value) or is_native_class(value): - return false - @warning_ignore("unsafe_cast") - if is_script(value) and (value as Script).get_instance_base_type() == "": - return true - if is_scene(value): - return true - @warning_ignore("unsafe_cast") - return not (value as Object).has_method('new') and not (value as Object).has_method('instance') - - -# only object form type Node and attached filename -static func is_instance_scene(instance :Variant) -> bool: - if instance is Node: - var node: Node = instance - return node.get_scene_file_path() != null and not node.get_scene_file_path().is_empty() - return false - - -static func can_be_instantiate(obj :Variant) -> bool: - if not obj or is_engine_type(obj): - return false - @warning_ignore("unsafe_cast") - return (obj as Object).has_method("new") - - -static func create_instance(clazz :Variant) -> GdUnitResult: - match typeof(clazz): - TYPE_OBJECT: - # test is given clazz already an instance - if is_instance(clazz): - return GdUnitResult.success(clazz) - @warning_ignore("unsafe_method_access") - return GdUnitResult.success(clazz.new()) - TYPE_STRING: - var clazz_name: String = clazz - if ClassDB.class_exists(clazz_name): - if Engine.has_singleton(clazz_name): - return GdUnitResult.error("Not allowed to create a instance for singelton '%s'." % clazz_name) - if not ClassDB.can_instantiate(clazz_name): - return GdUnitResult.error("Can't instance Engine class '%s'." % clazz_name) - return GdUnitResult.success(ClassDB.instantiate(clazz_name)) - else: - var clazz_path :String = extract_class_path(clazz_name)[0] - if not FileAccess.file_exists(clazz_path): - return GdUnitResult.error("Class '%s' not found." % clazz_name) - var script: GDScript = load(clazz_path) - if script != null: - return GdUnitResult.success(script.new()) - else: - return GdUnitResult.error("Can't create instance for '%s'." % clazz_name) - return GdUnitResult.error("Can't create instance for class '%s'." % str(clazz)) - - -## We do dispose 'GDScriptFunctionState' in a kacky style because the class is not visible anymore -static func dispose_function_state(func_state: Variant) -> void: - if func_state != null and str(func_state).contains("GDScriptFunctionState"): - @warning_ignore("unsafe_method_access") - func_state.completed.emit() - - -@warning_ignore("return_value_discarded") -static func extract_class_path(clazz :Variant) -> PackedStringArray: - var clazz_path := PackedStringArray() - if clazz is String: - @warning_ignore("unsafe_cast") - clazz_path.append(clazz as String) - return clazz_path - if is_instance(clazz): - # is instance a script instance? - var script: GDScript = clazz.script - if script != null: - return extract_class_path(script) - return clazz_path - - if clazz is GDScript: - var script: GDScript = clazz - if not script.resource_path.is_empty(): - clazz_path.append(script.resource_path) - return clazz_path - # if not found we go the expensive way and extract the path form the script by creating an instance - var arg_list := build_function_default_arguments(script, "_init") - var instance: Object = script.callv("new", arg_list) - var clazz_info := inst_to_dict(instance) - GdUnitTools.free_instance(instance) - @warning_ignore("unsafe_cast") - clazz_path.append(clazz_info["@path"] as String) - if clazz_info.has("@subpath"): - var sub_path :String = clazz_info["@subpath"] - if not sub_path.is_empty(): - var sub_paths := sub_path.split("/") - clazz_path += sub_paths - return clazz_path - return clazz_path - - -static func extract_class_name_from_class_path(clazz_path :PackedStringArray) -> String: - var base_clazz := clazz_path[0] - # return original class name if engine class - if ClassDB.class_exists(base_clazz): - return base_clazz - var clazz_name := to_pascal_case(base_clazz.get_basename().get_file()) - for path_index in range(1, clazz_path.size()): - clazz_name += "." + clazz_path[path_index] - return clazz_name - - -static func extract_class_name(clazz :Variant) -> GdUnitResult: - if clazz == null: - return GdUnitResult.error("Can't extract class name form a null value.") - - if is_instance(clazz): - # is instance a script instance? - var script: GDScript = clazz.script - if script != null: - return extract_class_name(script) - @warning_ignore("unsafe_cast") - return GdUnitResult.success((clazz as Object).get_class()) - - # extract name form full qualified class path - if clazz is String: - var clazz_name: String = clazz - if ClassDB.class_exists(clazz_name): - return GdUnitResult.success(clazz_name) - var source_script :GDScript = load(clazz_name) - clazz_name = GdScriptParser.new().get_class_name(source_script) - return GdUnitResult.success(to_pascal_case(clazz_name)) - - if is_primitive_type(clazz): - return GdUnitResult.error("Can't extract class name for an primitive '%s'" % type_as_string(typeof(clazz))) - - if is_script(clazz): - @warning_ignore("unsafe_cast") - if (clazz as Script).resource_path.is_empty(): - var class_path := extract_class_name_from_class_path(extract_class_path(clazz)) - return GdUnitResult.success(class_path); - return extract_class_name(clazz.resource_path) - - # need to create an instance for a class typ the extract the class name - @warning_ignore("unsafe_method_access") - var instance :Variant = clazz.new() - if instance == null: - return GdUnitResult.error("Can't create a instance for class '%s'" % str(clazz)) - var result := extract_class_name(instance) - @warning_ignore("return_value_discarded") - GdUnitTools.free_instance(instance) - return result - - -static func extract_inner_clazz_names(clazz_name :String, script_path :PackedStringArray) -> PackedStringArray: - var inner_classes := PackedStringArray() - - if ClassDB.class_exists(clazz_name): - return inner_classes - var script :GDScript = load(script_path[0]) - var map := script.get_script_constant_map() - for key :String in map.keys(): - var value :Variant = map.get(key) - if value is GDScript: - var class_path := extract_class_path(value) - @warning_ignore("return_value_discarded") - inner_classes.append(class_path[1]) - return inner_classes - - -static func extract_class_functions(clazz_name :String, script_path :PackedStringArray) -> Array: - if ClassDB.class_get_method_list(clazz_name): - return ClassDB.class_get_method_list(clazz_name) - - if not FileAccess.file_exists(script_path[0]): - return Array() - var script :GDScript = load(script_path[0]) - if script is GDScript: - # if inner class on class path we have to load the script from the script_constant_map - if script_path.size() == 2 and script_path[1] != "": - var inner_classes := script_path[1] - var map := script.get_script_constant_map() - script = map[inner_classes] - var clazz_functions :Array = script.get_method_list() - var base_clazz :String = script.get_instance_base_type() - if base_clazz: - return extract_class_functions(base_clazz, script_path) - return clazz_functions - return Array() - - -# scans all registert script classes for given -# if the class is public in the global space than return true otherwise false -# public class means the script class is defined by 'class_name ' -static func is_public_script_class(clazz_name :String) -> bool: - var script_classes:Array[Dictionary] = ProjectSettings.get_global_class_list() - for class_info in script_classes: - if class_info.has("class"): - if class_info["class"] == clazz_name: - return true - return false - - -static func build_function_default_arguments(script :GDScript, func_name :String) -> Array: - var arg_list := Array() - for func_sig in script.get_script_method_list(): - if func_sig["name"] == func_name: - var args :Array[Dictionary] = func_sig["args"] - for arg in args: - var value_type :int = arg["type"] - var default_value :Variant = default_value_by_type(value_type) - arg_list.append(default_value) - return arg_list - return arg_list - - -static func default_value_by_type(type :int) -> Variant: - assert(type < TYPE_MAX) - assert(type >= 0) - - match type: - TYPE_NIL: return null - TYPE_BOOL: return false - TYPE_INT: return 0 - TYPE_FLOAT: return 0.0 - TYPE_STRING: return "" - TYPE_VECTOR2: return Vector2.ZERO - TYPE_VECTOR2I: return Vector2i.ZERO - TYPE_VECTOR3: return Vector3.ZERO - TYPE_VECTOR3I: return Vector3i.ZERO - TYPE_VECTOR4: return Vector4.ZERO - TYPE_VECTOR4I: return Vector4i.ZERO - TYPE_RECT2: return Rect2() - TYPE_RECT2I: return Rect2i() - TYPE_TRANSFORM2D: return Transform2D() - TYPE_PLANE: return Plane() - TYPE_QUATERNION: return Quaternion() - TYPE_AABB: return AABB() - TYPE_BASIS: return Basis() - TYPE_TRANSFORM3D: return Transform3D() - TYPE_COLOR: return Color() - TYPE_NODE_PATH: return NodePath() - TYPE_RID: return RID() - TYPE_OBJECT: return null - TYPE_CALLABLE: return Callable() - TYPE_ARRAY: return [] - TYPE_DICTIONARY: return {} - TYPE_PACKED_BYTE_ARRAY: return PackedByteArray() - TYPE_PACKED_COLOR_ARRAY: return PackedColorArray() - TYPE_PACKED_INT32_ARRAY: return PackedInt32Array() - TYPE_PACKED_INT64_ARRAY: return PackedInt64Array() - TYPE_PACKED_FLOAT32_ARRAY: return PackedFloat32Array() - TYPE_PACKED_FLOAT64_ARRAY: return PackedFloat64Array() - TYPE_PACKED_STRING_ARRAY: return PackedStringArray() - TYPE_PACKED_VECTOR2_ARRAY: return PackedVector2Array() - TYPE_PACKED_VECTOR3_ARRAY: return PackedVector3Array() - - push_error("Can't determine a default value for type: '%s', Please create a Bug issue and attach the stacktrace please." % type) - return null - - -static func find_nodes_by_class(root: Node, cls: String, recursive: bool = false) -> Array[Node]: - if not recursive: - return _find_nodes_by_class_no_rec(root, cls) - return _find_nodes_by_class(root, cls) - - -static func _find_nodes_by_class_no_rec(parent: Node, cls: String) -> Array[Node]: - var result :Array[Node] = [] - for ch in parent.get_children(): - if ch.get_class() == cls: - result.append(ch) - return result - - -static func _find_nodes_by_class(root: Node, cls: String) -> Array[Node]: - var result :Array[Node] = [] - var stack :Array[Node] = [root] - while stack: - var node :Node = stack.pop_back() - if node.get_class() == cls: - result.append(node) - for ch in node.get_children(): - stack.push_back(ch) - return result diff --git a/addons/gdUnit4/src/core/GdObjects.gd.uid b/addons/gdUnit4/src/core/GdObjects.gd.uid deleted file mode 100644 index fd8f6d6e..00000000 --- a/addons/gdUnit4/src/core/GdObjects.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b7ldhc4ryfh1v diff --git a/addons/gdUnit4/src/core/GdUnit4Version.gd b/addons/gdUnit4/src/core/GdUnit4Version.gd deleted file mode 100644 index 3e6a334e..00000000 --- a/addons/gdUnit4/src/core/GdUnit4Version.gd +++ /dev/null @@ -1,65 +0,0 @@ -class_name GdUnit4Version -extends RefCounted - -const VERSION_PATTERN = "[center][color=#9887c4]gd[/color][color=#7a57d6]Unit[/color][color=#9887c4]4[/color] [color=#9887c4]${version}[/color][/center]" - -var _major :int -var _minor :int -var _patch :int - - -func _init(major :int, minor :int, patch :int) -> void: - _major = major - _minor = minor - _patch = patch - - -static func parse(value :String) -> GdUnit4Version: - var regex := RegEx.new() - @warning_ignore("return_value_discarded") - regex.compile("[a-zA-Z:,-]+") - var cleaned := regex.sub(value, "", true) - var parts := cleaned.split(".") - var major := parts[0].to_int() - var minor := parts[1].to_int() - var patch := parts[2].to_int() if parts.size() > 2 else 0 - return GdUnit4Version.new(major, minor, patch) - - -static func current() -> GdUnit4Version: - var config := ConfigFile.new() - @warning_ignore("return_value_discarded") - config.load('addons/gdUnit4/plugin.cfg') - @warning_ignore("unsafe_cast") - return parse(config.get_value('plugin', 'version') as String) - - -func equals(other :GdUnit4Version) -> bool: - return _major == other._major and _minor == other._minor and _patch == other._patch - - -func is_greater(other :GdUnit4Version) -> bool: - if _major > other._major: - return true - if _major == other._major and _minor > other._minor: - return true - return _major == other._major and _minor == other._minor and _patch > other._patch - - -static func init_version_label(label :Control) -> void: - var config := ConfigFile.new() - @warning_ignore("return_value_discarded") - config.load('addons/gdUnit4/plugin.cfg') - var version :String = config.get_value('plugin', 'version') - if label is RichTextLabel: - (label as RichTextLabel).text = VERSION_PATTERN.replace('${version}', version) - else: - (label as Label).text = "gdUnit4 " + version - - -func _to_string() -> String: - return "v%d.%d.%d" % [_major, _minor, _patch] - - -func documentation_version() -> String: - return "v%d.%d.x" % [_major, _minor] diff --git a/addons/gdUnit4/src/core/GdUnit4Version.gd.uid b/addons/gdUnit4/src/core/GdUnit4Version.gd.uid deleted file mode 100644 index 2b7462fe..00000000 --- a/addons/gdUnit4/src/core/GdUnit4Version.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bbaqjhpbxce3u diff --git a/addons/gdUnit4/src/core/GdUnitFileAccess.gd b/addons/gdUnit4/src/core/GdUnitFileAccess.gd deleted file mode 100644 index f6db5b4a..00000000 --- a/addons/gdUnit4/src/core/GdUnitFileAccess.gd +++ /dev/null @@ -1,232 +0,0 @@ -class_name GdUnitFileAccess -extends RefCounted - -const GDUNIT_TEMP := "user://tmp" - - -static func current_dir() -> String: - return ProjectSettings.globalize_path("res://") - - -static func clear_tmp() -> void: - delete_directory(GDUNIT_TEMP) - - -# Creates a new file under -static func create_temp_file(relative_path :String, file_name :String, mode := FileAccess.WRITE) -> FileAccess: - var file_path := create_temp_dir(relative_path) + "/" + file_name - var file := FileAccess.open(file_path, mode) - if file == null: - push_error("Error creating temporary file at: %s, %s" % [file_path, error_string(FileAccess.get_open_error())]) - return file - - -static func temp_dir() -> String: - if not DirAccess.dir_exists_absolute(GDUNIT_TEMP): - @warning_ignore("return_value_discarded") - DirAccess.make_dir_recursive_absolute(GDUNIT_TEMP) - return GDUNIT_TEMP - - -static func create_temp_dir(folder_name :String) -> String: - var new_folder := temp_dir() + "/" + folder_name - if not DirAccess.dir_exists_absolute(new_folder): - @warning_ignore("return_value_discarded") - DirAccess.make_dir_recursive_absolute(new_folder) - return new_folder - - -static func copy_file(from_file :String, to_dir :String) -> GdUnitResult: - var dir := DirAccess.open(to_dir) - if dir != null: - var to_file := to_dir + "/" + from_file.get_file() - prints("Copy %s to %s" % [from_file, to_file]) - var error := dir.copy(from_file, to_file) - if error != OK: - return GdUnitResult.error("Can't copy file form '%s' to '%s'. Error: '%s'" % [from_file, to_file, error_string(error)]) - return GdUnitResult.success(to_file) - return GdUnitResult.error("Directory not found: " + to_dir) - - -static func copy_directory(from_dir :String, to_dir :String, recursive :bool = false) -> bool: - if not DirAccess.dir_exists_absolute(from_dir): - push_error("Source directory not found '%s'" % from_dir) - return false - - # check if destination exists - if not DirAccess.dir_exists_absolute(to_dir): - # create it - var err := DirAccess.make_dir_recursive_absolute(to_dir) - if err != OK: - push_error("Can't create directory '%s'. Error: %s" % [to_dir, error_string(err)]) - return false - var source_dir := DirAccess.open(from_dir) - var dest_dir := DirAccess.open(to_dir) - if source_dir != null: - @warning_ignore("return_value_discarded") - source_dir.list_dir_begin() - var next := "." - - while next != "": - next = source_dir.get_next() - if next == "" or next == "." or next == "..": - continue - var source := source_dir.get_current_dir() + "/" + next - var dest := dest_dir.get_current_dir() + "/" + next - if source_dir.current_is_dir(): - if recursive: - @warning_ignore("return_value_discarded") - copy_directory(source + "/", dest, recursive) - continue - var err := source_dir.copy(source, dest) - if err != OK: - push_error("Error checked copy file '%s' to '%s'" % [source, dest]) - return false - - return true - else: - push_error("Directory not found: " + from_dir) - return false - - -static func delete_directory(path :String, only_content := false) -> void: - var dir := DirAccess.open(path) - if dir != null: - dir.include_hidden = true - @warning_ignore("return_value_discarded") - dir.list_dir_begin() - var file_name := "." - while file_name != "": - file_name = dir.get_next() - if file_name.is_empty() or file_name == "." or file_name == "..": - continue - var next := path + "/" +file_name - if dir.current_is_dir(): - delete_directory(next) - else: - # delete file - var err := dir.remove(next) - if err: - push_error("Delete %s failed: %s" % [next, error_string(err)]) - if not only_content: - var err := dir.remove(path) - if err: - push_error("Delete %s failed: %s" % [path, error_string(err)]) - - -static func delete_path_index_lower_equals_than(path :String, prefix :String, index :int) -> int: - var dir := DirAccess.open(path) - if dir == null: - return 0 - var deleted := 0 - @warning_ignore("return_value_discarded") - dir.list_dir_begin() - var next := "." - while next != "": - next = dir.get_next() - if next.is_empty() or next == "." or next == "..": - continue - if next.begins_with(prefix): - var current_index := next.split("_")[1].to_int() - if current_index <= index: - deleted += 1 - delete_directory(path + "/" + next) - return deleted - - -# scans given path for sub directories by given prefix and returns the highest index numer -# e.g. -static func find_last_path_index(path :String, prefix :String) -> int: - var dir := DirAccess.open(path) - if dir == null: - return 0 - var last_iteration := 0 - @warning_ignore("return_value_discarded") - dir.list_dir_begin() - var next := "." - while next != "": - next = dir.get_next() - if next.is_empty() or next == "." or next == "..": - continue - if next.begins_with(prefix): - var iteration := next.split("_")[1].to_int() - if iteration > last_iteration: - last_iteration = iteration - return last_iteration - - -static func as_resource_path(value: String) -> String: - if value.begins_with("res://"): - return value - return "res://" + value.trim_prefix("//").trim_prefix("/").trim_suffix("/") - - -static func scan_dir(path :String) -> PackedStringArray: - var dir := DirAccess.open(path) - if dir == null or not dir.dir_exists(path): - return PackedStringArray() - var content := PackedStringArray() - dir.include_hidden = true - @warning_ignore("return_value_discarded") - dir.list_dir_begin() - var next := "." - while next != "": - next = dir.get_next() - if next.is_empty() or next == "." or next == "..": - continue - @warning_ignore("return_value_discarded") - content.append(next) - return content - - -static func resource_as_array(resource_path :String) -> PackedStringArray: - var file := FileAccess.open(resource_path, FileAccess.READ) - if file == null: - push_error("ERROR: Can't read resource '%s'. %s" % [resource_path, error_string(FileAccess.get_open_error())]) - return PackedStringArray() - var file_content := PackedStringArray() - while not file.eof_reached(): - @warning_ignore("return_value_discarded") - file_content.append(file.get_line()) - return file_content - - -static func resource_as_string(resource_path :String) -> String: - var file := FileAccess.open(resource_path, FileAccess.READ) - if file == null: - push_error("ERROR: Can't read resource '%s'. %s" % [resource_path, error_string(FileAccess.get_open_error())]) - return "" - return file.get_as_text(true) - - -static func make_qualified_path(path :String) -> String: - if path.begins_with("res://"): - return path - if path.begins_with("//"): - return path.replace("//", "res://") - if path.begins_with("/"): - return "res:/" + path - return path - - -static func extract_zip(zip_package :String, dest_path :String) -> GdUnitResult: - var zip: ZIPReader = ZIPReader.new() - var err := zip.open(zip_package) - if err != OK: - return GdUnitResult.error("Extracting `%s` failed! Please collect the error log and report this. Error Code: %s" % [zip_package, err]) - var zip_entries: PackedStringArray = zip.get_files() - # Get base path and step over archive folder - var archive_path := zip_entries[0] - zip_entries.remove_at(0) - - for zip_entry in zip_entries: - var new_file_path: String = dest_path + "/" + zip_entry.replace(archive_path, "") - if zip_entry.ends_with("/"): - @warning_ignore("return_value_discarded") - DirAccess.make_dir_recursive_absolute(new_file_path) - continue - var file: FileAccess = FileAccess.open(new_file_path, FileAccess.WRITE) - file.store_buffer(zip.read_file(zip_entry)) - @warning_ignore("return_value_discarded") - zip.close() - return GdUnitResult.success(dest_path) diff --git a/addons/gdUnit4/src/core/GdUnitFileAccess.gd.uid b/addons/gdUnit4/src/core/GdUnitFileAccess.gd.uid deleted file mode 100644 index 14695c19..00000000 --- a/addons/gdUnit4/src/core/GdUnitFileAccess.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dflqb5germp5n diff --git a/addons/gdUnit4/src/core/GdUnitProperty.gd b/addons/gdUnit4/src/core/GdUnitProperty.gd deleted file mode 100644 index 3d050b19..00000000 --- a/addons/gdUnit4/src/core/GdUnitProperty.gd +++ /dev/null @@ -1,81 +0,0 @@ -class_name GdUnitProperty -extends RefCounted - - -var _name :String -var _help :String -var _type :int -var _value :Variant -var _value_set :PackedStringArray -var _default :Variant - - -func _init(p_name :String, p_type :int, p_value :Variant, p_default_value :Variant, p_help :="", p_value_set := PackedStringArray()) -> void: - _name = p_name - _type = p_type - _value = p_value - _value_set = p_value_set - _default = p_default_value - _help = p_help - - -func name() -> String: - return _name - - -func type() -> int: - return _type - - -func value() -> Variant: - return _value - - -func int_value() -> int: - return _value - -func value_as_string() -> String: - return _value - - -func value_set() -> PackedStringArray: - return _value_set - - -func is_selectable_value() -> bool: - return not _value_set.is_empty() - - -func set_value(p_value: Variant) -> void: - match _type: - TYPE_STRING: - _value = str(p_value) - TYPE_BOOL: - _value = type_convert(p_value, TYPE_BOOL) - TYPE_INT: - _value = type_convert(p_value, TYPE_INT) - TYPE_FLOAT: - _value = type_convert(p_value, TYPE_FLOAT) - TYPE_DICTIONARY: - _value = type_convert(p_value, TYPE_DICTIONARY) - _: - _value = p_value - - -func default() -> Variant: - return _default - - -func category() -> String: - var elements := _name.split("/") - if elements.size() > 3: - return elements[2] - return "" - - -func help() -> String: - return _help - - -func _to_string() -> String: - return "%-64s %-10s %-10s (%s) help:%s set:%s" % [name(), type(), value(), default(), help(), _value_set] diff --git a/addons/gdUnit4/src/core/GdUnitProperty.gd.uid b/addons/gdUnit4/src/core/GdUnitProperty.gd.uid deleted file mode 100644 index de104010..00000000 --- a/addons/gdUnit4/src/core/GdUnitProperty.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cqndh0nuu8ltx diff --git a/addons/gdUnit4/src/core/GdUnitResult.gd b/addons/gdUnit4/src/core/GdUnitResult.gd deleted file mode 100644 index 42392a5e..00000000 --- a/addons/gdUnit4/src/core/GdUnitResult.gd +++ /dev/null @@ -1,109 +0,0 @@ -class_name GdUnitResult -extends RefCounted - -enum { - SUCCESS, - WARN, - ERROR, - EMPTY -} - -var _state: int -var _warn_message := "" -var _error_message := "" -var _value :Variant = null - - -static func empty() -> GdUnitResult: - var result := GdUnitResult.new() - result._state = EMPTY - return result - - -static func success(p_value: Variant = "") -> GdUnitResult: - assert(p_value != null, "The value must not be NULL") - var result := GdUnitResult.new() - result._value = p_value - result._state = SUCCESS - return result - - -static func warn(p_warn_message: String, p_value: Variant = null) -> GdUnitResult: - assert(not p_warn_message.is_empty()) #,"The message must not be empty") - var result := GdUnitResult.new() - result._value = p_value - result._warn_message = p_warn_message - result._state = WARN - return result - - -static func error(p_error_message: String) -> GdUnitResult: - assert(not p_error_message.is_empty(), "The message must not be empty") - var result := GdUnitResult.new() - result._value = null - result._error_message = p_error_message - result._state = ERROR - return result - - -func is_success() -> bool: - return _state == SUCCESS - - -func is_warn() -> bool: - return _state == WARN - - -func is_error() -> bool: - return _state == ERROR - - -func is_empty() -> bool: - return _state == EMPTY - - -func value() -> Variant: - return _value - - -func value_as_string() -> String: - return _value - - -func or_else(p_value: Variant) -> Variant: - if not is_success(): - return p_value - return value() - - -func error_message() -> String: - return _error_message - - -func warn_message() -> String: - return _warn_message - - -func _to_string() -> String: - return str(GdUnitResult.serialize(self)) - - -static func serialize(result: GdUnitResult) -> Dictionary: - if result == null: - push_error("Can't serialize a Null object from type GdUnitResult") - return { - "state" : result._state, - "value" : var_to_str(result._value), - "warn_msg" : result._warn_message, - "err_msg" : result._error_message - } - - -static func deserialize(config: Dictionary) -> GdUnitResult: - var result := GdUnitResult.new() - var cfg_value: String = config.get("value", "") - result._value = str_to_var(cfg_value) - result._warn_message = config.get("warn_msg", null) - result._error_message = config.get("err_msg", null) - result._state = config.get("state") - return result diff --git a/addons/gdUnit4/src/core/GdUnitResult.gd.uid b/addons/gdUnit4/src/core/GdUnitResult.gd.uid deleted file mode 100644 index 2835c400..00000000 --- a/addons/gdUnit4/src/core/GdUnitResult.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cnvq3nb61ei76 diff --git a/addons/gdUnit4/src/core/GdUnitRunnerConfig.gd b/addons/gdUnit4/src/core/GdUnitRunnerConfig.gd deleted file mode 100644 index 9f36354d..00000000 --- a/addons/gdUnit4/src/core/GdUnitRunnerConfig.gd +++ /dev/null @@ -1,126 +0,0 @@ -class_name GdUnitRunnerConfig -extends Resource - -const GdUnitTools := preload("res://addons/gdUnit4/src/core/GdUnitTools.gd") - -const CONFIG_VERSION = "5.0" -const VERSION = "version" -const TESTS = "tests" -const SERVER_PORT = "server_port" -const EXIT_FAIL_FAST = "exit_on_first_fail" - -const CONFIG_FILE = "res://addons/gdUnit4/GdUnitRunner.cfg" - -var _config := { - VERSION : CONFIG_VERSION, - # a set of directories or testsuite paths as key and a optional set of testcases as values - - TESTS : Array([], TYPE_OBJECT, "RefCounted", GdUnitTestCase), - - # the port of running test server for this session - SERVER_PORT : -1 - } - - -func version() -> String: - return _config[VERSION] - - -func clear() -> GdUnitRunnerConfig: - _config[TESTS] = Array([], TYPE_OBJECT, "RefCounted", GdUnitTestCase) - return self - - -func set_server_port(port: int) -> GdUnitRunnerConfig: - _config[SERVER_PORT] = port - return self - - -func server_port() -> int: - return _config.get(SERVER_PORT, -1) - - -func add_test_cases(tests: Array[GdUnitTestCase]) -> GdUnitRunnerConfig: - test_cases().append_array(tests) - return self - - -func test_cases() -> Array[GdUnitTestCase]: - return _config.get(TESTS, []) - - -func save_config(path: String = CONFIG_FILE) -> GdUnitResult: - var file := FileAccess.open(path, FileAccess.WRITE) - if file == null: - var error := FileAccess.get_open_error() - return GdUnitResult.error("Can't write test runner configuration '%s'! %s" % [path, error_string(error)]) - - var to_save := { - VERSION : CONFIG_VERSION, - SERVER_PORT : _config.get(SERVER_PORT), - TESTS : Array() - } - - var tests: Array = to_save.get(TESTS) - for test in test_cases(): - tests.append(inst_to_dict(test)) - file.store_string(JSON.stringify(to_save, "\t")) - return GdUnitResult.success(path) - - -func load_config(path: String = CONFIG_FILE) -> GdUnitResult: - if not FileAccess.file_exists(path): - return GdUnitResult.warn("Can't find test runner configuration '%s'! Please select a test to run." % path) - var file := FileAccess.open(path, FileAccess.READ) - if file == null: - var error := FileAccess.get_open_error() - return GdUnitResult.error("Can't load test runner configuration '%s'! ERROR: %s." % [path, error_string(error)]) - var content := file.get_as_text() - if not content.is_empty() and content[0] == '{': - # Parse as json - var test_json_conv := JSON.new() - var error := test_json_conv.parse(content) - if error != OK: - return GdUnitResult.error("The runner configuration '%s' is invalid! The format is changed please delete it manually and start a new test run." % path) - var config: Dictionary = test_json_conv.get_data() - if not config.has(VERSION): - return GdUnitResult.error("The runner configuration '%s' is invalid! The format is changed please delete it manually and start a new test run." % path) - - var default: Array[Dictionary] = Array([], TYPE_DICTIONARY, "", null) - var tests_as_json: Array = config.get(TESTS, default) - _config = config - _config[TESTS] = convert_test_json_to_test_cases(tests_as_json) - - - fix_value_types() - return GdUnitResult.success(path) - - -func convert_test_json_to_test_cases(jsons: Array) -> Array[GdUnitTestCase]: - if jsons.is_empty(): - return [] - var tests := jsons.map(func(d: Dictionary) -> GdUnitTestCase: - var test: GdUnitTestCase = dict_to_inst(d) - # we need o covert manually to the corect type becaus JSON do not handle typed values - test.guid = GdUnitGUID.new(str(d["guid"])) - test.attribute_index = test.attribute_index as int - test.line_number = test.line_number as int - return test - ) - return Array(tests, TYPE_OBJECT, "RefCounted", GdUnitTestCase) - - -func fix_value_types() -> void: - # fix float value to int json stores all numbers as float - var server_port_: int = _config.get(SERVER_PORT, -1) - _config[SERVER_PORT] = server_port_ - - -func convert_Array_to_PackedStringArray(data: Dictionary) -> void: - for key in data.keys() as Array[String]: - var values :Array = data[key] - data[key] = PackedStringArray(values) - - -func _to_string() -> String: - return str(_config) diff --git a/addons/gdUnit4/src/core/GdUnitRunnerConfig.gd.uid b/addons/gdUnit4/src/core/GdUnitRunnerConfig.gd.uid deleted file mode 100644 index 60443d84..00000000 --- a/addons/gdUnit4/src/core/GdUnitRunnerConfig.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ltvpkh3ayklf diff --git a/addons/gdUnit4/src/core/GdUnitSceneRunnerImpl.gd b/addons/gdUnit4/src/core/GdUnitSceneRunnerImpl.gd deleted file mode 100644 index f2718537..00000000 --- a/addons/gdUnit4/src/core/GdUnitSceneRunnerImpl.gd +++ /dev/null @@ -1,622 +0,0 @@ -# This class provides a runner for scense to simulate interactions like keyboard or mouse -class_name GdUnitSceneRunnerImpl -extends GdUnitSceneRunner - - -var GdUnitFuncAssertImpl: GDScript = ResourceLoader.load("res://addons/gdUnit4/src/asserts/GdUnitFuncAssertImpl.gd", "GDScript", ResourceLoader.CACHE_MODE_REUSE) - - -# mapping of mouse buttons and his masks -const MAP_MOUSE_BUTTON_MASKS := { - MOUSE_BUTTON_LEFT : MOUSE_BUTTON_MASK_LEFT, - MOUSE_BUTTON_RIGHT : MOUSE_BUTTON_MASK_RIGHT, - MOUSE_BUTTON_MIDDLE : MOUSE_BUTTON_MASK_MIDDLE, - # https://github.com/godotengine/godot/issues/73632 - MOUSE_BUTTON_WHEEL_UP : 1 << (MOUSE_BUTTON_WHEEL_UP - 1), - MOUSE_BUTTON_WHEEL_DOWN : 1 << (MOUSE_BUTTON_WHEEL_DOWN - 1), - MOUSE_BUTTON_XBUTTON1 : MOUSE_BUTTON_MASK_MB_XBUTTON1, - MOUSE_BUTTON_XBUTTON2 : MOUSE_BUTTON_MASK_MB_XBUTTON2, -} - -var _is_disposed := false -var _current_scene: Node = null -var _awaiter: GdUnitAwaiter = GdUnitAwaiter.new() -var _verbose: bool -var _simulate_start_time: LocalTime -var _last_input_event: InputEvent = null -var _mouse_button_on_press := [] -var _key_on_press := [] -var _action_on_press := [] -var _curent_mouse_position: Vector2 -# holds the touch position for each touch index -# { index: int = position: Vector2} -var _current_touch_position: Dictionary = {} -# holds the curretn touch drag position -var _current_touch_drag_position: Vector2 = Vector2.ZERO - -# time factor settings -var _time_factor := 1.0 -var _saved_iterations_per_second: float -var _scene_auto_free := false - - -func _init(p_scene: Variant, p_verbose: bool, p_hide_push_errors := false) -> void: - _verbose = p_verbose - _saved_iterations_per_second = Engine.get_physics_ticks_per_second() - @warning_ignore("return_value_discarded") - set_time_factor(1) - # handle scene loading by resource path - if typeof(p_scene) == TYPE_STRING: - @warning_ignore("unsafe_cast") - if !ResourceLoader.exists(p_scene as String): - if not p_hide_push_errors: - push_error("GdUnitSceneRunner: Can't load scene by given resource path: '%s'. The resource does not exists." % p_scene) - return - if !str(p_scene).ends_with(".tscn") and !str(p_scene).ends_with(".scn") and !str(p_scene).begins_with("uid://"): - if not p_hide_push_errors: - push_error("GdUnitSceneRunner: The given resource: '%s'. is not a scene." % p_scene) - return - @warning_ignore("unsafe_cast") - _current_scene = (load(p_scene as String) as PackedScene).instantiate() - _scene_auto_free = true - else: - # verify we have a node instance - if not p_scene is Node: - if not p_hide_push_errors: - push_error("GdUnitSceneRunner: The given instance '%s' is not a Node." % p_scene) - return - _current_scene = p_scene - if _current_scene == null: - if not p_hide_push_errors: - push_error("GdUnitSceneRunner: Scene must be not null!") - return - - _scene_tree().root.add_child(_current_scene) - # do finally reset all open input events when the scene is removed - @warning_ignore("return_value_discarded") - _scene_tree().root.child_exiting_tree.connect(func f(child :Node) -> void: - if child == _current_scene: - # we need to disable the processing to avoid input flush buffer errors - _current_scene.process_mode = Node.PROCESS_MODE_DISABLED - _reset_input_to_default() - ) - _simulate_start_time = LocalTime.now() - # we need to set inital a valid window otherwise the warp_mouse() is not handled - move_window_to_foreground() - - # set inital mouse pos to 0,0 - var max_iteration_to_wait := 0 - while get_global_mouse_position() != Vector2.ZERO and max_iteration_to_wait < 100: - Input.warp_mouse(Vector2.ZERO) - max_iteration_to_wait += 1 - - -func _notification(what: int) -> void: - if what == NOTIFICATION_PREDELETE and is_instance_valid(self): - # reset time factor to normal - __deactivate_time_factor() - if is_instance_valid(_current_scene): - move_window_to_background() - _scene_tree().root.remove_child(_current_scene) - # do only free scenes instanciated by this runner - if _scene_auto_free: - _current_scene.free() - _is_disposed = true - _current_scene = null - - -func _scene_tree() -> SceneTree: - return Engine.get_main_loop() as SceneTree - - -func await_input_processed() -> void: - if scene() != null and scene().process_mode != Node.PROCESS_MODE_DISABLED: - Input.flush_buffered_events() - await (Engine.get_main_loop() as SceneTree).process_frame - await (Engine.get_main_loop() as SceneTree).physics_frame - - -@warning_ignore("return_value_discarded") -func simulate_action_pressed(action: String, event_index := -1) -> GdUnitSceneRunner: - simulate_action_press(action, event_index) - simulate_action_release(action, event_index) - return self - - -func simulate_action_press(action: String, event_index := -1) -> GdUnitSceneRunner: - __print_current_focus() - var event := InputEventAction.new() - event.pressed = true - event.action = action - event.event_index = event_index - _action_on_press.append(action) - return _handle_input_event(event) - - -func simulate_action_release(action: String, event_index := -1) -> GdUnitSceneRunner: - __print_current_focus() - var event := InputEventAction.new() - event.pressed = false - event.action = action - event.event_index = event_index - _action_on_press.erase(action) - return _handle_input_event(event) - - -@warning_ignore("return_value_discarded") -func simulate_key_pressed(key_code: int, shift_pressed := false, ctrl_pressed := false) -> GdUnitSceneRunner: - simulate_key_press(key_code, shift_pressed, ctrl_pressed) - await _scene_tree().process_frame - simulate_key_release(key_code, shift_pressed, ctrl_pressed) - return self - - -func simulate_key_press(key_code: int, shift_pressed := false, ctrl_pressed := false) -> GdUnitSceneRunner: - __print_current_focus() - var event := InputEventKey.new() - event.pressed = true - event.keycode = key_code as Key - event.physical_keycode = key_code as Key - event.unicode = key_code - event.alt_pressed = key_code == KEY_ALT - event.shift_pressed = shift_pressed or key_code == KEY_SHIFT - event.ctrl_pressed = ctrl_pressed or key_code == KEY_CTRL - _apply_input_modifiers(event) - _key_on_press.append(key_code) - return _handle_input_event(event) - - -func simulate_key_release(key_code: int, shift_pressed := false, ctrl_pressed := false) -> GdUnitSceneRunner: - __print_current_focus() - var event := InputEventKey.new() - event.pressed = false - event.keycode = key_code as Key - event.physical_keycode = key_code as Key - event.unicode = key_code - event.alt_pressed = key_code == KEY_ALT - event.shift_pressed = shift_pressed or key_code == KEY_SHIFT - event.ctrl_pressed = ctrl_pressed or key_code == KEY_CTRL - _apply_input_modifiers(event) - _key_on_press.erase(key_code) - return _handle_input_event(event) - - -func set_mouse_position(pos: Vector2) -> GdUnitSceneRunner: - var event := InputEventMouseMotion.new() - event.position = pos - event.global_position = get_global_mouse_position() - _apply_input_modifiers(event) - return _handle_input_event(event) - - -func get_mouse_position() -> Vector2: - if _last_input_event is InputEventMouse: - return (_last_input_event as InputEventMouse).position - var current_scene := scene() - if current_scene != null: - return current_scene.get_viewport().get_mouse_position() - return Vector2.ZERO - - -func get_global_mouse_position() -> Vector2: - return (Engine.get_main_loop() as SceneTree).root.get_mouse_position() - - -func simulate_mouse_move(position: Vector2) -> GdUnitSceneRunner: - var event := InputEventMouseMotion.new() - event.position = position - event.relative = position - get_mouse_position() - event.global_position = get_global_mouse_position() - _apply_input_mouse_mask(event) - _apply_input_modifiers(event) - return _handle_input_event(event) - - -@warning_ignore("return_value_discarded") -func simulate_mouse_move_relative(relative: Vector2, time: float = 1.0, trans_type: Tween.TransitionType = Tween.TRANS_LINEAR) -> GdUnitSceneRunner: - var tween := _scene_tree().create_tween() - _curent_mouse_position = get_mouse_position() - var final_position := _curent_mouse_position + relative - tween.tween_property(self, "_curent_mouse_position", final_position, time).set_trans(trans_type) - tween.play() - - while not get_mouse_position().is_equal_approx(final_position): - simulate_mouse_move(_curent_mouse_position) - await _scene_tree().process_frame - return self - - -@warning_ignore("return_value_discarded") -func simulate_mouse_move_absolute(position: Vector2, time: float = 1.0, trans_type: Tween.TransitionType = Tween.TRANS_LINEAR) -> GdUnitSceneRunner: - var tween := _scene_tree().create_tween() - _curent_mouse_position = get_mouse_position() - tween.tween_property(self, "_curent_mouse_position", position, time).set_trans(trans_type) - tween.play() - - while not get_mouse_position().is_equal_approx(position): - simulate_mouse_move(_curent_mouse_position) - await _scene_tree().process_frame - return self - - -@warning_ignore("return_value_discarded") -func simulate_mouse_button_pressed(button_index: MouseButton, double_click := false) -> GdUnitSceneRunner: - simulate_mouse_button_press(button_index, double_click) - simulate_mouse_button_release(button_index) - return self - - -func simulate_mouse_button_press(button_index: MouseButton, double_click := false) -> GdUnitSceneRunner: - var event := InputEventMouseButton.new() - event.button_index = button_index - event.pressed = true - event.double_click = double_click - _apply_input_mouse_position(event) - _apply_input_mouse_mask(event) - _apply_input_modifiers(event) - _mouse_button_on_press.append(button_index) - return _handle_input_event(event) - - -func simulate_mouse_button_release(button_index: MouseButton) -> GdUnitSceneRunner: - var event := InputEventMouseButton.new() - event.button_index = button_index - event.pressed = false - _apply_input_mouse_position(event) - _apply_input_mouse_mask(event) - _apply_input_modifiers(event) - _mouse_button_on_press.erase(button_index) - return _handle_input_event(event) - - -@warning_ignore("return_value_discarded") -func simulate_screen_touch_pressed(index: int, position: Vector2, double_tap := false) -> GdUnitSceneRunner: - simulate_screen_touch_press(index, position, double_tap) - simulate_screen_touch_release(index) - return self - - -@warning_ignore("return_value_discarded") -func simulate_screen_touch_press(index: int, position: Vector2, double_tap := false) -> GdUnitSceneRunner: - if is_emulate_mouse_from_touch(): - # we need to simulate in addition to the touch the mouse events - set_mouse_position(position) - simulate_mouse_button_press(MOUSE_BUTTON_LEFT) - # push touch press event at position - var event := InputEventScreenTouch.new() - event.window_id = scene().get_window().get_window_id() - event.index = index - event.position = position - event.double_tap = double_tap - event.pressed = true - _current_scene.get_viewport().push_input(event) - # save current drag position by index - _current_touch_position[index] = position - return self - - -@warning_ignore("return_value_discarded") -func simulate_screen_touch_release(index: int, double_tap := false) -> GdUnitSceneRunner: - if is_emulate_mouse_from_touch(): - # we need to simulate in addition to the touch the mouse events - simulate_mouse_button_release(MOUSE_BUTTON_LEFT) - # push touch release event at position - var event := InputEventScreenTouch.new() - event.window_id = scene().get_window().get_window_id() - event.index = index - event.position = get_screen_touch_drag_position(index) - event.pressed = false - event.double_tap = (_last_input_event as InputEventScreenTouch).double_tap if _last_input_event is InputEventScreenTouch else double_tap - _current_scene.get_viewport().push_input(event) - return self - - -func simulate_screen_touch_drag_relative(index: int, relative: Vector2, time: float = 1.0, trans_type: Tween.TransitionType = Tween.TRANS_LINEAR) -> GdUnitSceneRunner: - var current_position: Vector2 = _current_touch_position[index] - return await _do_touch_drag_at(index, current_position + relative, time, trans_type) - - -func simulate_screen_touch_drag_absolute(index: int, position: Vector2, time: float = 1.0, trans_type: Tween.TransitionType = Tween.TRANS_LINEAR) -> GdUnitSceneRunner: - return await _do_touch_drag_at(index, position, time, trans_type) - - -@warning_ignore("return_value_discarded") -func simulate_screen_touch_drag_drop(index: int, position: Vector2, drop_position: Vector2, time: float = 1.0, trans_type: Tween.TransitionType = Tween.TRANS_LINEAR) -> GdUnitSceneRunner: - simulate_screen_touch_press(index, position) - return await _do_touch_drag_at(index, drop_position, time, trans_type) - - -@warning_ignore("return_value_discarded") -func simulate_screen_touch_drag(index: int, position: Vector2) -> GdUnitSceneRunner: - if is_emulate_mouse_from_touch(): - simulate_mouse_move(position) - var event := InputEventScreenDrag.new() - event.window_id = scene().get_window().get_window_id() - event.index = index - event.position = position - event.relative = _get_screen_touch_drag_position_or_default(index, position) - position - event.velocity = event.relative / _scene_tree().root.get_process_delta_time() - event.pressure = 1.0 - _current_touch_position[index] = position - _current_scene.get_viewport().push_input(event) - return self - - -func get_screen_touch_drag_position(index: int) -> Vector2: - if _current_touch_position.has(index): - return _current_touch_position[index] - push_error("No touch drag position for index '%d' is set!" % index) - return Vector2.ZERO - - -func is_emulate_mouse_from_touch() -> bool: - return ProjectSettings.get_setting("input_devices/pointing/emulate_mouse_from_touch", true) - - -func _get_screen_touch_drag_position_or_default(index: int, default_position: Vector2) -> Vector2: - if _current_touch_position.has(index): - return _current_touch_position[index] - return default_position - - -@warning_ignore("return_value_discarded") -func _do_touch_drag_at(index: int, drag_position: Vector2, time: float, trans_type: Tween.TransitionType) -> GdUnitSceneRunner: - # start draging - var event := InputEventScreenDrag.new() - event.window_id = scene().get_window().get_window_id() - event.index = index - event.position = get_screen_touch_drag_position(index) - event.pressure = 1.0 - _current_touch_drag_position = event.position - - var tween := _scene_tree().create_tween() - tween.tween_property(self, "_current_touch_drag_position", drag_position, time).set_trans(trans_type) - tween.play() - - while not _current_touch_drag_position.is_equal_approx(drag_position): - if is_emulate_mouse_from_touch(): - # we need to simulate in addition to the drag the mouse move events - simulate_mouse_move(event.position) - # send touche drag event to new position - event.relative = _current_touch_drag_position - event.position - event.velocity = event.relative / _scene_tree().root.get_process_delta_time() - event.position = _current_touch_drag_position - _current_scene.get_viewport().push_input(event) - await _scene_tree().process_frame - - # finaly drop it - if is_emulate_mouse_from_touch(): - simulate_mouse_move(drag_position) - simulate_mouse_button_release(MOUSE_BUTTON_LEFT) - var touch_drop_event := InputEventScreenTouch.new() - touch_drop_event.window_id = event.window_id - touch_drop_event.index = event.index - touch_drop_event.position = drag_position - touch_drop_event.pressed = false - _current_scene.get_viewport().push_input(touch_drop_event) - await _scene_tree().process_frame - return self - - -func set_time_factor(time_factor: float = 1.0) -> GdUnitSceneRunner: - _time_factor = min(9.0, time_factor) - __activate_time_factor() - __print("set time factor: %f" % _time_factor) - __print("set physics physics_ticks_per_second: %d" % (_saved_iterations_per_second*_time_factor)) - return self - - -func simulate_frames(frames: int, delta_milli: int = -1) -> GdUnitSceneRunner: - var time_shift_frames :int = max(1, frames / _time_factor) - for frame in time_shift_frames: - if delta_milli == -1: - await _scene_tree().process_frame - else: - await _scene_tree().create_timer(delta_milli * 0.001).timeout - return self - - -func simulate_until_signal(signal_name: String, ...args: Array) -> GdUnitSceneRunner: - await _awaiter.await_signal_idle_frames(scene(), signal_name, args, 10000) - return self - - -func simulate_until_object_signal(source: Object, signal_name: String, ...args: Array) -> GdUnitSceneRunner: - await _awaiter.await_signal_idle_frames(source, signal_name, args, 10000) - return self - - -func await_func(func_name: String, ...args: Array) -> GdUnitFuncAssert: - return GdUnitFuncAssertImpl.new(scene(), func_name, args) - - -func await_func_on(instance: Object, func_name: String, ...args: Array) -> GdUnitFuncAssert: - return GdUnitFuncAssertImpl.new(instance, func_name, args) - - -func await_signal(signal_name: String, args := [], timeout := 2000 ) -> void: - await _awaiter.await_signal_on(scene(), signal_name, args, timeout) - - -func await_signal_on(source: Object, signal_name: String, args := [], timeout := 2000 ) -> void: - await _awaiter.await_signal_on(source, signal_name, args, timeout) - - -func move_window_to_foreground() -> GdUnitSceneRunner: - if not Engine.is_embedded_in_editor(): - DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED) - DisplayServer.window_move_to_foreground() - return self - - -func move_window_to_background() -> GdUnitSceneRunner: - if not Engine.is_embedded_in_editor(): - DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED) - DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_MINIMIZED) - return self - - -func _property_exists(name: String) -> bool: - return scene().get_property_list().any(func(properties :Dictionary) -> bool: return properties["name"] == name) - - -func get_property(name: String) -> Variant: - if not _property_exists(name): - return "The property '%s' not exist checked loaded scene." % name - return scene().get(name) - - -func set_property(name: String, value: Variant) -> bool: - if not _property_exists(name): - push_error("The property named '%s' cannot be set, it does not exist!" % name) - return false; - scene().set(name, value) - return true - - -func invoke(name: String, ...args: Array) -> Variant: - if scene().has_method(name): - return await scene().callv(name, args) - return "The method '%s' not exist checked loaded scene." % name - - -func find_child(name: String, recursive: bool = true, owned: bool = false) -> Node: - return scene().find_child(name, recursive, owned) - - -func _scene_name() -> String: - var scene_script :GDScript = scene().get_script() - var scene_name :String = scene().get_name() - if not scene_script: - return scene_name - if not scene_name.begins_with("@"): - return scene_name - return scene_script.resource_name.get_basename() - - -func __activate_time_factor() -> void: - Engine.set_time_scale(_time_factor) - Engine.set_physics_ticks_per_second((_saved_iterations_per_second * _time_factor) as int) - - -func __deactivate_time_factor() -> void: - Engine.set_time_scale(1) - Engine.set_physics_ticks_per_second(_saved_iterations_per_second as int) - - -# copy over current active modifiers -func _apply_input_modifiers(event: InputEvent) -> void: - if _last_input_event is InputEventWithModifiers and event is InputEventWithModifiers: - var last_input_event := _last_input_event as InputEventWithModifiers - var _event := event as InputEventWithModifiers - _event.meta_pressed = _event.meta_pressed or last_input_event.meta_pressed - _event.alt_pressed = _event.alt_pressed or last_input_event.alt_pressed - _event.shift_pressed = _event.shift_pressed or last_input_event.shift_pressed - _event.ctrl_pressed = _event.ctrl_pressed or last_input_event.ctrl_pressed - # this line results into reset the control_pressed state!!! - #event.command_or_control_autoremap = event.command_or_control_autoremap or _last_input_event.command_or_control_autoremap - - -# copy over current active mouse mask and combine with curren mask -func _apply_input_mouse_mask(event: InputEvent) -> void: - # first apply last mask - if _last_input_event is InputEventMouse and event is InputEventMouse: - (event as InputEventMouse).button_mask |= (_last_input_event as InputEventMouse).button_mask - if event is InputEventMouseButton: - var _event := event as InputEventMouseButton - var button_mask :int = MAP_MOUSE_BUTTON_MASKS.get(_event.get_button_index(), 0) - if _event.is_pressed(): - _event.button_mask |= button_mask - else: - _event.button_mask ^= button_mask - - -# copy over last mouse position if need -func _apply_input_mouse_position(event: InputEvent) -> void: - if _last_input_event is InputEventMouse and event is InputEventMouseButton: - (event as InputEventMouseButton).position = (_last_input_event as InputEventMouse).position - - -## handle input action via Input modifieres -func _handle_actions(event: InputEventAction) -> bool: - if not InputMap.event_is_action(event, event.action, true): - return false - __print(" process action %s (%s) <- %s" % [scene(), _scene_name(), event.as_text()]) - if event.is_pressed(): - Input.action_press(event.action, event.get_strength()) - else: - Input.action_release(event.action) - return true - - -# for handling read https://docs.godotengine.org/en/stable/tutorials/inputs/inputevent.html?highlight=inputevent#how-does-it-work -@warning_ignore("return_value_discarded") -func _handle_input_event(event: InputEvent) -> GdUnitSceneRunner: - if event is InputEventMouse: - Input.warp_mouse((event as InputEventMouse).position as Vector2) - Input.parse_input_event(event) - - if event is InputEventAction: - _handle_actions(event as InputEventAction) - - var current_scene := scene() - if is_instance_valid(current_scene): - # do not flush events if node processing disabled otherwise we run into errors at tree removed - if _current_scene.process_mode != Node.PROCESS_MODE_DISABLED: - Input.flush_buffered_events() - __print(" process event %s (%s) <- %s" % [current_scene, _scene_name(), event.as_text()]) - if(current_scene.has_method("_gui_input")): - (current_scene as Control)._gui_input(event) - if(current_scene.has_method("_unhandled_input")): - current_scene._unhandled_input(event) - current_scene.get_viewport().set_input_as_handled() - - # save last input event needs to be merged with next InputEventMouseButton - _last_input_event = event - return self - - -@warning_ignore("return_value_discarded") -func _reset_input_to_default() -> void: - # reset all mouse button to inital state if need - for m_button :int in _mouse_button_on_press.duplicate(): - if Input.is_mouse_button_pressed(m_button): - simulate_mouse_button_release(m_button) - _mouse_button_on_press.clear() - - for key_scancode :int in _key_on_press.duplicate(): - if Input.is_key_pressed(key_scancode): - simulate_key_release(key_scancode) - _key_on_press.clear() - - for action :String in _action_on_press.duplicate(): - if Input.is_action_pressed(action): - simulate_action_release(action) - _action_on_press.clear() - - if is_instance_valid(_current_scene) and _current_scene.process_mode != Node.PROCESS_MODE_DISABLED: - Input.flush_buffered_events() - _last_input_event = null - - -func __print(message: String) -> void: - if _verbose: - prints(message) - - -func __print_current_focus() -> void: - if not _verbose: - return - var focused_node := scene().get_viewport().gui_get_focus_owner() - if focused_node: - prints(" focus checked %s" % focused_node) - else: - prints(" no focus set") - - -func scene() -> Node: - if is_instance_valid(_current_scene): - return _current_scene - if not _is_disposed: - push_error("The current scene instance is not valid anymore! check your test is valid. e.g. check for missing awaits.") - return null diff --git a/addons/gdUnit4/src/core/GdUnitSceneRunnerImpl.gd.uid b/addons/gdUnit4/src/core/GdUnitSceneRunnerImpl.gd.uid deleted file mode 100644 index 152eeef5..00000000 --- a/addons/gdUnit4/src/core/GdUnitSceneRunnerImpl.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://7a566a4kfreu diff --git a/addons/gdUnit4/src/core/GdUnitSettings.gd b/addons/gdUnit4/src/core/GdUnitSettings.gd deleted file mode 100644 index f6bff127..00000000 --- a/addons/gdUnit4/src/core/GdUnitSettings.gd +++ /dev/null @@ -1,435 +0,0 @@ -@tool -class_name GdUnitSettings -extends RefCounted - - -const MAIN_CATEGORY = "gdunit4" -# Common Settings -const COMMON_SETTINGS = MAIN_CATEGORY + "/settings" - -const GROUP_COMMON = COMMON_SETTINGS + "/common" -const UPDATE_NOTIFICATION_ENABLED = GROUP_COMMON + "/update_notification_enabled" -const SERVER_TIMEOUT = GROUP_COMMON + "/server_connection_timeout_minutes" - -const GROUP_HOOKS = MAIN_CATEGORY + "/hooks" -const SESSION_HOOKS = GROUP_HOOKS + "/session_hooks" - -const GROUP_TEST = COMMON_SETTINGS + "/test" -const TEST_TIMEOUT = GROUP_TEST + "/test_timeout_seconds" -const TEST_LOOKUP_FOLDER = GROUP_TEST + "/test_lookup_folder" -const TEST_SUITE_NAMING_CONVENTION = GROUP_TEST + "/test_suite_naming_convention" -const TEST_DISCOVER_ENABLED = GROUP_TEST + "/test_discovery" -const TEST_FLAKY_CHECK = GROUP_TEST + "/flaky_check_enable" -const TEST_FLAKY_MAX_RETRIES = GROUP_TEST + "/flaky_max_retries" - - -# Report Setiings -const REPORT_SETTINGS = MAIN_CATEGORY + "/report" -const GROUP_GODOT = REPORT_SETTINGS + "/godot" -const REPORT_PUSH_ERRORS = GROUP_GODOT + "/push_error" -const REPORT_SCRIPT_ERRORS = GROUP_GODOT + "/script_error" -const REPORT_ORPHANS = REPORT_SETTINGS + "/verbose_orphans" -const GROUP_ASSERT = REPORT_SETTINGS + "/assert" -const REPORT_ASSERT_WARNINGS = GROUP_ASSERT + "/verbose_warnings" -const REPORT_ASSERT_ERRORS = GROUP_ASSERT + "/verbose_errors" -const REPORT_ASSERT_STRICT_NUMBER_TYPE_COMPARE = GROUP_ASSERT + "/strict_number_type_compare" - -# Godot debug stdout/logging settings -const CATEGORY_LOGGING := "debug/file_logging/" -const STDOUT_ENABLE_TO_FILE = CATEGORY_LOGGING + "enable_file_logging" -const STDOUT_WITE_TO_FILE = CATEGORY_LOGGING + "log_path" - - -# GdUnit Templates -const TEMPLATES = MAIN_CATEGORY + "/templates" -const TEMPLATES_TS = TEMPLATES + "/testsuite" -const TEMPLATE_TS_GD = TEMPLATES_TS + "/GDScript" -const TEMPLATE_TS_CS = TEMPLATES_TS + "/CSharpScript" - - -# UI Setiings -const UI_SETTINGS = MAIN_CATEGORY + "/ui" -const GROUP_UI_INSPECTOR = UI_SETTINGS + "/inspector" -const INSPECTOR_NODE_COLLAPSE = GROUP_UI_INSPECTOR + "/node_collapse" -const INSPECTOR_TREE_VIEW_MODE = GROUP_UI_INSPECTOR + "/tree_view_mode" -const INSPECTOR_TREE_SORT_MODE = GROUP_UI_INSPECTOR + "/tree_sort_mode" - - -# Shortcut Setiings -const SHORTCUT_SETTINGS = MAIN_CATEGORY + "/Shortcuts" -const GROUP_SHORTCUT_INSPECTOR = SHORTCUT_SETTINGS + "/inspector" -const SHORTCUT_INSPECTOR_RERUN_TEST = GROUP_SHORTCUT_INSPECTOR + "/rerun_test" -const SHORTCUT_INSPECTOR_RERUN_TEST_DEBUG = GROUP_SHORTCUT_INSPECTOR + "/rerun_test_debug" -const SHORTCUT_INSPECTOR_RUN_TEST_OVERALL = GROUP_SHORTCUT_INSPECTOR + "/run_test_overall" -const SHORTCUT_INSPECTOR_RUN_TEST_STOP = GROUP_SHORTCUT_INSPECTOR + "/run_test_stop" - -const GROUP_SHORTCUT_EDITOR = SHORTCUT_SETTINGS + "/editor" -const SHORTCUT_EDITOR_RUN_TEST = GROUP_SHORTCUT_EDITOR + "/run_test" -const SHORTCUT_EDITOR_RUN_TEST_DEBUG = GROUP_SHORTCUT_EDITOR + "/run_test_debug" -const SHORTCUT_EDITOR_CREATE_TEST = GROUP_SHORTCUT_EDITOR + "/create_test" - -const GROUP_SHORTCUT_FILESYSTEM = SHORTCUT_SETTINGS + "/filesystem" -const SHORTCUT_FILESYSTEM_RUN_TEST = GROUP_SHORTCUT_FILESYSTEM + "/run_test" -const SHORTCUT_FILESYSTEM_RUN_TEST_DEBUG = GROUP_SHORTCUT_FILESYSTEM + "/run_test_debug" - - -# Toolbar Setiings -const GROUP_UI_TOOLBAR = UI_SETTINGS + "/toolbar" -const INSPECTOR_TOOLBAR_BUTTON_RUN_OVERALL = GROUP_UI_TOOLBAR + "/run_overall" - -# Feature flags -const GROUP_FEATURE = MAIN_CATEGORY + "/feature" - - -# defaults -# server connection timeout in minutes -const DEFAULT_SERVER_TIMEOUT :int = 30 -# test case runtime timeout in seconds -const DEFAULT_TEST_TIMEOUT :int = 60*5 -# the folder to create new test-suites -const DEFAULT_TEST_LOOKUP_FOLDER := "test" - -# help texts -const HELP_TEST_LOOKUP_FOLDER := "Subfolder where test suites are located (or empty to use source folder directly)" - -enum NAMING_CONVENTIONS { - AUTO_DETECT, - SNAKE_CASE, - PASCAL_CASE, -} - - -const _VALUE_SET_SEPARATOR = "\f" # ASCII Form-feed character (AKA page break) - - -static func setup() -> void: - create_property_if_need(UPDATE_NOTIFICATION_ENABLED, true, "Show notification if new gdUnit4 version is found") - # test settings - create_property_if_need(SERVER_TIMEOUT, DEFAULT_SERVER_TIMEOUT, "Server connection timeout in minutes") - create_property_if_need(TEST_TIMEOUT, DEFAULT_TEST_TIMEOUT, "Test case runtime timeout in seconds") - create_property_if_need(TEST_LOOKUP_FOLDER, DEFAULT_TEST_LOOKUP_FOLDER, HELP_TEST_LOOKUP_FOLDER) - create_property_if_need(TEST_SUITE_NAMING_CONVENTION, NAMING_CONVENTIONS.AUTO_DETECT, "Naming convention to use when generating testsuites", NAMING_CONVENTIONS.keys()) - create_property_if_need(TEST_DISCOVER_ENABLED, false, "Automatically detect new tests in test lookup folders at runtime") - create_property_if_need(TEST_FLAKY_CHECK, false, "Rerun tests on failure and mark them as FLAKY") - create_property_if_need(TEST_FLAKY_MAX_RETRIES, 3, "Sets the number of retries for rerunning a flaky test") - # report settings - create_property_if_need(REPORT_PUSH_ERRORS, false, "Report push_error() as failure") - create_property_if_need(REPORT_SCRIPT_ERRORS, true, "Report script errors as failure") - create_property_if_need(REPORT_ORPHANS, true, "Report orphaned nodes after tests finish") - create_property_if_need(REPORT_ASSERT_ERRORS, true, "Report assertion failures as errors") - create_property_if_need(REPORT_ASSERT_WARNINGS, true, "Report assertion failures as warnings") - create_property_if_need(REPORT_ASSERT_STRICT_NUMBER_TYPE_COMPARE, true, "Compare number values strictly by type (real vs int)") - # inspector - create_property_if_need(INSPECTOR_NODE_COLLAPSE, true, - "Close testsuite node after a successful test run.") - create_property_if_need(INSPECTOR_TREE_VIEW_MODE, GdUnitInspectorTreeConstants.TREE_VIEW_MODE.TREE, - "Inspector panel presentation mode", GdUnitInspectorTreeConstants.TREE_VIEW_MODE.keys()) - create_property_if_need(INSPECTOR_TREE_SORT_MODE, GdUnitInspectorTreeConstants.SORT_MODE.UNSORTED, - "Inspector panel sorting mode", GdUnitInspectorTreeConstants.SORT_MODE.keys()) - create_property_if_need(INSPECTOR_TOOLBAR_BUTTON_RUN_OVERALL, false, - "Show 'Run overall Tests' button in the inspector toolbar") - create_property_if_need(TEMPLATE_TS_GD, GdUnitTestSuiteTemplate.default_GD_template(), "Test suite template to use") - create_shortcut_properties_if_need() - create_property_if_need(SESSION_HOOKS, {} as Dictionary[String,bool]) - migrate_properties() - - -static func migrate_properties() -> void: - var TEST_ROOT_FOLDER := "gdunit4/settings/test/test_root_folder" - if get_property(TEST_ROOT_FOLDER) != null: - migrate_property(TEST_ROOT_FOLDER,\ - TEST_LOOKUP_FOLDER,\ - DEFAULT_TEST_LOOKUP_FOLDER,\ - HELP_TEST_LOOKUP_FOLDER,\ - func(value :Variant) -> String: return DEFAULT_TEST_LOOKUP_FOLDER if value == null else value) - - -static func create_shortcut_properties_if_need() -> void: - # inspector - create_property_if_need(SHORTCUT_INSPECTOR_RERUN_TEST, GdUnitShortcut.default_keys(GdUnitShortcut.ShortCut.RERUN_TESTS), "Rerun the most recently executed tests") - create_property_if_need(SHORTCUT_INSPECTOR_RERUN_TEST_DEBUG, GdUnitShortcut.default_keys(GdUnitShortcut.ShortCut.RERUN_TESTS_DEBUG), "Rerun the most recently executed tests (Debug mode)") - create_property_if_need(SHORTCUT_INSPECTOR_RUN_TEST_OVERALL, GdUnitShortcut.default_keys(GdUnitShortcut.ShortCut.RUN_TESTS_OVERALL), "Runs all tests (Debug mode)") - create_property_if_need(SHORTCUT_INSPECTOR_RUN_TEST_STOP, GdUnitShortcut.default_keys(GdUnitShortcut.ShortCut.STOP_TEST_RUN), "Stop the current test execution") - # script editor - create_property_if_need(SHORTCUT_EDITOR_RUN_TEST, GdUnitShortcut.default_keys(GdUnitShortcut.ShortCut.RUN_TESTCASE), "Run the currently selected test") - create_property_if_need(SHORTCUT_EDITOR_RUN_TEST_DEBUG, GdUnitShortcut.default_keys(GdUnitShortcut.ShortCut.RUN_TESTCASE_DEBUG), "Run the currently selected test (Debug mode).") - create_property_if_need(SHORTCUT_EDITOR_CREATE_TEST, GdUnitShortcut.default_keys(GdUnitShortcut.ShortCut.CREATE_TEST), "Create a new test case for the currently selected function") - # filesystem - create_property_if_need(SHORTCUT_FILESYSTEM_RUN_TEST, GdUnitShortcut.default_keys(GdUnitShortcut.ShortCut.NONE), "Run all test suites in the selected folder or file") - create_property_if_need(SHORTCUT_FILESYSTEM_RUN_TEST_DEBUG, GdUnitShortcut.default_keys(GdUnitShortcut.ShortCut.NONE), "Run all test suites in the selected folder or file (Debug)") - - -static func create_property_if_need(name :String, default :Variant, help :="", value_set := PackedStringArray()) -> void: - if not ProjectSettings.has_setting(name): - #prints("GdUnit4: Set inital settings '%s' to '%s'." % [name, str(default)]) - ProjectSettings.set_setting(name, default) - - ProjectSettings.set_initial_value(name, default) - help = help if value_set.is_empty() else "%s%s%s" % [help, _VALUE_SET_SEPARATOR, value_set] - set_help(name, default, help) - - -static func set_help(property_name :String, value :Variant, help :String) -> void: - ProjectSettings.add_property_info({ - "name": property_name, - "type": typeof(value), - "hint": PROPERTY_HINT_TYPE_STRING, - "hint_string": help - }) - - -static func get_setting(name :String, default :Variant) -> Variant: - if ProjectSettings.has_setting(name): - return ProjectSettings.get_setting(name) - return default - - -static func is_update_notification_enabled() -> bool: - if ProjectSettings.has_setting(UPDATE_NOTIFICATION_ENABLED): - return ProjectSettings.get_setting(UPDATE_NOTIFICATION_ENABLED) - return false - - -static func set_update_notification(enable :bool) -> void: - ProjectSettings.set_setting(UPDATE_NOTIFICATION_ENABLED, enable) - @warning_ignore("return_value_discarded") - ProjectSettings.save() - - -static func get_log_path() -> String: - return ProjectSettings.get_setting(STDOUT_WITE_TO_FILE) - - -static func set_log_path(path :String) -> void: - ProjectSettings.set_setting(STDOUT_ENABLE_TO_FILE, true) - ProjectSettings.set_setting(STDOUT_WITE_TO_FILE, path) - @warning_ignore("return_value_discarded") - ProjectSettings.save() - - -static func get_session_hooks() -> Dictionary[String, bool]: - var property := get_property(SESSION_HOOKS) - if property == null: - return {} - var hooks: Dictionary[String, bool] = property.value() - return hooks - - -static func set_session_hooks(hooks: Dictionary[String, bool]) -> void: - var property := get_property(SESSION_HOOKS) - property.set_value(hooks) - update_property(property) - - -static func set_inspector_tree_sort_mode(sort_mode: GdUnitInspectorTreeConstants.SORT_MODE) -> void: - var property := get_property(INSPECTOR_TREE_SORT_MODE) - property.set_value(sort_mode) - update_property(property) - - -static func get_inspector_tree_sort_mode() -> GdUnitInspectorTreeConstants.SORT_MODE: - var property := get_property(INSPECTOR_TREE_SORT_MODE) - return property.value() if property != null else GdUnitInspectorTreeConstants.SORT_MODE.UNSORTED - - -static func set_inspector_tree_view_mode(tree_view_mode: GdUnitInspectorTreeConstants.TREE_VIEW_MODE) -> void: - var property := get_property(INSPECTOR_TREE_VIEW_MODE) - property.set_value(tree_view_mode) - update_property(property) - - -static func get_inspector_tree_view_mode() -> GdUnitInspectorTreeConstants.TREE_VIEW_MODE: - var property := get_property(INSPECTOR_TREE_VIEW_MODE) - return property.value() if property != null else GdUnitInspectorTreeConstants.TREE_VIEW_MODE.TREE - - -# the configured server connection timeout in ms -static func server_timeout() -> int: - return get_setting(SERVER_TIMEOUT, DEFAULT_SERVER_TIMEOUT) * 60 * 1000 - - -# the configured test case timeout in ms -static func test_timeout() -> int: - return get_setting(TEST_TIMEOUT, DEFAULT_TEST_TIMEOUT) * 1000 - - -# the root folder to store/generate test-suites -static func test_root_folder() -> String: - return get_setting(TEST_LOOKUP_FOLDER, DEFAULT_TEST_LOOKUP_FOLDER) - - -static func is_verbose_assert_warnings() -> bool: - return get_setting(REPORT_ASSERT_WARNINGS, true) - - -static func is_verbose_assert_errors() -> bool: - return get_setting(REPORT_ASSERT_ERRORS, true) - - -static func is_verbose_orphans() -> bool: - return get_setting(REPORT_ORPHANS, true) - - -static func is_strict_number_type_compare() -> bool: - return get_setting(REPORT_ASSERT_STRICT_NUMBER_TYPE_COMPARE, true) - - -static func is_report_push_errors() -> bool: - return get_setting(REPORT_PUSH_ERRORS, false) - - -static func is_report_script_errors() -> bool: - return get_setting(REPORT_SCRIPT_ERRORS, true) - - -static func is_inspector_node_collapse() -> bool: - return get_setting(INSPECTOR_NODE_COLLAPSE, true) - - -static func is_inspector_toolbar_button_show() -> bool: - return get_setting(INSPECTOR_TOOLBAR_BUTTON_RUN_OVERALL, true) - - -static func is_test_discover_enabled() -> bool: - return get_setting(TEST_DISCOVER_ENABLED, false) - - -static func is_test_flaky_check_enabled() -> bool: - return get_setting(TEST_FLAKY_CHECK, false) - - -static func is_feature_enabled(feature: String) -> bool: - return get_setting(feature, false) - - -static func get_flaky_max_retries() -> int: - return get_setting(TEST_FLAKY_MAX_RETRIES, 3) - - -static func set_test_discover_enabled(enable :bool) -> void: - var property := get_property(TEST_DISCOVER_ENABLED) - property.set_value(enable) - update_property(property) - - -static func is_log_enabled() -> bool: - return ProjectSettings.get_setting(STDOUT_ENABLE_TO_FILE) - - -static func list_settings(category: String) -> Array[GdUnitProperty]: - var settings: Array[GdUnitProperty] = [] - for property in ProjectSettings.get_property_list(): - var property_name :String = property["name"] - if property_name.begins_with(category): - settings.append(build_property(property_name, property)) - return settings - - -static func extract_value_set_from_help(value :String) -> PackedStringArray: - var split_value := value.split(_VALUE_SET_SEPARATOR) - if not split_value.size() > 1: - return PackedStringArray() - - var regex := RegEx.new() - @warning_ignore("return_value_discarded") - regex.compile("\\[(.+)\\]") - var matches := regex.search_all(split_value[1]) - if matches.is_empty(): - return PackedStringArray() - var values: String = matches[0].get_string(1) - return values.replacen(" ", "").replacen("\"", "").split(",", false) - - -static func extract_help_text(value :String) -> String: - return value.split(_VALUE_SET_SEPARATOR)[0] - - -static func update_property(property :GdUnitProperty) -> Variant: - var current_value :Variant = ProjectSettings.get_setting(property.name()) - if current_value != property.value(): - var error :Variant = validate_property_value(property) - if error != null: - return error - ProjectSettings.set_setting(property.name(), property.value()) - GdUnitSignals.instance().gdunit_settings_changed.emit(property) - _save_settings() - return null - - -static func reset_property(property :GdUnitProperty) -> void: - ProjectSettings.set_setting(property.name(), property.default()) - GdUnitSignals.instance().gdunit_settings_changed.emit(property) - _save_settings() - - -static func validate_property_value(property :GdUnitProperty) -> Variant: - match property.name(): - TEST_LOOKUP_FOLDER: - return validate_lookup_folder(property.value_as_string()) - _: return null - - -static func validate_lookup_folder(value :String) -> Variant: - if value.is_empty() or value == "/": - return null - if value.contains("res:"): - return "Test Lookup Folder: do not allowed to contains 'res://'" - if not value.is_valid_filename(): - return "Test Lookup Folder: contains invalid characters! e.g (: / \\ ? * \" | % < >)" - return null - - -static func save_property(name :String, value :Variant) -> void: - ProjectSettings.set_setting(name, value) - _save_settings() - - -static func _save_settings() -> void: - var err := ProjectSettings.save() - if err != OK: - push_error("Save GdUnit4 settings failed : %s" % error_string(err)) - return - - -static func has_property(name :String) -> bool: - return ProjectSettings.get_property_list().any(func(property :Dictionary) -> bool: return property["name"] == name) - - -static func get_property(name :String) -> GdUnitProperty: - for property in ProjectSettings.get_property_list(): - var property_name :String = property["name"] - if property_name == name: - return build_property(name, property) - return null - - -static func build_property(property_name: String, property: Dictionary) -> GdUnitProperty: - var value: Variant = ProjectSettings.get_setting(property_name) - var value_type: int = property["type"] - var default: Variant = ProjectSettings.property_get_revert(property_name) - var help: String = property["hint_string"] - var value_set := extract_value_set_from_help(help) - return GdUnitProperty.new(property_name, value_type, value, default, extract_help_text(help), value_set) - - -static func migrate_property(old_property :String, new_property :String, default_value :Variant, help :String, converter := Callable()) -> void: - var property := get_property(old_property) - if property == null: - prints("Migration not possible, property '%s' not found" % old_property) - return - var value :Variant = converter.call(property.value()) if converter.is_valid() else property.value() - ProjectSettings.set_setting(new_property, value) - ProjectSettings.set_initial_value(new_property, default_value) - set_help(new_property, value, help) - ProjectSettings.clear(old_property) - prints("Successfully migrated property '%s' -> '%s' value: %s" % [old_property, new_property, value]) - - -static func dump_to_tmp() -> void: - @warning_ignore("return_value_discarded") - ProjectSettings.save_custom("user://project_settings.godot") - - -static func restore_dump_from_tmp() -> void: - @warning_ignore("return_value_discarded") - DirAccess.copy_absolute("user://project_settings.godot", "res://project.godot") diff --git a/addons/gdUnit4/src/core/GdUnitSettings.gd.uid b/addons/gdUnit4/src/core/GdUnitSettings.gd.uid deleted file mode 100644 index cb7e30e1..00000000 --- a/addons/gdUnit4/src/core/GdUnitSettings.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://coby4unvmd3eh diff --git a/addons/gdUnit4/src/core/GdUnitSignalAwaiter.gd b/addons/gdUnit4/src/core/GdUnitSignalAwaiter.gd deleted file mode 100644 index 528e133f..00000000 --- a/addons/gdUnit4/src/core/GdUnitSignalAwaiter.gd +++ /dev/null @@ -1,81 +0,0 @@ -class_name GdUnitSignalAwaiter -extends RefCounted - -signal signal_emitted(action :Variant) - -const NO_ARG :Variant = GdUnitConstants.NO_ARG - -var _wait_on_idle_frame := false -var _interrupted := false -var _time_left :float = 0 -var _timeout_millis :int - - -func _init(timeout_millis :int, wait_on_idle_frame := false) -> void: - _timeout_millis = timeout_millis - _wait_on_idle_frame = wait_on_idle_frame - - -func _on_signal_emmited( - arg0 :Variant = NO_ARG, - arg1 :Variant = NO_ARG, - arg2 :Variant = NO_ARG, - arg3 :Variant = NO_ARG, - arg4 :Variant = NO_ARG, - arg5 :Variant = NO_ARG, - arg6 :Variant = NO_ARG, - arg7 :Variant = NO_ARG, - arg8 :Variant = NO_ARG, - arg9 :Variant = NO_ARG) -> void: - var signal_args :Variant = GdArrayTools.filter_value([arg0,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9], NO_ARG) - signal_emitted.emit(signal_args) - - -func is_interrupted() -> bool: - return _interrupted - - -func elapsed_time() -> float: - return _time_left - - -func on_signal(source :Object, signal_name :String, expected_signal_args :Array) -> Variant: - # register checked signal to wait for - @warning_ignore("return_value_discarded") - source.connect(signal_name, _on_signal_emmited) - # install timeout timer - var scene_tree := Engine.get_main_loop() as SceneTree - var timer := Timer.new() - scene_tree.root.add_child(timer) - timer.add_to_group("GdUnitTimers") - timer.set_one_shot(true) - @warning_ignore("return_value_discarded") - timer.timeout.connect(_do_interrupt, CONNECT_DEFERRED) - timer.start(_timeout_millis * 0.001 * Engine.get_time_scale()) - - # holds the emited value - var value :Variant - # wait for signal is emitted or a timeout is happen - while true: - value = await signal_emitted - if _interrupted: - break - if not (value is Array): - value = [value] - if expected_signal_args.size() == 0 or GdObjects.equals(value, expected_signal_args): - break - await scene_tree.process_frame - - source.disconnect(signal_name, _on_signal_emmited) - _time_left = timer.time_left - timer.queue_free() - await scene_tree.process_frame - @warning_ignore("unsafe_cast") - if value is Array and (value as Array).size() == 1: - return value[0] - return value - - -func _do_interrupt() -> void: - _interrupted = true - signal_emitted.emit(null) diff --git a/addons/gdUnit4/src/core/GdUnitSignalAwaiter.gd.uid b/addons/gdUnit4/src/core/GdUnitSignalAwaiter.gd.uid deleted file mode 100644 index 8eaf88b7..00000000 --- a/addons/gdUnit4/src/core/GdUnitSignalAwaiter.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ckx5jnr3ip6vp diff --git a/addons/gdUnit4/src/core/GdUnitSignalCollector.gd b/addons/gdUnit4/src/core/GdUnitSignalCollector.gd deleted file mode 100644 index d15d3843..00000000 --- a/addons/gdUnit4/src/core/GdUnitSignalCollector.gd +++ /dev/null @@ -1,129 +0,0 @@ -# It connects to all signals of given emitter and collects received signals and arguments -# The collected signals are cleand finally when the emitter is freed. -class_name GdUnitSignalCollector -extends RefCounted - -const NO_ARG :Variant = GdUnitConstants.NO_ARG -const SIGNAL_BLACK_LIST = []#["tree_exiting", "tree_exited", "child_exiting_tree"] - -# { -# emitter : { -# signal_name : [signal_args], -# ... -# } -# } -var _collected_signals :Dictionary = {} - - -func clear() -> void: - for emitter :Object in _collected_signals.keys(): - if is_instance_valid(emitter): - unregister_emitter(emitter) - - -# connect to all possible signals defined by the emitter -# prepares the signal collection to store received signals and arguments -func register_emitter(emitter: Object, force_recreate := false) -> void: - if is_instance_valid(emitter): - # check emitter is already registerd - if _collected_signals.has(emitter): - if not force_recreate: - return - # If the flag recreate is set to true, emitters that are already registered must be deregistered before recreating, - # otherwise signals that have already been collected will be evaluated. - unregister_emitter(emitter) - - _collected_signals[emitter] = Dictionary() - # connect to 'tree_exiting' of the emitter to finally release all acquired resources/connections. - if emitter is Node and !(emitter as Node).tree_exiting.is_connected(unregister_emitter): - (emitter as Node).tree_exiting.connect(unregister_emitter.bind(emitter)) - # connect to all signals of the emitter we want to collect - for signal_def in emitter.get_signal_list(): - var signal_name :String = signal_def["name"] - # set inital collected to empty - if not is_signal_collecting(emitter, signal_name): - _collected_signals[emitter][signal_name] = Array() - if SIGNAL_BLACK_LIST.find(signal_name) != -1: - continue - if !emitter.is_connected(signal_name, _on_signal_emmited): - var err := emitter.connect(signal_name, _on_signal_emmited.bind(emitter, signal_name)) - if err != OK: - push_error("Can't connect to signal %s on %s. Error: %s" % [signal_name, emitter, error_string(err)]) - - -# unregister all acquired resources/connections, otherwise it ends up in orphans -# is called when the emitter is removed from the parent -func unregister_emitter(emitter :Object) -> void: - if is_instance_valid(emitter): - for signal_def in emitter.get_signal_list(): - var signal_name :String = signal_def["name"] - if emitter.is_connected(signal_name, _on_signal_emmited): - emitter.disconnect(signal_name, _on_signal_emmited.bind(emitter, signal_name)) - @warning_ignore("return_value_discarded") - _collected_signals.erase(emitter) - - -# receives the signal from the emitter with all emitted signal arguments and additional the emitter and signal_name as last two arguements -func _on_signal_emmited( - arg0 :Variant= NO_ARG, - arg1 :Variant= NO_ARG, - arg2 :Variant= NO_ARG, - arg3 :Variant= NO_ARG, - arg4 :Variant= NO_ARG, - arg5 :Variant= NO_ARG, - arg6 :Variant= NO_ARG, - arg7 :Variant= NO_ARG, - arg8 :Variant= NO_ARG, - arg9 :Variant= NO_ARG, - arg10 :Variant= NO_ARG, - arg11 :Variant= NO_ARG) -> void: - var signal_args :Array = GdArrayTools.filter_value([arg0,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11], NO_ARG) - # extract the emitter and signal_name from the last two arguments (see line 61 where is added) - var signal_name :String = signal_args.pop_back() - var emitter :Object = signal_args.pop_back() - #prints("_on_signal_emmited:", emitter, signal_name, signal_args) - if is_signal_collecting(emitter, signal_name): - @warning_ignore("unsafe_cast") - (_collected_signals[emitter][signal_name] as Array).append(signal_args) - - -func reset_received_signals(emitter: Object, signal_name: String, signal_args: Array) -> void: - #_debug_signal_list("before claer"); - if _collected_signals.has(emitter): - var signals_by_emitter :Dictionary = _collected_signals[emitter] - if signals_by_emitter.has(signal_name): - var received_args: Array = _collected_signals[emitter][signal_name] - # We iterate backwarts over to received_args to remove matching args. - # This will avoid array corruption see comment on `erase` otherwise we need a timeconsuming duplicate before - for arg_pos: int in range(received_args.size()-1, -1, -1): - var arg: Variant = received_args[arg_pos] - if GdObjects.equals(arg, signal_args): - received_args.remove_at(arg_pos) - #_debug_signal_list("after claer"); - - -func is_signal_collecting(emitter: Object, signal_name: String) -> bool: - @warning_ignore("unsafe_cast") - return _collected_signals.has(emitter) and (_collected_signals[emitter] as Dictionary).has(signal_name) - - -func match(emitter :Object, signal_name :String, args :Array) -> bool: - #prints("match", signal_name, _collected_signals[emitter][signal_name]); - if _collected_signals.is_empty() or not _collected_signals.has(emitter): - return false - for received_args :Variant in _collected_signals[emitter][signal_name]: - #prints("testing", signal_name, received_args, "vs", args) - if GdObjects.equals(received_args, args): - return true - return false - - -func _debug_signal_list(message :String) -> void: - prints("-----", message, "-------") - prints("senders {") - for emitter :Object in _collected_signals: - prints("\t", emitter) - for signal_name :String in _collected_signals[emitter]: - var args :Variant = _collected_signals[emitter][signal_name] - prints("\t\t", signal_name, args) - prints("}") diff --git a/addons/gdUnit4/src/core/GdUnitSignalCollector.gd.uid b/addons/gdUnit4/src/core/GdUnitSignalCollector.gd.uid deleted file mode 100644 index 7f51e4f0..00000000 --- a/addons/gdUnit4/src/core/GdUnitSignalCollector.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cm0rbs8vhdhd1 diff --git a/addons/gdUnit4/src/core/GdUnitSignals.gd b/addons/gdUnit4/src/core/GdUnitSignals.gd deleted file mode 100644 index 53aafe99..00000000 --- a/addons/gdUnit4/src/core/GdUnitSignals.gd +++ /dev/null @@ -1,118 +0,0 @@ -class_name GdUnitSignals -extends RefCounted -## Singleton class that handles GdUnit's signal communication.[br] -## [br] -## This class manages all signals used to communicate test events, discovery, and status changes.[br] -## It uses a singleton pattern stored in Engine metadata to ensure a single instance.[br] -## [br] -## Signals are grouped by purpose:[br] -## - Client connection handling[br] -## - Test execution events[br] -## - Test discovery events[br] -## - Settings and status updates[br] -## [br] -## Example usage:[br] -## [codeblock] -## # Connect to test discovery -## GdUnitSignals.instance().gdunit_test_discovered.connect(self._on_test_discovered) -## -## # Emit test event -## GdUnitSignals.instance().gdunit_event.emit(test_event) -## [/codeblock] - - -## Emitted when a client connects to the GdUnit server.[br] -## [param client_id] The ID of the connected client. -@warning_ignore("unused_signal") -signal gdunit_client_connected(client_id: int) - - -## Emitted when a client disconnects from the GdUnit server.[br] -## [param client_id] The ID of the disconnected client. -@warning_ignore("unused_signal") -signal gdunit_client_disconnected(client_id: int) - - -## Emitted when a client terminates unexpectedly. -@warning_ignore("unused_signal") -signal gdunit_client_terminated() - - -## Emitted when a test execution event occurs.[br] -## [param event] The test event containing details about test execution. -@warning_ignore("unused_signal") -signal gdunit_event(event: GdUnitEvent) - - -## Emitted for test debug events during execution.[br] -## [param event] The debug event containing test execution details. -@warning_ignore("unused_signal") -signal gdunit_event_debug(event: GdUnitEvent) - - -## Emitted to broadcast a general message.[br] -## [param message] The message to broadcast. -@warning_ignore("unused_signal") -signal gdunit_message(message: String) - - -## Emitted to update test failure status.[br] -## [param is_failed] Whether the test has failed. -@warning_ignore("unused_signal") -signal gdunit_set_test_failed(is_failed: bool) - - -## Emitted when a GdUnit setting changes.[br] -## [param property] The property that was changed. -@warning_ignore("unused_signal") -signal gdunit_settings_changed(property: GdUnitProperty) - -## Called when a new test case is discovered during the discovery process. -## Custom implementations should connect to this signal and store the discovered test case as needed.[br] -## [param test_case] The discovered test case instance to be processed. -@warning_ignore("unused_signal") -signal gdunit_test_discover_added(test_case: GdUnitTestCase) - - -## Emitted when a test case is deleted.[br] -## [param test_case] The test case that was deleted. -@warning_ignore("unused_signal") -signal gdunit_test_discover_deleted(test_case: GdUnitTestCase) - - -## Emitted when a test case is modified.[br] -## [param test_case] The test case that was modified. -@warning_ignore("unused_signal") -signal gdunit_test_discover_modified(test_case: GdUnitTestCase) - - -const META_KEY := "GdUnitSignals" - - -## Returns the singleton instance of GdUnitSignals.[br] -## Creates a new instance if none exists.[br] -## [br] -## Returns: The GdUnitSignals singleton instance. -static func instance() -> GdUnitSignals: - if Engine.has_meta(META_KEY): - return Engine.get_meta(META_KEY) - var instance_ := GdUnitSignals.new() - Engine.set_meta(META_KEY, instance_) - return instance_ - - -## Cleans up the singleton instance and disconnects all signals.[br] -## [br] -## Should be called when GdUnit is shutting down or needs to reset.[br] -## Ensures proper cleanup of signal connections and resources. -static func dispose() -> void: - var signals := instance() - # cleanup connected signals - for signal_ in signals.get_signal_list(): - @warning_ignore("unsafe_cast") - for connection in signals.get_signal_connection_list(signal_["name"] as StringName): - var _signal: Signal = connection["signal"] - var _callable: Callable = connection["callable"] - _signal.disconnect(_callable) - signals = null - Engine.remove_meta(META_KEY) diff --git a/addons/gdUnit4/src/core/GdUnitSignals.gd.uid b/addons/gdUnit4/src/core/GdUnitSignals.gd.uid deleted file mode 100644 index cf97f408..00000000 --- a/addons/gdUnit4/src/core/GdUnitSignals.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://kj16fg0hf6kn diff --git a/addons/gdUnit4/src/core/GdUnitSingleton.gd b/addons/gdUnit4/src/core/GdUnitSingleton.gd deleted file mode 100644 index b8e08cc3..00000000 --- a/addons/gdUnit4/src/core/GdUnitSingleton.gd +++ /dev/null @@ -1,56 +0,0 @@ -################################################################################ -# Provides access to a global accessible singleton -# -# This is a workarount to the existing auto load singleton because of some bugs -# around plugin handling -################################################################################ -class_name GdUnitSingleton -extends Object - - -const GdUnitTools := preload("res://addons/gdUnit4/src/core/GdUnitTools.gd") -const MEATA_KEY := "GdUnitSingletons" - - -static func instance(name: String, clazz: Callable) -> Variant: - if Engine.has_meta(name): - return Engine.get_meta(name) - var singleton: Variant = clazz.call() - if is_instance_of(singleton, RefCounted): - @warning_ignore("unsafe_cast") - push_error("Invalid singleton implementation detected for '%s' is `%s`!" % [name, (singleton as RefCounted).get_class()]) - return - - Engine.set_meta(name, singleton) - GdUnitTools.prints_verbose("Register singleton '%s:%s'" % [name, singleton]) - var singletons: PackedStringArray = Engine.get_meta(MEATA_KEY, PackedStringArray()) - @warning_ignore("return_value_discarded") - singletons.append(name) - Engine.set_meta(MEATA_KEY, singletons) - return singleton - - -static func unregister(p_singleton: String, use_call_deferred: bool = false) -> void: - var singletons: PackedStringArray = Engine.get_meta(MEATA_KEY, PackedStringArray()) - if singletons.has(p_singleton): - GdUnitTools.prints_verbose("\n Unregister singleton '%s'" % p_singleton); - var index := singletons.find(p_singleton) - singletons.remove_at(index) - var instance_: Object = Engine.get_meta(p_singleton) - GdUnitTools.prints_verbose(" Free singleton instance '%s:%s'" % [p_singleton, instance_]) - @warning_ignore("return_value_discarded") - GdUnitTools.free_instance(instance_, use_call_deferred) - Engine.remove_meta(p_singleton) - GdUnitTools.prints_verbose(" Successfully freed '%s'" % p_singleton) - Engine.set_meta(MEATA_KEY, singletons) - - -static func dispose(use_call_deferred: bool = false) -> void: - # use a copy because unregister is modify the singletons array - var singletons: PackedStringArray = Engine.get_meta(MEATA_KEY, PackedStringArray()) - GdUnitTools.prints_verbose("----------------------------------------------------------------") - GdUnitTools.prints_verbose("Cleanup singletons %s" % singletons) - for singleton in PackedStringArray(singletons): - unregister(singleton, use_call_deferred) - Engine.remove_meta(MEATA_KEY) - GdUnitTools.prints_verbose("----------------------------------------------------------------") diff --git a/addons/gdUnit4/src/core/GdUnitSingleton.gd.uid b/addons/gdUnit4/src/core/GdUnitSingleton.gd.uid deleted file mode 100644 index 00c4d141..00000000 --- a/addons/gdUnit4/src/core/GdUnitSingleton.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://4sujouo3vf6d diff --git a/addons/gdUnit4/src/core/GdUnitTestResourceLoader.gd b/addons/gdUnit4/src/core/GdUnitTestResourceLoader.gd deleted file mode 100644 index 33b80e28..00000000 --- a/addons/gdUnit4/src/core/GdUnitTestResourceLoader.gd +++ /dev/null @@ -1,97 +0,0 @@ -class_name GdUnitTestResourceLoader -extends RefCounted - -const GdUnitTools := preload("res://addons/gdUnit4/src/core/GdUnitTools.gd") - -enum { - GD_SUITE, - CS_SUITE -} - - -static func load_test_suite(resource_path: String, script_type := GD_SUITE) -> Node: - match script_type: - GD_SUITE: - return load_test_suite_gd(resource_path) - CS_SUITE: - return load_test_suite_cs(resource_path) - assert("type '%s' is not implemented" % script_type) - return null - - -static func load_tests(resource_path: String) -> Dictionary: - var script := load_gd_script(resource_path) - var discovered_tests := {} - GdUnitTestDiscoverer.discover_tests(script, func(test: GdUnitTestCase) -> void: - discovered_tests[test.display_name] = test - ) - - return discovered_tests - - -static func load_test_suite_gd(resource_path: String) -> GdUnitTestSuite: - var script := load_gd_script(resource_path) - var discovered_tests: Array[GdUnitTestCase] = [] - GdUnitTestDiscoverer.discover_tests(script, func(test: GdUnitTestCase) -> void: - discovered_tests.append(test) - ) - # complete test suite wiht parsed test cases - return GdUnitTestSuiteScanner.new().load_suite(script, discovered_tests) - - -static func load_test_suite_cs(resource_path: String) -> Node: - if not GdUnit4CSharpApiLoader.is_api_loaded(): - return null - var script :Script = ClassDB.instantiate("CSharpScript") - script.source_code = GdUnitFileAccess.resource_as_string(resource_path) - script.resource_path = resource_path - script.reload() - return null - - -static func load_cs_script(resource_path: String, debug_write := false) -> Script: - if not GdUnit4CSharpApiLoader.is_api_loaded(): - return null - var script :Script = ClassDB.instantiate("CSharpScript") - script.source_code = GdUnitFileAccess.resource_as_string(resource_path) - var script_resource_path := resource_path.replace(resource_path.get_extension(), "cs") - if debug_write: - script_resource_path = GdUnitFileAccess.create_temp_dir("test") + "/%s" % script_resource_path.get_file() - print_debug("save resource:", script_resource_path) - DirAccess.remove_absolute(script_resource_path) - var err := ResourceSaver.save(script, script_resource_path) - if err != OK: - print_debug("Can't save debug resource",script_resource_path, "Error:", error_string(err)) - script.take_over_path(script_resource_path) - else: - script.take_over_path(resource_path) - script.reload() - return script - - -static func load_gd_script(resource_path: String, debug_write := false) -> GDScript: - # grap current level - var unsafe_method_access: Variant = ProjectSettings.get_setting("debug/gdscript/warnings/unsafe_method_access") - # disable and load the script - ProjectSettings.set_setting("debug/gdscript/warnings/unsafe_method_access", 0) - - var script := GDScript.new() - script.source_code = GdUnitFileAccess.resource_as_string(resource_path) - var script_resource_path := resource_path.replace(resource_path.get_extension(), "gd") - if debug_write: - script_resource_path = script_resource_path.replace("res://", GdUnitFileAccess.temp_dir() + "/") - #print_debug("save resource: ", script_resource_path) - DirAccess.remove_absolute(script_resource_path) - DirAccess.make_dir_recursive_absolute(script_resource_path.get_base_dir()) - var err := ResourceSaver.save(script, script_resource_path, ResourceSaver.FLAG_REPLACE_SUBRESOURCE_PATHS) - if err != OK: - print_debug("Can't save debug resource", script_resource_path, "Error:", error_string(err)) - script.take_over_path(script_resource_path) - else: - script.take_over_path(resource_path) - var error := script.reload() - if error != OK: - push_error("Errors on loading script %s. Error: %s" % [resource_path, error_string(error)]) - ProjectSettings.set_setting("debug/gdscript/warnings/unsafe_method_access", unsafe_method_access) - return script - #@warning_ignore("unsafe_cast") diff --git a/addons/gdUnit4/src/core/GdUnitTestResourceLoader.gd.uid b/addons/gdUnit4/src/core/GdUnitTestResourceLoader.gd.uid deleted file mode 100644 index cb57e902..00000000 --- a/addons/gdUnit4/src/core/GdUnitTestResourceLoader.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ierjyaem56m3 diff --git a/addons/gdUnit4/src/core/GdUnitTestSuiteBuilder.gd b/addons/gdUnit4/src/core/GdUnitTestSuiteBuilder.gd deleted file mode 100644 index 97a49b00..00000000 --- a/addons/gdUnit4/src/core/GdUnitTestSuiteBuilder.gd +++ /dev/null @@ -1,20 +0,0 @@ -class_name GdUnitTestSuiteBuilder -extends RefCounted - - -static func create(source :Script, line_number :int) -> GdUnitResult: - var test_suite_path := GdUnitTestSuiteScanner.resolve_test_suite_path(source.resource_path, GdUnitSettings.test_root_folder()) - # we need to save and close the testsuite and source if is current opened before modify - @warning_ignore("return_value_discarded") - ScriptEditorControls.save_an_open_script(source.resource_path) - @warning_ignore("return_value_discarded") - ScriptEditorControls.save_an_open_script(test_suite_path, true) - if source.get_class() == "CSharpScript": - return GdUnit4CSharpApiLoader.create_test_suite(source.resource_path, line_number+1, test_suite_path) - var parser := GdScriptParser.new() - var lines := source.source_code.split("\n") - var current_line := lines[line_number] - var func_name := parser.parse_func_name(current_line) - if func_name.is_empty(): - return GdUnitResult.error("No function found at line: %d." % line_number) - return GdUnitTestSuiteScanner.create_test_case(test_suite_path, func_name, source.resource_path) diff --git a/addons/gdUnit4/src/core/GdUnitTestSuiteBuilder.gd.uid b/addons/gdUnit4/src/core/GdUnitTestSuiteBuilder.gd.uid deleted file mode 100644 index 66f5e56a..00000000 --- a/addons/gdUnit4/src/core/GdUnitTestSuiteBuilder.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dthfh16tl5wqc diff --git a/addons/gdUnit4/src/core/GdUnitTestSuiteScanner.gd b/addons/gdUnit4/src/core/GdUnitTestSuiteScanner.gd deleted file mode 100644 index 63028970..00000000 --- a/addons/gdUnit4/src/core/GdUnitTestSuiteScanner.gd +++ /dev/null @@ -1,404 +0,0 @@ -class_name GdUnitTestSuiteScanner -extends RefCounted - -const TEST_FUNC_TEMPLATE =""" - -func test_${func_name}() -> void: - # remove this line and complete your test - assert_not_yet_implemented() -""" - - -# we exclude the gdunit source directorys by default -const exclude_scan_directories = [ - "res://addons/gdUnit4/bin", - "res://addons/gdUnit4/src", - "res://reports"] - - -const ARGUMENT_TIMEOUT := "timeout" -const ARGUMENT_SKIP := "do_skip" -const ARGUMENT_SKIP_REASON := "skip_reason" -const ARGUMENT_PARAMETER_SET := "test_parameters" - - -var _script_parser := GdScriptParser.new() -var _included_resources: PackedStringArray = [] -var _excluded_resources: PackedStringArray = [] -var _expression_runner := GdUnitExpressionRunner.new() -var _regex_extends_clazz_name := RegEx.create_from_string("extends[\\s]+([\\S]+)") - - -func prescan_testsuite_classes() -> void: - # scan and cache extends GdUnitTestSuite by class name an resource paths - var script_classes: Array[Dictionary] = ProjectSettings.get_global_class_list() - for script_meta in script_classes: - var base_class: String = script_meta["base"] - var resource_path: String = script_meta["path"] - if base_class == "GdUnitTestSuite": - @warning_ignore("return_value_discarded") - _included_resources.append(resource_path) - elif ClassDB.class_exists(base_class): - @warning_ignore("return_value_discarded") - _excluded_resources.append(resource_path) - - -func scan(resource_path: String) -> Array[Script]: - prescan_testsuite_classes() - # if single testsuite requested - if FileAccess.file_exists(resource_path): - var test_suite := _load_is_test_suite(resource_path) - if test_suite != null: - return [test_suite] - return [] - return scan_directory(resource_path) - - -func scan_directory(resource_path: String) -> Array[Script]: - prescan_testsuite_classes() - # We use the global cache to fast scan for test suites. - if _excluded_resources.has(resource_path): - return [] - - var base_dir := DirAccess.open(resource_path) - if base_dir == null: - prints("Given directory or file does not exists:", resource_path) - return [] - - prints("Scanning for test suites in:", resource_path) - return _scan_test_suites_scripts(base_dir, []) - - -func _scan_test_suites_scripts(dir: DirAccess, collected_suites: Array[Script]) -> Array[Script]: - if exclude_scan_directories.has(dir.get_current_dir()): - return collected_suites - var err := dir.list_dir_begin() - if err != OK: - push_error("Error on scanning directory %s" % dir.get_current_dir(), error_string(err)) - return collected_suites - var file_name := dir.get_next() - while file_name != "": - var resource_path := GdUnitTestSuiteScanner._file(dir, file_name) - if dir.current_is_dir(): - var sub_dir := DirAccess.open(resource_path) - if sub_dir != null: - @warning_ignore("return_value_discarded") - _scan_test_suites_scripts(sub_dir, collected_suites) - else: - var time := LocalTime.now() - var test_suite := _load_is_test_suite(resource_path) - if test_suite: - collected_suites.append(test_suite) - if OS.is_stdout_verbose() and time.elapsed_since_ms() > 300: - push_warning("Scanning of test-suite '%s' took more than 300ms: " % resource_path, time.elapsed_since()) - file_name = dir.get_next() - return collected_suites - - -static func _file(dir: DirAccess, file_name: String) -> String: - var current_dir := dir.get_current_dir() - if current_dir.ends_with("/"): - return current_dir + file_name - return current_dir + "/" + file_name - - -func _load_is_test_suite(resource_path: String) -> Script: - if not GdUnitTestSuiteScanner._is_script_format_supported(resource_path): - return null - - # We use the global cache to fast scan for test suites. - if _excluded_resources.has(resource_path): - return null - # Check in the global class cache whether the GdUnitTestSuite class has been extended. - if _included_resources.has(resource_path): - return GdUnitTestSuiteScanner.load_with_disabled_warnings(resource_path) - - # Otherwise we need to scan manual, we need to exclude classes where direct extends form Godot classes - # the resource loader can fail to load e.g. plugin classes with do preload other scripts - #var extends_from := get_extends_classname(resource_path) - # If not extends is defined or extends from a Godot class - #if extends_from.is_empty() or ClassDB.class_exists(extends_from): - # return null - # Finally, we need to load the class to determine it is a test suite - var script := GdUnitTestSuiteScanner.load_with_disabled_warnings(resource_path) - if not is_test_suite(script): - return null - return script - - -func load_suite(script: GDScript, tests: Array[GdUnitTestCase]) -> GdUnitTestSuite: - var test_suite: GdUnitTestSuite = script.new() - var first_test: GdUnitTestCase = tests.front() - test_suite.set_name(first_test.suite_name) - - # We need to group first all parameterized tests together to load the parameter set once - var grouped_by_test := GdArrayTools.group_by(tests, func(test: GdUnitTestCase) -> String: - return test.test_name - ) - # Extract function descriptors - var test_names: PackedStringArray = grouped_by_test.keys() - test_names.append("before") - var function_descriptors := _script_parser.get_function_descriptors(script, test_names) - - # Convert to test - for fd in function_descriptors: - if fd.name() == "before": - _handle_test_suite_arguments(test_suite, script, fd) - continue - - # Build test attributes from test method - var test_attribute := _build_test_attribute(script, fd) - # Create test from descriptor and given attributes - var test_group: Array = grouped_by_test[fd.name()] - for test: GdUnitTestCase in test_group: - # We need a copy, because of mutable state - var attribute: TestCaseAttribute = test_attribute.clone() - test_suite.add_child(_TestCase.new(test, attribute, fd)) - return test_suite - - -func _build_test_attribute(script: GDScript, fd: GdFunctionDescriptor) -> TestCaseAttribute: - var collected_unknown_aruments := PackedStringArray() - var attribute := TestCaseAttribute.new() - - # Collect test attributes - for arg: GdFunctionArgument in fd.args(): - if arg.type() == GdObjects.TYPE_FUZZER: - attribute.fuzzers.append(arg) - else: - # We allow underscore as prefix to prevent unused argument warnings - match arg.name().trim_prefix("_"): - ARGUMENT_TIMEOUT: - attribute.timeout = type_convert(arg.default(), TYPE_INT) - ARGUMENT_SKIP: - var result: Variant = _expression_runner.execute(script, arg.plain_value()) - if result is bool: - attribute.is_skipped = result - else: - push_error("Test expression '%s' cannot be evaluated because it is not of type bool!" % arg.plain_value()) - ARGUMENT_SKIP_REASON: - attribute.skip_reason = arg.plain_value() - Fuzzer.ARGUMENT_ITERATIONS: - attribute.fuzzer_iterations = type_convert(arg.default(), TYPE_INT) - Fuzzer.ARGUMENT_SEED: - attribute.test_seed = type_convert(arg.default(), TYPE_INT) - ARGUMENT_PARAMETER_SET: - collected_unknown_aruments.clear() - pass - _: - collected_unknown_aruments.append(arg.name()) - - # Verify for unknown arguments - if not collected_unknown_aruments.is_empty(): - attribute.is_skipped = true - attribute.skip_reason = "Unknown test case argument's %s found." % collected_unknown_aruments - - return attribute - - -# We load the test suites with disabled unsafe_method_access to avoid spamming loading errors -# `unsafe_method_access` will happen when using `assert_that` -static func load_with_disabled_warnings(resource_path: String) -> Script: - # grap current level - var unsafe_method_access: Variant = ProjectSettings.get_setting("debug/gdscript/warnings/unsafe_method_access") - - # disable and load the script - ProjectSettings.set_setting("debug/gdscript/warnings/unsafe_method_access", 0) - - var script: Script = ( - GdUnitTestResourceLoader.load_gd_script(resource_path) if resource_path.ends_with("resource") - else ResourceLoader.load(resource_path)) - - # restore - ProjectSettings.set_setting("debug/gdscript/warnings/unsafe_method_access", unsafe_method_access) - return script - - -static func is_test_suite(script: Script) -> bool: - if script is GDScript: - var stack := [script] - while not stack.is_empty(): - var current: Script = stack.pop_front() - var base: Script = current.get_base_script() - if base != null: - if base.resource_path.find("GdUnitTestSuite") != -1: - return true - stack.push_back(base) - elif script != null and script.get_class() == "CSharpScript": - return true - return false - - -static func _is_script_format_supported(resource_path: String) -> bool: - var ext := resource_path.get_extension() - return ext == "gd" or ext == "cs" - - -static func parse_test_suite_name(script: Script) -> String: - return script.resource_path.get_file().replace(".gd", "") - - -func _handle_test_suite_arguments(test_suite: GdUnitTestSuite, script: GDScript, fd: GdFunctionDescriptor) -> void: - for arg in fd.args(): - # We allow underscore as prefix to prevent unused argument warnings - match arg.name().trim_prefix("_"): - ARGUMENT_SKIP: - var result: Variant = _expression_runner.execute(script, arg.plain_value()) - if result is bool: - test_suite.__is_skipped = result - else: - push_error("Test expression '%s' cannot be evaluated because it is not of type bool!" % arg.plain_value()) - ARGUMENT_SKIP_REASON: - test_suite.__skip_reason = arg.plain_value() - _: - push_error("Unsuported argument `%s` found on before() at '%s'!" % [arg.name(), script.resource_path]) - - -# converts given file name by configured naming convention -static func _to_naming_convention(file_name: String) -> String: - var nc :int = GdUnitSettings.get_setting(GdUnitSettings.TEST_SUITE_NAMING_CONVENTION, 0) - match nc: - GdUnitSettings.NAMING_CONVENTIONS.AUTO_DETECT: - if GdObjects.is_snake_case(file_name): - return GdObjects.to_snake_case(file_name + "Test") - return GdObjects.to_pascal_case(file_name + "Test") - GdUnitSettings.NAMING_CONVENTIONS.SNAKE_CASE: - return GdObjects.to_snake_case(file_name + "Test") - GdUnitSettings.NAMING_CONVENTIONS.PASCAL_CASE: - return GdObjects.to_pascal_case(file_name + "Test") - push_error("Unexpected case") - return "--" - - -static func resolve_test_suite_path(source_script_path: String, test_root_folder: String = "test") -> String: - var file_name := source_script_path.get_basename().get_file() - var suite_name := _to_naming_convention(file_name) - if test_root_folder.is_empty() or test_root_folder == "/": - return source_script_path.replace(file_name, suite_name) - - # is user tmp - if source_script_path.begins_with("user://tmp"): - return normalize_path(source_script_path.replace("user://tmp", "user://tmp/" + test_root_folder)).replace(file_name, suite_name) - - # at first look up is the script under a "src" folder located - var test_suite_path: String - var src_folder := source_script_path.find("/src/") - if src_folder != -1: - test_suite_path = source_script_path.replace("/src/", "/"+test_root_folder+"/") - else: - var paths := source_script_path.split("/", false) - # is a plugin script? - if paths[1] == "addons": - test_suite_path = "%s//addons/%s/%s" % [paths[0], paths[2], test_root_folder] - # rebuild plugin path - for index in range(3, paths.size()): - test_suite_path += "/" + paths[index] - else: - test_suite_path = paths[0] + "//" + test_root_folder - for index in range(1, paths.size()): - test_suite_path += "/" + paths[index] - return normalize_path(test_suite_path).replace(file_name, suite_name) - - -static func normalize_path(path: String) -> String: - return path.replace("///", "/") - - -static func create_test_suite(test_suite_path: String, source_path: String) -> GdUnitResult: - # create directory if not exists - if not DirAccess.dir_exists_absolute(test_suite_path.get_base_dir()): - var error_ := DirAccess.make_dir_recursive_absolute(test_suite_path.get_base_dir()) - if error_ != OK: - return GdUnitResult.error("Can't create directoy at: %s. Error code %s" % [test_suite_path.get_base_dir(), error_]) - var script := GDScript.new() - script.source_code = GdUnitTestSuiteTemplate.build_template(source_path) - var error := ResourceSaver.save(script, test_suite_path) - if error != OK: - return GdUnitResult.error("Can't create test suite at: %s. Error code %s" % [test_suite_path, error]) - return GdUnitResult.success(test_suite_path) - - -static func get_test_case_line_number(resource_path: String, func_name: String) -> int: - var file := FileAccess.open(resource_path, FileAccess.READ) - if file != null: - var line_number := 0 - while not file.eof_reached(): - var row := file.get_line() - line_number += 1 - # ignore comments and empty lines and not test functions - if row.begins_with("#") || row.length() == 0 || row.find("func test_") == -1: - continue - # abort if test case name found - if row.find("func") != -1 and row.find("test_" + func_name) != -1: - return line_number - return -1 - - -func get_extends_classname(resource_path: String) -> String: - var file := FileAccess.open(resource_path, FileAccess.READ) - if file != null: - while not file.eof_reached(): - var row := file.get_line() - # skip comments and empty lines - if row.begins_with("#") || row.length() == 0: - continue - # Stop at first function - if row.contains("func"): - return "" - var result := _regex_extends_clazz_name.search(row) - if result != null: - return result.get_string(1) - return "" - - -static func add_test_case(resource_path: String, func_name: String) -> GdUnitResult: - var script := load_with_disabled_warnings(resource_path) - # count all exiting lines and add two as space to add new test case - var line_number := count_lines(script) + 2 - var func_body := TEST_FUNC_TEMPLATE.replace("${func_name}", func_name) - if Engine.is_editor_hint(): - # NOTE: Avoid using EditorInterface and EditorSettings directly, - # as it causes compilation errors in exported projects. - @warning_ignore_start("unsafe_method_access") - var editor_interface: Object = Engine.get_singleton("EditorInterface") - var settings: Object = editor_interface.get_editor_settings() - var ident_type: int = settings.get_setting("text_editor/behavior/indent/type") - var ident_size: int = settings.get_setting("text_editor/behavior/indent/size") - @warning_ignore_restore("unsafe_method_access") - if ident_type == 1: - func_body = func_body.replace(" ", "".lpad(ident_size, " ")) - script.source_code += func_body - var error := ResourceSaver.save(script, resource_path) - if error != OK: - return GdUnitResult.error("Can't add test case at: %s to '%s'. Error code %s" % [func_name, resource_path, error]) - return GdUnitResult.success({ "path" : resource_path, "line" : line_number}) - - -static func count_lines(script: Script) -> int: - return script.source_code.split("\n").size() - - -static func test_suite_exists(test_suite_path: String) -> bool: - return FileAccess.file_exists(test_suite_path) - - -static func test_case_exists(test_suite_path :String, func_name :String) -> bool: - if not test_suite_exists(test_suite_path): - return false - var script := load_with_disabled_warnings(test_suite_path) - for f in script.get_script_method_list(): - if f["name"] == "test_" + func_name: - return true - return false - - -static func create_test_case(test_suite_path: String, func_name: String, source_script_path: String) -> GdUnitResult: - if test_case_exists(test_suite_path, func_name): - var line_number := get_test_case_line_number(test_suite_path, func_name) - return GdUnitResult.success({ "path" : test_suite_path, "line" : line_number}) - - if not test_suite_exists(test_suite_path): - var result := create_test_suite(test_suite_path, source_script_path) - if result.is_error(): - return result - return add_test_case(test_suite_path, func_name) diff --git a/addons/gdUnit4/src/core/GdUnitTestSuiteScanner.gd.uid b/addons/gdUnit4/src/core/GdUnitTestSuiteScanner.gd.uid deleted file mode 100644 index 0f927d51..00000000 --- a/addons/gdUnit4/src/core/GdUnitTestSuiteScanner.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bju0nt1bgsc2s diff --git a/addons/gdUnit4/src/core/GdUnitTools.gd b/addons/gdUnit4/src/core/GdUnitTools.gd deleted file mode 100644 index 0742896a..00000000 --- a/addons/gdUnit4/src/core/GdUnitTools.gd +++ /dev/null @@ -1,144 +0,0 @@ -extends RefCounted - - -static var _richtext_normalize: RegEx - - -static func normalize_text(text :String) -> String: - return text.replace("\r", ""); - - -static func richtext_normalize(input :String) -> String: - if _richtext_normalize == null: - _richtext_normalize = to_regex("\\[/?(b|color|bgcolor|right|table|cell).*?\\]") - return _richtext_normalize.sub(input, "", true).replace("\r", "") - - -static func to_regex(pattern :String) -> RegEx: - var regex := RegEx.new() - var err := regex.compile(pattern) - if err != OK: - push_error("Can't compiling regx '%s'.\n ERROR: %s" % [pattern, error_string(err)]) - return regex - - -static func prints_verbose(message :String) -> void: - if OS.is_stdout_verbose(): - prints(message) - - -static func free_instance(instance :Variant, use_call_deferred :bool = false, is_stdout_verbose := false) -> bool: - if instance is Array: - var as_array: Array = instance - for element: Variant in as_array: - @warning_ignore("return_value_discarded") - free_instance(element) - as_array.clear() - return true - # do not free an already freed instance - if not is_instance_valid(instance): - return false - # do not free a class refernece - @warning_ignore("unsafe_cast") - if typeof(instance) == TYPE_OBJECT and (instance as Object).is_class("GDScriptNativeClass"): - return false - if is_stdout_verbose: - print_verbose("GdUnit4:gc():free instance ", instance) - @warning_ignore("unsafe_cast") - release_double(instance as Object) - if instance is RefCounted: - @warning_ignore("unsafe_cast") - (instance as RefCounted).notification(Object.NOTIFICATION_PREDELETE) - # If scene runner freed we explicit await all inputs are processed - if instance is GdUnitSceneRunnerImpl: - @warning_ignore("unsafe_cast") - await (instance as GdUnitSceneRunnerImpl).await_input_processed() - return true - else: - if instance is Timer: - var timer: Timer = instance - timer.stop() - if use_call_deferred: - timer.call_deferred("free") - else: - timer.free() - await (Engine.get_main_loop() as SceneTree).process_frame - return true - - @warning_ignore("unsafe_cast") - if instance is Node and (instance as Node).get_parent() != null: - var node: Node = instance - if is_stdout_verbose: - print_verbose("GdUnit4:gc():remove node from parent ", node.get_parent(), node) - if use_call_deferred: - node.get_parent().remove_child.call_deferred(node) - #instance.call_deferred("set_owner", null) - else: - node.get_parent().remove_child(node) - if is_stdout_verbose: - print_verbose("GdUnit4:gc():freeing `free()` the instance ", instance) - if use_call_deferred: - @warning_ignore("unsafe_cast") - (instance as Object).call_deferred("free") - else: - @warning_ignore("unsafe_cast") - (instance as Object).free() - return !is_instance_valid(instance) - - -static func _release_connections(instance :Object) -> void: - if is_instance_valid(instance): - # disconnect from all connected signals to force freeing, otherwise it ends up in orphans - for connection in instance.get_incoming_connections(): - var signal_ :Signal = connection["signal"] - var callable_ :Callable = connection["callable"] - #prints(instance, connection) - #prints("signal", signal_.get_name(), signal_.get_object()) - #prints("callable", callable_.get_object()) - if instance.has_signal(signal_.get_name()) and instance.is_connected(signal_.get_name(), callable_): - #prints("disconnect signal", signal_.get_name(), callable_) - instance.disconnect(signal_.get_name(), callable_) - release_timers() - - -static func release_timers() -> void: - # we go the new way to hold all gdunit timers in group 'GdUnitTimers' - var scene_tree := Engine.get_main_loop() as SceneTree - if scene_tree.root == null: - return - for node :Node in scene_tree.root.get_children(): - if is_instance_valid(node) and node.is_in_group("GdUnitTimers"): - if is_instance_valid(node): - scene_tree.root.remove_child.call_deferred(node) - (node as Timer).stop() - node.queue_free() - - -# the finally cleaup unfreed resources and singletons -static func dispose_all(use_call_deferred :bool = false) -> void: - release_timers() - GdUnitSingleton.dispose(use_call_deferred) - GdUnitSignals.dispose() - - -# if instance an mock or spy we need manually freeing the self reference -static func release_double(instance :Object) -> void: - if instance.has_method("__release_double"): - instance.call("__release_double") - - - -static func find_test_case(test_suite: Node, test_case_name: String, index := -1) -> _TestCase: - for test_case: _TestCase in test_suite.get_children(): - if test_case.test_name() == test_case_name: - if index != -1: - if test_case._test_case.attribute_index != index: - continue - return test_case - return null - - -static func register_expect_interupted_by_timeout(test_suite: Node, test_case_name: String) -> void: - var test_case := find_test_case(test_suite, test_case_name) - if test_case: - test_case.expect_to_interupt() diff --git a/addons/gdUnit4/src/core/GdUnitTools.gd.uid b/addons/gdUnit4/src/core/GdUnitTools.gd.uid deleted file mode 100644 index 7fb9578c..00000000 --- a/addons/gdUnit4/src/core/GdUnitTools.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://d05qgv6uu477i diff --git a/addons/gdUnit4/src/core/GodotVersionFixures.gd b/addons/gdUnit4/src/core/GodotVersionFixures.gd deleted file mode 100644 index 52993251..00000000 --- a/addons/gdUnit4/src/core/GodotVersionFixures.gd +++ /dev/null @@ -1,11 +0,0 @@ -## This service class contains helpers to wrap Godot functions and handle them carefully depending on the current Godot version -class_name GodotVersionFixures -extends RefCounted - - -# handle global_position fixed by https://github.com/godotengine/godot/pull/88473 -static func set_event_global_position(event: InputEventMouseMotion, global_position: Vector2) -> void: - if Engine.get_version_info().hex >= 0x40202 or Engine.get_version_info().hex == 0x40104: - event.global_position = event.position - else: - event.global_position = global_position diff --git a/addons/gdUnit4/src/core/GodotVersionFixures.gd.uid b/addons/gdUnit4/src/core/GodotVersionFixures.gd.uid deleted file mode 100644 index 38732b1e..00000000 --- a/addons/gdUnit4/src/core/GodotVersionFixures.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dehxycxsj68ev diff --git a/addons/gdUnit4/src/core/LocalTime.gd b/addons/gdUnit4/src/core/LocalTime.gd deleted file mode 100644 index fabaaf6f..00000000 --- a/addons/gdUnit4/src/core/LocalTime.gd +++ /dev/null @@ -1,114 +0,0 @@ -# This class provides Date/Time functionallity to Godot -class_name LocalTime -extends Resource - -enum TimeUnit { - DEFAULT = 0, - MILLIS = 1, - SECOND = 2, - MINUTE = 3, - HOUR = 4, - DAY = 5, - MONTH = 6, - YEAR = 7 -} - -const SECONDS_PER_MINUTE:int = 60 -const MINUTES_PER_HOUR:int = 60 -const HOURS_PER_DAY:int = 24 -const MILLIS_PER_SECOND:int = 1000 -const MILLIS_PER_MINUTE:int = MILLIS_PER_SECOND * SECONDS_PER_MINUTE -const MILLIS_PER_HOUR:int = MILLIS_PER_MINUTE * MINUTES_PER_HOUR - -var _time :int -var _hour :int -var _minute :int -var _second :int -var _millisecond :int - - -static func now() -> LocalTime: - return LocalTime.new(_get_system_time_msecs()) - - -static func of_unix_time(time_ms :int) -> LocalTime: - return LocalTime.new(time_ms) - - -static func local_time(hours :int, minutes :int, seconds :int, milliseconds :int) -> LocalTime: - return LocalTime.new(MILLIS_PER_HOUR * hours\ - + MILLIS_PER_MINUTE * minutes\ - + MILLIS_PER_SECOND * seconds\ - + milliseconds) - - -func elapsed_since() -> String: - return LocalTime.elapsed(LocalTime._get_system_time_msecs() - _time) - - -func elapsed_since_ms() -> int: - return LocalTime._get_system_time_msecs() - _time - - -func plus(time_unit :TimeUnit, value :int) -> LocalTime: - var addValue:int = 0 - match time_unit: - TimeUnit.MILLIS: - addValue = value - TimeUnit.SECOND: - addValue = value * MILLIS_PER_SECOND - TimeUnit.MINUTE: - addValue = value * MILLIS_PER_MINUTE - TimeUnit.HOUR: - addValue = value * MILLIS_PER_HOUR - @warning_ignore("return_value_discarded") - _init(_time + addValue) - return self - - -static func elapsed(p_time_ms :int) -> String: - var local_time_ := LocalTime.new(p_time_ms) - if local_time_._hour > 0: - return "%dh %dmin %ds %dms" % [local_time_._hour, local_time_._minute, local_time_._second, local_time_._millisecond] - if local_time_._minute > 0: - return "%dmin %ds %dms" % [local_time_._minute, local_time_._second, local_time_._millisecond] - if local_time_._second > 0: - return "%ds %dms" % [local_time_._second, local_time_._millisecond] - return "%dms" % local_time_._millisecond - - -# create from epoch timestamp in ms -func _init(time: int) -> void: - _time = time - @warning_ignore("integer_division") - _hour = (time / MILLIS_PER_HOUR) % 24 - @warning_ignore("integer_division") - _minute = (time / MILLIS_PER_MINUTE) % 60 - @warning_ignore("integer_division") - _second = (time / MILLIS_PER_SECOND) % 60 - _millisecond = time % 1000 - - -func hour() -> int: - return _hour - - -func minute() -> int: - return _minute - - -func second() -> int: - return _second - - -func millis() -> int: - return _millisecond - - -func _to_string() -> String: - return "%02d:%02d:%02d.%03d" % [_hour, _minute, _second, _millisecond] - - -# wraper to old OS.get_system_time_msecs() function -static func _get_system_time_msecs() -> int: - return Time.get_unix_time_from_system() * 1000 as int diff --git a/addons/gdUnit4/src/core/LocalTime.gd.uid b/addons/gdUnit4/src/core/LocalTime.gd.uid deleted file mode 100644 index 5fc94e3d..00000000 --- a/addons/gdUnit4/src/core/LocalTime.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dmta1h7ndfnko diff --git a/addons/gdUnit4/src/core/_TestCase.gd b/addons/gdUnit4/src/core/_TestCase.gd deleted file mode 100644 index 58409e79..00000000 --- a/addons/gdUnit4/src/core/_TestCase.gd +++ /dev/null @@ -1,243 +0,0 @@ -class_name _TestCase -extends Node - -signal completed() - - -var _test_case: GdUnitTestCase -var _attribute: TestCaseAttribute -var _current_iteration: int = -1 -var _expect_to_interupt := false -var _timer: Timer -var _interupted: bool = false -var _failed := false -var _parameter_set_resolver: GdUnitTestParameterSetResolver -var _is_disposed := false -var _func_state: Variant - - -func _init(test_case: GdUnitTestCase, attribute: TestCaseAttribute, fd: GdFunctionDescriptor) -> void: - _test_case = test_case - _attribute = attribute - set_function_descriptor(fd) - - -func execute(p_test_parameter := Array(), p_iteration := 0) -> void: - _failure_received(false) - _current_iteration = p_iteration - 1 - if _current_iteration == - 1: - _set_failure_handler() - set_timeout() - - if is_parameterized(): - execute_parameterized() - elif not p_test_parameter.is_empty(): - update_fuzzers(p_test_parameter, p_iteration) - _execute_test_case(test_name(), p_test_parameter) - else: - _execute_test_case(test_name(), []) - await completed - - -func execute_parameterized() -> void: - _failure_received(false) - set_timeout() - - # Resolve parameter set at runtime to include runtime variables - var test_parameters := await _resolve_test_parameters(_test_case.attribute_index) - if test_parameters.is_empty(): - return - - await _execute_test_case(test_name(), test_parameters) - - -func _resolve_test_parameters(attribute_index: int) -> Array: - var result := _parameter_set_resolver.load_parameter_sets(get_parent()) - if result.is_error(): - do_skip(true, result.error_message()) - await (Engine.get_main_loop() as SceneTree).process_frame - completed.emit() - return [] - - # validate the parameter set - var parameter_sets: Array = result.value() - result = _parameter_set_resolver.validate(parameter_sets, attribute_index) - if result.is_error(): - do_skip(true, result.error_message()) - await (Engine.get_main_loop() as SceneTree).process_frame - completed.emit() - return [] - - @warning_ignore("unsafe_method_access") - var test_parameters: Array = parameter_sets[attribute_index].duplicate() - # We need here to add a empty array to override the `test_parameters` to prevent initial "default" parameters from being used. - # This prevents objects in the argument list from being unnecessarily re-instantiated. - test_parameters.append([]) - - return test_parameters - - -func dispose() -> void: - if _is_disposed: - return - _is_disposed = true - Engine.remove_meta("GD_TEST_FAILURE") - stop_timer() - _remove_failure_handler() - _attribute.fuzzers.clear() - - -@warning_ignore("shadowed_variable_base_class", "redundant_await") -func _execute_test_case(name: String, test_parameter: Array) -> void: - # save the function state like GDScriptFunctionState to dispose at test timeout to prevent orphan state - _func_state = get_parent().callv(name, test_parameter) - await _func_state - # needs at least on await otherwise it breaks the awaiting chain - await (Engine.get_main_loop() as SceneTree).process_frame - completed.emit() - - -func update_fuzzers(input_values: Array, iteration: int) -> void: - for fuzzer :Variant in input_values: - if fuzzer is Fuzzer: - fuzzer._iteration_index = iteration + 1 - - -func set_timeout() -> void: - if is_instance_valid(_timer): - return - var time: float = _attribute.timeout / 1000.0 - _timer = Timer.new() - add_child(_timer) - _timer.set_name("gdunit_test_case_timer_%d" % _timer.get_instance_id()) - @warning_ignore("return_value_discarded") - _timer.timeout.connect(do_interrupt, CONNECT_DEFERRED) - _timer.set_one_shot(true) - _timer.set_wait_time(time) - _timer.set_autostart(false) - _timer.start() - - -func do_interrupt() -> void: - _interupted = true - # We need to dispose manually the function state here - GdObjects.dispose_function_state(_func_state) - if not is_expect_interupted(): - var execution_context:= GdUnitThreadManager.get_current_context().get_execution_context() - if is_fuzzed(): - execution_context.add_report(GdUnitReport.new()\ - .create(GdUnitReport.INTERUPTED, line_number(), GdAssertMessages.fuzzer_interuped(_current_iteration, "timedout"))) - else: - execution_context.add_report(GdUnitReport.new()\ - .create(GdUnitReport.INTERUPTED, line_number(), GdAssertMessages.test_timeout(_attribute.timeout))) - completed.emit() - - -func _set_failure_handler() -> void: - if not GdUnitSignals.instance().gdunit_set_test_failed.is_connected(_failure_received): - @warning_ignore("return_value_discarded") - GdUnitSignals.instance().gdunit_set_test_failed.connect(_failure_received) - - -func _remove_failure_handler() -> void: - if GdUnitSignals.instance().gdunit_set_test_failed.is_connected(_failure_received): - GdUnitSignals.instance().gdunit_set_test_failed.disconnect(_failure_received) - - -func _failure_received(is_failed: bool) -> void: - # is already failed? - if _failed: - return - _failed = is_failed - Engine.set_meta("GD_TEST_FAILURE", is_failed) - - -func stop_timer() -> void: - # finish outstanding timeouts - if is_instance_valid(_timer): - _timer.stop() - _timer.call_deferred("free") - _timer = null - - -func expect_to_interupt() -> void: - _expect_to_interupt = true - - -func is_interupted() -> bool: - return _interupted - - -func is_expect_interupted() -> bool: - return _expect_to_interupt - - -func is_parameterized() -> bool: - return _parameter_set_resolver.is_parameterized() - - -func is_skipped() -> bool: - return _attribute.is_skipped - - -func skip_info() -> String: - return _attribute.skip_reason - - -func id() -> GdUnitGUID: - return _test_case.guid - - -func test_name() -> String: - return _test_case.test_name - - -@warning_ignore("native_method_override") -func get_name() -> StringName: - return _test_case.test_name - - -func line_number() -> int: - return _test_case.line_number - - -func iterations() -> int: - return _attribute.fuzzer_iterations - - -func seed_value() -> int: - return _attribute.test_seed - - -func is_fuzzed() -> bool: - return not _attribute.fuzzers.is_empty() - - -func fuzzer_arguments() -> Array[GdFunctionArgument]: - return _attribute.fuzzers - - -func script_path() -> String: - return _test_case.source_file - - -func ResourcePath() -> String: - return _test_case.source_file - - -func generate_seed() -> void: - if _attribute.test_seed != -1: - seed(_attribute.test_seed) - - -func do_skip(skipped: bool, reason: String="") -> void: - _attribute.is_skipped = skipped - _attribute.skip_reason = reason - - -func set_function_descriptor(fd: GdFunctionDescriptor) -> void: - _parameter_set_resolver = GdUnitTestParameterSetResolver.new(fd) - - -func _to_string() -> String: - return "%s :%d (%dms)" % [get_name(), _test_case.line_number, _attribute.timeout] diff --git a/addons/gdUnit4/src/core/_TestCase.gd.uid b/addons/gdUnit4/src/core/_TestCase.gd.uid deleted file mode 100644 index 8642fad1..00000000 --- a/addons/gdUnit4/src/core/_TestCase.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cb2lkpvh0liiv diff --git a/addons/gdUnit4/src/core/assets/touch-button.png b/addons/gdUnit4/src/core/assets/touch-button.png deleted file mode 100644 index de424599..00000000 --- a/addons/gdUnit4/src/core/assets/touch-button.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e709c40067fec99c3b59c78a5a364da8c326a94c49a56337a46c98976d3db4cb -size 3292 diff --git a/addons/gdUnit4/src/core/assets/touch-button.png.import b/addons/gdUnit4/src/core/assets/touch-button.png.import deleted file mode 100644 index 7f469c3a..00000000 --- a/addons/gdUnit4/src/core/assets/touch-button.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://csgvrbao53xmv" -path="res://.godot/imported/touch-button.png-2fff40c8520d8e97a57db1b2b043f641.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/gdUnit4/src/core/assets/touch-button.png" -dest_files=["res://.godot/imported/touch-button.png-2fff40c8520d8e97a57db1b2b043f641.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/gdUnit4/src/core/attributes/TestCaseAttribute.gd b/addons/gdUnit4/src/core/attributes/TestCaseAttribute.gd deleted file mode 100644 index cf7a2b97..00000000 --- a/addons/gdUnit4/src/core/attributes/TestCaseAttribute.gd +++ /dev/null @@ -1,76 +0,0 @@ -class_name TestCaseAttribute -extends Resource -## Holds configuration and metadata for individual test cases.[br] -## [br] -## This class defines test behaviors and properties such as:[br] -## - Test timeouts[br] -## - Skip conditions[br] -## - Fuzzing parameters[br] -## - Random seed values[br] - - -## When set, no specific timeout value is configured and test will use the [code]test_timeout[/code][br] -## value from [GdUnitSettings]. -const DEFAULT_TIMEOUT := -1 - - -## The maximum time in milliseconds for test completion.[br] -## The test fails if execution exceeds this duration.[br] -## [br] -## When set to [constant DEFAULT_TIMEOUT], uses the value from [method GdUnitSettings.test_timeout]. -var timeout: int = DEFAULT_TIMEOUT: - set(value): - timeout = value - get: - if timeout == DEFAULT_TIMEOUT: - # get the default timeout from the settings - timeout = GdUnitSettings.test_timeout() - return timeout - - -## The seed used for random number generation in the test.[br] -## Ensures reproducible results for randomized test scenarios.[br] -## A value of -1 indicates no specific seed is set. -var test_seed: int = -1 - - -## Controls whether this test should be skipped during execution.[br] -## Useful for temporarily disabling tests without removing them. -var is_skipped := false - - -## Documents why the test is being skipped.[br] -## [br] -## Should explain the reason for skipping and ideally include:[br] -## - Why the test was disabled[br] -## - Under what conditions it should be re-enabled[br] -## - Any related issues or tickets -var skip_reason := "Unknown" - - -## Number of iterations to run when using fuzzers.[br] -## [br] -## Fuzzers generate random test data to help find edge cases.[br] -## Higher values provide better coverage but increase test duration. -var fuzzer_iterations: int = Fuzzer.ITERATION_DEFAULT_COUNT - - -## Array of fuzzer configurations for test parameters.[br] -## [br] -## Each [GdFunctionArgument] defines how random test data[br] -## should be generated for a particular parameter. -var fuzzers: Array[GdFunctionArgument] = [] - - -# There is a bug in `duplicate` see https://github.com/godotengine/godot/issues/98644 -# we need in addition to overwrite default values with the source values -@warning_ignore("native_method_override") -func clone() -> Resource: - var copy: TestCaseAttribute = TestCaseAttribute.new() - copy.timeout = timeout - copy.test_seed = test_seed - copy.is_skipped = is_skipped - copy.skip_reason = skip_reason - copy.fuzzer_iterations = fuzzer_iterations - copy.fuzzers = fuzzers.duplicate() - return copy diff --git a/addons/gdUnit4/src/core/attributes/TestCaseAttribute.gd.uid b/addons/gdUnit4/src/core/attributes/TestCaseAttribute.gd.uid deleted file mode 100644 index 85dc262e..00000000 --- a/addons/gdUnit4/src/core/attributes/TestCaseAttribute.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://d2bres53mgxnw diff --git a/addons/gdUnit4/src/core/command/GdUnitCommand.gd b/addons/gdUnit4/src/core/command/GdUnitCommand.gd deleted file mode 100644 index 659b6a3f..00000000 --- a/addons/gdUnit4/src/core/command/GdUnitCommand.gd +++ /dev/null @@ -1,41 +0,0 @@ -class_name GdUnitCommand -extends RefCounted - - -func _init(p_name :String, p_is_enabled: Callable, p_runnable: Callable, p_shortcut :GdUnitShortcut.ShortCut = GdUnitShortcut.ShortCut.NONE) -> void: - assert(p_name != null, "(%s) missing parameter 'name'" % p_name) - assert(p_is_enabled != null, "(%s) missing parameter 'is_enabled'" % p_name) - assert(p_runnable != null, "(%s) missing parameter 'runnable'" % p_name) - assert(p_shortcut != null, "(%s) missing parameter 'shortcut'" % p_name) - self.name = p_name - self.is_enabled = p_is_enabled - self.shortcut = p_shortcut - self.runnable = p_runnable - - -var name: String: - set(value): - name = value - get: - return name - - -var shortcut: GdUnitShortcut.ShortCut: - set(value): - shortcut = value - get: - return shortcut - - -var is_enabled: Callable: - set(value): - is_enabled = value - get: - return is_enabled - - -var runnable: Callable: - set(value): - runnable = value - get: - return runnable diff --git a/addons/gdUnit4/src/core/command/GdUnitCommand.gd.uid b/addons/gdUnit4/src/core/command/GdUnitCommand.gd.uid deleted file mode 100644 index 1df21a92..00000000 --- a/addons/gdUnit4/src/core/command/GdUnitCommand.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://crmuuvbqy4shs diff --git a/addons/gdUnit4/src/core/command/GdUnitCommandHandler.gd b/addons/gdUnit4/src/core/command/GdUnitCommandHandler.gd deleted file mode 100644 index 1f64e2ad..00000000 --- a/addons/gdUnit4/src/core/command/GdUnitCommandHandler.gd +++ /dev/null @@ -1,408 +0,0 @@ -class_name GdUnitCommandHandler -extends Object - -signal gdunit_runner_start() -signal gdunit_runner_stop(client_id :int) - - -const GdUnitTools := preload("res://addons/gdUnit4/src/core/GdUnitTools.gd") - -const CMD_RUN_OVERALL = "Debug Overall TestSuites" -const CMD_RUN_TESTCASE = "Run TestCases" -const CMD_RUN_TESTCASE_DEBUG = "Run TestCases (Debug)" -const CMD_RUN_TESTSUITE = "Run TestSuites" -const CMD_RUN_TESTSUITE_DEBUG = "Run TestSuites (Debug)" -const CMD_RERUN_TESTS = "ReRun Tests" -const CMD_RERUN_TESTS_DEBUG = "ReRun Tests (Debug)" -const CMD_STOP_TEST_RUN = "Stop Test Run" -const CMD_CREATE_TESTCASE = "Create TestCase" - -const SETTINGS_SHORTCUT_MAPPING := { - "N/A" : GdUnitShortcut.ShortCut.NONE, - GdUnitSettings.SHORTCUT_INSPECTOR_RERUN_TEST : GdUnitShortcut.ShortCut.RERUN_TESTS, - GdUnitSettings.SHORTCUT_INSPECTOR_RERUN_TEST_DEBUG : GdUnitShortcut.ShortCut.RERUN_TESTS_DEBUG, - GdUnitSettings.SHORTCUT_INSPECTOR_RUN_TEST_OVERALL : GdUnitShortcut.ShortCut.RUN_TESTS_OVERALL, - GdUnitSettings.SHORTCUT_INSPECTOR_RUN_TEST_STOP : GdUnitShortcut.ShortCut.STOP_TEST_RUN, - GdUnitSettings.SHORTCUT_EDITOR_RUN_TEST : GdUnitShortcut.ShortCut.RUN_TESTCASE, - GdUnitSettings.SHORTCUT_EDITOR_RUN_TEST_DEBUG : GdUnitShortcut.ShortCut.RUN_TESTCASE_DEBUG, - GdUnitSettings.SHORTCUT_EDITOR_CREATE_TEST : GdUnitShortcut.ShortCut.CREATE_TEST, - GdUnitSettings.SHORTCUT_FILESYSTEM_RUN_TEST : GdUnitShortcut.ShortCut.RUN_TESTSUITE, - GdUnitSettings.SHORTCUT_FILESYSTEM_RUN_TEST_DEBUG : GdUnitShortcut.ShortCut.RUN_TESTSUITE_DEBUG -} - -const CommandMapping := { - GdUnitShortcut.ShortCut.RUN_TESTS_OVERALL: GdUnitCommandHandler.CMD_RUN_OVERALL, - GdUnitShortcut.ShortCut.RUN_TESTCASE: GdUnitCommandHandler.CMD_RUN_TESTCASE, - GdUnitShortcut.ShortCut.RUN_TESTCASE_DEBUG: GdUnitCommandHandler.CMD_RUN_TESTCASE_DEBUG, - GdUnitShortcut.ShortCut.RUN_TESTSUITE: GdUnitCommandHandler.CMD_RUN_TESTSUITE, - GdUnitShortcut.ShortCut.RUN_TESTSUITE_DEBUG: GdUnitCommandHandler.CMD_RUN_TESTSUITE_DEBUG, - GdUnitShortcut.ShortCut.RERUN_TESTS: GdUnitCommandHandler.CMD_RERUN_TESTS, - GdUnitShortcut.ShortCut.RERUN_TESTS_DEBUG: GdUnitCommandHandler.CMD_RERUN_TESTS_DEBUG, - GdUnitShortcut.ShortCut.STOP_TEST_RUN: GdUnitCommandHandler.CMD_STOP_TEST_RUN, - GdUnitShortcut.ShortCut.CREATE_TEST: GdUnitCommandHandler.CMD_CREATE_TESTCASE, -} - -# the current test runner config -var _runner_config := GdUnitRunnerConfig.new() - -# holds the current connected gdUnit runner client id -var _client_id: int -# if no debug mode we have an process id -var _current_runner_process_id: int = 0 -# hold is current an test running -var _is_running: bool = false -# holds if the current running tests started in debug mode -var _running_debug_mode: bool - -var _commands := {} -var _shortcuts := {} - - -static func instance() -> GdUnitCommandHandler: - return GdUnitSingleton.instance("GdUnitCommandHandler", func() -> GdUnitCommandHandler: return GdUnitCommandHandler.new()) - - -@warning_ignore("return_value_discarded") -func _init() -> void: - assert_shortcut_mappings(SETTINGS_SHORTCUT_MAPPING) - - GdUnitSignals.instance().gdunit_event.connect(_on_event) - GdUnitSignals.instance().gdunit_client_connected.connect(_on_client_connected) - GdUnitSignals.instance().gdunit_client_disconnected.connect(_on_client_disconnected) - GdUnitSignals.instance().gdunit_settings_changed.connect(_on_settings_changed) - # preload previous test execution - @warning_ignore("return_value_discarded") - _runner_config.load_config() - - init_shortcuts() - var is_running := func(_script :Script) -> bool: return _is_running - var is_not_running := func(_script :Script) -> bool: return !_is_running - register_command(GdUnitCommand.new(CMD_RUN_OVERALL, is_not_running, cmd_run_overall.bind(true), GdUnitShortcut.ShortCut.RUN_TESTS_OVERALL)) - register_command(GdUnitCommand.new(CMD_RUN_TESTCASE, is_not_running, cmd_editor_run_test.bind(false), GdUnitShortcut.ShortCut.RUN_TESTCASE)) - register_command(GdUnitCommand.new(CMD_RUN_TESTCASE_DEBUG, is_not_running, cmd_editor_run_test.bind(true), GdUnitShortcut.ShortCut.RUN_TESTCASE_DEBUG)) - register_command(GdUnitCommand.new(CMD_RUN_TESTSUITE, is_not_running, cmd_run_test_suites.bind(false), GdUnitShortcut.ShortCut.RUN_TESTSUITE)) - register_command(GdUnitCommand.new(CMD_RUN_TESTSUITE_DEBUG, is_not_running, cmd_run_test_suites.bind(true), GdUnitShortcut.ShortCut.RUN_TESTSUITE_DEBUG)) - register_command(GdUnitCommand.new(CMD_RERUN_TESTS, is_not_running, cmd_run.bind(false), GdUnitShortcut.ShortCut.RERUN_TESTS)) - register_command(GdUnitCommand.new(CMD_RERUN_TESTS_DEBUG, is_not_running, cmd_run.bind(true), GdUnitShortcut.ShortCut.RERUN_TESTS_DEBUG)) - register_command(GdUnitCommand.new(CMD_CREATE_TESTCASE, is_not_running, cmd_create_test, GdUnitShortcut.ShortCut.CREATE_TEST)) - register_command(GdUnitCommand.new(CMD_STOP_TEST_RUN, is_running, cmd_stop.bind(_client_id), GdUnitShortcut.ShortCut.STOP_TEST_RUN)) - - # schedule discover tests if enabled and running inside the editor - if Engine.is_editor_hint() and GdUnitSettings.is_test_discover_enabled(): - var timer :SceneTreeTimer = (Engine.get_main_loop() as SceneTree).create_timer(5) - @warning_ignore("return_value_discarded") - timer.timeout.connect(cmd_discover_tests) - - -func _notification(what: int) -> void: - if what == NOTIFICATION_PREDELETE: - _commands.clear() - _shortcuts.clear() - - -func _do_process() -> void: - check_test_run_stopped_manually() - - -# is checking if the user has press the editor stop scene -func check_test_run_stopped_manually() -> void: - if is_test_running_but_stop_pressed(): - if GdUnitSettings.is_verbose_assert_warnings(): - push_warning("Test Runner scene was stopped manually, force stopping the current test run!") - cmd_stop(_client_id) - - -func is_test_running_but_stop_pressed() -> bool: - return _running_debug_mode and _is_running and not EditorInterface.is_playing_scene() - - -func assert_shortcut_mappings(mappings: Dictionary) -> void: - for shortcut: int in GdUnitShortcut.ShortCut.values(): - assert(mappings.values().has(shortcut), "missing settings mapping for shortcut '%s'!" % GdUnitShortcut.ShortCut.keys()[shortcut]) - - -func init_shortcuts() -> void: - for shortcut: int in GdUnitShortcut.ShortCut.values(): - if shortcut == GdUnitShortcut.ShortCut.NONE: - continue - var property_name: String = SETTINGS_SHORTCUT_MAPPING.find_key(shortcut) - var property := GdUnitSettings.get_property(property_name) - var keys := GdUnitShortcut.default_keys(shortcut) - if property != null: - keys = property.value() - var inputEvent := create_shortcut_input_even(keys) - register_shortcut(shortcut, inputEvent) - - -func create_shortcut_input_even(key_codes: PackedInt32Array) -> InputEventKey: - var inputEvent := InputEventKey.new() - inputEvent.pressed = true - for key_code in key_codes: - match key_code: - KEY_ALT: - inputEvent.alt_pressed = true - KEY_SHIFT: - inputEvent.shift_pressed = true - KEY_CTRL: - inputEvent.ctrl_pressed = true - _: - inputEvent.keycode = key_code as Key - inputEvent.physical_keycode = key_code as Key - return inputEvent - - -func register_shortcut(p_shortcut: GdUnitShortcut.ShortCut, p_input_event: InputEvent) -> void: - GdUnitTools.prints_verbose("register shortcut: '%s' to '%s'" % [GdUnitShortcut.ShortCut.keys()[p_shortcut], p_input_event.as_text()]) - var shortcut := Shortcut.new() - shortcut.set_events([p_input_event]) - var command_name := get_shortcut_command(p_shortcut) - _shortcuts[p_shortcut] = GdUnitShortcutAction.new(p_shortcut, shortcut, command_name) - - -func get_shortcut(shortcut_type: GdUnitShortcut.ShortCut) -> Shortcut: - return get_shortcut_action(shortcut_type).shortcut - - -func get_shortcut_action(shortcut_type: GdUnitShortcut.ShortCut) -> GdUnitShortcutAction: - return _shortcuts.get(shortcut_type) - - -func get_shortcut_command(p_shortcut: GdUnitShortcut.ShortCut) -> String: - return CommandMapping.get(p_shortcut, "unknown command") - - -func register_command(p_command: GdUnitCommand) -> void: - _commands[p_command.name] = p_command - - -func command(cmd_name: String) -> GdUnitCommand: - return _commands.get(cmd_name) - - -func cmd_run_test_suites(scripts: Array[Script], debug: bool, rerun := false) -> void: - # Update test discovery - GdUnitSignals.instance().gdunit_event.emit(GdUnitEventTestDiscoverStart.new()) - var tests_to_execute: Array[GdUnitTestCase] = [] - for script in scripts: - GdUnitTestDiscoverer.discover_tests(script, func(test_case: GdUnitTestCase) -> void: - tests_to_execute.append(test_case) - GdUnitTestDiscoverSink.discover(test_case) - ) - GdUnitSignals.instance().gdunit_event.emit(GdUnitEventTestDiscoverEnd.new(0, 0)) - GdUnitTestDiscoverer.console_log_discover_results(tests_to_execute) - - # create new runner runner_config for fresh run otherwise use saved one - if not rerun: - var result := _runner_config.clear()\ - .add_test_cases(tests_to_execute)\ - .save_config() - if result.is_error(): - push_error(result.error_message()) - return - cmd_run(debug) - - -func cmd_run_test_case(script: Script, test_case: String, test_param_index: int, debug: bool, rerun := false) -> void: - # Update test discovery - var tests_to_execute: Array[GdUnitTestCase] = [] - GdUnitSignals.instance().gdunit_event.emit(GdUnitEventTestDiscoverStart.new()) - GdUnitTestDiscoverer.discover_tests(script, func(test: GdUnitTestCase) -> void: - # We filter for a single test - if test.test_name == test_case: - # We only add selected parameterized test to the execution list - if test_param_index == -1: - tests_to_execute.append(test) - elif test.attribute_index == test_param_index: - tests_to_execute.append(test) - GdUnitTestDiscoverSink.discover(test) - ) - GdUnitSignals.instance().gdunit_event.emit(GdUnitEventTestDiscoverEnd.new(0, 0)) - GdUnitTestDiscoverer.console_log_discover_results(tests_to_execute) - - # create new runner config for fresh run otherwise use saved one - if not rerun: - var result := _runner_config.clear()\ - .add_test_cases(tests_to_execute)\ - .save_config() - if result.is_error(): - push_error(result.error_message()) - return - cmd_run(debug) - - -func cmd_run_tests(tests_to_execute: Array[GdUnitTestCase], debug: bool) -> void: - # Save tests to runner config before execute - var result := _runner_config.clear()\ - .add_test_cases(tests_to_execute)\ - .save_config() - if result.is_error(): - push_error(result.error_message()) - return - cmd_run(debug) - - -func cmd_run_overall(debug: bool) -> void: - var tests_to_execute := await GdUnitTestDiscoverer.run() - var result := _runner_config.clear()\ - .add_test_cases(tests_to_execute)\ - .save_config() - if result.is_error(): - push_error(result.error_message()) - return - cmd_run(debug) - - -func cmd_run(debug: bool) -> void: - # don't start is already running - if _is_running: - return - - # save current selected excution config - var server_port: int = Engine.get_meta("gdunit_server_port") - var result := _runner_config.set_server_port(server_port).save_config() - if result.is_error(): - push_error(result.error_message()) - return - # before start we have to save all changes - ScriptEditorControls.save_all_open_script() - gdunit_runner_start.emit() - _current_runner_process_id = -1 - _running_debug_mode = debug - if debug: - run_debug_mode() - else: - run_release_mode() - - -func cmd_stop(client_id: int) -> void: - # don't stop if is already stopped - if not _is_running: - return - _is_running = false - gdunit_runner_stop.emit(client_id) - if _running_debug_mode: - EditorInterface.stop_playing_scene() - elif _current_runner_process_id > 0: - if OS.is_process_running(_current_runner_process_id): - var result := OS.kill(_current_runner_process_id) - if result != OK: - push_error("ERROR checked stopping GdUnit Test Runner. error code: %s" % result) - _current_runner_process_id = -1 - - -func cmd_editor_run_test(debug: bool) -> void: - if is_active_script_editor(): - var cursor_line := active_base_editor().get_caret_line() - #run test case? - var regex := RegEx.new() - @warning_ignore("return_value_discarded") - regex.compile("(^func[ ,\t])(test_[a-zA-Z0-9_]*)") - var result := regex.search(active_base_editor().get_line(cursor_line)) - if result: - var func_name := result.get_string(2).strip_edges() - if func_name.begins_with("test_"): - cmd_run_test_case(active_script(), func_name, -1, debug) - return - # otherwise run the full test suite - var selected_test_suites: Array[Script] = [active_script()] - cmd_run_test_suites(selected_test_suites, debug) - - -func cmd_create_test() -> void: - if not is_active_script_editor(): - return - var cursor_line := active_base_editor().get_caret_line() - var result := GdUnitTestSuiteBuilder.create(active_script(), cursor_line) - if result.is_error(): - # show error dialog - push_error("Failed to create test case: %s" % result.error_message()) - return - var info: Dictionary = result.value() - var script_path: String = info.get("path") - var script_line: int = info.get("line") - ScriptEditorControls.edit_script(script_path, script_line) - - -func cmd_discover_tests() -> void: - await GdUnitTestDiscoverer.run() - - -func run_debug_mode() -> void: - EditorInterface.play_custom_scene("res://addons/gdUnit4/src/core/runners/GdUnitTestRunner.tscn") - _is_running = true - - -func run_release_mode() -> void: - var arguments := Array() - if OS.is_stdout_verbose(): - arguments.append("--verbose") - arguments.append("--no-window") - arguments.append("--path") - arguments.append(ProjectSettings.globalize_path("res://")) - arguments.append("res://addons/gdUnit4/src/core/runners/GdUnitTestRunner.tscn") - _current_runner_process_id = OS.create_process(OS.get_executable_path(), arguments, false); - _is_running = true - - -func is_active_script_editor() -> bool: - return EditorInterface.get_script_editor().get_current_editor() != null - - -func active_base_editor() -> TextEdit: - return EditorInterface.get_script_editor().get_current_editor().get_base_editor() - - -func active_script() -> Script: - return EditorInterface.get_script_editor().get_current_script() - - - -################################################################################ -# signals handles -################################################################################ -func _on_event(event: GdUnitEvent) -> void: - if event.type() == GdUnitEvent.SESSION_CLOSE: - cmd_stop(_client_id) - - -func _on_stop_pressed() -> void: - cmd_stop(_client_id) - - -func _on_run_pressed(debug := false) -> void: - cmd_run(debug) - - -func _on_run_overall_pressed(_debug := false) -> void: - cmd_run_overall(true) - - -func _on_settings_changed(property: GdUnitProperty) -> void: - if SETTINGS_SHORTCUT_MAPPING.has(property.name()): - var shortcut :GdUnitShortcut.ShortCut = SETTINGS_SHORTCUT_MAPPING.get(property.name()) - var value: PackedInt32Array = property.value() - var input_event := create_shortcut_input_even(value) - prints("Shortcut changed: '%s' to '%s'" % [GdUnitShortcut.ShortCut.keys()[shortcut], input_event.as_text()]) - var action := get_shortcut_action(shortcut) - if action != null: - action.update_shortcut(input_event) - else: - register_shortcut(shortcut, input_event) - if property.name() == GdUnitSettings.TEST_DISCOVER_ENABLED: - var timer :SceneTreeTimer = (Engine.get_main_loop() as SceneTree).create_timer(3) - @warning_ignore("return_value_discarded") - timer.timeout.connect(cmd_discover_tests) - - -################################################################################ -# Network stuff -################################################################################ -func _on_client_connected(client_id: int) -> void: - _client_id = client_id - - -func _on_client_disconnected(client_id: int) -> void: - # only stops is not in debug mode running and the current client - if not _running_debug_mode and _client_id == client_id: - cmd_stop(client_id) - _client_id = -1 diff --git a/addons/gdUnit4/src/core/command/GdUnitCommandHandler.gd.uid b/addons/gdUnit4/src/core/command/GdUnitCommandHandler.gd.uid deleted file mode 100644 index 42342b3f..00000000 --- a/addons/gdUnit4/src/core/command/GdUnitCommandHandler.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dooc00u4rahqp diff --git a/addons/gdUnit4/src/core/command/GdUnitShortcut.gd b/addons/gdUnit4/src/core/command/GdUnitShortcut.gd deleted file mode 100644 index 8fac4829..00000000 --- a/addons/gdUnit4/src/core/command/GdUnitShortcut.gd +++ /dev/null @@ -1,52 +0,0 @@ -class_name GdUnitShortcut -extends RefCounted - - -enum ShortCut { - NONE, - RUN_TESTS_OVERALL, - RUN_TESTCASE, - RUN_TESTCASE_DEBUG, - RUN_TESTSUITE, - RUN_TESTSUITE_DEBUG, - RERUN_TESTS, - RERUN_TESTS_DEBUG, - STOP_TEST_RUN, - CREATE_TEST, -} - -const DEFAULTS_MACOS := { - ShortCut.NONE : [], - ShortCut.RUN_TESTCASE : [Key.KEY_META, Key.KEY_ALT, Key.KEY_F5], - ShortCut.RUN_TESTCASE_DEBUG : [Key.KEY_META, Key.KEY_ALT, Key.KEY_F6], - ShortCut.RUN_TESTSUITE : [Key.KEY_META, Key.KEY_ALT, Key.KEY_F5], - ShortCut.RUN_TESTSUITE_DEBUG : [Key.KEY_META, Key.KEY_ALT, Key.KEY_F6], - ShortCut.RUN_TESTS_OVERALL : [Key.KEY_ALT, Key.KEY_F7], - ShortCut.STOP_TEST_RUN : [Key.KEY_ALT, Key.KEY_F8], - ShortCut.RERUN_TESTS : [Key.KEY_ALT, Key.KEY_F5], - ShortCut.RERUN_TESTS_DEBUG : [Key.KEY_ALT, Key.KEY_F6], - ShortCut.CREATE_TEST : [Key.KEY_META, Key.KEY_ALT, Key.KEY_F10], -} - -const DEFAULTS_WINDOWS := { - ShortCut.NONE : [], - ShortCut.RUN_TESTCASE : [Key.KEY_CTRL, Key.KEY_ALT, Key.KEY_F5], - ShortCut.RUN_TESTCASE_DEBUG : [Key.KEY_CTRL,Key.KEY_ALT, Key.KEY_F6], - ShortCut.RUN_TESTSUITE : [Key.KEY_CTRL, Key.KEY_ALT, Key.KEY_F5], - ShortCut.RUN_TESTSUITE_DEBUG : [Key.KEY_CTRL,Key.KEY_ALT, Key.KEY_F6], - ShortCut.RUN_TESTS_OVERALL : [Key.KEY_ALT, Key.KEY_F7], - ShortCut.STOP_TEST_RUN : [Key.KEY_ALT, Key.KEY_F8], - ShortCut.RERUN_TESTS : [Key.KEY_ALT, Key.KEY_F5], - ShortCut.RERUN_TESTS_DEBUG : [Key.KEY_ALT, Key.KEY_F6], - ShortCut.CREATE_TEST : [Key.KEY_CTRL, Key.KEY_ALT, Key.KEY_F10], -} - - -static func default_keys(shortcut :ShortCut) -> PackedInt32Array: - match OS.get_name().to_lower(): - 'windows': - return DEFAULTS_WINDOWS[shortcut] - 'macos': - return DEFAULTS_MACOS[shortcut] - _: - return DEFAULTS_WINDOWS[shortcut] diff --git a/addons/gdUnit4/src/core/command/GdUnitShortcut.gd.uid b/addons/gdUnit4/src/core/command/GdUnitShortcut.gd.uid deleted file mode 100644 index fb7896db..00000000 --- a/addons/gdUnit4/src/core/command/GdUnitShortcut.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bsg0clvy7wf0m diff --git a/addons/gdUnit4/src/core/command/GdUnitShortcutAction.gd b/addons/gdUnit4/src/core/command/GdUnitShortcutAction.gd deleted file mode 100644 index c49e83e5..00000000 --- a/addons/gdUnit4/src/core/command/GdUnitShortcutAction.gd +++ /dev/null @@ -1,40 +0,0 @@ -class_name GdUnitShortcutAction -extends RefCounted - - -func _init(p_type :GdUnitShortcut.ShortCut, p_shortcut :Shortcut, p_command :String) -> void: - assert(p_type != null, "missing parameter 'type'") - assert(p_shortcut != null, "missing parameter 'shortcut'") - assert(p_command != null, "missing parameter 'command'") - self.type = p_type - self.shortcut = p_shortcut - self.command = p_command - - -var type: GdUnitShortcut.ShortCut: - set(value): - type = value - get: - return type - - -var shortcut: Shortcut: - set(value): - shortcut = value - get: - return shortcut - - -var command: String: - set(value): - command = value - get: - return command - - -func update_shortcut(input_event: InputEventKey) -> void: - shortcut.set_events([input_event]) - - -func _to_string() -> String: - return "GdUnitShortcutAction: %s (%s) -> %s" % [GdUnitShortcut.ShortCut.keys()[type], shortcut.get_as_text(), command] diff --git a/addons/gdUnit4/src/core/command/GdUnitShortcutAction.gd.uid b/addons/gdUnit4/src/core/command/GdUnitShortcutAction.gd.uid deleted file mode 100644 index 286b4d5d..00000000 --- a/addons/gdUnit4/src/core/command/GdUnitShortcutAction.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cmlh3hniafm5s diff --git a/addons/gdUnit4/src/core/discovery/GdUnitGUID.gd b/addons/gdUnit4/src/core/discovery/GdUnitGUID.gd deleted file mode 100644 index 00332f90..00000000 --- a/addons/gdUnit4/src/core/discovery/GdUnitGUID.gd +++ /dev/null @@ -1,46 +0,0 @@ -## A class representing a globally unique identifier for GdUnit test elements. -## Uses random values to generate unique identifiers that can be used -## to track and reference test cases and suites across the test framework. -class_name GdUnitGUID -extends RefCounted - - -## The internal string representation of the GUID. -## Generated using Godot's ResourceUID system when no existing GUID is provided. -var _guid: String - - -## Creates a new GUID instance. -## If no GUID is provided, generates a new one using Godot's ResourceUID system. -func _init(from_guid: String = "") -> void: - if from_guid.is_empty(): - _guid = _generate_guid() - else: - _guid = from_guid - - -## Compares this GUID with another for equality. -## Returns true if both GUIDs represent the same unique identifier. -func equals(other: GdUnitGUID) -> bool: - return other._guid == _guid - - -## Generates a custom GUID using random bytes.[br] -## The format uses 16 random bytes encoded to hex and formatted with hyphens. -static func _generate_guid() -> String: - # Pre-allocate array with exact size needed - var bytes := PackedByteArray() - bytes.resize(16) - - # Fill with random bytes - for i in range(16): - bytes[i] = randi() % 256 - - bytes[6] = (bytes[6] & 0x0f) | 0x40 - bytes[8] = (bytes[8] & 0x3f) | 0x80 - - return bytes.hex_encode().insert(8, "-").insert(16, "-").insert(24, "-") - - -func _to_string() -> String: - return _guid diff --git a/addons/gdUnit4/src/core/discovery/GdUnitGUID.gd.uid b/addons/gdUnit4/src/core/discovery/GdUnitGUID.gd.uid deleted file mode 100644 index 08f1f325..00000000 --- a/addons/gdUnit4/src/core/discovery/GdUnitGUID.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://d4lobvde8tufj diff --git a/addons/gdUnit4/src/core/discovery/GdUnitTestCase.gd b/addons/gdUnit4/src/core/discovery/GdUnitTestCase.gd deleted file mode 100644 index 766f9eab..00000000 --- a/addons/gdUnit4/src/core/discovery/GdUnitTestCase.gd +++ /dev/null @@ -1,125 +0,0 @@ -## GdUnitTestCase -## A class representing a single test case in GdUnit4. -## This class is used as a data container to hold all relevant information about a test case, -## including its location, dependencies, and metadata for test discovery and execution. - -class_name GdUnitTestCase -extends RefCounted - -## A unique identifier for the test case. Used to track and reference specific test instances. -var guid := GdUnitGUID.new() - -## The resource path to the test suite -var suite_resource_path: String - -## The name of the test method/function. Should start with "test_" prefix. -var test_name: String - -## The class name of the test suite containing this test case. -var suite_name: String - -## The fully qualified name of the test case following C# namespace pattern: -## Constructed from the folder path (where folders are dot-separated), the test suite name, and the test case name. -## All parts are joined by dots: {folder1.folder2.folder3}.{suite_name}.{test_name} -var fully_qualified_name: String - -var display_name: String - -## Index tracking test attributes for ordered execution. Default is 0. -## Higher values indicate later execution in the test sequence. -var attribute_index: int - -## Flag indicating if this test requires the Godot runtime environment. -## Tests requiring runtime cannot be executed in isolation. -var require_godot_runtime: bool = true - -## The path to the source file containing this test case. -## Used for test discovery and execution. -var source_file: String - -## Optional holds the assembly location for C# tests -var assembly_location: String = "" - -## The line number where the test case is defined in the source file. -## Used for navigation and error reporting. -var line_number: int = -1 - -## Additional metadata about the test case, such as: -## - tags: Array[String] - Test categories/tags for filtering -## - timeout: int - Maximum execution time in milliseconds -## - skip: bool - Whether the test should be skipped -## - dependencies: Array[String] - Required test dependencies -var metadata: Dictionary = {} - - -static func from_dict(dict: Dictionary) -> GdUnitTestCase: - var test := GdUnitTestCase.new() - test.guid = GdUnitGUID.new(str(dict["guid"])) - test.suite_resource_path = dict["suite_resource_path"] if dict.has("suite_resource_path") else dict["source_file"] - test.suite_name = dict["managed_type"] - test.test_name = dict["test_name"] - test.display_name = dict["simple_name"] - test.fully_qualified_name = dict["fully_qualified_name"] - test.attribute_index = dict["attribute_index"] - test.source_file = dict["source_file"] - test.line_number = dict["line_number"] - test.require_godot_runtime = dict["require_godot_runtime"] - test.assembly_location = dict["assembly_location"] - return test - - -static func to_dict(test: GdUnitTestCase) -> Dictionary: - return { - "guid": test.guid._guid, - "suite_resource_path": test.suite_resource_path, - "managed_type": test.suite_name, - "test_name" : test.test_name, - "simple_name" : test.display_name, - "fully_qualified_name" : test.fully_qualified_name, - "attribute_index" : test.attribute_index, - "source_file" : test.source_file, - "line_number" : test.line_number, - "require_godot_runtime" : test.require_godot_runtime, - "assembly_location" : test.assembly_location - } - - -static func from(_suite_resource_path: String, _source_file: String, _line_number: int, _test_name: String, _attribute_index := -1, _test_parameters := "") -> GdUnitTestCase: - if(_source_file == null or _source_file.is_empty()): - prints(_test_name) - - assert(_test_name != null and not _test_name.is_empty(), "Precondition: The parameter 'test_name' is not set") - assert(_source_file != null and not _source_file.is_empty(), "Precondition: The parameter 'source_file' is not set") - - var test := GdUnitTestCase.new() - test.suite_resource_path = _suite_resource_path - test.test_name = _test_name - test.source_file = _source_file - test.line_number = _line_number - test.attribute_index = _attribute_index - test._build_suite_name() - test._build_display_name(_test_parameters) - test._build_fully_qualified_name(_suite_resource_path) - return test - - -func _build_suite_name() -> void: - suite_name = source_file.get_file().get_basename() - assert(suite_name != null and not suite_name.is_empty(), "Precondition: The parameter 'suite_name' can't be resolved") - - -func _build_display_name(_test_parameters: String) -> void: - if attribute_index == -1: - display_name = test_name - else: - display_name = "%s:%d (%s)" % [test_name, attribute_index, _test_parameters.trim_prefix("[").trim_suffix("]").replace('"', "'")] - - -func _build_fully_qualified_name(_resource_path: String) -> void: - var name_space := _resource_path.trim_prefix("res://").trim_suffix(".gd").trim_suffix(".cs").replace("/", ".") - - if attribute_index == -1: - fully_qualified_name = "%s.%s" % [name_space, test_name] - else: - fully_qualified_name = "%s.%s.%s" % [name_space, test_name, display_name] - assert(fully_qualified_name != null and not fully_qualified_name.is_empty(), "Precondition: The parameter 'fully_qualified_name' can't be resolved") diff --git a/addons/gdUnit4/src/core/discovery/GdUnitTestCase.gd.uid b/addons/gdUnit4/src/core/discovery/GdUnitTestCase.gd.uid deleted file mode 100644 index 8cfe8d7d..00000000 --- a/addons/gdUnit4/src/core/discovery/GdUnitTestCase.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://i4kgxeu6rjiv diff --git a/addons/gdUnit4/src/core/discovery/GdUnitTestDiscoverGuard.gd b/addons/gdUnit4/src/core/discovery/GdUnitTestDiscoverGuard.gd deleted file mode 100644 index 6af8255a..00000000 --- a/addons/gdUnit4/src/core/discovery/GdUnitTestDiscoverGuard.gd +++ /dev/null @@ -1,323 +0,0 @@ -## Guards and tracks test case changes during test discovery and file modifications.[br] -## [br] -## This guard maintains a cache of discovered tests to track changes between test runs and during[br] -## file modifications. It is optimized for performance using simple but effective test identity checks.[br] -## [br] -## Test Change Detection:[br] -## - Moved tests: The test implementation remains at a different line number[br] -## - Renamed tests: The test line position remains but the test name changed[br] -## - Deleted tests: A previously discovered test was removed[br] -## - Added tests: A new test was discovered[br] -## [br] -## Cache Management:[br] -## - Maintains test identity through unique GdUnitTestCase GUIDs[br] -## - Maps source files to their discovered test cases[br] -## - Tracks only essential metadata (line numbers, names) to minimize memory use[br] -## [br] -## Change Detection Strategy:[br] -## The guard uses a lightweight approach by comparing only line numbers and test names.[br] -## This avoids expensive operations like test content parsing or similarity checks.[br] -## [br] -## Event Handling:[br] -## - Emits events on test changes through GdUnitSignals[br] -## - Synchronizes cache with test discovery events[br] -## - Notifies UI about test changes[br] -## [br] -## Example usage:[br] -## [codeblock] -## # Create guard for tracking test changes -## var guard := GdUnitTestDiscoverGuard.new() -## -## # Connect to test discovery events -## GdUnitSignals.instance().gdunit_test_discovered.connect(guard.sync_test_added) -## -## # Discover tests and track changes -## await guard.discover(test_script) -## [/codeblock] -class_name GdUnitTestDiscoverGuard -extends Object - - - -static func instance() -> GdUnitTestDiscoverGuard: - return GdUnitSingleton.instance("GdUnitTestDiscoverGuard", func() -> GdUnitTestDiscoverGuard: - return GdUnitTestDiscoverGuard.new() - ) - - -## Maps source files to their discovered test cases.[br] -## [br] -## Key: Test suite source file path[br] -## Value: Array of [class GdUnitTestCase] instances -var _discover_cache := {} - - -## Tracks discovered test changes for debug purposes.[br] -## [br] -## Available in debug mode only. Contains dictionaries:[br] -## - changed_tests: Tests that were moved or renamed[br] -## - deleted_tests: Tests that were removed[br] -## - added_tests: New tests that were discovered -var _discovered_changes := {} - - -## Controls test change debug tracking.[br] -## [br] -## When true, maintains _discovered_changes for debugging.[br] -## Used primarily in tests to verify change detection. -var _is_debug := false - - -## Creates a new guard instance.[br] -## [br] -## [param is_debug] When true, enables change tracking for debugging. -func _init(is_debug := false) -> void: - _is_debug = is_debug - # Register for discovery events to sync the cache - @warning_ignore("return_value_discarded") - GdUnitSignals.instance().gdunit_test_discover_added.connect(sync_test_added) - GdUnitSignals.instance().gdunit_test_discover_deleted.connect(sync_test_deleted) - GdUnitSignals.instance().gdunit_test_discover_modified.connect(sync_test_modified) - GdUnitSignals.instance().gdunit_event.connect(handle_discover_events) - - -## Adds a discovered test to the cache.[br] -## [br] -## [param test_case] The test case to add to the cache. -func sync_test_added(test_case: GdUnitTestCase) -> void: - var test_cases: Array[GdUnitTestCase] = _discover_cache.get_or_add(test_case.source_file, Array([], TYPE_OBJECT, "RefCounted", GdUnitTestCase)) - test_cases.append(test_case) - - -## Removes a test from the cache.[br] -## [br] -## [param test_case] The test case to remove from the cache. -func sync_test_deleted(test_case: GdUnitTestCase) -> void: - var test_cases: Array[GdUnitTestCase] = _discover_cache.get_or_add(test_case.source_file, Array([], TYPE_OBJECT, "RefCounted", GdUnitTestCase)) - test_cases.erase(test_case) - - -## Updates a test from the cache.[br] -## [br] -## [param test_case] The test case to update from the cache. -func sync_test_modified(changed_test: GdUnitTestCase) -> void: - var test_cases: Array[GdUnitTestCase] = _discover_cache.get_or_add(changed_test.source_file, Array([], TYPE_OBJECT, "RefCounted", GdUnitTestCase)) - for test in test_cases: - if test.guid == changed_test.guid: - test.test_name = changed_test.test_name - test.display_name = changed_test.display_name - test.line_number = changed_test.line_number - break - - -## Handles test discovery events.[br] -## [br] -## Resets the cache when a new discovery starts.[br] -## [param event] The discovery event to handle. -func handle_discover_events(event: GdUnitEvent) -> void: - # reset the cache on fresh discovery - if event.type() == GdUnitEvent.DISCOVER_START: - _discover_cache = {} - - -## Registers a callback for discovered tests.[br] -## [br] -## Default sink writes to [class GdUnitTestDiscoverSink]. -static func default_discover_sink(test_case: GdUnitTestCase) -> void: - GdUnitTestDiscoverSink.discover(test_case) - - -## Finds a test case by its unique identifier.[br] -## [br] -## Searches through all cached test cases across all test suites[br] -## to find a test with the matching GUID.[br] -## [br] -## [param id] The GUID of the test to find[br] -## Returns the matching test case or null if not found. -func find_test_by_id(id: GdUnitGUID) -> GdUnitTestCase: - for test_sets: Array[GdUnitTestCase] in _discover_cache.values(): - for test in test_sets: - if test.guid.equals(id): - return test - - return null - - -func get_discovered_tests() -> Array[GdUnitTestCase]: - var discovered_tests: Array[GdUnitTestCase] = [] - for test_sets: Array[GdUnitTestCase] in _discover_cache.values(): - discovered_tests.append_array(test_sets) - return discovered_tests - - -## Discovers tests in a script and tracks changes.[br] -## [br] -## Handles both GDScript and C# test suites.[br] -## The guard maintains test identity through changes.[br] -## [br] -## [param script] The test script to analyze[br] -## [param discover_sink] Optional callback for test discovery events -func discover(script: Script, discover_sink: Callable = default_discover_sink) -> void: - # Verify the script has no errors before run test discovery - var result := script.reload(true) - if result != OK: - return - - if _is_debug: - _discovered_changes["changed_tests"] = Array([], TYPE_OBJECT, "RefCounted", GdUnitTestCase) - _discovered_changes["deleted_tests"] = Array([], TYPE_OBJECT, "RefCounted", GdUnitTestCase) - _discovered_changes["added_tests"] = Array([], TYPE_OBJECT, "RefCounted", GdUnitTestCase) - - if GdUnitTestSuiteScanner.is_test_suite(script): - # for cs scripts we need to recomplie before discover new tests - if script.get_class() == "CSharpScript": - await rebuild_project(script) - - # rediscover all tests - var source_file := script.resource_path - var discovered_tests: Array[GdUnitTestCase] = [] - - GdUnitTestDiscoverer.discover_tests(script, func(test_case: GdUnitTestCase) -> void: - discovered_tests.append(test_case) - ) - - # The suite is never discovered, we add all discovered tests - if not _discover_cache.has(source_file): - for test_case in discovered_tests: - discover_sink.call(test_case) - return - - sync_moved_tests(source_file, discovered_tests) - sync_renamed_tests(source_file, discovered_tests) - sync_deleted_tests(source_file, discovered_tests) - sync_added_tests(source_file, discovered_tests, discover_sink) - - -## Synchronizes moved tests between discover cycles.[br] -## [br] -## A test is considered moved when:[br] -## - It has the same name[br] -## - But a different line number[br] -## [br] -## [param source_file] suite source path[br] -## [param discovered_tests] Newly discovered tests -func sync_moved_tests(source_file: String, discovered_tests: Array[GdUnitTestCase]) -> void: - @warning_ignore("unsafe_method_access") - var cache: Array[GdUnitTestCase] = _discover_cache.get(source_file).duplicate() - for discovered_test in discovered_tests: - # lookup in cache - var original_tests: Array[GdUnitTestCase] = cache.filter(is_test_moved.bind(discovered_test)) - for test in original_tests: - # update the line_number - var line_number_before := test.line_number - test.line_number = discovered_test.line_number - GdUnitSignals.instance().gdunit_test_discover_modified.emit(test) - if _is_debug: - prints("-> moved test id:%s %s: line:(%d -> %d)" % [test.guid, test.display_name, line_number_before, test.line_number]) - @warning_ignore("unsafe_method_access") - _discovered_changes.get_or_add("changed_tests", Array([], TYPE_OBJECT, "RefCounted", GdUnitTestCase)).append(test) - - -## Synchronizes renamed tests between discover cycles.[br] -## [br] -## A test is considered renamed when:[br] -## - It has the same line number[br] -## - But a different name[br] -## [br] -## [param source_file] suite source path[br] -## [param discovered_tests] Newly discovered tests -func sync_renamed_tests(source_file: String, discovered_tests: Array[GdUnitTestCase]) -> void: - @warning_ignore("unsafe_method_access") - var cache: Array[GdUnitTestCase] = _discover_cache.get(source_file).duplicate() - for discovered_test in discovered_tests: - # lookup in cache - var original_tests: Array[GdUnitTestCase] = cache.filter(is_test_renamed.bind(discovered_test)) - for test in original_tests: - # update the renaming names - var original_display_name := test.display_name - test.test_name = discovered_test.test_name - test.display_name = discovered_test.display_name - GdUnitSignals.instance().gdunit_test_discover_modified.emit(test) - if _is_debug: - prints("-> renamed test id:%s %s -> %s" % [test.guid, original_display_name, test.display_name]) - @warning_ignore("unsafe_method_access") - _discovered_changes.get_or_add("changed_tests", Array([], TYPE_OBJECT, "RefCounted", GdUnitTestCase)).append(test) - - -## Synchronizes deleted tests between discover cycles.[br] -## [br] -## A test is considered deleted when:[br] -## - It exists in the cache[br] -## - But is not found in the newly discovered tests[br] -## [br] -## [param source_file] suite source path[br] -## [param discovered_tests] Newly discovered tests -func sync_deleted_tests(source_file: String, discovered_tests: Array[GdUnitTestCase]) -> void: - @warning_ignore("unsafe_method_access") - var cache: Array[GdUnitTestCase] = _discover_cache.get(source_file).duplicate() - # lookup in cache - for test in cache: - if not discovered_tests.any(test_equals.bind(test)): - GdUnitSignals.instance().gdunit_test_discover_deleted.emit(test) - if _is_debug: - prints("-> deleted test id:%s %s:%d" % [test.guid, test.display_name, test.line_number]) - @warning_ignore("unsafe_method_access") - _discovered_changes.get_or_add("deleted_tests", Array([], TYPE_OBJECT, "RefCounted", GdUnitTestCase)).append(test) - - -## Synchronizes newly added tests between discover cycles.[br] -## [br] -## A test is considered added when:[br] -## - It exists in the newly discovered tests[br] -## - But is not found in the cache[br] -## [br] -## [param source_file] suite source path[br] -## [param discovered_tests] Newly discovered tests[br] -## [param discover_sink] Callback to handle newly discovered tests -func sync_added_tests(source_file: String, discovered_tests: Array[GdUnitTestCase], discover_sink: Callable) -> void: - @warning_ignore("unsafe_method_access") - var cache: Array[GdUnitTestCase] = _discover_cache.get(source_file).duplicate() - # lookup in cache - for test in discovered_tests: - if not cache.any(test_equals.bind(test)): - discover_sink.call(test) - if _is_debug: - prints("-> added test id:%s %s:%d" % [test.guid, test.display_name, test.line_number]) - @warning_ignore("unsafe_method_access") - _discovered_changes.get_or_add("added_tests", Array([], TYPE_OBJECT, "RefCounted", GdUnitTestCase)).append(test) - - -func is_test_renamed(left: GdUnitTestCase, right: GdUnitTestCase) -> bool: - return left.line_number == right.line_number and left.test_name != right.test_name - - -func is_test_moved(left: GdUnitTestCase, right: GdUnitTestCase) -> bool: - return left.line_number != right.line_number and left.test_name == right.test_name - - -func test_equals(left: GdUnitTestCase, right: GdUnitTestCase) -> bool: - return left.display_name == right.display_name - - -# do rebuild the entire project, there is actual no way to enforce the Godot engine itself to do this -func rebuild_project(script: Script) -> void: - var class_path := ProjectSettings.globalize_path(script.resource_path) - print_rich("[color=CORNFLOWER_BLUE]GdUnitTestDiscoverGuard: CSharpScript change detected on: '%s' [/color]" % class_path) - var scene_tree := Engine.get_main_loop() as SceneTree - await scene_tree.process_frame - - var output := [] - var exit_code := OS.execute("dotnet", ["--version"], output) - if exit_code == -1: - print_rich("[color=CORNFLOWER_BLUE]GdUnitTestDiscoverGuard:[/color] [color=RED]Rebuild the project failed.[/color]") - print_rich("[color=CORNFLOWER_BLUE]GdUnitTestDiscoverGuard:[/color] [color=RED]Can't find installed `dotnet`! Please check your environment is setup correctly.[/color]") - return - - print_rich("[color=CORNFLOWER_BLUE]GdUnitTestDiscoverGuard:[/color] [color=DEEP_SKY_BLUE]Found dotnet v%s[/color]" % str(output[0]).strip_edges()) - output.clear() - - exit_code = OS.execute("dotnet", ["build"], output) - print_rich("[color=CORNFLOWER_BLUE]GdUnitTestDiscoverGuard:[/color] [color=DEEP_SKY_BLUE]Rebuild the project ... [/color]") - for out: String in output: - print_rich("[color=DEEP_SKY_BLUE] %s" % out.strip_edges()) - await scene_tree.process_frame diff --git a/addons/gdUnit4/src/core/discovery/GdUnitTestDiscoverGuard.gd.uid b/addons/gdUnit4/src/core/discovery/GdUnitTestDiscoverGuard.gd.uid deleted file mode 100644 index 788ede26..00000000 --- a/addons/gdUnit4/src/core/discovery/GdUnitTestDiscoverGuard.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cojycdwxjbkf3 diff --git a/addons/gdUnit4/src/core/discovery/GdUnitTestDiscoverSink.gd b/addons/gdUnit4/src/core/discovery/GdUnitTestDiscoverSink.gd deleted file mode 100644 index 5d0e5b68..00000000 --- a/addons/gdUnit4/src/core/discovery/GdUnitTestDiscoverSink.gd +++ /dev/null @@ -1,13 +0,0 @@ -## A static utility class that acts as a central sink for test case discovery events in GdUnit4. -## Instead of implementing custom sink classes, test discovery consumers should connect to -## the GdUnitSignals.gdunit_test_discovered signal to receive test case discoveries. -## This design allows for a more flexible and decoupled test discovery system. -class_name GdUnitTestDiscoverSink -extends RefCounted - - -## Emits a discovered test case through the GdUnitSignals system.[br] -## Sends the test case to all listeners connected to the gdunit_test_discovered signal.[br] -## [member test_case] The discovered test case to be broadcast to all connected listeners. -static func discover(test_case: GdUnitTestCase) -> void: - GdUnitSignals.instance().gdunit_test_discover_added.emit(test_case) diff --git a/addons/gdUnit4/src/core/discovery/GdUnitTestDiscoverSink.gd.uid b/addons/gdUnit4/src/core/discovery/GdUnitTestDiscoverSink.gd.uid deleted file mode 100644 index 648ab17b..00000000 --- a/addons/gdUnit4/src/core/discovery/GdUnitTestDiscoverSink.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ct0kk6824vhxf diff --git a/addons/gdUnit4/src/core/discovery/GdUnitTestDiscoverer.gd b/addons/gdUnit4/src/core/discovery/GdUnitTestDiscoverer.gd deleted file mode 100644 index cb3e4071..00000000 --- a/addons/gdUnit4/src/core/discovery/GdUnitTestDiscoverer.gd +++ /dev/null @@ -1,171 +0,0 @@ -class_name GdUnitTestDiscoverer -extends RefCounted - - -static func run() -> Array[GdUnitTestCase]: - console_log("Running test discovery ..") - await (Engine.get_main_loop() as SceneTree).process_frame - GdUnitSignals.instance().gdunit_event.emit(GdUnitEventTestDiscoverStart.new()) - - # We run the test discovery in an extra thread so that the main thread is not blocked - var t:= Thread.new() - @warning_ignore("return_value_discarded") - t.start(func () -> Array[GdUnitTestCase]: - # Loading previous test session - var runner_config := GdUnitRunnerConfig.new() - runner_config.load_config() - var recovered_tests := runner_config.test_cases() - var test_suite_directories := scan_all_test_directories(GdUnitSettings.test_root_folder()) - var scanner := GdUnitTestSuiteScanner.new() - - var collected_tests: Array[GdUnitTestCase] = [] - var collected_test_suites: Array[Script] = [] - # collect test suites - for test_suite_dir in test_suite_directories: - collected_test_suites.append_array(scanner.scan_directory(test_suite_dir)) - - # Do sync the main thread before emit the discovered test suites to the inspector - await (Engine.get_main_loop() as SceneTree).process_frame - for test_suites_script in collected_test_suites: - discover_tests(test_suites_script, func(test_case: GdUnitTestCase) -> void: - # Sync test uid from last test session - recover_test_guid(test_case, recovered_tests) - collected_tests.append(test_case) - GdUnitTestDiscoverSink.discover(test_case) - ) - - console_log_discover_results(collected_tests) - if !recovered_tests.is_empty(): - console_log("Recovered last test session successfully, %d tests restored." % recovered_tests.size(), true) - return collected_tests - ) - # wait unblocked to the tread is finished - while t.is_alive(): - await (Engine.get_main_loop() as SceneTree).process_frame - # needs finally to wait for finish - var test_to_execute: Array[GdUnitTestCase] = await t.wait_to_finish() - GdUnitSignals.instance().gdunit_event.emit(GdUnitEventTestDiscoverEnd.new(0, 0)) - return test_to_execute - - -## Restores the last test run session by loading the test run config file and rediscover the tests -static func restore_last_session() -> void: - if GdUnitSettings.is_test_discover_enabled(): - return - - var runner_config := GdUnitRunnerConfig.new() - var result := runner_config.load_config() - # Report possible config loading errors - if result.is_error(): - console_log("Recovery of the last test session failed: %s" % result.error_message(), true) - # If no config file found, skip test recovery - if result.is_warn(): - return - - # If no tests recorded, skip test recovery - var test_cases := runner_config.test_cases() - if test_cases.size() == 0: - return - - # We run the test session restoring in an extra thread so that the main thread is not blocked - var t:= Thread.new() - t.start(func () -> void: - # Do sync the main thread before emit the discovered test suites to the inspector - await (Engine.get_main_loop() as SceneTree).process_frame - console_log("Recovering last test session ..", true) - GdUnitSignals.instance().gdunit_event.emit(GdUnitEventTestDiscoverStart.new()) - for test_case in test_cases: - GdUnitTestDiscoverSink.discover(test_case) - GdUnitSignals.instance().gdunit_event.emit(GdUnitEventTestDiscoverEnd.new(0, 0)) - console_log("Recovered last test session successfully, %d tests restored." % test_cases.size(), true) - ) - t.wait_to_finish() - - -static func recover_test_guid(current: GdUnitTestCase, recovered_tests: Array[GdUnitTestCase]) -> void: - for recovered_test in recovered_tests: - if recovered_test.fully_qualified_name == current.fully_qualified_name: - current.guid = recovered_test.guid - - -static func console_log_discover_results(tests: Array[GdUnitTestCase]) -> void: - var grouped_by_suites := GdArrayTools.group_by(tests, func(test: GdUnitTestCase) -> String: - return test.source_file - ) - for suite_tests: Array in grouped_by_suites.values(): - var test_case: GdUnitTestCase = suite_tests[0] - console_log("Discover: TestSuite %s with %d tests found" % [test_case.source_file, suite_tests.size()]) - console_log("Discover tests done, %d TestSuites and total %d Tests found. " % [grouped_by_suites.size(), tests.size()]) - console_log("") - - -static func console_log(message: String, on_console := false) -> void: - prints(message) - if on_console: - GdUnitSignals.instance().gdunit_message.emit(message) - - -static func filter_tests(method: Dictionary) -> bool: - var method_name: String = method["name"] - return method_name.begins_with("test_") - - -static func default_discover_sink(test_case: GdUnitTestCase) -> void: - GdUnitTestDiscoverSink.discover(test_case) - - -static func discover_tests(source_script: Script, discover_sink := default_discover_sink) -> void: - if source_script is GDScript: - var test_names := source_script.get_script_method_list()\ - .filter(filter_tests)\ - .map(func(method: Dictionary) -> String: return method["name"]) - # no tests discovered? - if test_names.is_empty(): - return - - var parser := GdScriptParser.new() - var fds := parser.get_function_descriptors(source_script as GDScript, test_names) - for fd in fds: - var resolver := GdFunctionParameterSetResolver.new(fd) - for test_case in resolver.resolve_test_cases(source_script as GDScript): - discover_sink.call(test_case) - elif source_script.get_class() == "CSharpScript": - if not GdUnit4CSharpApiLoader.is_api_loaded(): - return - for test_case in GdUnit4CSharpApiLoader.discover_tests(source_script): - discover_sink.call(test_case) - - -static func scan_all_test_directories(root: String) -> PackedStringArray: - var base_directory := "res://" - # If the test root folder is configured as blank, "/", or "res://", use the root folder as described in the settings panel - if root.is_empty() or root == "/" or root == base_directory: - return [base_directory] - return scan_test_directories(base_directory, root, []) - - -static func scan_test_directories(base_directory: String, test_directory: String, test_suite_paths: PackedStringArray) -> PackedStringArray: - print_verbose("Scannning for test directory '%s' at %s" % [test_directory, base_directory]) - for directory in DirAccess.get_directories_at(base_directory): - if directory.begins_with("."): - continue - var current_directory := normalize_path(base_directory + "/" + directory) - if FileAccess.file_exists(current_directory + "/.gdignore"): - continue - if GdUnitTestSuiteScanner.exclude_scan_directories.has(current_directory): - continue - if match_test_directory(directory, test_directory): - @warning_ignore("return_value_discarded") - test_suite_paths.append(current_directory) - else: - @warning_ignore("return_value_discarded") - scan_test_directories(current_directory, test_directory, test_suite_paths) - return test_suite_paths - - -static func normalize_path(path: String) -> String: - return path.replace("///", "//") - - -static func match_test_directory(directory: String, test_directory: String) -> bool: - return directory == test_directory or test_directory.is_empty() or test_directory == "/" or test_directory == "res://" diff --git a/addons/gdUnit4/src/core/discovery/GdUnitTestDiscoverer.gd.uid b/addons/gdUnit4/src/core/discovery/GdUnitTestDiscoverer.gd.uid deleted file mode 100644 index acb1b090..00000000 --- a/addons/gdUnit4/src/core/discovery/GdUnitTestDiscoverer.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://uakc3vyaaagr diff --git a/addons/gdUnit4/src/core/event/GdUnitEvent.gd b/addons/gdUnit4/src/core/event/GdUnitEvent.gd deleted file mode 100644 index 6bec1059..00000000 --- a/addons/gdUnit4/src/core/event/GdUnitEvent.gd +++ /dev/null @@ -1,206 +0,0 @@ -class_name GdUnitEvent -extends Resource - -const WARNINGS = "warnings" -const FAILED = "failed" -const FLAKY = "flaky" -const ERRORS = "errors" -const SKIPPED = "skipped" -const ELAPSED_TIME = "elapsed_time" -const ORPHAN_NODES = "orphan_nodes" -const ERROR_COUNT = "error_count" -const FAILED_COUNT = "failed_count" -const SKIPPED_COUNT = "skipped_count" -const RETRY_COUNT = "retry_count" - -enum { - INIT, - STOP, - TESTSUITE_BEFORE, - TESTSUITE_AFTER, - TESTCASE_BEFORE, - TESTCASE_AFTER, - DISCOVER_START, - DISCOVER_END, - SESSION_START, - SESSION_CLOSE -} - -var _event_type: int -var _guid: GdUnitGUID -var _resource_path: String -var _suite_name: String -var _test_name: String -var _total_count: int = 0 -var _statistics := Dictionary() -var _reports: Array[GdUnitReport] = [] - - -func suite_before(p_resource_path: String, p_suite_name: String, p_total_count: int) -> GdUnitEvent: - _guid = GdUnitGUID.new() - _event_type = TESTSUITE_BEFORE - _resource_path = p_resource_path - _suite_name = p_suite_name - _test_name = "before" - _total_count = p_total_count - return self - - -func suite_after(p_resource_path: String, p_suite_name: String, p_statistics: Dictionary = {}, p_reports: Array[GdUnitReport] = []) -> GdUnitEvent: - _guid = GdUnitGUID.new() - _event_type = TESTSUITE_AFTER - _resource_path = p_resource_path - _suite_name = p_suite_name - _test_name = "after" - _statistics = p_statistics - _reports = p_reports - return self - - -func test_before(p_guid: GdUnitGUID) -> GdUnitEvent: - _event_type = TESTCASE_BEFORE - _guid = p_guid - return self - - -func test_after(p_guid: GdUnitGUID, p_statistics: Dictionary = {}, p_reports :Array[GdUnitReport] = []) -> GdUnitEvent: - _event_type = TESTCASE_AFTER - _guid = p_guid - _statistics = p_statistics - _reports = p_reports - return self - - -func type() -> int: - return _event_type - - -func guid() -> GdUnitGUID: - return _guid - - -func suite_name() -> String: - return _suite_name - - -func test_name() -> String: - return _test_name - - -func elapsed_time() -> int: - return _statistics.get(ELAPSED_TIME, 0) - - -func orphan_nodes() -> int: - return _statistics.get(ORPHAN_NODES, 0) - - -func statistic(p_type :String) -> int: - return _statistics.get(p_type, 0) - - -func total_count() -> int: - return _total_count - - -func success_count() -> int: - return total_count() - error_count() - failed_count() - skipped_count() - - -func error_count() -> int: - return _statistics.get(ERROR_COUNT, 0) - - -func failed_count() -> int: - return _statistics.get(FAILED_COUNT, 0) - - -func skipped_count() -> int: - return _statistics.get(SKIPPED_COUNT, 0) - - -func retry_count() -> int: - return _statistics.get(RETRY_COUNT, 0) - - -func resource_path() -> String: - return _resource_path - - -func is_success() -> bool: - return not is_failed() and not is_error() - - -func is_warning() -> bool: - return _statistics.get(WARNINGS, false) - - -func is_failed() -> bool: - return _statistics.get(FAILED, false) - - -func is_error() -> bool: - return _statistics.get(ERRORS, false) - - -func is_flaky() -> bool: - return _statistics.get(FLAKY, false) - - -func is_skipped() -> bool: - return _statistics.get(SKIPPED, false) - - -func reports() -> Array[GdUnitReport]: - return _reports - - -func _to_string() -> String: - return "Event: %s id:%s %s:%s, %s, %s" % [_event_type, _guid, _suite_name, _test_name, _statistics, _reports] - - -func serialize() -> Dictionary: - var serialized := { - "type" : _event_type, - "resource_path": _resource_path, - "suite_name" : _suite_name, - "test_name" : _test_name, - "total_count" : _total_count, - "statistics" : _statistics - } - if _guid != null: - serialized["guid"] = _guid._guid - serialized["reports"] = _serialize_TestReports() - return serialized - - -func deserialize(serialized: Dictionary) -> GdUnitEvent: - _event_type = serialized.get("type", null) - _guid = GdUnitGUID.new(str(serialized.get("guid", ""))) - _resource_path = serialized.get("resource_path", null) - _suite_name = serialized.get("suite_name", null) - _test_name = serialized.get("test_name", "unknown") - _total_count = serialized.get("total_count", 0) - _statistics = serialized.get("statistics", Dictionary()) - if serialized.has("reports"): - # needs this workaround to copy typed values in the array - var reports_to_deserializ :Array[Dictionary] = [] - @warning_ignore("unsafe_cast") - reports_to_deserializ.append_array(serialized.get("reports") as Array) - _reports = _deserialize_reports(reports_to_deserializ) - return self - - -func _serialize_TestReports() -> Array[Dictionary]: - var serialized_reports :Array[Dictionary] = [] - for report in _reports: - serialized_reports.append(report.serialize()) - return serialized_reports - - -func _deserialize_reports(p_reports: Array[Dictionary]) -> Array[GdUnitReport]: - var deserialized_reports :Array[GdUnitReport] = [] - for report in p_reports: - var test_report := GdUnitReport.new().deserialize(report) - deserialized_reports.append(test_report) - return deserialized_reports diff --git a/addons/gdUnit4/src/core/event/GdUnitEvent.gd.uid b/addons/gdUnit4/src/core/event/GdUnitEvent.gd.uid deleted file mode 100644 index 8a259172..00000000 --- a/addons/gdUnit4/src/core/event/GdUnitEvent.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c4wkq83n4a4bk diff --git a/addons/gdUnit4/src/core/event/GdUnitEventInit.gd b/addons/gdUnit4/src/core/event/GdUnitEventInit.gd deleted file mode 100644 index 774e7d4f..00000000 --- a/addons/gdUnit4/src/core/event/GdUnitEventInit.gd +++ /dev/null @@ -1,6 +0,0 @@ -class_name GdUnitInit -extends GdUnitEvent - - -func _init() -> void: - _event_type = INIT diff --git a/addons/gdUnit4/src/core/event/GdUnitEventInit.gd.uid b/addons/gdUnit4/src/core/event/GdUnitEventInit.gd.uid deleted file mode 100644 index a7e1498a..00000000 --- a/addons/gdUnit4/src/core/event/GdUnitEventInit.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c8t36rmkcsvqm diff --git a/addons/gdUnit4/src/core/event/GdUnitEventStop.gd b/addons/gdUnit4/src/core/event/GdUnitEventStop.gd deleted file mode 100644 index d7a3c11c..00000000 --- a/addons/gdUnit4/src/core/event/GdUnitEventStop.gd +++ /dev/null @@ -1,6 +0,0 @@ -class_name GdUnitStop -extends GdUnitEvent - - -func _init() -> void: - _event_type = STOP diff --git a/addons/gdUnit4/src/core/event/GdUnitEventStop.gd.uid b/addons/gdUnit4/src/core/event/GdUnitEventStop.gd.uid deleted file mode 100644 index fa3d212a..00000000 --- a/addons/gdUnit4/src/core/event/GdUnitEventStop.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cg768i3qgef2x diff --git a/addons/gdUnit4/src/core/event/GdUnitEventTestDiscoverEnd.gd b/addons/gdUnit4/src/core/event/GdUnitEventTestDiscoverEnd.gd deleted file mode 100644 index c6194ef3..00000000 --- a/addons/gdUnit4/src/core/event/GdUnitEventTestDiscoverEnd.gd +++ /dev/null @@ -1,19 +0,0 @@ -class_name GdUnitEventTestDiscoverEnd -extends GdUnitEvent - - -var _total_testsuites: int - - -func _init(testsuite_count: int, test_count: int) -> void: - _event_type = DISCOVER_END - _total_testsuites = testsuite_count - _total_count = test_count - - -func total_test_suites() -> int: - return _total_testsuites - - -func total_tests() -> int: - return _total_count diff --git a/addons/gdUnit4/src/core/event/GdUnitEventTestDiscoverEnd.gd.uid b/addons/gdUnit4/src/core/event/GdUnitEventTestDiscoverEnd.gd.uid deleted file mode 100644 index bb01a6b2..00000000 --- a/addons/gdUnit4/src/core/event/GdUnitEventTestDiscoverEnd.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bt4blgp4lw3p0 diff --git a/addons/gdUnit4/src/core/event/GdUnitEventTestDiscoverStart.gd b/addons/gdUnit4/src/core/event/GdUnitEventTestDiscoverStart.gd deleted file mode 100644 index c7dd36f7..00000000 --- a/addons/gdUnit4/src/core/event/GdUnitEventTestDiscoverStart.gd +++ /dev/null @@ -1,6 +0,0 @@ -class_name GdUnitEventTestDiscoverStart -extends GdUnitEvent - - -func _init() -> void: - _event_type = DISCOVER_START diff --git a/addons/gdUnit4/src/core/event/GdUnitEventTestDiscoverStart.gd.uid b/addons/gdUnit4/src/core/event/GdUnitEventTestDiscoverStart.gd.uid deleted file mode 100644 index 06bc4665..00000000 --- a/addons/gdUnit4/src/core/event/GdUnitEventTestDiscoverStart.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://npuh47e34ud2 diff --git a/addons/gdUnit4/src/core/event/GdUnitSessionClose.gd b/addons/gdUnit4/src/core/event/GdUnitSessionClose.gd deleted file mode 100644 index 52dab3ff..00000000 --- a/addons/gdUnit4/src/core/event/GdUnitSessionClose.gd +++ /dev/null @@ -1,6 +0,0 @@ -class_name GdUnitSessionClose -extends GdUnitEvent - - -func _init() -> void: - _event_type = SESSION_CLOSE diff --git a/addons/gdUnit4/src/core/event/GdUnitSessionClose.gd.uid b/addons/gdUnit4/src/core/event/GdUnitSessionClose.gd.uid deleted file mode 100644 index c9022705..00000000 --- a/addons/gdUnit4/src/core/event/GdUnitSessionClose.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://eqiw85rg4fgn diff --git a/addons/gdUnit4/src/core/event/GdUnitSessionStart.gd b/addons/gdUnit4/src/core/event/GdUnitSessionStart.gd deleted file mode 100644 index 420ad538..00000000 --- a/addons/gdUnit4/src/core/event/GdUnitSessionStart.gd +++ /dev/null @@ -1,6 +0,0 @@ -class_name GdUnitSessionStart -extends GdUnitEvent - - -func _init() -> void: - _event_type = SESSION_START diff --git a/addons/gdUnit4/src/core/event/GdUnitSessionStart.gd.uid b/addons/gdUnit4/src/core/event/GdUnitSessionStart.gd.uid deleted file mode 100644 index bd07390a..00000000 --- a/addons/gdUnit4/src/core/event/GdUnitSessionStart.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://hpagtimkbhev diff --git a/addons/gdUnit4/src/core/execution/GdUnitExecutionContext.gd b/addons/gdUnit4/src/core/execution/GdUnitExecutionContext.gd deleted file mode 100644 index 457fd678..00000000 --- a/addons/gdUnit4/src/core/execution/GdUnitExecutionContext.gd +++ /dev/null @@ -1,269 +0,0 @@ -## The execution context -## It contains all the necessary information about the executed stage, such as memory observers, reports, orphan monitor -class_name GdUnitExecutionContext - -enum GC_ORPHANS_CHECK { - NONE, - SUITE_HOOK_AFTER, - TEST_HOOK_AFTER, - TEST_CASE -} - - -var _parent_context: GdUnitExecutionContext -var _sub_context: Array[GdUnitExecutionContext] = [] -var _orphan_monitor: GdUnitOrphanNodesMonitor -var _memory_observer: GdUnitMemoryObserver -var _report_collector: GdUnitTestReportCollector -var _timer: LocalTime -var _test_case_name: StringName -var _test_case_parameter_set: Array -var _name: String -var _test_execution_iteration: int = 0 -var _flaky_test_check := GdUnitSettings.is_test_flaky_check_enabled() -var _flaky_test_retries := GdUnitSettings.get_flaky_max_retries() -var _orphans := -1 - - -var error_monitor: GodotGdErrorMonitor = null: - get: - if _parent_context != null: - return _parent_context.error_monitor - if error_monitor == null: - error_monitor = GodotGdErrorMonitor.new() - return error_monitor - - -var test_suite: GdUnitTestSuite = null: - get: - if _parent_context != null: - return _parent_context.test_suite - return test_suite - - -var test_case: _TestCase = null: - get: - if test_case == null and _parent_context != null: - return _parent_context.test_case - return test_case - - -func _init(name: StringName, parent_context: GdUnitExecutionContext = null) -> void: - _name = name - _parent_context = parent_context - _timer = LocalTime.now() - _orphan_monitor = GdUnitOrphanNodesMonitor.new(name) - _orphan_monitor.start() - _memory_observer = GdUnitMemoryObserver.new() - _report_collector = GdUnitTestReportCollector.new() - if parent_context != null: - parent_context._sub_context.append(self) - - -func dispose() -> void: - _timer = null - _orphan_monitor = null - _report_collector = null - _memory_observer = null - _parent_context = null - test_suite = null - test_case = null - dispose_sub_contexts() - - -func dispose_sub_contexts() -> void: - for context in _sub_context: - context.dispose() - _sub_context.clear() - - -static func of(pe: GdUnitExecutionContext) -> GdUnitExecutionContext: - var context := GdUnitExecutionContext.new(pe._test_case_name, pe) - context._test_case_name = pe._test_case_name - context._test_execution_iteration = pe._test_execution_iteration - return context - - -static func of_test_suite(p_test_suite: GdUnitTestSuite) -> GdUnitExecutionContext: - assert(p_test_suite, "test_suite is null") - var context := GdUnitExecutionContext.new(p_test_suite.get_name()) - context.test_suite = p_test_suite - return context - - -static func of_test_case(pe: GdUnitExecutionContext, p_test_case: _TestCase) -> GdUnitExecutionContext: - assert(p_test_case, "test_case is null") - var context := GdUnitExecutionContext.new(p_test_case.get_name(), pe) - context.test_case = p_test_case - return context - - -static func of_parameterized_test(pe: GdUnitExecutionContext, test_case_name: String, test_case_parameter_set: Array) -> GdUnitExecutionContext: - var context := GdUnitExecutionContext.new(test_case_name, pe) - context._test_case_name = test_case_name - context._test_case_parameter_set = test_case_parameter_set - return context - - -func get_test_suite_path() -> String: - return test_suite.get_script().resource_path - - -func get_test_suite_name() -> StringName: - return test_suite.get_name() - - -func get_test_case_name() -> StringName: - if _test_case_name.is_empty(): - return test_case._test_case.display_name - return _test_case_name - - -func error_monitor_start() -> void: - error_monitor.start() - - -func error_monitor_stop() -> void: - await error_monitor.scan() - for error_report in error_monitor.to_reports(): - if error_report.is_error(): - _report_collector.push_back(error_report) - - -func orphan_monitor_start() -> void: - _orphan_monitor.start() - - -func orphan_monitor_stop() -> void: - _orphan_monitor.stop() - - -func add_report(report: GdUnitReport) -> GdUnitReport: - _report_collector.push_back(report) - return report - - -func reports() -> Array[GdUnitReport]: - return _report_collector.reports() - - -func collect_reports(recursive: bool) -> Array[GdUnitReport]: - if not recursive: - return reports() - - # we combine the reports of test_before(), test_after() and test() to be reported by `fire_test_ended` - # we strictly need to copy the reports before adding sub context reports to avoid manipulation of the current context - var current_reports := reports().duplicate() - for sub_context in _sub_context: - current_reports.append_array(sub_context.collect_reports(true)) - - return current_reports - - -func calculate_statistics(reports_: Array[GdUnitReport]) -> Dictionary: - var failed_count := GdUnitTestReportCollector.count_failures(reports_) - var error_count := GdUnitTestReportCollector.count_errors(reports_) - var warn_count := GdUnitTestReportCollector.count_warnings(reports_) - var skip_count := GdUnitTestReportCollector.count_skipped(reports_) - var is_failed := !is_success() - var orphan_count := _count_orphans() - var elapsed_time := _timer.elapsed_since_ms() - var retries := 1 if _parent_context == null else _sub_context.size() - # Mark as flaky if it is successful, but errors were counted - var is_flaky := retries > 1 and not is_failed - # In the case of a flakiness test, we do not report an error counter, as an unreliable test is considered successful - # after a certain number of repetitions. - if is_flaky: - failed_count = 0 - - return { - GdUnitEvent.RETRY_COUNT: retries, - GdUnitEvent.ELAPSED_TIME: elapsed_time, - GdUnitEvent.FAILED: is_failed, - GdUnitEvent.ERRORS: error_count > 0, - GdUnitEvent.WARNINGS: warn_count > 0, - GdUnitEvent.FLAKY: is_flaky, - GdUnitEvent.SKIPPED: skip_count > 0, - GdUnitEvent.FAILED_COUNT: failed_count, - GdUnitEvent.ERROR_COUNT: error_count, - GdUnitEvent.SKIPPED_COUNT: skip_count, - GdUnitEvent.ORPHAN_NODES: orphan_count, - } - - -func is_success() -> bool: - if _sub_context.is_empty(): - return not _report_collector.has_failures() - # we on test suite level? - if _parent_context == null: - return not _report_collector.has_failures() - - return _sub_context[-1].is_success() and not _report_collector.has_failures() - - -func is_skipped() -> bool: - return ( - _sub_context.any(func(c :GdUnitExecutionContext) -> bool: - return c.is_skipped()) - or test_case.is_skipped() if test_case != null else false - ) - - -func is_interupted() -> bool: - return false if test_case == null else test_case.is_interupted() - - -func _count_orphans() -> int: - if _orphans != -1: - return _orphans - - var orphans := 0 - for c in _sub_context: - if _orphan_monitor.orphan_nodes() != c._orphan_monitor.orphan_nodes(): - orphans += c._count_orphans() - - _orphans = _orphan_monitor.orphan_nodes() - if _orphan_monitor.orphan_nodes() != orphans: - _orphans -= orphans - - return _orphans - - -func sum(accum: int, number: int) -> int: - return accum + number - - -func retry_execution() -> bool: - var retry := _test_execution_iteration < 1 if not _flaky_test_check else _test_execution_iteration < _flaky_test_retries - if retry: - _test_execution_iteration += 1 - return retry - - -func register_auto_free(obj: Variant) -> Variant: - return _memory_observer.register_auto_free(obj) - - -## Runs the gdunit garbage collector to free registered object and handle orphan node reporting -func gc(gc_orphan_check: GC_ORPHANS_CHECK = GC_ORPHANS_CHECK.NONE) -> void: - # unreference last used assert form the test to prevent memory leaks - GdUnitThreadManager.get_current_context().clear_assert() - await _memory_observer.gc() - orphan_monitor_stop() - - var orphans := _count_orphans() - match(gc_orphan_check): - GC_ORPHANS_CHECK.SUITE_HOOK_AFTER: - if orphans > 0: - reports().push_front(GdUnitReport.new() \ - .create(GdUnitReport.WARN, 1, GdAssertMessages.orphan_detected_on_suite_setup(orphans))) - - GC_ORPHANS_CHECK.TEST_HOOK_AFTER: - if orphans > 0: - reports().push_front(GdUnitReport.new()\ - .create(GdUnitReport.WARN, 1, GdAssertMessages.orphan_detected_on_test_setup(orphans))) - - GC_ORPHANS_CHECK.TEST_CASE: - if orphans > 0: - reports().push_front(GdUnitReport.new()\ - .create(GdUnitReport.WARN, test_case.line_number(), GdAssertMessages.orphan_detected_on_test(orphans))) diff --git a/addons/gdUnit4/src/core/execution/GdUnitExecutionContext.gd.uid b/addons/gdUnit4/src/core/execution/GdUnitExecutionContext.gd.uid deleted file mode 100644 index 87b63acc..00000000 --- a/addons/gdUnit4/src/core/execution/GdUnitExecutionContext.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dm5otinunwsc1 diff --git a/addons/gdUnit4/src/core/execution/GdUnitMemoryObserver.gd b/addons/gdUnit4/src/core/execution/GdUnitMemoryObserver.gd deleted file mode 100644 index dd03a313..00000000 --- a/addons/gdUnit4/src/core/execution/GdUnitMemoryObserver.gd +++ /dev/null @@ -1,135 +0,0 @@ -## The memory watcher for objects that have been registered and are released when 'gc' is called. -class_name GdUnitMemoryObserver -extends RefCounted - -const TAG_OBSERVE_INSTANCE := "GdUnit4_observe_instance_" -const TAG_AUTO_FREE = "GdUnit4_marked_auto_free" -const GdUnitTools = preload("res://addons/gdUnit4/src/core/GdUnitTools.gd") - - -var _store :Array[Variant] = [] -# enable for debugging purposes -var _is_stdout_verbose := false -const _show_debug := false - - -## Registration of an instance to be released when an execution phase is completed -func register_auto_free(obj :Variant) -> Variant: - if not is_instance_valid(obj): - return obj - # do not register on GDScriptNativeClass - @warning_ignore("unsafe_cast") - if typeof(obj) == TYPE_OBJECT and (obj as Object).is_class("GDScriptNativeClass") : - return obj - #if obj is GDScript or obj is ScriptExtension: - # return obj - if obj is MainLoop: - push_error("GdUnit4: Avoid to add mainloop to auto_free queue %s" % obj) - return - if _is_stdout_verbose: - print_verbose("GdUnit4:gc():register auto_free(%s)" % obj) - # only register pure objects - if obj is GdUnitSceneRunner: - _store.push_back(obj) - else: - _store.append(obj) - _tag_object(obj) - return obj - - -# to disable instance guard when run into issues. -static func _is_instance_guard_enabled() -> bool: - return false - - -static func debug_observe(name :String, obj :Object, indent :int = 0) -> void: - if not _show_debug: - return - var script :GDScript= obj if obj is GDScript else obj.get_script() - if script: - var base_script :GDScript = script.get_base_script() - @warning_ignore("unsafe_method_access") - prints("".lpad(indent, " "), name, obj, obj.get_class(), "reference_count:", obj.get_reference_count() if obj is RefCounted else 0, "script:", script, script.resource_path) - if base_script: - debug_observe("+", base_script, indent+1) - else: - @warning_ignore("unsafe_method_access") - prints(name, obj, obj.get_class(), obj.get_name()) - - -static func guard_instance(obj :Object) -> void: - if not _is_instance_guard_enabled(): - return - var tag := TAG_OBSERVE_INSTANCE + str(abs(obj.get_instance_id())) - if Engine.has_meta(tag): - return - debug_observe("Gard on instance", obj) - Engine.set_meta(tag, obj) - - -static func unguard_instance(obj :Object, verbose := true) -> void: - if not _is_instance_guard_enabled(): - return - var tag := TAG_OBSERVE_INSTANCE + str(abs(obj.get_instance_id())) - if verbose: - debug_observe("unguard instance", obj) - if Engine.has_meta(tag): - Engine.remove_meta(tag) - - -static func gc_guarded_instance(name :String, instance :Object) -> void: - if not _is_instance_guard_enabled(): - return - await (Engine.get_main_loop() as SceneTree).process_frame - unguard_instance(instance, false) - if is_instance_valid(instance) and instance is RefCounted: - # finally do this very hacky stuff - # we need to manually unreferece to avoid leaked scripts - # but still leaked GDScriptFunctionState exists - #var script :GDScript = instance.get_script() - #if script: - # var base_script :GDScript = script.get_base_script() - # if base_script: - # base_script.unreference() - debug_observe(name, instance) - (instance as RefCounted).unreference() - await (Engine.get_main_loop() as SceneTree).process_frame - - -static func gc_on_guarded_instances() -> void: - if not _is_instance_guard_enabled(): - return - for tag in Engine.get_meta_list(): - if tag.begins_with(TAG_OBSERVE_INSTANCE): - var instance :Object = Engine.get_meta(tag) - await gc_guarded_instance("Leaked instance detected:", instance) - await GdUnitTools.free_instance(instance, false) - - -# store the object into global store aswell to be verified by 'is_marked_auto_free' -func _tag_object(obj :Variant) -> void: - var tagged_object: Array = Engine.get_meta(TAG_AUTO_FREE, []) - tagged_object.append(obj) - Engine.set_meta(TAG_AUTO_FREE, tagged_object) - - -## Runs over all registered objects and releases them -func gc() -> void: - if _store.is_empty(): - return - # give engine time to free objects to process objects marked by queue_free() - await (Engine.get_main_loop() as SceneTree).process_frame - if _is_stdout_verbose: - print_verbose("GdUnit4:gc():running", " freeing %d objects .." % _store.size()) - var tagged_objects: Array = Engine.get_meta(TAG_AUTO_FREE, []) - while not _store.is_empty(): - var value :Variant = _store.pop_front() - tagged_objects.erase(value) - await GdUnitTools.free_instance(value, _is_stdout_verbose) - assert(_store.is_empty(), "The memory observer has still entries in the store!") - - -## Checks whether the specified object is registered for automatic release -static func is_marked_auto_free(obj: Variant) -> bool: - var tagged_objects: Array = Engine.get_meta(TAG_AUTO_FREE, []) - return tagged_objects.has(obj) diff --git a/addons/gdUnit4/src/core/execution/GdUnitMemoryObserver.gd.uid b/addons/gdUnit4/src/core/execution/GdUnitMemoryObserver.gd.uid deleted file mode 100644 index a6692bbb..00000000 --- a/addons/gdUnit4/src/core/execution/GdUnitMemoryObserver.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ibpnqu61f7yw diff --git a/addons/gdUnit4/src/core/execution/GdUnitTestReportCollector.gd b/addons/gdUnit4/src/core/execution/GdUnitTestReportCollector.gd deleted file mode 100644 index 5f42d148..00000000 --- a/addons/gdUnit4/src/core/execution/GdUnitTestReportCollector.gd +++ /dev/null @@ -1,62 +0,0 @@ -# Collects all reports seperated as warnings, failures and errors -class_name GdUnitTestReportCollector -extends RefCounted - - -var _reports :Array[GdUnitReport] = [] - - -static func __filter_is_error(report :GdUnitReport) -> bool: - return report.is_error() - - -static func __filter_is_failure(report :GdUnitReport) -> bool: - return report.is_failure() - - -static func __filter_is_warning(report :GdUnitReport) -> bool: - return report.is_warning() - - -static func __filter_is_skipped(report :GdUnitReport) -> bool: - return report.is_skipped() - - -static func count_failures(reports_: Array[GdUnitReport]) -> int: - return reports_.filter(__filter_is_failure).size() - - -static func count_errors(reports_: Array[GdUnitReport]) -> int: - return reports_.filter(__filter_is_error).size() - - -static func count_warnings(reports_: Array[GdUnitReport]) -> int: - return reports_.filter(__filter_is_warning).size() - - -static func count_skipped(reports_: Array[GdUnitReport]) -> int: - return reports_.filter(__filter_is_skipped).size() - - -func has_failures() -> bool: - return _reports.any(__filter_is_failure) - - -func has_errors() -> bool: - return _reports.any(__filter_is_error) - - -func has_warnings() -> bool: - return _reports.any(__filter_is_warning) - - -func has_skipped() -> bool: - return _reports.any(__filter_is_skipped) - - -func reports() -> Array[GdUnitReport]: - return _reports - - -func push_back(report :GdUnitReport) -> void: - _reports.push_back(report) diff --git a/addons/gdUnit4/src/core/execution/GdUnitTestReportCollector.gd.uid b/addons/gdUnit4/src/core/execution/GdUnitTestReportCollector.gd.uid deleted file mode 100644 index 771e5b20..00000000 --- a/addons/gdUnit4/src/core/execution/GdUnitTestReportCollector.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cl13ejhh26vv7 diff --git a/addons/gdUnit4/src/core/execution/GdUnitTestSuiteExecutor.gd b/addons/gdUnit4/src/core/execution/GdUnitTestSuiteExecutor.gd deleted file mode 100644 index e3fd510c..00000000 --- a/addons/gdUnit4/src/core/execution/GdUnitTestSuiteExecutor.gd +++ /dev/null @@ -1,48 +0,0 @@ -## The executor to run a test-suite -class_name GdUnitTestSuiteExecutor - - -# preload all asserts here -@warning_ignore("unused_private_class_variable") -var _assertions := GdUnitAssertions.new() -var _executeStage := GdUnitTestSuiteExecutionStage.new() -var _debug_mode : bool - -func _init(debug_mode :bool = false) -> void: - _executeStage.set_debug_mode(debug_mode) - _debug_mode = debug_mode - - -func execute(test_suite :GdUnitTestSuite) -> void: - var orphan_detection_enabled := GdUnitSettings.is_verbose_orphans() - if not orphan_detection_enabled: - prints("!!! Reporting orphan nodes is disabled. Please check GdUnit settings.") - - (Engine.get_main_loop() as SceneTree).root.call_deferred("add_child", test_suite) - await (Engine.get_main_loop() as SceneTree).process_frame - await _executeStage.execute(GdUnitExecutionContext.of_test_suite(test_suite)) - - -func run_and_wait(tests: Array[GdUnitTestCase]) -> void: - if !_debug_mode: - GdUnitSignals.instance().gdunit_event.emit(GdUnitInit.new()) - # first we group all tests by resource path - var grouped_by_suites := GdArrayTools.group_by(tests, func(test: GdUnitTestCase) -> String: - return test.suite_resource_path - ) - var scanner := GdUnitTestSuiteScanner.new() - for suite_path: String in grouped_by_suites.keys(): - @warning_ignore("unsafe_call_argument") - var suite_tests: Array[GdUnitTestCase] = Array(grouped_by_suites[suite_path], TYPE_OBJECT, "RefCounted", GdUnitTestCase) - var script := GdUnitTestSuiteScanner.load_with_disabled_warnings(suite_path) - if script.get_class() == "GDScript": - var test_suite := scanner.load_suite(script as GDScript, suite_tests) - await execute(test_suite) - else: - await GdUnit4CSharpApiLoader.execute(suite_tests) - if !_debug_mode: - GdUnitSignals.instance().gdunit_event.emit(GdUnitStop.new()) - - -func fail_fast(enabled :bool) -> void: - _executeStage.fail_fast(enabled) diff --git a/addons/gdUnit4/src/core/execution/GdUnitTestSuiteExecutor.gd.uid b/addons/gdUnit4/src/core/execution/GdUnitTestSuiteExecutor.gd.uid deleted file mode 100644 index 38263f2b..00000000 --- a/addons/gdUnit4/src/core/execution/GdUnitTestSuiteExecutor.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://hl8otc6pepsh diff --git a/addons/gdUnit4/src/core/execution/stages/GdUnitTestCaseAfterStage.gd b/addons/gdUnit4/src/core/execution/stages/GdUnitTestCaseAfterStage.gd deleted file mode 100644 index d3c62455..00000000 --- a/addons/gdUnit4/src/core/execution/stages/GdUnitTestCaseAfterStage.gd +++ /dev/null @@ -1,22 +0,0 @@ -## The test case shutdown hook implementation.[br] -## It executes the 'test_after()' block from the test-suite. -class_name GdUnitTestCaseAfterStage -extends IGdUnitExecutionStage - - -var _call_stage: bool - - -func _init(call_stage := true) -> void: - _call_stage = call_stage - - -func _execute(context: GdUnitExecutionContext) -> void: - var test_suite := context.test_suite - - if _call_stage: - @warning_ignore("redundant_await") - await test_suite.after_test() - - await context.gc(GdUnitExecutionContext.GC_ORPHANS_CHECK.TEST_HOOK_AFTER) - await context.error_monitor_stop() diff --git a/addons/gdUnit4/src/core/execution/stages/GdUnitTestCaseAfterStage.gd.uid b/addons/gdUnit4/src/core/execution/stages/GdUnitTestCaseAfterStage.gd.uid deleted file mode 100644 index 2707e05a..00000000 --- a/addons/gdUnit4/src/core/execution/stages/GdUnitTestCaseAfterStage.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ddknkun7aw51d diff --git a/addons/gdUnit4/src/core/execution/stages/GdUnitTestCaseBeforeStage.gd b/addons/gdUnit4/src/core/execution/stages/GdUnitTestCaseBeforeStage.gd deleted file mode 100644 index 4e04fad2..00000000 --- a/addons/gdUnit4/src/core/execution/stages/GdUnitTestCaseBeforeStage.gd +++ /dev/null @@ -1,19 +0,0 @@ -## The test case startup hook implementation.[br] -## It executes the 'test_before()' block from the test-suite. -class_name GdUnitTestCaseBeforeStage -extends IGdUnitExecutionStage - -var _call_stage :bool - - -func _init(call_stage := true) -> void: - _call_stage = call_stage - - -func _execute(context :GdUnitExecutionContext) -> void: - var test_suite := context.test_suite - - if _call_stage: - @warning_ignore("redundant_await") - await test_suite.before_test() - context.error_monitor_start() diff --git a/addons/gdUnit4/src/core/execution/stages/GdUnitTestCaseBeforeStage.gd.uid b/addons/gdUnit4/src/core/execution/stages/GdUnitTestCaseBeforeStage.gd.uid deleted file mode 100644 index 864e7b8a..00000000 --- a/addons/gdUnit4/src/core/execution/stages/GdUnitTestCaseBeforeStage.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c8gq3sb8q6xih diff --git a/addons/gdUnit4/src/core/execution/stages/GdUnitTestCaseExecutionStage.gd b/addons/gdUnit4/src/core/execution/stages/GdUnitTestCaseExecutionStage.gd deleted file mode 100644 index 12cc6fde..00000000 --- a/addons/gdUnit4/src/core/execution/stages/GdUnitTestCaseExecutionStage.gd +++ /dev/null @@ -1,37 +0,0 @@ -## The test case execution stage.[br] -class_name GdUnitTestCaseExecutionStage -extends IGdUnitExecutionStage - - -var _stage_single_test: IGdUnitExecutionStage = GdUnitTestCaseSingleExecutionStage.new() -var _stage_fuzzer_test: IGdUnitExecutionStage = GdUnitTestCaseFuzzedExecutionStage.new() - - -## Executes the test case 'test_()'.[br] -## It executes synchronized following stages[br] -## -> test_before() [br] -## -> test_case() [br] -## -> test_after() [br] -@warning_ignore("redundant_await") -func _execute(context :GdUnitExecutionContext) -> void: - var test_case := context.test_case - - context.error_monitor_start() - - if test_case.is_fuzzed(): - await _stage_fuzzer_test.execute(context) - else: - await _stage_single_test.execute(context) - - await context.gc() - await context.error_monitor_stop() - - # finally free the test instance - if is_instance_valid(context.test_case): - context.test_case.dispose() - - -func set_debug_mode(debug_mode :bool = false) -> void: - super.set_debug_mode(debug_mode) - _stage_single_test.set_debug_mode(debug_mode) - _stage_fuzzer_test.set_debug_mode(debug_mode) diff --git a/addons/gdUnit4/src/core/execution/stages/GdUnitTestCaseExecutionStage.gd.uid b/addons/gdUnit4/src/core/execution/stages/GdUnitTestCaseExecutionStage.gd.uid deleted file mode 100644 index 8079e2fd..00000000 --- a/addons/gdUnit4/src/core/execution/stages/GdUnitTestCaseExecutionStage.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://brfrhige0dbmm diff --git a/addons/gdUnit4/src/core/execution/stages/GdUnitTestSuiteAfterStage.gd b/addons/gdUnit4/src/core/execution/stages/GdUnitTestSuiteAfterStage.gd deleted file mode 100644 index 03bbd0f7..00000000 --- a/addons/gdUnit4/src/core/execution/stages/GdUnitTestSuiteAfterStage.gd +++ /dev/null @@ -1,29 +0,0 @@ -## The test suite shutdown hook implementation.[br] -## It executes the 'after()' block from the test-suite. -class_name GdUnitTestSuiteAfterStage -extends IGdUnitExecutionStage - - -const GdUnitTools := preload("res://addons/gdUnit4/src/core/GdUnitTools.gd") - - -func _execute(context :GdUnitExecutionContext) -> void: - var test_suite := context.test_suite - - @warning_ignore("redundant_await") - await test_suite.after() - await context.gc(GdUnitExecutionContext.GC_ORPHANS_CHECK.SUITE_HOOK_AFTER) - - var reports := context.collect_reports(false) - var statistics := context.calculate_statistics(reports) - fire_event(GdUnitEvent.new()\ - .suite_after(context.get_test_suite_path(),\ - test_suite.get_name(), - statistics, - reports)) - GdUnitFileAccess.clear_tmp() - # Guard that checks if all doubled (spy/mock) objects are released - await GdUnitClassDoubler.check_leaked_instances() - # we hide the scene/main window after runner is finished - if not Engine.is_embedded_in_editor(): - DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_MINIMIZED) diff --git a/addons/gdUnit4/src/core/execution/stages/GdUnitTestSuiteAfterStage.gd.uid b/addons/gdUnit4/src/core/execution/stages/GdUnitTestSuiteAfterStage.gd.uid deleted file mode 100644 index 0695b809..00000000 --- a/addons/gdUnit4/src/core/execution/stages/GdUnitTestSuiteAfterStage.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://vs73mmj8rsbs diff --git a/addons/gdUnit4/src/core/execution/stages/GdUnitTestSuiteBeforeStage.gd b/addons/gdUnit4/src/core/execution/stages/GdUnitTestSuiteBeforeStage.gd deleted file mode 100644 index e9fa7186..00000000 --- a/addons/gdUnit4/src/core/execution/stages/GdUnitTestSuiteBeforeStage.gd +++ /dev/null @@ -1,14 +0,0 @@ -## The test suite startup hook implementation.[br] -## It executes the 'before()' block from the test-suite. -class_name GdUnitTestSuiteBeforeStage -extends IGdUnitExecutionStage - - -func _execute(context :GdUnitExecutionContext) -> void: - var test_suite := context.test_suite - - fire_event(GdUnitEvent.new()\ - .suite_before(context.get_test_suite_path(), test_suite.get_name(), test_suite.get_child_count())) - - @warning_ignore("redundant_await") - await test_suite.before() diff --git a/addons/gdUnit4/src/core/execution/stages/GdUnitTestSuiteBeforeStage.gd.uid b/addons/gdUnit4/src/core/execution/stages/GdUnitTestSuiteBeforeStage.gd.uid deleted file mode 100644 index 411d0c76..00000000 --- a/addons/gdUnit4/src/core/execution/stages/GdUnitTestSuiteBeforeStage.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ce78xguk84kwb diff --git a/addons/gdUnit4/src/core/execution/stages/GdUnitTestSuiteExecutionStage.gd b/addons/gdUnit4/src/core/execution/stages/GdUnitTestSuiteExecutionStage.gd deleted file mode 100644 index ac921e07..00000000 --- a/addons/gdUnit4/src/core/execution/stages/GdUnitTestSuiteExecutionStage.gd +++ /dev/null @@ -1,147 +0,0 @@ -## The test suite main execution stage.[br] -class_name GdUnitTestSuiteExecutionStage -extends IGdUnitExecutionStage - -const GdUnitTools := preload("res://addons/gdUnit4/src/core/GdUnitTools.gd") - -var _stage_before :IGdUnitExecutionStage = GdUnitTestSuiteBeforeStage.new() -var _stage_after :IGdUnitExecutionStage = GdUnitTestSuiteAfterStage.new() -var _stage_test :IGdUnitExecutionStage = GdUnitTestCaseExecutionStage.new() -var _fail_fast := false - - -## Executes all tests of an test suite.[br] -## It executes synchronized following stages[br] -## -> before() [br] -## -> run all test cases [br] -## -> after() [br] -func _execute(context :GdUnitExecutionContext) -> void: - if context.test_suite.__is_skipped: - await fire_test_suite_skipped(context) - else: - @warning_ignore("return_value_discarded") - GdUnitMemoryObserver.guard_instance(context.test_suite.__awaiter) - await _stage_before.execute(context) - for test_case_index in context.test_suite.get_child_count(): - # iterate only over test cases - var test_case := context.test_suite.get_child(test_case_index) as _TestCase - if not is_instance_valid(test_case): - continue - context.test_suite.set_active_test_case(test_case.test_name()) - await _stage_test.execute(GdUnitExecutionContext.of_test_case(context, test_case)) - # stop on first error or if fail fast is enabled - if _fail_fast and not context.is_success(): - break - if test_case.is_interupted(): - # it needs to go this hard way to kill the outstanding awaits of a test case when the test timed out - # we delete the current test suite where is execute the current test case to kill the function state - # and replace it by a clone without function state - context.test_suite = await clone_test_suite(context.test_suite) - await _stage_after.execute(context) - GdUnitMemoryObserver.unguard_instance(context.test_suite.__awaiter) - await (Engine.get_main_loop() as SceneTree).process_frame - context.test_suite.free() - context.dispose() - - -# clones a test suite and moves the test cases to new instance -func clone_test_suite(test_suite :GdUnitTestSuite) -> GdUnitTestSuite: - await (Engine.get_main_loop() as SceneTree).process_frame - dispose_timers(test_suite) - await GdUnitMemoryObserver.gc_guarded_instance("Manually free on awaiter", test_suite.__awaiter) - var parent := test_suite.get_parent() - var _test_suite := GdUnitTestSuite.new() - parent.remove_child(test_suite) - copy_properties(test_suite, _test_suite) - for child in test_suite.get_children(): - test_suite.remove_child(child) - _test_suite.add_child(child) - parent.add_child(_test_suite) - @warning_ignore("return_value_discarded") - GdUnitMemoryObserver.guard_instance(_test_suite.__awaiter) - # finally free current test suite instance - test_suite.free() - await (Engine.get_main_loop() as SceneTree).process_frame - return _test_suite - - -func dispose_timers(test_suite :GdUnitTestSuite) -> void: - GdUnitTools.release_timers() - for child in test_suite.get_children(): - if child is Timer: - (child as Timer).stop() - test_suite.remove_child(child) - child.free() - - -func copy_properties(source :Object, target :Object) -> void: - if not source is _TestCase and not source is GdUnitTestSuite: - return - for property in source.get_property_list(): - var property_name :String = property["name"] - if property_name == "__awaiter": - continue - target.set(property_name, source.get(property_name)) - - -func fire_test_suite_skipped(context :GdUnitExecutionContext) -> void: - var test_suite := context.test_suite - var skip_count := test_suite.get_child_count() - fire_event(GdUnitEvent.new()\ - .suite_before(context.get_test_suite_path(), test_suite.get_name(), skip_count)) - - - for test_case_index in context.test_suite.get_child_count(): - # iterate only over test cases - var test_case := context.test_suite.get_child(test_case_index) as _TestCase - if not is_instance_valid(test_case): - continue - var test_case_context := GdUnitExecutionContext.of_test_case(context, test_case) - fire_event(GdUnitEvent.new().test_before(test_case.id())) - # use skip count 0 because we counted it over the complete test suite - fire_test_skipped(test_case_context, 0) - - - var statistics := { - GdUnitEvent.ORPHAN_NODES: 0, - GdUnitEvent.ELAPSED_TIME: 0, - GdUnitEvent.WARNINGS: false, - GdUnitEvent.ERRORS: false, - GdUnitEvent.ERROR_COUNT: 0, - GdUnitEvent.FAILED: false, - GdUnitEvent.FAILED_COUNT: 0, - GdUnitEvent.SKIPPED_COUNT: skip_count, - GdUnitEvent.SKIPPED: true - } - var report := GdUnitReport.new().create(GdUnitReport.SKIPPED, -1, GdAssertMessages.test_suite_skipped(test_suite.__skip_reason, skip_count)) - fire_event(GdUnitEvent.new().suite_after(context.get_test_suite_path(), test_suite.get_name(), statistics, [report])) - await (Engine.get_main_loop() as SceneTree).process_frame - - -func fire_test_skipped(context: GdUnitExecutionContext, skip_count := 1) -> void: - var test_case := context.test_case - var statistics := { - GdUnitEvent.ORPHAN_NODES: 0, - GdUnitEvent.ELAPSED_TIME: 0, - GdUnitEvent.WARNINGS: false, - GdUnitEvent.ERRORS: false, - GdUnitEvent.ERROR_COUNT: 0, - GdUnitEvent.FAILED: false, - GdUnitEvent.FAILED_COUNT: 0, - GdUnitEvent.SKIPPED: true, - GdUnitEvent.SKIPPED_COUNT: skip_count, - } - var report := GdUnitReport.new() \ - .create(GdUnitReport.SKIPPED, test_case.line_number(), GdAssertMessages.test_skipped("Skipped from the entire test suite")) - fire_event(GdUnitEvent.new().test_after(test_case.id(), statistics, [report])) - - -func set_debug_mode(debug_mode :bool = false) -> void: - super.set_debug_mode(debug_mode) - _stage_before.set_debug_mode(debug_mode) - _stage_after.set_debug_mode(debug_mode) - _stage_test.set_debug_mode(debug_mode) - - -func fail_fast(enabled :bool) -> void: - _fail_fast = enabled diff --git a/addons/gdUnit4/src/core/execution/stages/GdUnitTestSuiteExecutionStage.gd.uid b/addons/gdUnit4/src/core/execution/stages/GdUnitTestSuiteExecutionStage.gd.uid deleted file mode 100644 index 98878317..00000000 --- a/addons/gdUnit4/src/core/execution/stages/GdUnitTestSuiteExecutionStage.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bfbyfr8ocwivm diff --git a/addons/gdUnit4/src/core/execution/stages/IGdUnitExecutionStage.gd b/addons/gdUnit4/src/core/execution/stages/IGdUnitExecutionStage.gd deleted file mode 100644 index 39de3809..00000000 --- a/addons/gdUnit4/src/core/execution/stages/IGdUnitExecutionStage.gd +++ /dev/null @@ -1,39 +0,0 @@ -## The interface of execution stage.[br] -## An execution stage is defined as an encapsulated task that can execute 1-n substages covered by its own execution context.[br] -## Execution stage are always called synchronously. -class_name IGdUnitExecutionStage -extends RefCounted - -var _debug_mode := false - - -## Executes synchronized the implemented stage in its own execution context.[br] -## example:[br] -## [codeblock] -## # waits for 100ms -## await MyExecutionStage.new().execute() -## [/codeblock][br] -func execute(context :GdUnitExecutionContext) -> void: - GdUnitThreadManager.get_current_context().set_execution_context(context) - @warning_ignore("redundant_await") - await _execute(context) - - -## Sends the event to registered listeners -func fire_event(event :GdUnitEvent) -> void: - if _debug_mode: - GdUnitSignals.instance().gdunit_event_debug.emit(event) - else: - GdUnitSignals.instance().gdunit_event.emit(event) - - -## Internal testing stuff.[br] -## Sets the executor into debug mode to emit `GdUnitEvent` via signal `gdunit_event_debug` -func set_debug_mode(debug_mode :bool) -> void: - _debug_mode = debug_mode - - -## The execution phase to be carried out. -func _execute(_context :GdUnitExecutionContext) -> void: - @warning_ignore("assert_always_false") - assert(false, "The execution stage is not implemented") diff --git a/addons/gdUnit4/src/core/execution/stages/IGdUnitExecutionStage.gd.uid b/addons/gdUnit4/src/core/execution/stages/IGdUnitExecutionStage.gd.uid deleted file mode 100644 index 0e92e3ee..00000000 --- a/addons/gdUnit4/src/core/execution/stages/IGdUnitExecutionStage.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://blqjb8vicbune diff --git a/addons/gdUnit4/src/core/execution/stages/fuzzed/GdUnitTestCaseFuzzedExecutionStage.gd b/addons/gdUnit4/src/core/execution/stages/fuzzed/GdUnitTestCaseFuzzedExecutionStage.gd deleted file mode 100644 index 73a7a66e..00000000 --- a/addons/gdUnit4/src/core/execution/stages/fuzzed/GdUnitTestCaseFuzzedExecutionStage.gd +++ /dev/null @@ -1,52 +0,0 @@ -## The test case execution stage.[br] -class_name GdUnitTestCaseFuzzedExecutionStage -extends IGdUnitExecutionStage - -var _stage_before :IGdUnitExecutionStage = GdUnitTestCaseBeforeStage.new(false) -var _stage_after :IGdUnitExecutionStage = GdUnitTestCaseAfterStage.new(false) -var _stage_test :IGdUnitExecutionStage = GdUnitTestCaseFuzzedTestStage.new() - - -func _execute(context :GdUnitExecutionContext) -> void: - fire_event(GdUnitEvent.new().test_before(context.test_case.id())) - - while context.retry_execution(): - var test_context := GdUnitExecutionContext.of(context) - await _stage_before.execute(test_context) - if not context.test_case.is_skipped(): - await _stage_test.execute(GdUnitExecutionContext.of(test_context)) - await _stage_after.execute(test_context) - if test_context.is_success() or test_context.is_skipped() or test_context.is_interupted(): - break - - context.gc() - if context.is_skipped(): - fire_test_skipped(context) - else: - var reports: = context.collect_reports(true) - var statistics := context.calculate_statistics(reports) - fire_event(GdUnitEvent.new().test_after(context.test_case.id(), statistics, reports)) - -func set_debug_mode(debug_mode :bool = false) -> void: - super.set_debug_mode(debug_mode) - _stage_before.set_debug_mode(debug_mode) - _stage_after.set_debug_mode(debug_mode) - _stage_test.set_debug_mode(debug_mode) - - -func fire_test_skipped(context: GdUnitExecutionContext) -> void: - var test_case := context.test_case - var statistics := { - GdUnitEvent.ORPHAN_NODES: 0, - GdUnitEvent.ELAPSED_TIME: 0, - GdUnitEvent.WARNINGS: false, - GdUnitEvent.ERRORS: false, - GdUnitEvent.ERROR_COUNT: 0, - GdUnitEvent.FAILED: false, - GdUnitEvent.FAILED_COUNT: 0, - GdUnitEvent.SKIPPED: true, - GdUnitEvent.SKIPPED_COUNT: 1, - } - var report := GdUnitReport.new() \ - .create(GdUnitReport.SKIPPED, test_case.line_number(), GdAssertMessages.test_skipped(test_case.skip_info())) - fire_event(GdUnitEvent.new().test_after(test_case.id(), statistics, [report])) diff --git a/addons/gdUnit4/src/core/execution/stages/fuzzed/GdUnitTestCaseFuzzedExecutionStage.gd.uid b/addons/gdUnit4/src/core/execution/stages/fuzzed/GdUnitTestCaseFuzzedExecutionStage.gd.uid deleted file mode 100644 index 533c600b..00000000 --- a/addons/gdUnit4/src/core/execution/stages/fuzzed/GdUnitTestCaseFuzzedExecutionStage.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bur2on601qwvw diff --git a/addons/gdUnit4/src/core/execution/stages/fuzzed/GdUnitTestCaseFuzzedTestStage.gd b/addons/gdUnit4/src/core/execution/stages/fuzzed/GdUnitTestCaseFuzzedTestStage.gd deleted file mode 100644 index 62dda37e..00000000 --- a/addons/gdUnit4/src/core/execution/stages/fuzzed/GdUnitTestCaseFuzzedTestStage.gd +++ /dev/null @@ -1,55 +0,0 @@ -## The fuzzed test case execution stage.[br] -class_name GdUnitTestCaseFuzzedTestStage -extends IGdUnitExecutionStage - -var _expression_runner := GdUnitExpressionRunner.new() - - -## Executes a test case with given fuzzers 'test_()' iterative.[br] -## It executes synchronized following stages[br] -## -> test_case() [br] -func _execute(context :GdUnitExecutionContext) -> void: - var test_suite := context.test_suite - var test_case := context.test_case - var fuzzers := create_fuzzers(test_suite, test_case) - - # guard on fuzzers - for fuzzer in fuzzers: - @warning_ignore("return_value_discarded") - GdUnitMemoryObserver.guard_instance(fuzzer) - - for iteration in test_case.iterations(): - @warning_ignore("redundant_await") - await test_suite.before_test() - await test_case.execute(fuzzers, iteration) - @warning_ignore("redundant_await") - await test_suite.after_test() - if test_case.is_interupted(): - break - # interrupt at first failure - var reports := context.reports() - if not reports.is_empty(): - var report :GdUnitReport = reports.pop_front() - reports.append(GdUnitReport.new() \ - .create(GdUnitReport.FAILURE, report.line_number(), GdAssertMessages.fuzzer_interuped(iteration, report.message()))) - break - await context.gc(GdUnitExecutionContext.GC_ORPHANS_CHECK.TEST_CASE) - - # unguard on fuzzers - if not test_case.is_interupted(): - for fuzzer in fuzzers: - GdUnitMemoryObserver.unguard_instance(fuzzer) - - -func create_fuzzers(test_suite :GdUnitTestSuite, test_case :_TestCase) -> Array[Fuzzer]: - if not test_case.is_fuzzed(): - return Array() - test_case.generate_seed() - var fuzzers :Array[Fuzzer] = [] - for fuzzer_arg in test_case.fuzzer_arguments(): - @warning_ignore("unsafe_cast") - var fuzzer := _expression_runner.to_fuzzer(test_suite.get_script() as GDScript, fuzzer_arg.plain_value() as String) - fuzzer._iteration_index = 0 - fuzzer._iteration_limit = test_case.iterations() - fuzzers.append(fuzzer) - return fuzzers diff --git a/addons/gdUnit4/src/core/execution/stages/fuzzed/GdUnitTestCaseFuzzedTestStage.gd.uid b/addons/gdUnit4/src/core/execution/stages/fuzzed/GdUnitTestCaseFuzzedTestStage.gd.uid deleted file mode 100644 index 83ca05ec..00000000 --- a/addons/gdUnit4/src/core/execution/stages/fuzzed/GdUnitTestCaseFuzzedTestStage.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dky6221ssl6re diff --git a/addons/gdUnit4/src/core/execution/stages/single/GdUnitTestCaseSingleExecutionStage.gd b/addons/gdUnit4/src/core/execution/stages/single/GdUnitTestCaseSingleExecutionStage.gd deleted file mode 100644 index 70d687f4..00000000 --- a/addons/gdUnit4/src/core/execution/stages/single/GdUnitTestCaseSingleExecutionStage.gd +++ /dev/null @@ -1,53 +0,0 @@ -## The test case execution stage.[br] -class_name GdUnitTestCaseSingleExecutionStage -extends IGdUnitExecutionStage - - -var _stage_before :IGdUnitExecutionStage = GdUnitTestCaseBeforeStage.new() -var _stage_after :IGdUnitExecutionStage = GdUnitTestCaseAfterStage.new() -var _stage_test :IGdUnitExecutionStage = GdUnitTestCaseSingleTestStage.new() - - -func _execute(context :GdUnitExecutionContext) -> void: - fire_event(GdUnitEvent.new().test_before(context.test_case.id())) - while context.retry_execution(): - var test_context := GdUnitExecutionContext.of(context) - await _stage_before.execute(test_context) - if not test_context.is_skipped(): - await _stage_test.execute(GdUnitExecutionContext.of(test_context)) - await _stage_after.execute(test_context) - if test_context.is_success() or test_context.is_skipped() or test_context.is_interupted(): - break - - context.gc() - if context.is_skipped(): - fire_test_skipped(context) - else: - var reports: = context.collect_reports(true) - var statistics := context.calculate_statistics(reports) - fire_event(GdUnitEvent.new().test_after(context.test_case.id(), statistics, reports)) - - -func set_debug_mode(debug_mode :bool = false) -> void: - super.set_debug_mode(debug_mode) - _stage_before.set_debug_mode(debug_mode) - _stage_after.set_debug_mode(debug_mode) - _stage_test.set_debug_mode(debug_mode) - - -func fire_test_skipped(context: GdUnitExecutionContext) -> void: - var test_case := context.test_case - var statistics := { - GdUnitEvent.ORPHAN_NODES: 0, - GdUnitEvent.ELAPSED_TIME: 0, - GdUnitEvent.WARNINGS: false, - GdUnitEvent.ERRORS: false, - GdUnitEvent.ERROR_COUNT: 0, - GdUnitEvent.FAILED: false, - GdUnitEvent.FAILED_COUNT: 0, - GdUnitEvent.SKIPPED: true, - GdUnitEvent.SKIPPED_COUNT: 1, - } - var report := GdUnitReport.new() \ - .create(GdUnitReport.SKIPPED, test_case.line_number(), GdAssertMessages.test_skipped(test_case.skip_info())) - fire_event(GdUnitEvent.new().test_after(test_case.id(), statistics, [report])) diff --git a/addons/gdUnit4/src/core/execution/stages/single/GdUnitTestCaseSingleExecutionStage.gd.uid b/addons/gdUnit4/src/core/execution/stages/single/GdUnitTestCaseSingleExecutionStage.gd.uid deleted file mode 100644 index 547f856a..00000000 --- a/addons/gdUnit4/src/core/execution/stages/single/GdUnitTestCaseSingleExecutionStage.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ckbcmvbm3bee8 diff --git a/addons/gdUnit4/src/core/execution/stages/single/GdUnitTestCaseSingleTestStage.gd b/addons/gdUnit4/src/core/execution/stages/single/GdUnitTestCaseSingleTestStage.gd deleted file mode 100644 index 9006b368..00000000 --- a/addons/gdUnit4/src/core/execution/stages/single/GdUnitTestCaseSingleTestStage.gd +++ /dev/null @@ -1,11 +0,0 @@ -## The single test case execution stage.[br] -class_name GdUnitTestCaseSingleTestStage -extends IGdUnitExecutionStage - - -## Executes a single test case 'test_()'.[br] -## It executes synchronized following stages[br] -## -> test_case() [br] -func _execute(context :GdUnitExecutionContext) -> void: - await context.test_case.execute() - await context.gc(GdUnitExecutionContext.GC_ORPHANS_CHECK.TEST_CASE) diff --git a/addons/gdUnit4/src/core/execution/stages/single/GdUnitTestCaseSingleTestStage.gd.uid b/addons/gdUnit4/src/core/execution/stages/single/GdUnitTestCaseSingleTestStage.gd.uid deleted file mode 100644 index 16791711..00000000 --- a/addons/gdUnit4/src/core/execution/stages/single/GdUnitTestCaseSingleTestStage.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cq4bgmdjjl77j diff --git a/addons/gdUnit4/src/core/hooks/GdUnitBaseReporterTestSessionHook.gd b/addons/gdUnit4/src/core/hooks/GdUnitBaseReporterTestSessionHook.gd deleted file mode 100644 index 0f87ad1b..00000000 --- a/addons/gdUnit4/src/core/hooks/GdUnitBaseReporterTestSessionHook.gd +++ /dev/null @@ -1,78 +0,0 @@ -class_name GdUnitBaseReporterTestSessionHook -extends GdUnitTestSessionHook - - -var test_session: GdUnitTestSession: - get: - return test_session - set(value): - # disconnect first possible connected listener - if test_session != null: - test_session.test_event.disconnect(_on_test_event) - # add listening to current session - test_session = value - if test_session != null: - test_session.test_event.connect(_on_test_event) - - -var _report_summary: GdUnitReportSummary -var _reporter: GdUnitTestReporter -var _report_writer: GdUnitReportWriter -var _report_converter: Callable - -func _init(report_writer: GdUnitReportWriter, hook_name: String, hook_description: String, report_converter: Callable) -> void: - super(hook_name, hook_description) - _reporter = GdUnitTestReporter.new() - _report_writer = report_writer - _report_converter = report_converter - - -func startup(session: GdUnitTestSession) -> GdUnitResult: - test_session = session - _report_summary = GdUnitReportSummary.new(_report_converter) - _reporter.init_summary() - - return GdUnitResult.success() - - -func shutdown(session: GdUnitTestSession) -> GdUnitResult: - var report_path := _report_writer.write(session.report_path, _report_summary) - session.send_message("Open {0} Report at: file://{1}".format([_report_writer.output_format(), report_path])) - - return GdUnitResult.success() - - -func _on_test_event(event: GdUnitEvent) -> void: - match event.type(): - GdUnitEvent.TESTSUITE_BEFORE: - _reporter.init_statistics() - _report_summary.add_testsuite_report(event.resource_path(), event.suite_name(), event.total_count()) - GdUnitEvent.TESTSUITE_AFTER: - var statistics := _reporter.build_test_suite_statisitcs(event) - _report_summary.update_testsuite_counters( - event.resource_path(), - _reporter.error_count(statistics), - _reporter.failed_count(statistics), - _reporter.orphan_nodes(statistics), - _reporter.skipped_count(statistics), - _reporter.flaky_count(statistics), - event.elapsed_time()) - _report_summary.add_testsuite_reports( - event.resource_path(), - event.reports() - ) - GdUnitEvent.TESTCASE_BEFORE: - var test := test_session.find_test_by_id(event.guid()) - _report_summary.add_testcase(test.source_file, test.suite_name, test.display_name) - GdUnitEvent.TESTCASE_AFTER: - _reporter.add_test_statistics(event) - var test := test_session.find_test_by_id(event.guid()) - _report_summary.set_counters(test.source_file, - test.display_name, - event.error_count(), - event.failed_count(), - event.orphan_nodes(), - event.is_skipped(), - event.is_flaky(), - event.elapsed_time()) - _report_summary.add_reports(test.source_file, test.display_name, event.reports()) diff --git a/addons/gdUnit4/src/core/hooks/GdUnitBaseReporterTestSessionHook.gd.uid b/addons/gdUnit4/src/core/hooks/GdUnitBaseReporterTestSessionHook.gd.uid deleted file mode 100644 index 8c973a68..00000000 --- a/addons/gdUnit4/src/core/hooks/GdUnitBaseReporterTestSessionHook.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://carpav0doacrx diff --git a/addons/gdUnit4/src/core/hooks/GdUnitHtmlReporterTestSessionHook.gd b/addons/gdUnit4/src/core/hooks/GdUnitHtmlReporterTestSessionHook.gd deleted file mode 100644 index 4b8f390f..00000000 --- a/addons/gdUnit4/src/core/hooks/GdUnitHtmlReporterTestSessionHook.gd +++ /dev/null @@ -1,9 +0,0 @@ -class_name GdUnitHtmlReporterTestSessionHook -extends GdUnitBaseReporterTestSessionHook - -const GdUnitTools := preload("res://addons/gdUnit4/src/core/GdUnitTools.gd") - - -func _init() -> void: - super(GdUnitHtmlReportWriter.new(), "GdUnitHtmlTestReporter", "The Html test reporting hook.", GdUnitTools.richtext_normalize) - set_meta("SYSTEM_HOOK", true) diff --git a/addons/gdUnit4/src/core/hooks/GdUnitHtmlReporterTestSessionHook.gd.uid b/addons/gdUnit4/src/core/hooks/GdUnitHtmlReporterTestSessionHook.gd.uid deleted file mode 100644 index 19a15878..00000000 --- a/addons/gdUnit4/src/core/hooks/GdUnitHtmlReporterTestSessionHook.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://1etm8aqdrkqm diff --git a/addons/gdUnit4/src/core/hooks/GdUnitTestSessionHook.gd b/addons/gdUnit4/src/core/hooks/GdUnitTestSessionHook.gd deleted file mode 100644 index 23850e4a..00000000 --- a/addons/gdUnit4/src/core/hooks/GdUnitTestSessionHook.gd +++ /dev/null @@ -1,111 +0,0 @@ -## @since GdUnit4 5.1.0 -## -## Base class for creating custom test session hooks in GdUnit4.[br] -## [br] -## [i]Test session hooks allow users to extend the GdUnit4 test framework by providing -## custom functionality that runs at specific points during the test execution lifecycle. -## This base class defines the interface that all test session hooks must implement.[/i] -## [br] -## [br] -## [b][u]Usage[/u][/b][br] -## 1. Create a new class that extends GdUnitTestSessionHook[br] -## 2. Override the required methods (startup, shutdown)[br] -## 3. Register your hook with the test engine (using the GdUnit4 settings dialog)[br] -## [br] -## [b][u]Example[/u][/b] -## [codeblock] -## class_name MyCustomTestHook -## extends GdUnitTestSessionHook -## -## func _init(): -## super("MyHook", "This is a description") -## -## func startup(session: GdUnitTestSession) -> GdUnitResult: -## session.send_message("Custom hook initialized") -## # Initialize resources, setup test environment, etc. -## return GdUnitResult.success() -## -## func shutdown(session: GdUnitTestSession) -> GdUnitResult: -## session.send_message("Custom hook cleanup completed") -## # Cleanup resources, generate reports, etc. -## return GdUnitResult.success() -## [/codeblock] -## -## [b][u]Hook Lifecycle[/u][/b][br] -## 1. [i][b]Registration[/b][/i]: Hooks are registered with the test engine via settings dialog[br] -## 2. [i][b]Priority Sorting[/b][/i]: Hooks are sorted by priority[br] -## 3. [i][b]Startup[/b][/i]: startup() is called before test execution begins, if it returns an error is shown in the console[br] -## 4. [i][b]Test Execution[/b][/i]: Tests run normally (only if all hooks started successfully)[br] -## 5. [i][b]Shutdown[/b][/i]: shutdown() is called after all tests complete, regardless of startup success[br] -## [br] -## [b][u]Priority System[/u][/b][br] -## The priority system allows controlling the execution order of multiple hooks.[br] -## - The order can be changed in the GdUnit4 settings dialog.[br] -## - The priority of system hooks cannot be changed and they cannot be deleted.[br] -## [br] -## [b][u]Session Access[/u][/b][br] -## -## Both [i]startup()[/i] and [i]shutdown()[/i] methods receive a [GdUnitTestSession] parameter that provides:[br] -## - Access to test cases being executed[br] -## - Event emission capabilities for test progress tracking[br] -## - Message sending functionality for logging and communication[br] -class_name GdUnitTestSessionHook -extends RefCounted - - -## The display name of this hook. -var name: String: - get: - return name - - -## A detailed description of what this hook does. -var description: String: - get: - return description - - -## Initializes a new test session hook. -## -## [param _name] The display name for this hook -## [param _description] A detailed description of the hook's functionality -func _init(_name: String, _description: String) -> void: - self.name = _name - self.description = _description - - -## Called when the test session starts up, before any tests are executed.[br] -## [br] -## [color=yellow][i]This method should be overridden to implement custom initialization logic[/i][/color][br] -## [br] -## such as:[br] -## - Setting up test databases or external services[br] -## - Initializing mock objects or test fixtures[br] -## - Configuring logging or reporting systems[br] -## - Preparing the test environment[br] -## - Subscribing to test events via the session[br] -## [br] -## [param session] The test session instance providing access to test data and communication[br] -## [b]return:[/b] [code]GdUnitResult.success()[/code] if initialization succeeds, or [code]GdUnitResult.error("error")[/code] with -## an error message if initialization fails. -func startup(_session: GdUnitTestSession) -> GdUnitResult: - return GdUnitResult.error("%s:startup is not implemented" % get_script().resource_path) - - -## Called when the test session shuts down, after all tests have completed.[br] -## [br] -## [color=yellow][i]This method should be overridden to implement custom cleanup logic[/i][/color][br] -## [br] -## such as:[br] -## - Cleaning up test databases or external services[br] -## - Generating test reports or artifacts[br] -## - Releasing resources allocated during startup[br] -## - Performing final validation or assertions[br] -## - Processing collected test events and data[br] -## [br] -## [param session] The test session instance providing access to test results and communication[br] -## [b]return:[/b] [code]GdUnitResult.success()[/code] if cleanup succeeds, or [code]GdUnitResult.error("error")[/code] with -## an error message if cleanup fails. Cleanup errors are typically logged -## but don't prevent the test engine from shutting down. -func shutdown(_session: GdUnitTestSession) -> GdUnitResult: - return GdUnitResult.error("%s:shutdown is not implemented" % get_script().resource_path) diff --git a/addons/gdUnit4/src/core/hooks/GdUnitTestSessionHook.gd.uid b/addons/gdUnit4/src/core/hooks/GdUnitTestSessionHook.gd.uid deleted file mode 100644 index e149ee8c..00000000 --- a/addons/gdUnit4/src/core/hooks/GdUnitTestSessionHook.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bc2ru0ffg38cx diff --git a/addons/gdUnit4/src/core/hooks/GdUnitTestSessionHookService.gd b/addons/gdUnit4/src/core/hooks/GdUnitTestSessionHookService.gd deleted file mode 100644 index 5a9bdcb8..00000000 --- a/addons/gdUnit4/src/core/hooks/GdUnitTestSessionHookService.gd +++ /dev/null @@ -1,191 +0,0 @@ -class_name GdUnitTestSessionHookService -extends Object - - -var enigne_hooks: Array[GdUnitTestSessionHook] = []: - get: - return enigne_hooks - set(value): - enigne_hooks.append(value) - - -var _save_settings: bool = false - - -static func instance() -> GdUnitTestSessionHookService: - return GdUnitSingleton.instance("GdUnitTestSessionHookService", func()->GdUnitTestSessionHookService: - GdUnitSignals.instance().gdunit_message.emit("Installing GdUnit4 session system hooks.") - var service := GdUnitTestSessionHookService.new() - # Register default system hooks here - service._save_settings = false - service.register(GdUnitHtmlReporterTestSessionHook.new()) - service.register(GdUnitXMLReporterTestSessionHook.new()) - service.load_hook_settings() - service._save_settings = true - return service - ) - - -static func contains_hook(current: GdUnitTestSessionHook, other: GdUnitTestSessionHook) -> bool: - return current.get_script().resource_path == other.get_script().resource_path - - -func find_custom(hook: GdUnitTestSessionHook) -> int: - for index in enigne_hooks.size(): - if contains_hook.call(enigne_hooks[index], hook): - return index - return -1 - - -func load_hook(hook_resourc_path: String) -> GdUnitResult: - if !FileAccess.file_exists(hook_resourc_path): - return GdUnitResult.error("The hook '%s' not exists." % hook_resourc_path) - var script: GDScript = load(hook_resourc_path) - if script.get_base_script() != GdUnitTestSessionHook: - return GdUnitResult.error("The hook '%s' must inhertit from 'GdUnitTestSessionHook'." % hook_resourc_path) - - return GdUnitResult.success(script.new()) - - -func enable_hook(hook: GdUnitTestSessionHook, enabled: bool) -> void: - _enable_hook(hook, enabled) - GdUnitSignals.instance().gdunit_message.emit("Session hook '{name}' {enabled}.".format({ - "name": hook.name, - "enabled": "enabled" if enabled else "disabled"}) - ) - save_hock_setttings() - - -func register(hook: GdUnitTestSessionHook, enabled: bool = true) -> GdUnitResult: - if find_custom(hook) != -1: - return GdUnitResult.error("A hook instance of '%s' is already registered." % hook.get_script().resource_path) - - _enable_hook(hook, enabled) - enigne_hooks.append(hook) - save_hock_setttings() - GdUnitSignals.instance().gdunit_message.emit("Session hook '%s' installed." % hook.name) - - return GdUnitResult.success() - - -func unregister(hook: GdUnitTestSessionHook) -> GdUnitResult: - var hook_index := find_custom(hook) - if hook_index == -1: - return GdUnitResult.error("The hook instance of '%s' is NOT registered." % hook.get_script().resource_path) - - enigne_hooks.remove_at(hook_index) - save_hock_setttings() - return GdUnitResult.success() - - -func move_before(hook: GdUnitTestSessionHook, before: GdUnitTestSessionHook) -> void: - var before_index := find_custom(before) - var hook_index := find_custom(hook) - - # Verify the hook to move is behind the hook to be moved - if before_index >= hook_index: - return - - enigne_hooks.remove_at(hook_index) - enigne_hooks.insert(before_index, hook) - save_hock_setttings() - - -func move_after(hook: GdUnitTestSessionHook, after: GdUnitTestSessionHook) -> void: - var after_index := find_custom(after) - var hook_index := find_custom(hook) - - # Verify the hook to move is before the hook to be moved - if after_index <= hook_index: - return - - enigne_hooks.remove_at(hook_index) - enigne_hooks.insert(after_index, hook) - save_hock_setttings() - - -func execute_startup(session: GdUnitTestSession) -> GdUnitResult: - return await execute("startup", session) - - -func execute_shutdown(session: GdUnitTestSession) -> GdUnitResult: - return await execute("shutdown", session, true) - - -func execute(hook_func: String, session: GdUnitTestSession, reverse := false) -> GdUnitResult: - var failed_hook_calls: Array[GdUnitResult] = [] - - for hook_index in enigne_hooks.size(): - var index := enigne_hooks.size()-hook_index-1 if reverse else hook_index - var hook: = enigne_hooks[index] - if not is_enabled(hook): - continue - if OS.is_stdout_verbose(): - GdUnitSignals.instance().gdunit_message.emit("Session hook '%s' > %s()" % [hook.name, hook_func]) - var result: GdUnitResult = await hook.call(hook_func, session) - if result == null: - failed_hook_calls.push_back(GdUnitResult.error("Result is null! Check '%s'" % hook.get_script().resource_path)) - elif result.is_error(): - failed_hook_calls.push_back(result) - - if failed_hook_calls.is_empty(): - return GdUnitResult.success() - - var errors := failed_hook_calls.map(func(result: GdUnitResult) -> String: - return "Hook call '%s' failed with error: '%s'" % [hook_func, result.error_message()] - ) - return GdUnitResult.error( "\n".join(errors)) - - -func save_hock_setttings() -> void: - if not _save_settings: - return - - var hooks_to_save: Dictionary[String, bool] = {} - for hook in enigne_hooks: - var enabled: bool = hook.get_meta("enabled") - hooks_to_save[hook.get_script().resource_path] = enabled - - GdUnitSettings.set_session_hooks(hooks_to_save) - - -func load_hook_settings() -> void: - var hooks_resource_paths := GdUnitSettings.get_session_hooks() - if hooks_resource_paths.is_empty(): - return - - for hock_path: String in hooks_resource_paths.keys(): - var enabled := hooks_resource_paths[hock_path] - - # Do not reinstall already installed hooks - var existing_hook: GdUnitTestSessionHook = enigne_hooks.filter(func(element: GdUnitTestSessionHook) -> bool: - return element.get_script().resource_path == hock_path - ).front() - # Applay enabled settings - if existing_hook != null: - _enable_hook(existing_hook, enabled) - continue - - # Load additional hooks - var result := load_hook(hock_path) - if result.is_error(): - push_error(result.error_message()) - continue - - GdUnitSignals.instance().gdunit_message.emit("Installing GdUnit4 session hooks.") - var hook: GdUnitTestSessionHook = result.value() - - result = register(hook, enabled) - if result.is_error(): - push_error(result.error_message()) - continue - - -static func is_enabled(hook: GdUnitTestSessionHook) -> bool: - if hook.has_meta("enabled"): - return hook.get_meta("enabled") - return true - - -func _enable_hook(hook: GdUnitTestSessionHook, enabled: bool) -> void: - hook.set_meta("enabled", enabled) diff --git a/addons/gdUnit4/src/core/hooks/GdUnitTestSessionHookService.gd.uid b/addons/gdUnit4/src/core/hooks/GdUnitTestSessionHookService.gd.uid deleted file mode 100644 index ca770f4f..00000000 --- a/addons/gdUnit4/src/core/hooks/GdUnitTestSessionHookService.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b83ijyttsj34w diff --git a/addons/gdUnit4/src/core/hooks/GdUnitXMLReporterTestSessionHook.gd b/addons/gdUnit4/src/core/hooks/GdUnitXMLReporterTestSessionHook.gd deleted file mode 100644 index 94caef59..00000000 --- a/addons/gdUnit4/src/core/hooks/GdUnitXMLReporterTestSessionHook.gd +++ /dev/null @@ -1,11 +0,0 @@ -class_name GdUnitXMLReporterTestSessionHook -extends GdUnitBaseReporterTestSessionHook - - -func _init() -> void: - super(JUnitXmlReportWriter.new(), "GdUnitXMLTestReporter", "The JUnit XML test reporting hook.", convert_report_message) - set_meta("SYSTEM_HOOK", true) - - -func convert_report_message(value: String) -> String: - return value diff --git a/addons/gdUnit4/src/core/hooks/GdUnitXMLReporterTestSessionHook.gd.uid b/addons/gdUnit4/src/core/hooks/GdUnitXMLReporterTestSessionHook.gd.uid deleted file mode 100644 index 049277bc..00000000 --- a/addons/gdUnit4/src/core/hooks/GdUnitXMLReporterTestSessionHook.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cg7fh7nftc48e diff --git a/addons/gdUnit4/src/core/parse/GdClassDescriptor.gd b/addons/gdUnit4/src/core/parse/GdClassDescriptor.gd deleted file mode 100644 index fc83742c..00000000 --- a/addons/gdUnit4/src/core/parse/GdClassDescriptor.gd +++ /dev/null @@ -1,25 +0,0 @@ -class_name GdClassDescriptor -extends RefCounted - - -var _name :String -var _is_inner_class :bool -var _functions :Array[GdFunctionDescriptor] - - -func _init(p_name :String, p_is_inner_class :bool, p_functions :Array[GdFunctionDescriptor]) -> void: - _name = p_name - _is_inner_class = p_is_inner_class - _functions = p_functions - - -func name() -> String: - return _name - - -func is_inner_class() -> bool: - return _is_inner_class - - -func functions() -> Array[GdFunctionDescriptor]: - return _functions diff --git a/addons/gdUnit4/src/core/parse/GdClassDescriptor.gd.uid b/addons/gdUnit4/src/core/parse/GdClassDescriptor.gd.uid deleted file mode 100644 index c35b2a6d..00000000 --- a/addons/gdUnit4/src/core/parse/GdClassDescriptor.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c1ipsxino6xxt diff --git a/addons/gdUnit4/src/core/parse/GdDefaultValueDecoder.gd b/addons/gdUnit4/src/core/parse/GdDefaultValueDecoder.gd deleted file mode 100644 index f1b22440..00000000 --- a/addons/gdUnit4/src/core/parse/GdDefaultValueDecoder.gd +++ /dev/null @@ -1,290 +0,0 @@ -# holds all decodings for default values -class_name GdDefaultValueDecoder -extends GdUnitSingleton - - -@warning_ignore("unused_parameter") -var _decoders := { - TYPE_NIL: func(value :Variant) -> String: return "null", - TYPE_STRING: func(value :Variant) -> String: return '"%s"' % value, - TYPE_STRING_NAME: _on_type_StringName, - TYPE_BOOL: func(value :Variant) -> String: return str(value).to_lower(), - TYPE_FLOAT: func(value :Variant) -> String: return '%f' % value, - TYPE_COLOR: _on_type_Color, - TYPE_ARRAY: _on_type_Array.bind(TYPE_ARRAY), - TYPE_PACKED_BYTE_ARRAY: _on_type_Array.bind(TYPE_PACKED_BYTE_ARRAY), - TYPE_PACKED_STRING_ARRAY: _on_type_Array.bind(TYPE_PACKED_STRING_ARRAY), - TYPE_PACKED_FLOAT32_ARRAY: _on_type_Array.bind(TYPE_PACKED_FLOAT32_ARRAY), - TYPE_PACKED_FLOAT64_ARRAY: _on_type_Array.bind(TYPE_PACKED_FLOAT64_ARRAY), - TYPE_PACKED_INT32_ARRAY: _on_type_Array.bind(TYPE_PACKED_INT32_ARRAY), - TYPE_PACKED_INT64_ARRAY: _on_type_Array.bind(TYPE_PACKED_INT64_ARRAY), - TYPE_PACKED_COLOR_ARRAY: _on_type_Array.bind(TYPE_PACKED_COLOR_ARRAY), - TYPE_PACKED_VECTOR2_ARRAY: _on_type_Array.bind(TYPE_PACKED_VECTOR2_ARRAY), - TYPE_PACKED_VECTOR3_ARRAY: _on_type_Array.bind(TYPE_PACKED_VECTOR3_ARRAY), - TYPE_PACKED_VECTOR4_ARRAY: _on_type_Array.bind(TYPE_PACKED_VECTOR4_ARRAY), - TYPE_DICTIONARY: _on_type_Dictionary, - TYPE_RID: _on_type_RID, - TYPE_NODE_PATH: _on_type_NodePath, - TYPE_VECTOR2: _on_type_Vector.bind(TYPE_VECTOR2), - TYPE_VECTOR2I: _on_type_Vector.bind(TYPE_VECTOR2I), - TYPE_VECTOR3: _on_type_Vector.bind(TYPE_VECTOR3), - TYPE_VECTOR3I: _on_type_Vector.bind(TYPE_VECTOR3I), - TYPE_VECTOR4: _on_type_Vector.bind(TYPE_VECTOR4), - TYPE_VECTOR4I: _on_type_Vector.bind(TYPE_VECTOR4I), - TYPE_RECT2: _on_type_Rect2, - TYPE_RECT2I: _on_type_Rect2i, - TYPE_PLANE: _on_type_Plane, - TYPE_QUATERNION: _on_type_Quaternion, - TYPE_AABB: _on_type_AABB, - TYPE_BASIS: _on_type_Basis, - TYPE_CALLABLE: _on_type_Callable, - TYPE_SIGNAL: _on_type_Signal, - TYPE_TRANSFORM2D: _on_type_Transform2D, - TYPE_TRANSFORM3D: _on_type_Transform3D, - TYPE_PROJECTION: _on_type_Projection, - TYPE_OBJECT: _on_type_Object -} - -static func _regex(pattern: String) -> RegEx: - var regex := RegEx.new() - var err := regex.compile(pattern) - if err != OK: - push_error("error '%s' checked pattern '%s'" % [err, pattern]) - return null - return regex - - -func get_decoder(type: int) -> Callable: - return _decoders.get(type, func(value :Variant) -> String: return '%s' % value) - - -func _on_type_StringName(value: StringName) -> String: - if value.is_empty(): - return 'StringName()' - return 'StringName("%s")' % value - - -func _on_type_Object(value: Variant, _type: int) -> String: - return str(value) - - -func _on_type_Color(color: Color) -> String: - if color == Color.BLACK: - return "Color()" - return "Color%s" % color - - -func _on_type_NodePath(path: NodePath) -> String: - if path.is_empty(): - return 'NodePath()' - return 'NodePath("%s")' % path - - -func _on_type_Callable(_cb: Callable) -> String: - return 'Callable()' - - -func _on_type_Signal(_s: Signal) -> String: - return 'Signal()' - - -func _on_type_Dictionary(dict: Dictionary) -> String: - if dict.is_empty(): - return '{}' - return str(dict) - - -func _on_type_Array(value: Variant, type: int) -> String: - match type: - TYPE_ARRAY: - return str(value) - - TYPE_PACKED_COLOR_ARRAY: - var colors := PackedStringArray() - for color: Color in value: - @warning_ignore("return_value_discarded") - colors.append(_on_type_Color(color)) - if colors.is_empty(): - return "PackedColorArray()" - return "PackedColorArray([%s])" % ", ".join(colors) - - TYPE_PACKED_VECTOR2_ARRAY: - var vectors := PackedStringArray() - for vector: Vector2 in value: - @warning_ignore("return_value_discarded") - vectors.append(_on_type_Vector(vector, TYPE_VECTOR2)) - if vectors.is_empty(): - return "PackedVector2Array()" - return "PackedVector2Array([%s])" % ", ".join(vectors) - - TYPE_PACKED_VECTOR3_ARRAY: - var vectors := PackedStringArray() - for vector: Vector3 in value: - @warning_ignore("return_value_discarded") - vectors.append(_on_type_Vector(vector, TYPE_VECTOR3)) - if vectors.is_empty(): - return "PackedVector3Array()" - return "PackedVector3Array([%s])" % ", ".join(vectors) - - TYPE_PACKED_VECTOR4_ARRAY: - var vectors := PackedStringArray() - for vector: Vector4 in value: - @warning_ignore("return_value_discarded") - vectors.append(_on_type_Vector(vector, TYPE_VECTOR4)) - if vectors.is_empty(): - return "PackedVector4Array()" - return "PackedVector4Array([%s])" % ", ".join(vectors) - - TYPE_PACKED_STRING_ARRAY: - var values := PackedStringArray() - for v: String in value: - @warning_ignore("return_value_discarded") - values.append('"%s"' % v) - if values.is_empty(): - return "PackedStringArray()" - return "PackedStringArray([%s])" % ", ".join(values) - - TYPE_PACKED_BYTE_ARRAY,\ - TYPE_PACKED_FLOAT32_ARRAY,\ - TYPE_PACKED_FLOAT64_ARRAY,\ - TYPE_PACKED_INT32_ARRAY,\ - TYPE_PACKED_INT64_ARRAY: - var vectors := PackedStringArray() - for vector: Variant in value: - @warning_ignore("return_value_discarded") - vectors.append(str(vector)) - if vectors.is_empty(): - return GdObjects.type_as_string(type) + "()" - return "%s([%s])" % [GdObjects.type_as_string(type), ", ".join(vectors)] - return "unknown array type %d" % type - - -func _on_type_Vector(value: Variant, type: int) -> String: - - if typeof(value) != type: - push_error("Internal Error: type missmatch detected for value '%s', expects type %s" % [value, type_string(type)]) - return "" - - match type: - TYPE_VECTOR2: - if value == Vector2(): - return "Vector2()" - return "Vector2%s" % value - TYPE_VECTOR2I: - if value == Vector2i(): - return "Vector2i()" - return "Vector2i%s" % value - TYPE_VECTOR3: - if value == Vector3(): - return "Vector3()" - return "Vector3%s" % value - TYPE_VECTOR3I: - if value == Vector3i(): - return "Vector3i()" - return "Vector3i%s" % value - TYPE_VECTOR4: - if value == Vector4(): - return "Vector4()" - return "Vector4%s" % value - TYPE_VECTOR4I: - if value == Vector4i(): - return "Vector4i()" - return "Vector4i%s" % value - return "unknown vector type %d" % type - - -func _on_type_Transform2D(transform: Transform2D) -> String: - if transform == Transform2D(): - return "Transform2D()" - return "Transform2D(Vector2%s, Vector2%s, Vector2%s)" % [transform.x, transform.y, transform.origin] - - -func _on_type_Transform3D(transform: Transform3D) -> String: - if transform == Transform3D(): - return "Transform3D()" - return "Transform3D(Vector3%s, Vector3%s, Vector3%s, Vector3%s)" % [transform.basis.x, transform.basis.y, transform.basis.z, transform.origin] - - -func _on_type_Projection(projection: Projection) -> String: - return "Projection(Vector4%s, Vector4%s, Vector4%s, Vector4%s)" % [projection.x, projection.y, projection.z, projection.w] - - -@warning_ignore("unused_parameter") -func _on_type_RID(value: RID) -> String: - return "RID()" - - -func _on_type_Rect2(rect: Rect2) -> String: - if rect == Rect2(): - return "Rect2()" - return "Rect2(Vector2%s, Vector2%s)" % [rect.position, rect.size] - - -func _on_type_Rect2i(rect: Variant) -> String: - if rect == Rect2i(): - return "Rect2i()" - return "Rect2i(Vector2i%s, Vector2i%s)" % [rect.position, rect.size] - - -func _on_type_Plane(plane: Plane) -> String: - if plane == Plane(): - return "Plane()" - return "Plane(%d, %d, %d, %d)" % [plane.x, plane.y, plane.z, plane.d] - - -func _on_type_Quaternion(quaternion: Quaternion) -> String: - if quaternion == Quaternion(): - return "Quaternion()" - return "Quaternion(%d, %d, %d, %d)" % [quaternion.x, quaternion.y, quaternion.z, quaternion.w] - - -func _on_type_AABB(aabb: AABB) -> String: - if aabb == AABB(): - return "AABB()" - return "AABB(Vector3%s, Vector3%s)" % [aabb.position, aabb.size] - - -func _on_type_Basis(basis: Basis) -> String: - if basis == Basis(): - return "Basis()" - return "Basis(Vector3%s, Vector3%s, Vector3%s)" % [basis.x, basis.y, basis.z] - - -static func decode(value: Variant) -> String: - var type := typeof(value) - @warning_ignore("unsafe_cast") - if GdArrayTools.is_type_array(type) and (value as Array).is_empty(): - return "" - # For Variant types we need to determine the original type - if type == GdObjects.TYPE_VARIANT: - type = typeof(value) - var decoder := _get_value_decoder(type) - if decoder == null: - push_error("No value decoder registered for type '%d'! Please open a Bug issue at 'https://github.com/MikeSchulze/gdUnit4/issues/new/choose'." % type) - return "null" - if type == TYPE_OBJECT: - return decoder.call(value, type) - return decoder.call(value) - - -static func decode_typed(type: int, value: Variant) -> String: - if value == null: - return "null" - # For Variant types we need to determine the original type - if type == GdObjects.TYPE_VARIANT: - type = typeof(value) - var decoder := _get_value_decoder(type) - if decoder == null: - push_error("No value decoder registered for type '%d'! Please open a Bug issue at 'https://github.com/MikeSchulze/gdUnit4/issues/new/choose'." % type) - return "null" - if type == TYPE_OBJECT: - return decoder.call(value, type) - return decoder.call(value) - - -static func _get_value_decoder(type: int) -> Callable: - var decoder: GdDefaultValueDecoder = instance( - "GdUnitDefaultValueDecoders", - func() -> GdDefaultValueDecoder: - return GdDefaultValueDecoder.new()) - return decoder.get_decoder(type) diff --git a/addons/gdUnit4/src/core/parse/GdDefaultValueDecoder.gd.uid b/addons/gdUnit4/src/core/parse/GdDefaultValueDecoder.gd.uid deleted file mode 100644 index 77e9e472..00000000 --- a/addons/gdUnit4/src/core/parse/GdDefaultValueDecoder.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://lklwx7a3htjd diff --git a/addons/gdUnit4/src/core/parse/GdFunctionArgument.gd b/addons/gdUnit4/src/core/parse/GdFunctionArgument.gd deleted file mode 100644 index bd38eb2a..00000000 --- a/addons/gdUnit4/src/core/parse/GdFunctionArgument.gd +++ /dev/null @@ -1,208 +0,0 @@ -class_name GdFunctionArgument -extends RefCounted - - -const GdUnitTools := preload("res://addons/gdUnit4/src/core/GdUnitTools.gd") -const UNDEFINED: String = "<-NO_ARG->" -const ARG_PARAMETERIZED_TEST := ["test_parameters", "_test_parameters"] - -static var _fuzzer_regex: RegEx -static var _cleanup_leading_spaces: RegEx -static var _fix_comma_space: RegEx - -var _name: String -var _type: int -var _type_hint: int -var _default_value: Variant -var _parameter_sets: PackedStringArray = [] - - -func _init(p_name: String, p_type: int, value: Variant = UNDEFINED, p_type_hint: int = TYPE_NIL) -> void: - _init_static_variables() - _name = p_name - _type = p_type - _type_hint = p_type_hint - if value != null and p_name in ARG_PARAMETERIZED_TEST: - _parameter_sets = _parse_parameter_set(str(value)) - _default_value = value - # is argument a fuzzer? - if _type == TYPE_OBJECT and _fuzzer_regex.search(_name): - _type = GdObjects.TYPE_FUZZER - - -func _init_static_variables() -> void: - if _fuzzer_regex == null: - _fuzzer_regex = GdUnitTools.to_regex("((?!(fuzzer_(seed|iterations)))fuzzer?\\w+)( ?+= ?+| ?+:= ?+| ?+:Fuzzer ?+= ?+|)") - _cleanup_leading_spaces = RegEx.create_from_string("(?m)^[ \t]+") - _fix_comma_space = RegEx.create_from_string(""", {0,}\t{0,}(?=(?:[^"]*"[^"]*")*[^"]*$)(?!\\s)""") - - -func name() -> String: - return _name - - -func default() -> Variant: - return type_convert(_default_value, _type) - - -func set_value(value: String) -> void: - # we onle need to apply default values for Objects, all others are provided by the method descriptor - if _type == GdObjects.TYPE_FUZZER: - _default_value = value - return - if _name in ARG_PARAMETERIZED_TEST: - _parameter_sets = _parse_parameter_set(value) - _default_value = value - return - - if _type == TYPE_NIL or _type == GdObjects.TYPE_VARIANT: - _type = _extract_value_type(value) - if _type == GdObjects.TYPE_VARIANT and _default_value == null: - _default_value = value - if _default_value == null: - match _type: - TYPE_DICTIONARY: - _default_value = as_dictionary(value) - TYPE_ARRAY: - _default_value = as_array(value) - GdObjects.TYPE_FUZZER: - _default_value = value - _: - _default_value = str_to_var(value) - # if converting fails assign the original value without converting - if _default_value == null and value != null: - _default_value = value - #prints("set default_value: ", _default_value, "with type %d" % _type, " from original: '%s'" % value) - - -func _extract_value_type(value: String) -> int: - if value != UNDEFINED: - if _fuzzer_regex.search(_name): - return GdObjects.TYPE_FUZZER - if value.rfind(")") == value.length()-1: - return GdObjects.TYPE_FUNC - return _type - - -func value_as_string() -> String: - if has_default(): - return GdDefaultValueDecoder.decode_typed(_type, _default_value) - return "" - - -func plain_value() -> Variant: - return _default_value - - -func type() -> int: - return _type - - -func type_hint() -> int: - return _type_hint - - -func has_default() -> bool: - return not is_same(_default_value, UNDEFINED) - - -func is_typed_array() -> bool: - return _type == TYPE_ARRAY and _type_hint != TYPE_NIL - - -func is_parameter_set() -> bool: - return _name in ARG_PARAMETERIZED_TEST - - -func parameter_sets() -> PackedStringArray: - return _parameter_sets - - -static func get_parameter_set(parameters :Array[GdFunctionArgument]) -> GdFunctionArgument: - for current in parameters: - if current != null and current.is_parameter_set(): - return current - return null - - -func _to_string() -> String: - var s := _name - if _type != TYPE_NIL: - s += ": " + GdObjects.type_as_string(_type) - if _type_hint != TYPE_NIL: - s += "[%s]" % GdObjects.type_as_string(_type_hint) - if has_default(): - s += "=" + value_as_string() - return s - - -func _parse_parameter_set(input :String) -> PackedStringArray: - if not input.contains("["): - return [] - - input = _cleanup_leading_spaces.sub(input, "", true) - input = input.replace("\n", "").strip_edges().trim_prefix("[").trim_suffix("]").trim_prefix("]") - var single_quote := false - var double_quote := false - var array_end := 0 - var current_index := 0 - var output :PackedStringArray = [] - var buf := input.to_utf8_buffer() - var collected_characters: = PackedByteArray() - var matched :bool = false - - for c in buf: - current_index += 1 - matched = current_index == buf.size() - @warning_ignore("return_value_discarded") - collected_characters.push_back(c) - - match c: - # ' ': ignore spaces between array elements - 32: if array_end == 0 and (not double_quote and not single_quote): - collected_characters.remove_at(collected_characters.size()-1) - # ',': step over array element seperator ',' - 44: if array_end == 0: - matched = true - collected_characters.remove_at(collected_characters.size()-1) - # '`': - 39: single_quote = !single_quote - # '"': - 34: if not single_quote: double_quote = !double_quote - # '[' - 91: if not double_quote and not single_quote: array_end +=1 # counts array open - # ']' - 93: if not double_quote and not single_quote: array_end -=1 # counts array closed - - # if array closed than collect the element - if matched: - var parameters := _fix_comma_space.sub(collected_characters.get_string_from_utf8(), ", ", true) - if not parameters.is_empty(): - @warning_ignore("return_value_discarded") - output.append(parameters) - collected_characters.clear() - matched = false - return output - - -## value converters - -func as_array(value: String) -> Array: - if value == "Array()" or value == "[]": - return [] - - if value.begins_with("Array("): - value = value.lstrip("Array(").rstrip(")") - if value.begins_with("["): - return str_to_var(value) - return [] - - -func as_dictionary(value: String) -> Dictionary: - if value == "Dictionary()": - return {} - if value.begins_with("Dictionary("): - value = value.lstrip("Dictionary(").rstrip(")") - if value.begins_with("{"): - return str_to_var(value) - return {} diff --git a/addons/gdUnit4/src/core/parse/GdFunctionArgument.gd.uid b/addons/gdUnit4/src/core/parse/GdFunctionArgument.gd.uid deleted file mode 100644 index 4d744c31..00000000 --- a/addons/gdUnit4/src/core/parse/GdFunctionArgument.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c1fyr61upo4ts diff --git a/addons/gdUnit4/src/core/parse/GdFunctionDescriptor.gd b/addons/gdUnit4/src/core/parse/GdFunctionDescriptor.gd deleted file mode 100644 index 7eae4b2f..00000000 --- a/addons/gdUnit4/src/core/parse/GdFunctionDescriptor.gd +++ /dev/null @@ -1,286 +0,0 @@ -class_name GdFunctionDescriptor -extends RefCounted - -var _is_virtual :bool -var _is_static :bool -var _is_engine :bool -var _is_coroutine :bool -var _name :String -var _source_path: String -var _line_number :int -var _return_type :int -var _return_class :String -var _args : Array[GdFunctionArgument] -var _varargs :Array[GdFunctionArgument] - - - -static func create(p_name: String, p_source_path: String, p_source_line: int, p_return_type: int, p_args: Array[GdFunctionArgument] = []) -> GdFunctionDescriptor: - var fd := GdFunctionDescriptor.new(p_name, p_source_line, false, false, false, p_return_type, "", p_args) - fd.enrich_file_info(p_source_path, p_source_line) - return fd - -static func create_static(p_name: String, p_source_path: String, p_source_line: int, p_return_type: int, p_args: Array[GdFunctionArgument] = []) -> GdFunctionDescriptor: - var fd := GdFunctionDescriptor.new(p_name, p_source_line, false, true, false, p_return_type, "", p_args) - fd.enrich_file_info(p_source_path, p_source_line) - return fd - - -func _init(p_name :String, - p_line_number :int, - p_is_virtual :bool, - p_is_static :bool, - p_is_engine :bool, - p_return_type :int, - p_return_class :String, - p_args : Array[GdFunctionArgument], - p_varargs :Array[GdFunctionArgument] = []) -> void: - _name = p_name - _line_number = p_line_number - _return_type = p_return_type - _return_class = p_return_class - _is_virtual = p_is_virtual - _is_static = p_is_static - _is_engine = p_is_engine - _is_coroutine = false - _args = p_args - _varargs = p_varargs - - -func with_return_class(clazz_name: String) -> GdFunctionDescriptor: - _return_class = clazz_name - return self - - -func name() -> String: - return _name - - -func source_path() -> String: - return _source_path - - -func line_number() -> int: - return _line_number - - -func is_virtual() -> bool: - return _is_virtual - - -func is_static() -> bool: - return _is_static - - -func is_engine() -> bool: - return _is_engine - - -func is_vararg() -> bool: - return not _varargs.is_empty() - - -func is_coroutine() -> bool: - return _is_coroutine - - -func is_parameterized() -> bool: - for current in _args: - var arg :GdFunctionArgument = current - if arg.name() in GdFunctionArgument.ARG_PARAMETERIZED_TEST: - return true - return false - - -func is_private() -> bool: - return name().begins_with("_") and not is_virtual() - - -func return_type() -> int: - return _return_type - - -func return_type_as_string() -> String: - if return_type() == TYPE_NIL: - return "void" - if (return_type() == TYPE_OBJECT or return_type() == GdObjects.TYPE_ENUM) and not _return_class.is_empty(): - return _return_class - return GdObjects.type_as_string(return_type()) - - -func set_argument_value(arg_name: String, value: String) -> void: - var argument: GdFunctionArgument = _args.filter(func(arg: GdFunctionArgument) -> bool: - return arg.name() == arg_name - ).front() - if argument != null: - argument.set_value(value) - - -func enrich_arguments(arguments: Array[Dictionary]) -> void: - for arg_index: int in arguments.size(): - var arg: Dictionary = arguments[arg_index] - if arg["type"] != GdObjects.TYPE_VARARG: - var arg_name: String = arg["name"] - var arg_value: String = arg["value"] - set_argument_value(arg_name, arg_value) - - -func enrich_file_info(p_source_path: String, p_line_number: int) -> void: - _source_path = p_source_path - _line_number = p_line_number - - -func args() -> Array[GdFunctionArgument]: - return _args - - -func varargs() -> Array[GdFunctionArgument]: - return _varargs - - -func typed_args() -> String: - var collect := PackedStringArray() - for arg in args(): - @warning_ignore("return_value_discarded") - collect.push_back(arg._to_string()) - for arg in varargs(): - @warning_ignore("return_value_discarded") - collect.push_back(arg._to_string()) - return ", ".join(collect) - - -func _to_string() -> String: - var fsignature := "virtual " if is_virtual() else "" - if _return_type == TYPE_NIL: - return fsignature + "[Line:%s] func %s(%s):" % [line_number(), name(), typed_args()] - var func_template := fsignature + "[Line:%s] func %s(%s) -> %s:" - if is_static(): - func_template= "[Line:%s] static func %s(%s) -> %s:" - return func_template % [line_number(), name(), typed_args(), return_type_as_string()] - - -# extract function description given by Object.get_method_list() -static func extract_from(descriptor :Dictionary, is_engine_ := true) -> GdFunctionDescriptor: - var func_name: String = descriptor["name"] - var function_flags: int = descriptor["flags"] - var return_descriptor: Dictionary = descriptor["return"] - var clazz_name: String = return_descriptor["class_name"] - var is_virtual_: bool = function_flags & METHOD_FLAG_VIRTUAL - var is_static_: bool = function_flags & METHOD_FLAG_STATIC - var is_vararg_: bool = function_flags & METHOD_FLAG_VARARG - - return GdFunctionDescriptor.new( - func_name, - -1, - is_virtual_, - is_static_, - is_engine_, - _extract_return_type(return_descriptor), - clazz_name, - _extract_args(descriptor), - _build_varargs(is_vararg_) - ) - -# temporary exclude GlobalScope enums -const enum_fix := [ - "Side", - "Corner", - "Orientation", - "ClockDirection", - "HorizontalAlignment", - "VerticalAlignment", - "InlineAlignment", - "EulerOrder", - "Error", - "Key", - "MIDIMessage", - "MouseButton", - "MouseButtonMask", - "JoyButton", - "JoyAxis", - "PropertyHint", - "PropertyUsageFlags", - "MethodFlags", - "Variant.Type", - "Control.LayoutMode"] - - -static func _extract_return_type(return_info :Dictionary) -> int: - var type :int = return_info["type"] - var usage :int = return_info["usage"] - if type == TYPE_INT and usage & PROPERTY_USAGE_CLASS_IS_ENUM: - return GdObjects.TYPE_ENUM - if type == TYPE_NIL and usage & PROPERTY_USAGE_NIL_IS_VARIANT: - return GdObjects.TYPE_VARIANT - if type == TYPE_NIL and usage == 6: - return GdObjects.TYPE_VOID - return type - - -static func _extract_args(descriptor :Dictionary) -> Array[GdFunctionArgument]: - var args_ :Array[GdFunctionArgument] = [] - var arguments :Array = descriptor["args"] - var defaults :Array = descriptor["default_args"] - # iterate backwards because the default values are stored from right to left - while not arguments.is_empty(): - var arg :Dictionary = arguments.pop_back() - var arg_name := _argument_name(arg) - var arg_type := _argument_type(arg) - var arg_type_hint := _argument_hint(arg) - #var arg_class: StringName = arg["class_name"] - var default_value: Variant = GdFunctionArgument.UNDEFINED if defaults.is_empty() else defaults.pop_back() - args_.push_front(GdFunctionArgument.new(arg_name, arg_type, default_value, arg_type_hint)) - return args_ - - -static func _build_varargs(p_is_vararg :bool) -> Array[GdFunctionArgument]: - var varargs_ :Array[GdFunctionArgument] = [] - if not p_is_vararg: - return varargs_ - varargs_.push_back(GdFunctionArgument.new("varargs", GdObjects.TYPE_VARARG, '')) - return varargs_ - - -static func _argument_name(arg :Dictionary) -> String: - return arg["name"] - - -static func _argument_type(arg :Dictionary) -> int: - var type :int = arg["type"] - var usage :int = arg["usage"] - - if type == TYPE_OBJECT: - if arg["class_name"] == "Node": - return GdObjects.TYPE_NODE - if arg["class_name"] == "Fuzzer": - return GdObjects.TYPE_FUZZER - - # if the argument untyped we need to scan the assignef value type - if type == TYPE_NIL and usage == PROPERTY_USAGE_NIL_IS_VARIANT: - return GdObjects.TYPE_VARIANT - return type - - -static func _argument_hint(arg :Dictionary) -> int: - var hint :int = arg["hint"] - var hint_string :String = arg["hint_string"] - - match hint: - PROPERTY_HINT_ARRAY_TYPE: - return GdObjects.string_to_type(hint_string) - _: - return 0 - - -static func _argument_type_as_string(arg :Dictionary) -> String: - var type := _argument_type(arg) - match type: - TYPE_NIL: - return "" - TYPE_OBJECT: - var clazz_name :String = arg["class_name"] - if not clazz_name.is_empty(): - return clazz_name - return "" - _: - return GdObjects.type_as_string(type) diff --git a/addons/gdUnit4/src/core/parse/GdFunctionDescriptor.gd.uid b/addons/gdUnit4/src/core/parse/GdFunctionDescriptor.gd.uid deleted file mode 100644 index f11d0ec4..00000000 --- a/addons/gdUnit4/src/core/parse/GdFunctionDescriptor.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bascqhwocxsl4 diff --git a/addons/gdUnit4/src/core/parse/GdFunctionParameterSetResolver.gd b/addons/gdUnit4/src/core/parse/GdFunctionParameterSetResolver.gd deleted file mode 100644 index 9c45e625..00000000 --- a/addons/gdUnit4/src/core/parse/GdFunctionParameterSetResolver.gd +++ /dev/null @@ -1,188 +0,0 @@ -class_name GdFunctionParameterSetResolver -extends RefCounted - -const CLASS_TEMPLATE = """ -class_name _ParameterExtractor extends '${clazz_path}' - -func __extract_test_parameters() -> Array: - return ${test_params} - -""" - -const EXCLUDE_PROPERTIES_TO_COPY = [ - "script", - "type", - "Node", - "_import_path"] - - -var _fd: GdFunctionDescriptor -var _static_sets_by_index := {} -var _is_static := true - -func _init(fd: GdFunctionDescriptor) -> void: - _fd = fd - - -func resolve_test_cases(script: GDScript) -> Array[GdUnitTestCase]: - if not is_parameterized(): - return [GdUnitTestCase.from(script.resource_path, _fd.source_path(), _fd.line_number(), _fd.name())] - return extract_test_cases_by_reflection(script) - - -func is_parameterized() -> bool: - return _fd.is_parameterized() - - -func is_parameter_sets_static() -> bool: - return _is_static - - -func is_parameter_set_static(index: int) -> bool: - return _is_static and _static_sets_by_index.get(index, false) - - -# validates the given arguments are complete and matches to required input fields of the test function -func validate(input_value_set: Array) -> String: - var input_arguments := _fd.args() - # check given parameter set with test case arguments - var expected_arg_count := input_arguments.size() - 1 - for input_values :Variant in input_value_set: - var parameter_set_index := input_value_set.find(input_values) - if input_values is Array: - var arr_values: Array = input_values - var current_arg_count := arr_values.size() - if current_arg_count != expected_arg_count: - return "\n The parameter set at index [%d] does not match the expected input parameters!\n The test case requires [%d] input parameters, but the set contains [%d]" % [parameter_set_index, expected_arg_count, current_arg_count] - var error := validate_parameter_types(input_arguments, arr_values, parameter_set_index) - if not error.is_empty(): - return error - else: - return "\n The parameter set at index [%d] does not match the expected input parameters!\n Expecting an array of input values." % parameter_set_index - return "" - - -static func validate_parameter_types(input_arguments: Array, input_values: Array, parameter_set_index: int) -> String: - for i in input_arguments.size(): - var input_param: GdFunctionArgument = input_arguments[i] - # only check the test input arguments - if input_param.is_parameter_set(): - continue - var input_param_type := input_param.type() - var input_value :Variant = input_values[i] - var input_value_type := typeof(input_value) - # input parameter is not typed or is Variant we skip the type test - if input_param_type == TYPE_NIL or input_param_type == GdObjects.TYPE_VARIANT: - continue - # is input type enum allow int values - if input_param_type == GdObjects.TYPE_VARIANT and input_value_type == TYPE_INT: - continue - # allow only equal types and object == null - if input_param_type == TYPE_OBJECT and input_value_type == TYPE_NIL: - continue - if input_param_type != input_value_type: - return "\n The parameter set at index [%d] does not match the expected input parameters!\n The value '%s' does not match the required input parameter <%s>." % [parameter_set_index, input_value, input_param] - return "" - - -func extract_test_cases_by_reflection(script: GDScript) -> Array[GdUnitTestCase]: - var source: Node = script.new() - source.queue_free() - - var fa := GdFunctionArgument.get_parameter_set(_fd.args()) - var parameter_sets := fa.parameter_sets() - # if no parameter set detected we need to resolve it by using reflection - if parameter_sets.size() == 0: - _is_static = false - return _extract_test_cases_by_reflection(source, script) - else: - var test_cases: Array[GdUnitTestCase] = [] - var property_names := _extract_property_names(source) - for parameter_set_index in parameter_sets.size(): - var parameter_set := parameter_sets[parameter_set_index] - _static_sets_by_index[parameter_set_index] = _is_static_parameter_set(parameter_set, property_names) - @warning_ignore("return_value_discarded") - test_cases.append(GdUnitTestCase.from(script.resource_path, _fd.source_path(), _fd.line_number(), _fd.name(), parameter_set_index, parameter_set)) - parameter_set_index += 1 - return test_cases - - -func _extract_property_names(source: Node) -> PackedStringArray: - return source.get_property_list()\ - .map(func(property :Dictionary) -> String: return property["name"])\ - .filter(func(property :String) -> bool: return !EXCLUDE_PROPERTIES_TO_COPY.has(property)) - - -# tests if the test property set contains an property reference by name, if not the parameter set holds only static values -func _is_static_parameter_set(parameters :String, property_names :PackedStringArray) -> bool: - for property_name in property_names: - if parameters.contains(property_name): - _is_static = false - return false - return true - - -func _extract_test_cases_by_reflection(source: Node, script: GDScript) -> Array[GdUnitTestCase]: - var parameter_sets := load_parameter_sets(source) - var test_cases: Array[GdUnitTestCase] = [] - for index in parameter_sets.size(): - var parameter_set := str(parameter_sets[index]) - @warning_ignore("return_value_discarded") - test_cases.append(GdUnitTestCase.from(script.resource_path, _fd.source_path(), _fd.line_number(), _fd.name(), index, parameter_set)) - return test_cases - - -# extracts the arguments from the given test case, using kind of reflection solution -# to restore the parameters from a string representation to real instance type -func load_parameter_sets(source: Node) -> Array: - var source_script: GDScript = source.get_script() - var parameter_arg := GdFunctionArgument.get_parameter_set(_fd.args()) - var source_code := CLASS_TEMPLATE \ - .replace("${clazz_path}", source_script.resource_path) \ - .replace("${test_params}", parameter_arg.value_as_string()) - var script := GDScript.new() - script.source_code = source_code - # enable this lines only for debuging - #script.resource_path = GdUnitFileAccess.create_temp_dir("parameter_extract") + "/%s__.gd" % test_case.get_name() - #DirAccess.remove_absolute(script.resource_path) - #ResourceSaver.save(script, script.resource_path) - var result := script.reload() - if result != OK: - push_error("Extracting test parameters failed! Script loading error: %s" % result) - return [] - var instance: Node = script.new() - GdFunctionParameterSetResolver.copy_properties(source, instance) - instance.queue_free() - var parameter_sets: Array = instance.call("__extract_test_parameters") - return fixure_typed_parameters(parameter_sets, _fd.args()) - - -func fixure_typed_parameters(parameter_sets: Array, arg_descriptors: Array[GdFunctionArgument]) -> Array: - for parameter_set_index in parameter_sets.size(): - var parameter_set: Array = parameter_sets[parameter_set_index] - # run over all function arguments - for parameter_index in parameter_set.size(): - var parameter :Variant = parameter_set[parameter_index] - var arg_descriptor: GdFunctionArgument = arg_descriptors[parameter_index] - if parameter is Array: - var as_array: Array = parameter - # we need to convert the untyped array to the expected typed version - if arg_descriptor.is_typed_array(): - parameter_set[parameter_index] = Array(as_array, arg_descriptor.type_hint(), "", null) - return parameter_sets - - -static func copy_properties(source: Object, dest: Object) -> void: - for property in source.get_property_list(): - var property_name :String = property["name"] - var property_value :Variant = source.get(property_name) - if EXCLUDE_PROPERTIES_TO_COPY.has(property_name): - continue - #if dest.get(property_name) == null: - # prints("|%s|" % property_name, source.get(property_name)) - - # check for invalid name property - if property_name == "name" and property_value == "": - dest.set(property_name, ""); - continue - dest.set(property_name, property_value) diff --git a/addons/gdUnit4/src/core/parse/GdFunctionParameterSetResolver.gd.uid b/addons/gdUnit4/src/core/parse/GdFunctionParameterSetResolver.gd.uid deleted file mode 100644 index 083918b5..00000000 --- a/addons/gdUnit4/src/core/parse/GdFunctionParameterSetResolver.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://d0q8x2w5alxsx diff --git a/addons/gdUnit4/src/core/parse/GdScriptParser.gd b/addons/gdUnit4/src/core/parse/GdScriptParser.gd deleted file mode 100644 index a1025082..00000000 --- a/addons/gdUnit4/src/core/parse/GdScriptParser.gd +++ /dev/null @@ -1,764 +0,0 @@ -class_name GdScriptParser -extends RefCounted - -const GdUnitTools := preload("res://addons/gdUnit4/src/core/GdUnitTools.gd") - -const TYPE_VOID = GdObjects.TYPE_VOID -const TYPE_VARIANT = GdObjects.TYPE_VARIANT -const TYPE_VARARG = GdObjects.TYPE_VARARG -const TYPE_FUNC = GdObjects.TYPE_FUNC -const TYPE_FUZZER = GdObjects.TYPE_FUZZER -const TYPE_ENUM = GdObjects.TYPE_ENUM - - -var TOKEN_NOT_MATCH := Token.new("") -var TOKEN_SPACE := SkippableToken.new(" ") -var TOKEN_TABULATOR := SkippableToken.new("\t") -var TOKEN_NEW_LINE := SkippableToken.new("\n") -var TOKEN_COMMENT := SkippableToken.new("#") -var TOKEN_CLASS_NAME := RegExToken.new("class_name", GdUnitTools.to_regex("(class_name)\\s+([\\w\\p{L}\\p{N}_]+) (extends[a-zA-Z]+:)|(class_name)\\s+([\\w\\p{L}\\p{N}_]+)"), 5) -var TOKEN_INNER_CLASS := TokenInnerClass.new("class", GdUnitTools.to_regex("(class)\\s+(\\w\\p{L}\\p{N}_]+) (extends[a-zA-Z]+:)|(class)\\s+([\\w\\p{L}\\p{N}_]+)"), 5) -var TOKEN_EXTENDS := RegExToken.new("extends", GdUnitTools.to_regex("extends\\s+")) -var TOKEN_ENUM := RegExToken.new("enum", GdUnitTools.to_regex("enum\\s+")) -var TOKEN_FUNCTION_STATIC_DECLARATION := RegExToken.new("static func", GdUnitTools.to_regex("^static\\s+func\\s+([\\w\\p{L}\\p{N}_]+)"), 1) -var TOKEN_FUNCTION_DECLARATION := RegExToken.new("func", GdUnitTools.to_regex("^func\\s+([\\w\\p{L}\\p{N}_]+)"), 1) -var TOKEN_FUNCTION := Token.new(".") -var TOKEN_FUNCTION_RETURN_TYPE := Token.new("->") -var TOKEN_FUNCTION_END := Token.new("):") -var TOKEN_ARGUMENT_ASIGNMENT := Token.new("=") -var TOKEN_ARGUMENT_TYPE_ASIGNMENT := Token.new(":=") -var TOKEN_ARGUMENT_FUZZER := FuzzerToken.new(GdUnitTools.to_regex("((?!(fuzzer_(seed|iterations)))fuzzer?\\w+)( ?+= ?+| ?+:= ?+| ?+:Fuzzer ?+= ?+|)")) -var TOKEN_ARGUMENT_TYPE := Token.new(":") -var TOKEN_ARGUMENT_VARIADIC := Token.new("...") -var TOKEN_ARGUMENT_SEPARATOR := Token.new(",") -var TOKEN_BRACKET_ROUND_OPEN := Token.new("(") -var TOKEN_BRACKET_ROUND_CLOSE := Token.new(")") -var TOKEN_BRACKET_SQUARE_OPEN := Token.new("[") -var TOKEN_BRACKET_SQUARE_CLOSE := Token.new("]") -var TOKEN_BRACKET_CURLY_OPEN := Token.new("{") -var TOKEN_BRACKET_CURLY_CLOSE := Token.new("}") - - -var OPERATOR_ADD := Operator.new("+") -var OPERATOR_SUB := Operator.new("-") -var OPERATOR_MUL := Operator.new("*") -var OPERATOR_DIV := Operator.new("/") -var OPERATOR_REMAINDER := Operator.new("%") - -var TOKENS :Array[Token] = [ - TOKEN_SPACE, - TOKEN_TABULATOR, - TOKEN_NEW_LINE, - TOKEN_COMMENT, - TOKEN_BRACKET_ROUND_OPEN, - TOKEN_BRACKET_ROUND_CLOSE, - TOKEN_BRACKET_SQUARE_OPEN, - TOKEN_BRACKET_SQUARE_CLOSE, - TOKEN_BRACKET_CURLY_OPEN, - TOKEN_BRACKET_CURLY_CLOSE, - TOKEN_CLASS_NAME, - TOKEN_INNER_CLASS, - TOKEN_EXTENDS, - TOKEN_ENUM, - TOKEN_FUNCTION_STATIC_DECLARATION, - TOKEN_FUNCTION_DECLARATION, - TOKEN_ARGUMENT_FUZZER, - TOKEN_ARGUMENT_TYPE_ASIGNMENT, - TOKEN_ARGUMENT_ASIGNMENT, - TOKEN_ARGUMENT_TYPE, - TOKEN_ARGUMENT_VARIADIC, - TOKEN_FUNCTION, - TOKEN_ARGUMENT_SEPARATOR, - TOKEN_FUNCTION_RETURN_TYPE, - OPERATOR_ADD, - OPERATOR_SUB, - OPERATOR_MUL, - OPERATOR_DIV, - OPERATOR_REMAINDER, -] - -var _regex_strip_comments := GdUnitTools.to_regex("^([^#\"']|'[^']*'|\"[^\"]*\")*\\K#.*") -var _scanned_inner_classes := PackedStringArray() -var _script_constants := {} -var _is_awaiting := GdUnitTools.to_regex("\\bawait\\s+(?![^\"]*\"[^\"]*$)(?!.*#.*await)") - - -static func to_unix_format(input :String) -> String: - return input.replace("\r\n", "\n") - - -class Token extends RefCounted: - var _token: String - var _consumed: int - var _is_operator: bool - - func _init(p_token: String, p_is_operator := false) -> void: - _token = p_token - _is_operator = p_is_operator - _consumed = p_token.length() - - func match(input: String, pos: int) -> bool: - return input.findn(_token, pos) == pos - - func value() -> Variant: - return _token - - func is_operator() -> bool: - return _is_operator - - func is_inner_class() -> bool: - return _token == "class" - - func is_variable() -> bool: - return false - - func is_token(token_name :String) -> bool: - return _token == token_name - - func is_skippable() -> bool: - return false - - func _to_string() -> String: - return "Token{" + _token + "}" - - -class Operator extends Token: - func _init(p_value: String) -> void: - super(p_value, true) - - func _to_string() -> String: - return "OperatorToken{%s}" % [_token] - - -# A skippable token, is just a placeholder like space or tabs -class SkippableToken extends Token: - - func _init(p_token: String) -> void: - super(p_token) - - func is_skippable() -> bool: - return true - - -# Token to parse function arguments -class Variable extends Token: - var _plain_value :String - var _typed_value :Variant - var _type :int = TYPE_NIL - - - func _init(p_value: String) -> void: - super(p_value) - _type = _scan_type(p_value) - _plain_value = p_value - _typed_value = _cast_to_type(p_value, _type) - - - func _scan_type(p_value: String) -> int: - if p_value.begins_with("\"") and p_value.ends_with("\""): - return TYPE_STRING - var type_ := GdObjects.string_to_type(p_value) - if type_ != TYPE_NIL: - return type_ - if p_value.is_valid_int(): - return TYPE_INT - if p_value.is_valid_float(): - return TYPE_FLOAT - if p_value.is_valid_hex_number(): - return TYPE_INT - return TYPE_OBJECT - - - func _cast_to_type(p_value :String, p_type: int) -> Variant: - match p_type: - TYPE_STRING: - return p_value#.substr(1, p_value.length() - 2) - TYPE_INT: - return p_value.to_int() - TYPE_FLOAT: - return p_value.to_float() - return p_value - - - func is_variable() -> bool: - return true - - - func type() -> int: - return _type - - - func value() -> Variant: - return _typed_value - - - func plain_value() -> String: - return _plain_value - - - func _to_string() -> String: - return "Variable{%s: %s : '%s'}" % [_plain_value, GdObjects.type_as_string(_type), _token] - - -class RegExToken extends Token: - var _regex: RegEx - var _extract_group_index: int - var _value := "" - - - func _init(token: String, regex: RegEx, extract_group_index: int = -1) -> void: - super(token, false) - _regex = regex - _extract_group_index = extract_group_index - - - func match(input: String, pos: int) -> bool: - var matching := _regex.search(input, pos) - if matching == null or pos != matching.get_start(): - return false - if _extract_group_index != -1: - _value = matching.get_string(_extract_group_index) - _consumed = matching.get_end() - matching.get_start() - return true - - - func value() -> String: - return _value - - -# Token to parse Fuzzers -class FuzzerToken extends RegExToken: - - - func _init(regex: RegEx) -> void: - super("fuzzer", regex, 1) - - - func name() -> String: - return value() - - - func type() -> int: - return GdObjects.TYPE_FUZZER - - - func _to_string() -> String: - return "FuzzerToken{%s: '%s'}" % [value(), _token] - - -class TokenInnerClass extends RegExToken: - var _content := PackedStringArray() - - - static func _strip_leading_spaces(input: String) -> String: - var characters := input.to_utf8_buffer() - while not characters.is_empty(): - if characters[0] != 0x20: - break - characters.remove_at(0) - return characters.get_string_from_utf8() - - - static func _consumed_bytes(row: String) -> int: - return row.replace(" ", "").replace(" ", "").length() - - - func _init(token: String, p_regex: RegEx, extract_group_index: int = -1) -> void: - super(token, p_regex, extract_group_index) - - - func is_class_name(clazz_name: String) -> bool: - return value() == clazz_name - - - func content() -> PackedStringArray: - return _content - - - @warning_ignore_start("return_value_discarded") - func parse(source_rows: PackedStringArray, offset: int) -> void: - # add class signature - _content.clear() - _content.append(source_rows[offset]) - # parse class content - for row_index in range(offset+1, source_rows.size()): - # scan until next non tab - var source_row := source_rows[row_index] - var row := TokenInnerClass._strip_leading_spaces(source_row) - if row.is_empty() or row.begins_with("\t") or row.begins_with("#"): - # fold all line to left by removing leading tabs and spaces - if source_row.begins_with("\t"): - source_row = source_row.trim_prefix("\t") - # refomat invalid empty lines - if source_row.dedent().is_empty(): - _content.append("") - else: - _content.append(source_row) - continue - break - _consumed += TokenInnerClass._consumed_bytes("".join(_content)) - @warning_ignore_restore("return_value_discarded") - - - func _to_string() -> String: - return "TokenInnerClass{%s}" % [value()] - - - -func get_token(input: String, current_index: int) -> Token: - for t in TOKENS: - if t.match(input, current_index): - return t - return TOKEN_NOT_MATCH - - -func next_token(input: String, current_index: int, ignore_tokens :Array[Token] = []) -> Token: - var token := TOKEN_NOT_MATCH - for t :Token in TOKENS.filter(func(t :Token) -> bool: return not ignore_tokens.has(t)): - - if t.match(input, current_index): - token = t - break - if token == OPERATOR_SUB: - token = tokenize_value(input, current_index, token) - if token == TOKEN_NOT_MATCH: - return tokenize_value(input, current_index, token, ignore_tokens.has(TOKEN_FUNCTION)) - return token - - -func tokenize_value(input: String, current: int, token: Token, ignore_dots := false) -> Token: - var next := 0 - var current_token := "" - # test for '--', '+-', '*-', '/-', '%-', or at least '-x' - var test_for_sign := (token == null or token.is_operator()) and input[current] == "-" - while current + next < len(input): - var character := input[current + next] as String - # if first charater a sign - # or allowend charset - # or is a float value - if (test_for_sign and next==0) \ - or is_allowed_character(character) \ - or (character == "." and (ignore_dots or current_token.is_valid_int())): - current_token += character - next += 1 - continue - break - if current_token != "": - return Variable.new(current_token) - return TOKEN_NOT_MATCH - - -# const ALLOWED_CHARACTERS := "0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\"" -func is_allowed_character(input: String) -> bool: - var code_point := input.unicode_at(0) - # Unicode - if code_point > 127: - # This is a Unicode character (Chinese, Japanese, etc.) - return true - # ASCII digit 0-9 - if code_point >= 48 and code_point <= 57: - return true - # ASCII lowercase a-z - if code_point >= 97 and code_point <= 122: - return true - # ASCII uppercase A-Z - if code_point >= 65 and code_point <= 90: - return true - # underscore _ - if code_point == 95: - return true - # quotes '" - if code_point == 34 or code_point == 39: - return true - return false - - -func parse_return_token(input: String) -> Variable: - var index := input.rfind(TOKEN_FUNCTION_RETURN_TYPE._token) - if index == -1: - return TOKEN_NOT_MATCH - index += TOKEN_FUNCTION_RETURN_TYPE._consumed - # We scan for the return value exclusive '.' token because it could be referenced to a - # external or internal class e.g. 'func foo() -> InnerClass.Bar:' - var token := next_token(input, index, [TOKEN_FUNCTION]) - while !token.is_variable() and token != TOKEN_NOT_MATCH: - index += token._consumed - token = next_token(input, index, [TOKEN_FUNCTION]) - return token - - -func get_function_descriptors(script: GDScript, included_functions: PackedStringArray = []) -> Array[GdFunctionDescriptor]: - var fds: Array[GdFunctionDescriptor] = [] - for method_descriptor in script.get_script_method_list(): - var func_name: String = method_descriptor["name"] - if included_functions.is_empty() or func_name in included_functions: - # exclude type set/geters - if is_getter_or_setter(func_name): - continue - if not fds.any(func(fd: GdFunctionDescriptor) -> bool: return fd.name() == func_name): - fds.append(GdFunctionDescriptor.extract_from(method_descriptor, false)) - - # we need to enrich it by default arguments and line number by parsing the script - # the engine core functions has no valid methods to get this info - _prescan_script(script) - _enrich_function_descriptor(script, fds) - return fds - - -func is_getter_or_setter(func_name: String) -> bool: - return func_name.begins_with("@") and (func_name.ends_with("getter") or func_name.ends_with("setter")) - - -func _parse_function_arguments(input: String) -> Array[Dictionary]: - var arguments: Array[Dictionary] = [] - var current_index := 0 - var token: Token = null - var bracket := 0 - var in_function := false - - - while current_index < len(input): - token = next_token(input, current_index) - # fallback to not end in a endless loop - if token == TOKEN_NOT_MATCH: - var error : = """ - Parsing Error: Invalid token at pos %d found. - Please report this error! - source_code: - -------------------------------------------------------------- - %s - -------------------------------------------------------------- - """.dedent() % [current_index, input] - push_error(error) - current_index += 1 - continue - current_index += token._consumed - if token.is_skippable(): - continue - if token == TOKEN_BRACKET_ROUND_OPEN : - in_function = true - bracket += 1 - if token == TOKEN_BRACKET_ROUND_CLOSE: - bracket -= 1 - # if function end? - if in_function and bracket == 0: - return arguments - # is function - if token == TOKEN_FUNCTION_DECLARATION: - continue - - # is value argument - if in_function: - var arg_value := "" - var current_argument := { - "name" : "", - "value" : GdFunctionArgument.UNDEFINED, - "type" : TYPE_VARIANT - } - - # parse type and default value - while current_index < len(input): - token = next_token(input, current_index) - current_index += token._consumed - if token.is_skippable(): - continue - - if token.is_variable() && current_argument["name"] == "": - arguments.append(current_argument) - current_argument["name"] = (token as Variable).plain_value() - continue - - match token: - # is fuzzer argument - TOKEN_ARGUMENT_FUZZER: - arg_value = _parse_end_function(input.substr(current_index), true) - current_index += arg_value.length() - current_argument["name"] = (token as FuzzerToken).name() - current_argument["value"] = arg_value.lstrip(" ") - current_argument["type"] = TYPE_FUZZER - arguments.append(current_argument) - continue - - TOKEN_ARGUMENT_VARIADIC: - current_argument["type"] = TYPE_VARARG - - TOKEN_ARGUMENT_TYPE: - token = next_token(input, current_index) - if token == TOKEN_SPACE: - current_index += token._consumed - token = next_token(input, current_index) - current_index += token._consumed - if current_argument["type"] != TYPE_VARARG: - current_argument["type"] = GdObjects.string_to_type((token as Variable).plain_value()) - - TOKEN_ARGUMENT_TYPE_ASIGNMENT: - arg_value = _parse_end_function(input.substr(current_index), true) - current_index += arg_value.length() - current_argument["value"] = arg_value.lstrip(" ") - TOKEN_ARGUMENT_ASIGNMENT: - token = next_token(input, current_index) - arg_value = _parse_end_function(input.substr(current_index), true) - current_index += arg_value.length() - current_argument["value"] = arg_value.lstrip(" ") - - TOKEN_BRACKET_SQUARE_OPEN: - bracket += 1 - TOKEN_BRACKET_CURLY_OPEN: - bracket += 1 - TOKEN_BRACKET_ROUND_OPEN : - bracket += 1 - # if value a function? - if bracket > 1: - # complete the argument value - var func_begin := input.substr(current_index-TOKEN_BRACKET_ROUND_OPEN ._consumed) - var func_body := _parse_end_function(func_begin) - arg_value += func_body - # fix parse index to end of value - current_index += func_body.length() - TOKEN_BRACKET_ROUND_OPEN ._consumed - TOKEN_BRACKET_ROUND_CLOSE._consumed - TOKEN_BRACKET_SQUARE_CLOSE: - bracket -= 1 - TOKEN_BRACKET_CURLY_CLOSE: - bracket -= 1 - TOKEN_BRACKET_ROUND_CLOSE: - bracket -= 1 - # end of function - if bracket == 0: - break - TOKEN_ARGUMENT_SEPARATOR: - if bracket <= 1: - # next argument - current_argument = { - "name" : "", - "value" : GdFunctionArgument.UNDEFINED, - "type" : GdObjects.TYPE_VARIANT - } - continue - return arguments - - -func _parse_end_function(input: String, remove_trailing_char := false) -> String: - # find end of function - var current_index := 0 - var bracket_count := 0 - var in_array := 0 - var in_dict := 0 - var end_of_func := false - - while current_index < len(input) and not end_of_func: - var character := input[current_index] - # step over strings - if character == "'" : - current_index = input.find("'", current_index+1) + 1 - if current_index == 0: - push_error("Parsing error on '%s', can't evaluate end of string." % input) - return "" - continue - if character == '"' : - # test for string blocks - if input.find('"""', current_index) == current_index: - current_index = input.find('"""', current_index+3) + 3 - else: - current_index = input.find('"', current_index+1) + 1 - if current_index == 0: - push_error("Parsing error on '%s', can't evaluate end of string." % input) - return "" - continue - - match character: - # count if inside an array - "[": in_array += 1 - "]": in_array -= 1 - # count if inside an dictionary - "{": in_dict += 1 - "}": in_dict -= 1 - # count if inside a function - "(": bracket_count += 1 - ")": - bracket_count -= 1 - if bracket_count < 0 and in_array <= 0 and in_dict <= 0: - end_of_func = true - ",": - if bracket_count == 0 and in_array == 0 and in_dict <= 0: - end_of_func = true - current_index += 1 - if remove_trailing_char: - # check if the parsed value ends with comma or end of doubled breaked - # `,` or `())` - var trailing_char := input[current_index-1] - if trailing_char == ',' or (bracket_count < 0 and trailing_char == ')'): - return input.substr(0, current_index-1) - return input.substr(0, current_index) - - -func extract_inner_class(source_rows: PackedStringArray, clazz_name :String) -> PackedStringArray: - for row_index in source_rows.size(): - var input := source_rows[row_index] - var token := next_token(input, 0) - if token.is_inner_class(): - @warning_ignore("unsafe_method_access") - if token.is_class_name(clazz_name): - @warning_ignore("unsafe_method_access") - token.parse(source_rows, row_index) - @warning_ignore("unsafe_method_access") - return token.content() - return PackedStringArray() - - -func extract_func_signature(rows: PackedStringArray, index: int) -> String: - var signature := "" - - for rowIndex in range(index, rows.size()): - var row := rows[rowIndex] - row = _regex_strip_comments.sub(row, "").strip_edges(false) - if row.is_empty(): - continue - signature += row + "\n" - if is_func_end(row): - return signature.strip_edges() - push_error("Can't fully extract function signature of '%s'" % rows[index]) - return "" - - -func get_class_name(script :GDScript) -> String: - var source_code := GdScriptParser.to_unix_format(script.source_code) - var source_rows := source_code.split("\n") - - for index :int in min(10, source_rows.size()): - var input := source_rows[index] - var token := next_token(input, 0) - if token == TOKEN_CLASS_NAME: - return token.value() - # if no class_name found extract from file name - return GdObjects.to_pascal_case(script.resource_path.get_basename().get_file()) - - -func parse_func_name(input: String) -> String: - if TOKEN_FUNCTION_DECLARATION.match(input, 0): - return TOKEN_FUNCTION_DECLARATION.value() - if TOKEN_FUNCTION_STATIC_DECLARATION.match(input, 0): - return TOKEN_FUNCTION_STATIC_DECLARATION.value() - push_error("Can't extract function name from '%s'" % input) - return "" - - -## Enriches the function descriptor by line number and argument default values -## - enrich all function descriptors form current script up to all inherited scrips -func _enrich_function_descriptor(script: GDScript, fds: Array[GdFunctionDescriptor]) -> void: - var enriched_functions := {} # Use Dictionary for O(1) lookup instead of PackedStringArray - var script_to_scan := script - while script_to_scan != null: - # do not scan the test suite base class itself - if script_to_scan.resource_path == "res://addons/gdUnit4/src/GdUnitTestSuite.gd": - break - - var rows := script_to_scan.source_code.split("\n") - for rowIndex in rows.size(): - var input := rows[rowIndex] - # step over inner class functions - if input.begins_with("\t"): - continue - # skip comments and empty lines - if input.begins_with("#") or input.length() == 0: - continue - var token := next_token(input, 0) - if token != TOKEN_FUNCTION_STATIC_DECLARATION and token != TOKEN_FUNCTION_DECLARATION: - continue - - var function_name: String = token.value() - # Skip if already enriched (from parent class scan) - if enriched_functions.has(function_name): - continue - - # Find matching function descriptor - var fd: GdFunctionDescriptor = null - for candidate in fds: - if candidate.name() == function_name: - fd = candidate - break - if fd == null: - continue - # Mark as enriched - enriched_functions[function_name] = true - var func_signature := extract_func_signature(rows, rowIndex) - var func_arguments := _parse_function_arguments(func_signature) - # enrich missing default values - fd.enrich_arguments(func_arguments) - fd.enrich_file_info(script_to_scan.resource_path, rowIndex + 1) - fd._is_coroutine = is_func_coroutine(rows, rowIndex) - # enrich return class name if not set - if fd.return_type() == TYPE_OBJECT and fd._return_class in ["", "Resource", "RefCounted"]: - var var_token := parse_return_token(func_signature) - if var_token != TOKEN_NOT_MATCH and var_token.type() == TYPE_OBJECT: - fd._return_class = _patch_inner_class_names(var_token.plain_value(), "") - # if the script ihnerits we need to scan this also - script_to_scan = script_to_scan.get_base_script() - - -func is_func_coroutine(rows :PackedStringArray, index :int) -> bool: - var is_coroutine := false - for rowIndex in range(index+1, rows.size()): - var input := rows[rowIndex].strip_edges() - if input.begins_with("#") or input.is_empty(): - continue - var token := next_token(input, 0) - # scan until next function - if token == TOKEN_FUNCTION_STATIC_DECLARATION or token == TOKEN_FUNCTION_DECLARATION: - break - - if _is_awaiting.search(input): - return true - return is_coroutine - - -func is_inner_class(clazz_path :PackedStringArray) -> bool: - return clazz_path.size() > 1 - - -func is_func_end(row :String) -> bool: - return row.strip_edges(false, true).ends_with(":") - - -func _patch_inner_class_names(clazz :String, clazz_name :String = "") -> String: - var inner_clazz_name := clazz.split(".")[0] - if _scanned_inner_classes.has(inner_clazz_name): - return inner_clazz_name - #var base_clazz := clazz_name.split(".")[0] - #return base_clazz + "." + clazz - if _script_constants.has(clazz): - return clazz_name + "." + clazz - return clazz - - -func _prescan_script(script: GDScript) -> void: - _script_constants = script.get_script_constant_map() - for key :String in _script_constants.keys(): - var value :Variant = _script_constants.get(key) - if value is GDScript: - @warning_ignore("return_value_discarded") - _scanned_inner_classes.append(key) - - -func parse(clazz_name :String, clazz_path :PackedStringArray) -> GdUnitResult: - if clazz_path.is_empty(): - return GdUnitResult.error("Invalid script path '%s'" % clazz_path) - var is_inner_class_ := is_inner_class(clazz_path) - var script :GDScript = load(clazz_path[0]) - _prescan_script(script) - - if is_inner_class_: - var inner_class_name := clazz_path[1] - if _scanned_inner_classes.has(inner_class_name): - # do load only on inner class source code and enrich the stored script instance - var source_code := _load_inner_class(script, inner_class_name) - script = _script_constants.get(inner_class_name) - script.source_code = source_code - var function_descriptors := get_function_descriptors(script) - var gd_class := GdClassDescriptor.new(clazz_name, is_inner_class_, function_descriptors) - return GdUnitResult.success(gd_class) - - -func _load_inner_class(script: GDScript, inner_clazz: String) -> String: - var source_rows := GdScriptParser.to_unix_format(script.source_code).split("\n") - # extract all inner class names - var inner_class_code := extract_inner_class(source_rows, inner_clazz) - return "\n".join(inner_class_code) diff --git a/addons/gdUnit4/src/core/parse/GdScriptParser.gd.uid b/addons/gdUnit4/src/core/parse/GdScriptParser.gd.uid deleted file mode 100644 index e6acfdab..00000000 --- a/addons/gdUnit4/src/core/parse/GdScriptParser.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://47c36e540hgy diff --git a/addons/gdUnit4/src/core/parse/GdUnitExpressionRunner.gd b/addons/gdUnit4/src/core/parse/GdUnitExpressionRunner.gd deleted file mode 100644 index 9faf830b..00000000 --- a/addons/gdUnit4/src/core/parse/GdUnitExpressionRunner.gd +++ /dev/null @@ -1,74 +0,0 @@ -class_name GdUnitExpressionRunner -extends RefCounted - -const CLASS_TEMPLATE = """ -class_name _ExpressionRunner extends '${clazz_path}' - -func __run_expression() -> Variant: - return $expression - -""" - -var constructor_args_regex := RegEx.create_from_string("new\\((?.*)\\)") - - -func execute(src_script: GDScript, value: Variant) -> Variant: - if typeof(value) != TYPE_STRING: - return value - - var expression: String = value - var parameter_map := src_script.get_script_constant_map() - for key: String in parameter_map.keys(): - var parameter_value: Variant = parameter_map[key] - # check we need to construct from inner class - # we need to use the original class instance from the script_constant_map otherwise we run into a runtime error - if expression.begins_with(key + ".new") and parameter_value is GDScript: - var object: GDScript = parameter_value - var args := build_constructor_arguments(parameter_map, expression.substr(expression.find("new"))) - if args.is_empty(): - return object.new() - return object.callv("new", args) - - var script := GDScript.new() - var resource_path := "res://addons/gdUnit4/src/Fuzzers.gd" if src_script.resource_path.is_empty() else src_script.resource_path - script.source_code = CLASS_TEMPLATE.dedent()\ - .replace("${clazz_path}", resource_path)\ - .replace("$expression", expression) - #script.take_over_path(resource_path) - @warning_ignore("return_value_discarded") - script.reload(true) - var runner: Object = script.new() - if runner.has_method("queue_free"): - (runner as Node).queue_free() - @warning_ignore("unsafe_method_access") - return runner.__run_expression() - - -func build_constructor_arguments(parameter_map: Dictionary, expression: String) -> Array[Variant]: - var result := constructor_args_regex.search(expression) - var extracted_arguments := result.get_string("args").strip_edges() - if extracted_arguments.is_empty(): - return [] - var arguments :Array = extracted_arguments.split(",") - return arguments.map(func(argument: String) -> Variant: - var value := argument.strip_edges() - - # is argument an constant value - if parameter_map.has(value): - return parameter_map[value] - # is typed named value like Vector3.ONE - for type:int in GdObjects.TYPE_AS_STRING_MAPPINGS: - var type_as_string:String = GdObjects.TYPE_AS_STRING_MAPPINGS[type] - if value.begins_with(type_as_string): - return type_convert(value, type) - # is value a string - if value.begins_with("'") or value.begins_with('"'): - return value.trim_prefix("'").trim_suffix("'").trim_prefix('"').trim_suffix('"') - # fallback to default value converting - return str_to_var(value) - ) - - -func to_fuzzer(src_script: GDScript, expression: String) -> Fuzzer: - @warning_ignore("unsafe_cast") - return execute(src_script, expression) as Fuzzer diff --git a/addons/gdUnit4/src/core/parse/GdUnitExpressionRunner.gd.uid b/addons/gdUnit4/src/core/parse/GdUnitExpressionRunner.gd.uid deleted file mode 100644 index 143f3083..00000000 --- a/addons/gdUnit4/src/core/parse/GdUnitExpressionRunner.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://8gc4dp0ot52d diff --git a/addons/gdUnit4/src/core/parse/GdUnitTestParameterSetResolver.gd b/addons/gdUnit4/src/core/parse/GdUnitTestParameterSetResolver.gd deleted file mode 100644 index 527661da..00000000 --- a/addons/gdUnit4/src/core/parse/GdUnitTestParameterSetResolver.gd +++ /dev/null @@ -1,163 +0,0 @@ -## @deprecated see GdFunctionParameterSetResolver -class_name GdUnitTestParameterSetResolver -extends RefCounted - -const CLASS_TEMPLATE = """ -class_name _ParameterExtractor extends '${clazz_path}' - -func __extract_test_parameters() -> Array: - return ${test_params} - -""" - -const EXCLUDE_PROPERTIES_TO_COPY = [ - "script", - "type", - "Node", - "_import_path"] - - -var _fd: GdFunctionDescriptor -var _static_sets_by_index := {} -var _is_static := true - -func _init(fd: GdFunctionDescriptor) -> void: - _fd = fd - - -func is_parameterized() -> bool: - return _fd.is_parameterized() - - -func is_parameter_sets_static() -> bool: - return _is_static - - -func is_parameter_set_static(index: int) -> bool: - return _is_static and _static_sets_by_index.get(index, false) - - -# validates the given arguments are complete and matches to required input fields of the test function -func validate(parameter_sets: Array, parameter_set_index: int) -> GdUnitResult: - if parameter_sets.size() < parameter_set_index: - return GdUnitResult.error("Internal error: the resolved paremeterset has invalid size.") - - var input_values: Array = parameter_sets[parameter_set_index] - if input_values == null: - return GdUnitResult.error("The parameter set '%s' must be an Array!" % parameter_sets[parameter_set_index]) - - # check given parameter set with test case arguments - var input_arguments := _fd.args() - var expected_arg_count := input_arguments.size() - 1 #(-1 we exclude the parameter set itself) - var current_arg_count := input_values.size() - if current_arg_count != expected_arg_count: - var arg_names := input_arguments\ - .filter(func(arg: GdFunctionArgument) -> bool: return not arg.is_parameter_set())\ - .map(func(arg: GdFunctionArgument) -> String: return str(arg)) - - return GdUnitResult.error(""" - The test data set at index (%d) does not match the expected test arguments: - test function: [color=snow]func test...(%s)[/color] - test input values: [color=snow]%s[/color] - """ - .dedent() % [parameter_set_index, ",".join(arg_names), input_values]) - return GdUnitTestParameterSetResolver.validate_parameter_types(input_arguments, input_values) - - -static func validate_parameter_types(input_arguments: Array[GdFunctionArgument], input_values: Array) -> GdUnitResult: - for i in input_arguments.size(): - var input_param: GdFunctionArgument = input_arguments[i] - # only check the test input arguments - if input_param.is_parameter_set(): - continue - var input_param_type := input_param.type() - var input_value :Variant = input_values[i] - var input_value_type := typeof(input_value) - # input parameter is not typed or is Variant we skip the type test - if input_param_type == TYPE_NIL or input_param_type == GdObjects.TYPE_VARIANT: - continue - # is input type enum allow int values - if input_param_type == GdObjects.TYPE_VARIANT and input_value_type == TYPE_INT: - continue - # allow only equal types and object == null - if input_param_type == TYPE_OBJECT and input_value_type == TYPE_NIL: - continue - if input_param_type != input_value_type: - return GdUnitResult.error(""" - The test data value does not match the expected input type! - input value: [color=snow]'%s', <%s>[/color] - expected argument: [color=snow]%s[/color] - """ - .dedent() % [input_value, type_string(input_value_type), str(input_param)]) - return GdUnitResult.success("No errors found.") - - -func _extract_property_names(node :Node) -> PackedStringArray: - return node.get_property_list()\ - .map(func(property :Dictionary) -> String: return property["name"])\ - .filter(func(property :String) -> bool: return !EXCLUDE_PROPERTIES_TO_COPY.has(property)) - - -# tests if the test property set contains an property reference by name, if not the parameter set holds only static values -func _is_static_parameter_set(parameters :String, property_names :PackedStringArray) -> bool: - for property_name in property_names: - if parameters.contains(property_name): - _is_static = false - return false - return true - - -# extracts the arguments from the given test case, using kind of reflection solution -# to restore the parameters from a string representation to real instance type -func load_parameter_sets(test_suite: Node) -> GdUnitResult: - var source_script: Script = test_suite.get_script() - var parameter_arg := GdFunctionArgument.get_parameter_set(_fd.args()) - var source_code := CLASS_TEMPLATE \ - .replace("${clazz_path}", source_script.resource_path) \ - .replace("${test_params}", parameter_arg.value_as_string()) - var script := GDScript.new() - script.source_code = source_code - # enable this lines only for debuging - #script.resource_path = GdUnitFileAccess.create_temp_dir("parameter_extract") + "/%s__.gd" % test_case.get_name() - #DirAccess.remove_absolute(script.resource_path) - #ResourceSaver.save(script, script.resource_path) - var result := script.reload() - if result != OK: - return GdUnitResult.error("Extracting test parameters failed! Script loading error: %s" % error_string(result)) - var instance :Object = script.new() - GdUnitTestParameterSetResolver.copy_properties(test_suite, instance) - (instance as Node).queue_free() - var parameter_sets: Array = instance.call("__extract_test_parameters") - fixure_typed_parameters(parameter_sets, _fd.args()) - return GdUnitResult.success(parameter_sets) - - -func fixure_typed_parameters(parameter_sets: Array, arg_descriptors: Array[GdFunctionArgument]) -> Array: - for parameter_set_index in parameter_sets.size(): - var parameter_set: Array = parameter_sets[parameter_set_index] - # run over all function arguments - for parameter_index in parameter_set.size(): - var parameter :Variant = parameter_set[parameter_index] - var arg_descriptor: GdFunctionArgument = arg_descriptors[parameter_index] - if parameter is Array: - var as_array: Array = parameter - # we need to convert the untyped array to the expected typed version - if arg_descriptor.is_typed_array(): - parameter_set[parameter_index] = Array(as_array, arg_descriptor.type_hint(), "", null) - return parameter_sets - - -static func copy_properties(source: Object, dest: Object) -> void: - for property in source.get_property_list(): - var property_name :String = property["name"] - var property_value :Variant = source.get(property_name) - if EXCLUDE_PROPERTIES_TO_COPY.has(property_name): - continue - #if dest.get(property_name) == null: - # prints("|%s|" % property_name, source.get(property_name)) - - # check for invalid name property - if property_name == "name" and property_value == "": - dest.set(property_name, ""); - continue - dest.set(property_name, property_value) diff --git a/addons/gdUnit4/src/core/parse/GdUnitTestParameterSetResolver.gd.uid b/addons/gdUnit4/src/core/parse/GdUnitTestParameterSetResolver.gd.uid deleted file mode 100644 index 5953ad47..00000000 --- a/addons/gdUnit4/src/core/parse/GdUnitTestParameterSetResolver.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://buij3yet6d2hg diff --git a/addons/gdUnit4/src/core/report/GdUnitReport.gd b/addons/gdUnit4/src/core/report/GdUnitReport.gd deleted file mode 100644 index eb7ed2e5..00000000 --- a/addons/gdUnit4/src/core/report/GdUnitReport.gd +++ /dev/null @@ -1,74 +0,0 @@ -class_name GdUnitReport -extends Resource - -# report type -enum { - SUCCESS, - WARN, - FAILURE, - ORPHAN, - TERMINATED, - INTERUPTED, - ABORT, - SKIPPED, -} - -var _type :int -var _line_number :int -var _message :String - - -func create(p_type :int, p_line_number :int, p_message :String) -> GdUnitReport: - _type = p_type - _line_number = p_line_number - _message = p_message - return self - - -func type() -> int: - return _type - - -func line_number() -> int: - return _line_number - - -func message() -> String: - return _message - - -func is_skipped() -> bool: - return _type == SKIPPED - - -func is_warning() -> bool: - return _type == WARN - - -func is_failure() -> bool: - return _type == FAILURE - - -func is_error() -> bool: - return _type == TERMINATED or _type == INTERUPTED or _type == ABORT - - -func _to_string() -> String: - if _line_number == -1: - return "[color=green]line [/color][color=aqua]:[/color] %s" % [_message] - return "[color=green]line [/color][color=aqua]%d:[/color] %s" % [_line_number, _message] - - -func serialize() -> Dictionary: - return { - "type" :_type, - "line_number" :_line_number, - "message" :_message - } - - -func deserialize(serialized :Dictionary) -> GdUnitReport: - _type = serialized["type"] - _line_number = serialized["line_number"] - _message = serialized["message"] - return self diff --git a/addons/gdUnit4/src/core/report/GdUnitReport.gd.uid b/addons/gdUnit4/src/core/report/GdUnitReport.gd.uid deleted file mode 100644 index f25a1cf7..00000000 --- a/addons/gdUnit4/src/core/report/GdUnitReport.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cq37movmiy3l1 diff --git a/addons/gdUnit4/src/core/runners/GdUnitTestCIRunner.gd b/addons/gdUnit4/src/core/runners/GdUnitTestCIRunner.gd deleted file mode 100644 index 34dcfa38..00000000 --- a/addons/gdUnit4/src/core/runners/GdUnitTestCIRunner.gd +++ /dev/null @@ -1,470 +0,0 @@ -#warning-ignore-all:return_value_discarded -class_name GdUnitTestCIRunner -extends "res://addons/gdUnit4/src/core/runners/GdUnitTestSessionRunner.gd" -## Command line test runner implementation.[br] -## [br] -## This runner is designed for CI/CD pipelines and command line test execution.[br] -## Features:[br] -## - Command line options for test configuration[br] -## - HTML and JUnit report generation[br] -## - Console output with colored formatting[br] -## - Progress and error reporting[br] -## - Test history management[br] -## [br] -## Example usage:[br] -## [codeblock] -## # Run all tests in a directory -## runtest -a -## -## # Run specific test suite with ignored tests -## runtest -a -i -## [/codeblock] - -const GdUnitTools := preload("res://addons/gdUnit4/src/core/GdUnitTools.gd") - -var _console := GdUnitCSIMessageWriter.new() -var _console_reporter: GdUnitConsoleTestReporter -var _headless_mode_ignore := false -var _runner_config_file := "" -var _debug_cmd_args := PackedStringArray() -var _included_tests := PackedStringArray() -var _excluded_tests := PackedStringArray() - -## Command line options configuration -var _cmd_options := CmdOptions.new([ - CmdOption.new( - "-a, --add", - "-a ", - "Adds the given test suite or directory to the execution pipeline.", - TYPE_STRING - ), - CmdOption.new( - "-i, --ignore", - "-i ", - "Adds the given test suite or test case to the ignore list.", - TYPE_STRING - ), - CmdOption.new( - "-c, --continue", - "", - """By default GdUnit will abort checked first test failure to be fail fast, - instead of stop after first failure you can use this option to run the complete test set.""".dedent() - ), - CmdOption.new( - "-conf, --config", - "-conf [testconfiguration.cfg]", - "Run all tests by given test configuration. Default is 'GdUnitRunner.cfg'", - TYPE_STRING, - true - ), - CmdOption.new( - "-help", "", - "Shows this help message." - ), - CmdOption.new("--help-advanced", "", - "Shows advanced options." - ) - ], - [ - # advanced options - CmdOption.new( - "-rd, --report-directory", - "-rd ", - "Specifies the output directory in which the reports are to be written. The default is res://reports/.", - TYPE_STRING, - true - ), - CmdOption.new( - "-rc, --report-count", - "-rc ", - "Specifies how many reports are saved before they are deleted. The default is %s." % str(GdUnitConstants.DEFAULT_REPORT_HISTORY_COUNT), - TYPE_INT, - true - ), - #CmdOption.new("--list-suites", "--list-suites [directory]", "Lists all test suites located in the given directory.", TYPE_STRING), - #CmdOption.new("--describe-suite", "--describe-suite ", "Shows the description of selected test suite.", TYPE_STRING), - CmdOption.new( - "--info", "", - "Shows the GdUnit version info" - ), - CmdOption.new( - "--selftest", "", - "Runs the GdUnit self test" - ), - CmdOption.new( - "--ignoreHeadlessMode", - "--ignoreHeadlessMode", - "By default, running GdUnit4 in headless mode is not allowed. You can switch off the headless mode check by set this property." - ), - ]) - - -func _init() -> void: - super() - - -func _ready() -> void: - super() - # stop checked first test failure to fail fast - _executor.fail_fast(true) - _console_reporter = GdUnitConsoleTestReporter.new(_console, true) - GdUnitSignals.instance().gdunit_message.connect(_on_send_message) - - -func _notification(what: int) -> void: - super(what) - if what == NOTIFICATION_PREDELETE: - prints("Finallize .. done") - - -func init_runner() -> void: - init_gd_unit() - - -## Returns the exit code based on test results.[br] -## Maps test report status to process exit codes. -func get_exit_code() -> int: - return report_exit_code() - - -## Cleanup and quit the runner.[br] -## [br] -## [param code] The exit code to return. -func quit(code: int) -> void: - _state = EXIT - GdUnitTools.dispose_all() - await GdUnitMemoryObserver.gc_on_guarded_instances() - await super(code) - - -## Prints info message to console.[br] -## [br] -## [param message] The message to print.[br] -## [param color] Optional color for the message. -func console_info(message: String, color: Color = Color.WHITE) -> void: - _console.color(color).println_message(message) - - -## Prints error message to console.[br] -## [br] -## [param message] The error message to print. -func console_error(message: String) -> void: - _console.prints_error(message) - - -## Prints warning message to console.[br] -## [br] -## [param message] The warning message to print. -func console_warning(message: String) -> void: - _console.prints_warning(message) - - -## Sets the directory for test reports.[br] -## [br] -## [param path] The path where reports should be written. -func set_report_dir(path: String) -> void: - report_base_path = ProjectSettings.globalize_path(GdUnitFileAccess.make_qualified_path(path)) - console_info( - "Set write reports to %s" % report_base_path, - Color.DEEP_SKY_BLUE - ) - - -## Sets how many report files to keep.[br] -## [br] -## [param count] The number of reports to keep. -func set_report_count(count: String) -> void: - var report_count := count.to_int() - if report_count < 1: - console_error( - "Invalid report history count '%s' set back to default %d" - % [count, GdUnitConstants.DEFAULT_REPORT_HISTORY_COUNT] - ) - max_report_history = GdUnitConstants.DEFAULT_REPORT_HISTORY_COUNT - else: - console_info( - "Set report history count to %s" % count, - Color.DEEP_SKY_BLUE - ) - max_report_history = report_count - - -## Disables fail-fast mode to run all tests.[br] -## By default tests stop on first failure. -func disable_fail_fast() -> void: - console_info( - "Disabled fail fast!", - Color.DEEP_SKY_BLUE - ) - @warning_ignore("unsafe_method_access") - _executor.fail_fast(false) - - -func run_self_test() -> void: - console_info( - "Run GdUnit4 self tests.", - Color.DEEP_SKY_BLUE - ) - disable_fail_fast() - - - -## Shows GdUnit and Godot version information. -func show_version() -> void: - console_info( - "Godot %s" % Engine.get_version_info().get("string") as String, - Color.DARK_SALMON - ) - var config := ConfigFile.new() - config.load("addons/gdUnit4/plugin.cfg") - console_info( - "GdUnit4 %s" % config.get_value("plugin", "version") as String, - Color.DARK_SALMON - ) - quit(RETURN_SUCCESS) - - -## Ignores headless mode restrictions.[br] -## Allows tests to run in headless mode despite limitations. -func check_headless_mode() -> void: - _headless_mode_ignore = true - - -## Shows available command line options.[br] -## [br] -## [param show_advanced] Whether to show advanced options. -func show_options(show_advanced: bool = false) -> void: - console_info( - """ - Usage: - runtest -a - runtest -a -i - """.dedent(), - Color.DARK_SALMON - ) - console_info( - "-- Options ---------------------------------------------------------------------------------------", - Color.DARK_SALMON - ) - for option in _cmd_options.default_options(): - descripe_option(option) - if show_advanced: - console_info( - "-- Advanced options --------------------------------------------------------------------------", - Color.DARK_SALMON - ) - for option in _cmd_options.advanced_options(): - descripe_option(option) - - -## Describes a single command line option.[br] -## [br] -## [param cmd_option] The option to describe. -func descripe_option(cmd_option: CmdOption) -> void: - console_info( - " %-40s" % str(cmd_option.commands()), - Color.CORNFLOWER_BLUE - ) - console_info( - cmd_option.description(), - Color.LIGHT_GREEN - ) - if not cmd_option.help().is_empty(): - console_info( - "%-4s %s" % ["", cmd_option.help()], - Color.DARK_TURQUOISE - ) - console_info("") - - -## Loads test configuration from file.[br] -## [br] -## [param path] Path to the configuration file. -func load_test_config(path := GdUnitRunnerConfig.CONFIG_FILE) -> void: - console_info( - "Loading test configuration %s\n" % path, - Color.CORNFLOWER_BLUE - ) - _runner_config_file = path - _runner_config.load_config(path) - - -## Shows basic help and exits. -func show_help() -> void: - show_options() - quit(RETURN_SUCCESS) - - -## Shows advanced help and exits. -func show_advanced_help() -> void: - show_options(true) - quit(RETURN_SUCCESS) - - -## Gets command line arguments.[br] -## Returns debug args if set, otherwise actual command line args. -func get_cmdline_args() -> PackedStringArray: - if _debug_cmd_args.is_empty(): - return OS.get_cmdline_args() - return _debug_cmd_args - - -## Initializes the test runner and processes command line arguments. -func init_gd_unit() -> void: - console_info( - """ - -------------------------------------------------------------------------------------------------- - GdUnit4 Comandline Tool - --------------------------------------------------------------------------------------------------""".dedent(), - Color.DARK_SALMON - ) - - var cmd_parser := CmdArgumentParser.new(_cmd_options, "GdUnitCmdTool.gd") - var result := cmd_parser.parse(get_cmdline_args()) - if result.is_error(): - console_error(result.error_message()) - show_options() - console_error("Abnormal exit with %d" % RETURN_ERROR) - quit(RETURN_ERROR) - return - if result.is_empty(): - show_help() - return - # build runner config by given commands - var commands :Array[CmdCommand] = [] - @warning_ignore("unsafe_cast") - commands.append_array(result.value() as Array) - result = ( - CmdCommandHandler.new(_cmd_options) - .register_cb("-help", show_help) - .register_cb("--help-advanced", show_advanced_help) - .register_cb("-a", add_test_suite) - .register_cbv("-a", add_test_suites) - .register_cb("-i", skip_test_suite) - .register_cbv("-i", skip_test_suites) - .register_cb("-rd", set_report_dir) - .register_cb("-rc", set_report_count) - .register_cb("--selftest", run_self_test) - .register_cb("-c", disable_fail_fast) - .register_cb("-conf", load_test_config) - .register_cb("--info", show_version) - .register_cb("--ignoreHeadlessMode", check_headless_mode) - .execute(commands) - ) - if result.is_error(): - console_error(result.error_message()) - quit(RETURN_ERROR) - return - - if DisplayServer.get_name() == "headless": - if _headless_mode_ignore: - console_warning(""" - Headless mode is ignored by option '--ignoreHeadlessMode'" - - Please note that tests that use UI interaction do not work correctly in headless mode. - Godot 'InputEvents' are not transported by the Godot engine in headless mode and therefore - have no effect in the test! - """.dedent() - ) - else: - console_error(""" - Headless mode is not supported! - - Please note that tests that use UI interaction do not work correctly in headless mode. - Godot 'InputEvents' are not transported by the Godot engine in headless mode and therefore - have no effect in the test! - - You can run with '--ignoreHeadlessMode' to swtich off this check. - """.dedent() - ) - console_error( - "Abnormal exit with %d" % RETURN_ERROR_HEADLESS_NOT_SUPPORTED - ) - quit(RETURN_ERROR_HEADLESS_NOT_SUPPORTED) - return - - _test_cases = discover_tests() - if _test_cases.is_empty(): - console_info("No test cases found, abort test run!", Color.YELLOW) - console_info("Exit code: %d" % RETURN_SUCCESS, Color.DARK_SALMON) - quit(RETURN_SUCCESS) - return - _state = RUN - - -func discover_tests() -> Array[GdUnitTestCase]: - var gdunit_test_discover_added := GdUnitSignals.instance().gdunit_test_discover_added - - _test_cases = _runner_config.test_cases() - var scanner := GdUnitTestSuiteScanner.new() - for path in _included_tests: - var scripts := scanner.scan(path) - for script in scripts: - GdUnitTestDiscoverer.discover_tests(script, func(test: GdUnitTestCase) -> void: - if not is_skipped(test): - #_console.println_message("discoverd %s" % test.display_name) - _test_cases.append(test) - gdunit_test_discover_added.emit(test) - ) - - return _test_cases - - -func add_test_suite(path: String) -> void: - _included_tests.append(path) - - -func add_test_suites(paths: PackedStringArray) -> void: - _included_tests.append_array(paths) - - -func skip_test_suite(path: String) -> void: - _excluded_tests.append(path) - - -func skip_test_suites(paths: PackedStringArray) -> void: - _excluded_tests.append_array(paths) - - -func is_skipped(test: GdUnitTestCase) -> bool: - for skipped_info in _excluded_tests: - - # is suite skipped by full path or suite name - if skipped_info == test.suite_name or test.source_file.contains(skipped_info): - return true - var skip_file := skipped_info.replace("res://", "") - - # check for skipped single test - if not skip_file.contains(":"): - continue - var parts: PackedStringArray = skip_file.rsplit(":") - var skipped_suite := parts[0] - var skipped_test := parts[1] - # is suite skipped by full path or suite name - if (skipped_suite == test.suite_name or test.source_file.contains(skipped_suite)) and skipped_test == test.test_name: - return true - - return false - - -func _on_send_message(message: String) -> void: - _console.color(Color.CORNFLOWER_BLUE).println_message(message) - - -func _on_gdunit_event(event: GdUnitEvent) -> void: - match event.type(): - GdUnitEvent.SESSION_START: - _console_reporter.test_session = _test_session - GdUnitEvent.SESSION_CLOSE: - _console_reporter.test_session = null - - -func report_exit_code() -> int: - if _console_reporter.total_error_count() + _console_reporter.total_failure_count() > 0: - console_info("Exit code: %d" % RETURN_ERROR, Color.FIREBRICK) - return RETURN_ERROR - if _console_reporter.total_orphan_count() > 0: - console_info("Exit code: %d" % RETURN_WARNING, Color.GOLDENROD) - return RETURN_WARNING - console_info("Exit code: %d" % RETURN_SUCCESS, Color.DARK_SALMON) - return RETURN_SUCCESS diff --git a/addons/gdUnit4/src/core/runners/GdUnitTestCIRunner.gd.uid b/addons/gdUnit4/src/core/runners/GdUnitTestCIRunner.gd.uid deleted file mode 100644 index c7d89252..00000000 --- a/addons/gdUnit4/src/core/runners/GdUnitTestCIRunner.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c60bwkw5e0bgo diff --git a/addons/gdUnit4/src/core/runners/GdUnitTestRunner.gd b/addons/gdUnit4/src/core/runners/GdUnitTestRunner.gd deleted file mode 100644 index 5af6c9b9..00000000 --- a/addons/gdUnit4/src/core/runners/GdUnitTestRunner.gd +++ /dev/null @@ -1,87 +0,0 @@ -extends "res://addons/gdUnit4/src/core/runners/GdUnitTestSessionRunner.gd" -## Runner implementation used by the editor UI.[br] -## [br] -## This runner connects to a GdUnit server via TCP to report test results.[br] -## Test results are reported in real-time and displayed in the editor UI.[br] -## [br] -## The runner uses an RPC message protocol to communicate status and events:[br] -## - Messages to report progress[br] -## - Events to report test results[br] - -## The TCP client used to connect to the GdUnit server -@onready var _client: GdUnitTcpClient = $GdUnitTcpClient -@onready var _version_label: Control = %Version - - -func _init() -> void: - super() - # We set the default max report history to 1 - max_report_history = 1 - - -func _ready() -> void: - super() - GdUnit4Version.init_version_label(_version_label) - - var config_result := _runner_config.load_config() - if config_result.is_error(): - push_error(config_result.error_message()) - _state = EXIT - return - @warning_ignore("return_value_discarded") - _client.connect("connection_failed", _on_connection_failed) - GdUnitSignals.instance().gdunit_message.connect(_on_send_message) - var result := _client.start("127.0.0.1", _runner_config.server_port()) - if result.is_error(): - push_error(result.error_message()) - return - - -## Cleanup and quit the runner.[br] -## [br] -## [param code] The exit code to return. -func quit(code: int) -> void: - if code != RETURN_SUCCESS: - _state = EXIT - await GdUnitMemoryObserver.gc_on_guarded_instances() - - -## Called when the TCP connection to the GdUnit server fails.[br] -## Stops the test execution.[br] -## [br] -## [param message] The error message describing the failure. -func _on_connection_failed(message: String) -> void: - prints("_on_connection_failed", message) - _state = STOP - - -## Initializes the test runner.[br] -## Waits for TCP client connection and then scans for test suites.[br] -## Reports the number of found test suites via TCP message. -func init_runner() -> void: - # wait until client is connected to the GdUnitServer - if _client.is_client_connected(): - await gdUnitInit() - _state = RUN - - -## Initializes the GdUnit framework.[br] -## Sends initial message about number of test suites. -func gdUnitInit() -> void: - #enable_manuall_polling() - _test_cases = _runner_config.test_cases() - await get_tree().process_frame - - -## Sends a message via TCP to the GdUnit server.[br] -## [br] -## [param message] The message to send. -func _on_send_message(message: String) -> void: - _client.send(RPCMessage.of(message)) - - -## Handles GdUnit events by sending them via TCP to the server.[br] -## [br] -## [param event] The event to send. -func _on_gdunit_event(event: GdUnitEvent) -> void: - _client.send(RPCGdUnitEvent.of(event)) diff --git a/addons/gdUnit4/src/core/runners/GdUnitTestRunner.gd.uid b/addons/gdUnit4/src/core/runners/GdUnitTestRunner.gd.uid deleted file mode 100644 index 895829aa..00000000 --- a/addons/gdUnit4/src/core/runners/GdUnitTestRunner.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://rof73we1mvyk diff --git a/addons/gdUnit4/src/core/runners/GdUnitTestRunner.tscn b/addons/gdUnit4/src/core/runners/GdUnitTestRunner.tscn deleted file mode 100644 index eaa6f1ab..00000000 --- a/addons/gdUnit4/src/core/runners/GdUnitTestRunner.tscn +++ /dev/null @@ -1,34 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://belidlfknh74r"] - -[ext_resource type="Script" path="res://addons/gdUnit4/src/core/runners/GdUnitTestRunner.gd" id="1"] -[ext_resource type="Script" path="res://addons/gdUnit4/src/network/GdUnitTcpClient.gd" id="2"] - -[node name="Control" type="Node"] -script = ExtResource("1") - -[node name="GdUnitTcpClient" type="Node" parent="."] -script = ExtResource("2") - -[node name="HBoxContainer" type="HBoxContainer" parent="."] -custom_minimum_size = Vector2(0, 24) -layout_direction = 2 -anchors_preset = 12 -anchor_top = 1.0 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 0 -size_flags_horizontal = 3 -size_flags_vertical = 10 -alignment = 2 - -[node name="Version" type="RichTextLabel" parent="HBoxContainer"] -unique_name_in_owner = true -custom_minimum_size = Vector2(128, 0) -layout_mode = 2 -size_flags_horizontal = 10 -bbcode_enabled = true -scroll_active = false -shortcut_keys_enabled = false -horizontal_alignment = 1 -justification_flags = 0 diff --git a/addons/gdUnit4/src/core/runners/GdUnitTestSession.gd b/addons/gdUnit4/src/core/runners/GdUnitTestSession.gd deleted file mode 100644 index c789847b..00000000 --- a/addons/gdUnit4/src/core/runners/GdUnitTestSession.gd +++ /dev/null @@ -1,169 +0,0 @@ -## -## @since GdUnit4 5.1.0 -## -## Represents a test execution session in GdUnit4.[br] -## [br] -## [i]A test session encapsulates a complete test execution cycle, managing the collection -## of test cases to be executed and providing communication channels for test events -## and messages. This class serves as the central coordination point for test execution -## and allows hooks and other components to interact with the running test session.[/i][br] -## [br] -## [b][u]Key Features[/u][/b][br] -## - [i][b]Test Case Management[/b][/i]: Maintains a collection of test cases to be executed[br] -## - [i][b]Event Broadcasting[/b][/i]: Forwards GdUnit events to session-specific listeners[br] -## - [i][b]Message Communication[/b][/i]: Provides a channel for sending messages during test execution[br] -## - [i][b]Hook Integration[/b][/i]: Passed to test session hooks for startup and shutdown operations[br] -## [br] -## [b][u]Usage in Test Hooks[/u][/b] -## [codeblock] -## func startup(session: GdUnitTestSession) -> GdUnitResult: -## # Access test cases -## print("Running %d test cases" % session.test_cases.size()) -## -## # Send status messages -## session.send_message("Custom hook initialized") -## -## # Listen for test events -## session.test_event.connect(_on_test_event) -## -## return GdUnitResult.success() -## -## func _on_test_event(event: GdUnitEvent) -> void: -## print("Test event received: %s" % event.type) -## [/codeblock] -## [br] -## [b][u]Event Flow[/u][/b][br] -## 1. Session is created with a collection of test cases[br] -## 2. Session connects to the global GdUnit event system[br] -## 3. During test execution, events are automatically forwarded to session listeners[br] -## 4. Hooks and other components can subscribe to session events[br] -## 5. Messages can be sent through the session for logging and communication[br] -class_name GdUnitTestSession -extends RefCounted - - -## Emitted when a test execution event occurs.[br] -## [br] -## [i]This signal forwards events from the global GdUnit event system to session-specific -## listeners. It allows hooks and other session components to react to test events -## without directly connecting to the global event system.[/i][br] -## [br] -## [u]Common event types include:[/u][br] -## - Test suite start/end events[br] -## - Test case start/end events[br] -## - Test assertion events[br] -## - Test failure/error events[br] -## -## [param event] The test event containing details about test execution, timing, and results -@warning_ignore("unused_signal") -signal test_event(event: GdUnitEvent) - - -## [b][color=red]@readonly: Should not be modified directly during test execution![/color][/b][br] -## Collection of test cases to be executed in this session.[br] -## [br] -## This array contains all the test cases that will be run during the session. -## Test hooks can access this collection to: -## - Get the total number of tests to be executed -## - Access individual test case metadata -## - Perform setup/teardown based on test case requirements -## - Generate reports or statistics about the test suite -## -## The collection is typically populated before session startup and remains -## constant during test execution. -var _test_cases : Array[GdUnitTestCase] = [] - - -## [b][color=red]@readonly: The report path should not be modified after session creation![/color][/b][br] -## The file system path where test reports for this session will be generated.[br] -## [br] -## [i]This property provides centralized access to the report output location, -## allowing test hooks, reporters, and other components to reference the same -## report path without coupling to specific reporter implementations.[/i][br] -## [br] -## [b][u]Common use cases include:[/u][/b][br] -## - Test hooks generating additional report files in the same directory[br] -## - Custom reporters creating supplementary output files[br] -## - Post-processing scripts that need to locate generated reports[br] -## - Cleanup operations that need to manage report artifacts[br] -## [br] -## [b][u]Example Usage:[/u][/b] -## [codeblock] -## # In a test hook -## func startup(session: GdUnitTestSession) -> GdUnitResult: -## var report_dir = session.report_path.get_base_dir() -## var custom_report = report_dir.path_join("custom_metrics.json") -## # Generate additional reports in the same location -## return GdUnitResult.success() -## -## func shutdown(session: GdUnitTestSession) -> GdUnitResult: -## session.send_message("Reports available at: " + session.report_path) -## return GdUnitResult.success() -## [/codeblock] -## [br] -## The path is set during session initialization and remains constant throughout -## the test execution lifecycle. -var report_path: String: - get: - return report_path - - -## Initializes the test session and sets up event forwarding.[br] -## [br] -## [i]This constructor automatically connects to the global GdUnit event system -## and forwards all events to the session's test_event signal. This allows -## session-specific components to listen for test events without managing -## global signal connections.[/i] -func _init(test_cases: Array[GdUnitTestCase], session_report_path: String) -> void: - # We build a copy to prevent a user is modifing the tests - _test_cases = test_cases.duplicate(true) - report_path = session_report_path - GdUnitSignals.instance().gdunit_event.connect(func(event: GdUnitEvent) -> void: - test_event.emit(event) - ) - - -## Finds a test case by its unique identifier.[br] -## [br] -## [i]Searches through all test cases to find a test with the matching GUID.[/i][br] -## [br] -## [param id] The GUID of the test to find[br] -## Returns the matching test case or null if not found. -func find_test_by_id(id: GdUnitGUID) -> GdUnitTestCase: - for test in _test_cases: - if test.guid.equals(id): - return test - - return null - - -## Sends a message through the GdUnit messaging system.[br] -## [br] -## [i]This method provides a convenient way for test hooks and other session -## components to send messages that will be handled by the GdUnit framework.[/i] -## [br][br] -## [b][u]Messages are typically used for:[/u][/b][br] -## - Status updates during test execution[br] -## - Progress reporting from test hooks[br] -## - Debug information and logging[br] -## - User notifications and alerts[br] -## [br] -## The message will be processed by the global GdUnit message system and -## may be displayed in the test runner UI, logged to files, or handled -## by other registered message handlers. -## [br] -## [b][u]Example Usage:[/u][/b] -## [codeblock] -## # In a test hook -## func startup(session: GdUnitTestSession) -> GdUnitResult: -## session.send_message("Database connection established") -## return GdUnitResult.success() -## -## func shutdown(session: GdUnitTestSession) -> GdUnitResult: -## session.send_message("Generated test report: report.html") -## return GdUnitResult.success() -## ``` -## [/codeblock] -## [param message] The message text to send through the GdUnit messaging system -func send_message(message: String) -> void: - GdUnitSignals.instance().gdunit_message.emit(message) diff --git a/addons/gdUnit4/src/core/runners/GdUnitTestSession.gd.uid b/addons/gdUnit4/src/core/runners/GdUnitTestSession.gd.uid deleted file mode 100644 index 700e3e66..00000000 --- a/addons/gdUnit4/src/core/runners/GdUnitTestSession.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://difxtk3nrahpi diff --git a/addons/gdUnit4/src/core/runners/GdUnitTestSessionRunner.gd b/addons/gdUnit4/src/core/runners/GdUnitTestSessionRunner.gd deleted file mode 100644 index 6551e085..00000000 --- a/addons/gdUnit4/src/core/runners/GdUnitTestSessionRunner.gd +++ /dev/null @@ -1,180 +0,0 @@ -extends Node -## The base test runner implementation.[br] -## [br] -## This class provides the core functionality to execute test suites with following features:[br] -## - Loading and initialization of test suites[br] -## - Executing test suites and managing test states[br] -## - Event dispatching and test reporting[br] -## - Support for headless mode[br] -## - Plugin version verification[br] -## [br] -## Supported by specialized runners:[br] -## - [b]GdUnitTestRunner[/b]: Used in the editor, connects via tcp to report test results[br] -## - [b]GdUnitCLRunner[/b]: A command line interface runner, writes test reports to file[br] -## The test runner runs checked default in fail-fast mode, it stops checked first test failure. - -## Overall test run status codes used by the runners -const RETURN_SUCCESS = 0 -const RETURN_ERROR = 100 -const RETURN_ERROR_HEADLESS_NOT_SUPPORTED = 103 -const RETURN_ERROR_GODOT_VERSION_NOT_SUPPORTED = 104 -const RETURN_WARNING = 101 - -## Specifies the Node name under which the runner is registered -const GDUNIT_RUNNER = "GdUnitRunner" - -## The current runner configuration -@warning_ignore("unused_private_class_variable") -var _runner_config := GdUnitRunnerConfig.new() - -## The test suite executor instance -var _executor: GdUnitTestSuiteExecutor -var _hooks : GdUnitTestSessionHookService - -## Current runner state -var _state := READY - -## Current tests to be processed -var _test_cases: Array[GdUnitTestCase] = [] - - -## Configured report base path (can be set on CI test runner) -var report_base_path: String = GdUnitFileAccess.current_dir() + "reports": - get: - return report_base_path - - -## Current session report path -var report_path: String: - get: - return "%s/%s%d" % [report_base_path, GdUnitConstants.REPORT_DIR_PREFIX, current_report_history_index] - - -## Current report history index, if max_report_history > 1 we scan for the next index over the existing reports -var current_report_history_index: int: - get: - if max_report_history > 1: - return GdUnitFileAccess.find_last_path_index(report_base_path, GdUnitConstants.REPORT_DIR_PREFIX) + 1 - else: - return 1 - - -## Controls how many report historys will be hold -var max_report_history: int = GdUnitConstants.DEFAULT_REPORT_HISTORY_COUNT: - get: - return max_report_history - set(value): - max_report_history = value - - -# holds the current test session context -var _test_session: GdUnitTestSession - -## Runner state machine -enum { - READY, - INIT, - RUN, - STOP, - EXIT -} - -func _init() -> void: - if OS.get_cmdline_args().size() == 1: - DisplayServer.window_set_title("GdUnit4 Runner (Debug Mode)") - else: - DisplayServer.window_set_title("GdUnit4 Runner (Release Mode)") - if not Engine.is_embedded_in_editor(): - # minimize scene window checked debug mode - DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_MINIMIZED) - # store current runner instance to engine meta data to can be access in as a singleton - Engine.set_meta(GDUNIT_RUNNER, self) - - -# Called when the node enters the scene tree for the first time. -func _ready() -> void: - if Engine.get_version_info().hex < 0x40300: - printerr("The GdUnit4 plugin requires Godot version 4.3 or higher to run.") - quit(RETURN_ERROR_GODOT_VERSION_NOT_SUPPORTED) - return - _executor = GdUnitTestSuiteExecutor.new() - - GdUnitSignals.instance().gdunit_event.connect(_on_gdunit_event) - _state = INIT - - -func _notification(what: int) -> void: - if what == NOTIFICATION_PREDELETE: - Engine.remove_meta(GDUNIT_RUNNER) - - -## Main test runner loop. Is called every frame to manage the test execution. -func _process(_delta: float) -> void: - match _state: - INIT: - await init_runner() - RUN: - _hooks = GdUnitTestSessionHookService.instance() - _test_session = GdUnitTestSession.new(_test_cases, report_path) - GdUnitSignals.instance().gdunit_event.emit(GdUnitSessionStart.new()) - # process next test suite - set_process(false) - var result := await _hooks.execute_startup(_test_session) - if result.is_error(): - push_error(result.error_message()) - await _executor.run_and_wait(_test_cases) - result = await _hooks.execute_shutdown(_test_session) - if result.is_error(): - push_error(result.error_message()) - _state = STOP - set_process(true) - GdUnitSignals.instance().gdunit_event.emit(GdUnitSessionClose.new()) - cleanup_report_history() - STOP: - _state = EXIT - # give the engine small amount time to finish the rpc - await get_tree().create_timer(0.1).timeout - await quit(get_exit_code()) - - -## Used by the inheriting runners to initialize test execution -func init_runner() -> void: - await get_tree().process_frame - - -func cleanup_report_history() -> int: - return GdUnitFileAccess.delete_path_index_lower_equals_than( - report_path.get_base_dir(), - GdUnitConstants.REPORT_DIR_PREFIX, - current_report_history_index-1-max_report_history) - - -## Returns the exit code when the test run is finished.[br] -## Abstract method to be implemented by the inheriting runners. -func get_exit_code() -> int: - return RETURN_SUCCESS - - -## Quits the test runner with given exit code. -func quit(code: int) -> void: - await get_tree().process_frame - await get_tree().physics_frame - get_tree().quit(code) - - -func prints_warning(message: String) -> void: - prints(message) - - -## Default event handler to process test events.[br] -## Should be overridden by concrete runner implementation. -@warning_ignore("unused_parameter") -func _on_gdunit_event(event: GdUnitEvent) -> void: - pass - - -## Event bridge from C# GdUnit4.ITestEventListener.cs[br] -## Used to handle test events from C# tests. -# gdlint: disable=function-name -func PublishEvent(data: Dictionary) -> void: - _on_gdunit_event(GdUnitEvent.new().deserialize(data)) diff --git a/addons/gdUnit4/src/core/runners/GdUnitTestSessionRunner.gd.uid b/addons/gdUnit4/src/core/runners/GdUnitTestSessionRunner.gd.uid deleted file mode 100644 index 1735e2ec..00000000 --- a/addons/gdUnit4/src/core/runners/GdUnitTestSessionRunner.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bkgcd3ukyv02c diff --git a/addons/gdUnit4/src/core/templates/test_suite/GdUnitTestSuiteDefaultTemplate.gd b/addons/gdUnit4/src/core/templates/test_suite/GdUnitTestSuiteDefaultTemplate.gd deleted file mode 100644 index 20325ac1..00000000 --- a/addons/gdUnit4/src/core/templates/test_suite/GdUnitTestSuiteDefaultTemplate.gd +++ /dev/null @@ -1,36 +0,0 @@ -class_name GdUnitTestSuiteDefaultTemplate -extends RefCounted - - -const DEFAULT_TEMP_TS_GD =""" - # GdUnit generated TestSuite - class_name ${suite_class_name} - extends GdUnitTestSuite - @warning_ignore('unused_parameter') - @warning_ignore('return_value_discarded') - - # TestSuite generated from - const __source: String = '${source_resource_path}' -""" - - -const DEFAULT_TEMP_TS_CS = """ - // GdUnit generated TestSuite - - using Godot; - using GdUnit4; - - namespace ${name_space} - { - using static Assertions; - using static Utils; - - [TestSuite] - public class ${suite_class_name} - { - // TestSuite generated from - private const string sourceClazzPath = "${source_resource_path}"; - - } - } -""" diff --git a/addons/gdUnit4/src/core/templates/test_suite/GdUnitTestSuiteDefaultTemplate.gd.uid b/addons/gdUnit4/src/core/templates/test_suite/GdUnitTestSuiteDefaultTemplate.gd.uid deleted file mode 100644 index 7ed67fb0..00000000 --- a/addons/gdUnit4/src/core/templates/test_suite/GdUnitTestSuiteDefaultTemplate.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ceebaaf33485v diff --git a/addons/gdUnit4/src/core/templates/test_suite/GdUnitTestSuiteTemplate.gd b/addons/gdUnit4/src/core/templates/test_suite/GdUnitTestSuiteTemplate.gd deleted file mode 100644 index 6fc282db..00000000 --- a/addons/gdUnit4/src/core/templates/test_suite/GdUnitTestSuiteTemplate.gd +++ /dev/null @@ -1,144 +0,0 @@ -class_name GdUnitTestSuiteTemplate -extends RefCounted - -const TEMPLATE_ID_GD = 1000 -const TEMPLATE_ID_CS = 2000 - -const SUPPORTED_TAGS_GD = """ - GdScript Tags are replaced when the test-suite is created. - - # The class name of the test-suite, formed from the source script. - ${suite_class_name} - # is used to build the test suite class name - class_name ${suite_class_name} - extends GdUnitTestSuite - - - # The class name in pascal case, formed from the source script. - ${source_class} - # can be used to create the class e.g. for source 'MyClass' - var my_test_class := ${source_class}.new() - # will be result in - var my_test_class := MyClass.new() - - # The class as variable name in snake case, formed from the source script. - ${source_var} - # Can be used to build the variable name e.g. for source 'MyClass' - var ${source_var} := ${source_class}.new() - # will be result in - var my_class := MyClass.new() - - # The full resource path from which the file was created. - ${source_resource_path} - # Can be used to load the script in your test - var my_script := load(${source_resource_path}) - # will be result in - var my_script := load("res://folder/my_class.gd") -""" - -const SUPPORTED_TAGS_CS = """ - C# Tags are replaced when the test-suite is created. - - // The namespace name of the test-suite - ${name_space} - namespace ${name_space} - - // The class name of the test-suite, formed from the source class. - ${suite_class_name} - // is used to build the test suite class name - [TestSuite] - public class ${suite_class_name} - - // The class name formed from the source class. - ${source_class} - // can be used to create the class e.g. for source 'MyClass' - private string myTestClass = new ${source_class}(); - // will be result in - private string myTestClass = new MyClass(); - - // The class as variable name in camelCase, formed from the source class. - ${source_var} - // Can be used to build the variable name e.g. for source 'MyClass' - private object ${source_var} = new ${source_class}(); - // will be result in - private object myClass = new MyClass(); - - // The full resource path from which the file was created. - ${source_resource_path} - // Can be used to load the script in your test - private object myScript = GD.Load(${source_resource_path}); - // will be result in - private object myScript = GD.Load("res://folder/MyClass.cs"); -""" - -const TAG_TEST_SUITE_CLASS = "${suite_class_name}" -const TAG_SOURCE_CLASS_NAME = "${source_class}" -const TAG_SOURCE_CLASS_VARNAME = "${source_var}" -const TAG_SOURCE_RESOURCE_PATH = "${source_resource_path}" - - -static func default_GD_template() -> String: - return GdUnitTestSuiteDefaultTemplate.DEFAULT_TEMP_TS_GD.dedent().trim_prefix("\n") - - -static func default_CS_template() -> String: - return GdUnitTestSuiteDefaultTemplate.DEFAULT_TEMP_TS_CS.dedent().trim_prefix("\n") - - -static func build_template(source_path: String) -> String: - var clazz_name :String = GdObjects.to_pascal_case(GdObjects.extract_class_name(source_path).value_as_string()) - var template: String = GdUnitSettings.get_setting(GdUnitSettings.TEMPLATE_TS_GD, default_GD_template()) - - return template\ - .replace(TAG_TEST_SUITE_CLASS, clazz_name+"Test")\ - .replace(TAG_SOURCE_RESOURCE_PATH, source_path)\ - .replace(TAG_SOURCE_CLASS_NAME, clazz_name)\ - .replace(TAG_SOURCE_CLASS_VARNAME, GdObjects.to_snake_case(clazz_name)) - - -static func default_template(template_id :int) -> String: - if template_id != TEMPLATE_ID_GD and template_id != TEMPLATE_ID_CS: - push_error("Invalid template '%d' id! Cant load testsuite template" % template_id) - return "" - if template_id == TEMPLATE_ID_GD: - return default_GD_template() - return default_CS_template() - - -static func load_template(template_id :int) -> String: - if template_id != TEMPLATE_ID_GD and template_id != TEMPLATE_ID_CS: - push_error("Invalid template '%d' id! Cant load testsuite template" % template_id) - return "" - if template_id == TEMPLATE_ID_GD: - return GdUnitSettings.get_setting(GdUnitSettings.TEMPLATE_TS_GD, default_GD_template()) - return GdUnitSettings.get_setting(GdUnitSettings.TEMPLATE_TS_CS, default_CS_template()) - - -static func save_template(template_id :int, template :String) -> void: - if template_id != TEMPLATE_ID_GD and template_id != TEMPLATE_ID_CS: - push_error("Invalid template '%d' id! Cant load testsuite template" % template_id) - return - if template_id == TEMPLATE_ID_GD: - GdUnitSettings.save_property(GdUnitSettings.TEMPLATE_TS_GD, template.dedent().trim_prefix("\n")) - elif template_id == TEMPLATE_ID_CS: - GdUnitSettings.save_property(GdUnitSettings.TEMPLATE_TS_CS, template.dedent().trim_prefix("\n")) - - -static func reset_to_default(template_id :int) -> void: - if template_id != TEMPLATE_ID_GD and template_id != TEMPLATE_ID_CS: - push_error("Invalid template '%d' id! Cant load testsuite template" % template_id) - return - if template_id == TEMPLATE_ID_GD: - GdUnitSettings.save_property(GdUnitSettings.TEMPLATE_TS_GD, default_GD_template()) - else: - GdUnitSettings.save_property(GdUnitSettings.TEMPLATE_TS_CS, default_CS_template()) - - -static func load_tags(template_id :int) -> String: - if template_id != TEMPLATE_ID_GD and template_id != TEMPLATE_ID_CS: - push_error("Invalid template '%d' id! Cant load testsuite template" % template_id) - return "Error checked loading tags" - if template_id == TEMPLATE_ID_GD: - return SUPPORTED_TAGS_GD - else: - return SUPPORTED_TAGS_CS diff --git a/addons/gdUnit4/src/core/templates/test_suite/GdUnitTestSuiteTemplate.gd.uid b/addons/gdUnit4/src/core/templates/test_suite/GdUnitTestSuiteTemplate.gd.uid deleted file mode 100644 index a8627f40..00000000 --- a/addons/gdUnit4/src/core/templates/test_suite/GdUnitTestSuiteTemplate.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bqinvriib2uxv diff --git a/addons/gdUnit4/src/core/thread/GdUnitThreadContext.gd b/addons/gdUnit4/src/core/thread/GdUnitThreadContext.gd deleted file mode 100644 index f2b2672c..00000000 --- a/addons/gdUnit4/src/core/thread/GdUnitThreadContext.gd +++ /dev/null @@ -1,66 +0,0 @@ -class_name GdUnitThreadContext -extends RefCounted - -var _thread :Thread -var _thread_name :String -var _thread_id :int -var _signal_collector :GdUnitSignalCollector -var _execution_context :GdUnitExecutionContext -var _asserts := [] - - -func _init(thread :Thread = null) -> void: - if thread != null: - _thread = thread - _thread_name = thread.get_meta("name") - _thread_id = thread.get_id() as int - else: - _thread_name = "main" - _thread_id = OS.get_main_thread_id() - _signal_collector = GdUnitSignalCollector.new() - - -func dispose() -> void: - clear_assert() - if is_instance_valid(_signal_collector): - _signal_collector.clear() - _signal_collector = null - _execution_context = null - _thread = null - - -func clear_assert() -> void: - _asserts.clear() - - -func set_assert(value :GdUnitAssert) -> void: - if value != null: - _asserts.append(value) - - -func get_assert() -> GdUnitAssert: - return null if _asserts.is_empty() else _asserts[-1] - - -func set_execution_context(context :GdUnitExecutionContext) -> void: - _execution_context = context - - -func get_execution_context() -> GdUnitExecutionContext: - return _execution_context - - -func get_execution_context_id() -> int: - return _execution_context.get_instance_id() - - -func get_signal_collector() -> GdUnitSignalCollector: - return _signal_collector - - -func thread_id() -> int: - return _thread_id - - -func _to_string() -> String: - return "ThreadContext <%s>: %s " % [_thread_name, _thread_id] diff --git a/addons/gdUnit4/src/core/thread/GdUnitThreadContext.gd.uid b/addons/gdUnit4/src/core/thread/GdUnitThreadContext.gd.uid deleted file mode 100644 index 747a6bb4..00000000 --- a/addons/gdUnit4/src/core/thread/GdUnitThreadContext.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bbnovcu4fci0e diff --git a/addons/gdUnit4/src/core/thread/GdUnitThreadManager.gd b/addons/gdUnit4/src/core/thread/GdUnitThreadManager.gd deleted file mode 100644 index 31b10782..00000000 --- a/addons/gdUnit4/src/core/thread/GdUnitThreadManager.gd +++ /dev/null @@ -1,64 +0,0 @@ -## A manager to run new thread and crate a ThreadContext shared over the actual test run -class_name GdUnitThreadManager -extends Object - -## { = } -var _thread_context_by_id := {} -## holds the current thread id -var _current_thread_id :int = -1 - -func _init() -> void: - # add initail the main thread - _current_thread_id = OS.get_thread_caller_id() - _thread_context_by_id[OS.get_main_thread_id()] = GdUnitThreadContext.new() - - -static func instance() -> GdUnitThreadManager: - return GdUnitSingleton.instance("GdUnitThreadManager", func() -> GdUnitThreadManager: return GdUnitThreadManager.new()) - - -## Runs a new thread by given name and Callable.[br] -## A new GdUnitThreadContext is created, which is used for the actual test execution.[br] -## We need this custom implementation while this bug is not solved -## Godot issue https://github.com/godotengine/godot/issues/79637 -static func run(name :String, cb :Callable) -> Variant: - return await instance()._run(name, cb) - - -## Returns the current valid thread context -static func get_current_context() -> GdUnitThreadContext: - return instance()._get_current_context() - - -func _run(name :String, cb :Callable) -> Variant: - # we do this hack because of `OS.get_thread_caller_id()` not returns the current id - # when await process_frame is called inside the fread - var save_current_thread_id := _current_thread_id - var thread := Thread.new() - thread.set_meta("name", name) - @warning_ignore("return_value_discarded") - thread.start(cb) - _current_thread_id = thread.get_id() as int - _register_thread(thread, _current_thread_id) - var result :Variant = await thread.wait_to_finish() - _unregister_thread(_current_thread_id) - # restore original thread id - _current_thread_id = save_current_thread_id - return result - - -func _register_thread(thread :Thread, thread_id :int) -> void: - var context := GdUnitThreadContext.new(thread) - _thread_context_by_id[thread_id] = context - - -func _unregister_thread(thread_id :int) -> void: - var context: GdUnitThreadContext = _thread_context_by_id.get(thread_id) - if context: - @warning_ignore("return_value_discarded") - _thread_context_by_id.erase(thread_id) - context.dispose() - - -func _get_current_context() -> GdUnitThreadContext: - return _thread_context_by_id.get(_current_thread_id) diff --git a/addons/gdUnit4/src/core/thread/GdUnitThreadManager.gd.uid b/addons/gdUnit4/src/core/thread/GdUnitThreadManager.gd.uid deleted file mode 100644 index 8b45643c..00000000 --- a/addons/gdUnit4/src/core/thread/GdUnitThreadManager.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://frnnd5anspey diff --git a/addons/gdUnit4/src/core/writers/GdUnitCSIMessageWriter.gd b/addons/gdUnit4/src/core/writers/GdUnitCSIMessageWriter.gd deleted file mode 100644 index 3f5090e1..00000000 --- a/addons/gdUnit4/src/core/writers/GdUnitCSIMessageWriter.gd +++ /dev/null @@ -1,227 +0,0 @@ -@tool -class_name GdUnitCSIMessageWriter -extends GdUnitMessageWriter -## A message writer implementation using ANSI/CSI escape codes for console output.[br] -## [br] -## This writer provides formatted message output using CSI (Control Sequence Introducer) codes.[br] -## It supports:[br] -## - Color using RGB values[br] -## - Text styles (bold, italic, underline)[br] -## - Cursor positioning and text alignment[br] -## [br] -## Used primarily for console-based test execution and CI/CD environments. - - -enum { - COLOR_TABLE, - COLOR_RGB -} - -const CSI_BOLD = "" -const CSI_ITALIC = "" -const CSI_UNDERLINE = "" -const CSI_RESET = "" - -# Control Sequence Introducer -var _debug_show_color_codes := false -var _color_mode := COLOR_TABLE - -## Current cursor position in the line -var _current_pos := 0 - -# Pre-compiled regex patterns for tag matching -var _tag_regex: RegEx - - -## Constructs CSI style codes based on flags.[br] -## [br] -## [param flags] The style flags to apply (BOLD, ITALIC, UNDERLINE).[br] -## Returns the corresponding CSI codes. -func _apply_style_flags(flags: int) -> String: - var _style := "" - if flags & BOLD: - _style += CSI_BOLD - if flags & ITALIC: - _style += CSI_ITALIC - if flags & UNDERLINE: - _style += CSI_UNDERLINE - return _style - - -## Converts a color string (named or hex) to a Color object -func _parse_color(color_str: String) -> Color: - return Color.from_string(color_str.strip_edges().to_lower(), Color.WHITE) - - -## Generates CSI color code for foreground color -func _color_to_csi_fg(c: Color) -> String: - return "[38;2;%d;%d;%dm" % [c.r8 * c.a, c.g8 * c.a, c.b8 * c.a] - - -## Generates CSI color code for background color -func _color_to_csi_bg(c: Color) -> String: - return "[48;2;%d;%d;%dm" % [c.r8 * c.a, c.g8 * c.a, c.b8 * c.a] - - -func _init_regex_patterns() -> void: - if not _tag_regex: - _tag_regex = RegEx.new() - # Match all richtext tags: [tag], [tag=value], [/tag] - _tag_regex.compile(r"\[/?(?:color|bgcolor|b|i|u)(?:=[^\]]+)?\]") - - -func _extract_color_from_tag(tag: String, tag_assign: String) -> Color: - var tag_assign_length := tag_assign.length() - var color_value := tag.substr(tag_assign_length, tag.length() - tag_assign_length - 1) - return _parse_color(color_value) - - -## Optimized richtext to CSI conversion using regex and lookup processing -func _bbcode_tags_to_csi_codes(message: String) -> String: - _init_regex_patterns() - - var result := "" - var last_pos := 0 - var color_stack: Array[Color] = [] - var bgcolor_stack: Array[Color] = [] - - # Find all richtext tags - var matches := _tag_regex.search_all(message) - - for match in matches: - var start_pos := match.get_start() - var end_pos := match.get_end() - var tag := match.get_string(0) - - # Add text before this tag - result += message.substr(last_pos, start_pos - last_pos) - - # Process the tag - if tag.begins_with("[color="): - var fg_color := _extract_color_from_tag(tag, "[color=") - color_stack.push_back(fg_color) - result += _color_to_csi_fg(fg_color) - elif tag.begins_with("[bgcolor="): - var bg_color := _extract_color_from_tag(tag, "[bgcolor=") - bgcolor_stack.push_back(bg_color) - result += _color_to_csi_bg(bg_color) - elif tag == "[b]": - result += CSI_BOLD - elif tag == "[i]": - result += CSI_ITALIC - elif tag == "[u]": - result += CSI_UNDERLINE - elif tag == "[/color]": - result += CSI_RESET - if color_stack.size() > 0: - color_stack.pop_back() - # Restore remaining styles and colors - if color_stack.size() > 0: - result += _color_to_csi_fg(color_stack[-1]) - if bgcolor_stack.size() > 0: - result += _color_to_csi_bg(bgcolor_stack[-1]) - elif tag == "[/bgcolor]": - result += CSI_RESET - if bgcolor_stack.size() > 0: - bgcolor_stack.pop_back() - # Restore remaining styles and colors - if color_stack.size() > 0: - result += _color_to_csi_fg(color_stack[-1]) - if bgcolor_stack.size() > 0: - result += _color_to_csi_bg(bgcolor_stack[-1]) - elif tag in ["[/b]", "[/i]", "[/u]"]: - result += CSI_RESET - # Restore remaining colors after style reset - if color_stack.size() > 0: - result += _color_to_csi_fg(color_stack[-1]) - if bgcolor_stack.size() > 0: - result += _color_to_csi_bg(bgcolor_stack[-1]) - - last_pos = end_pos - - # Add remaining text after last tag - result += message.substr(last_pos) - - return result - - -## Implementation of basic message output with formatting. -func _print_message(_message: String, _color: Color, _indent: int, _flags: int) -> void: - var text := _bbcode_tags_to_csi_codes(_message) - var indent_text := "".lpad(_indent * 2) - var _style := _apply_style_flags(_flags) - printraw("%s[38;2;%d;%d;%dm%s%s" % [indent_text, _color.r8, _color.g8, _color.b8, _style, text]) - _current_pos += _indent * 2 + text.length() - - -## Implementation of line-ending message output with formatting. -func _println_message(_message: String, _color: Color, _indent: int, _flags: int) -> void: - _print_message(_message, _color, _indent, _flags) - prints() - _current_pos = 0 - - -## Implementation of positioned message output with formatting. -func _print_at(_message: String, cursor_pos: int, _color: Color, _effect: Effect, _align: Align, _flags: int) -> void: - if _align == Align.RIGHT: - cursor_pos = cursor_pos - _message.length() - - if cursor_pos > _current_pos: - printraw("[%dG" % cursor_pos) # Move cursor to absolute position - else: - _message = " " + _message - - var _style := _apply_style_flags(_flags) - printraw("[38;2;%d;%d;%dm%s%s" % [_color.r8, _color.g8, _color.b8, _style, _message]) - _current_pos = cursor_pos + _message.length() - - -## Writes a line break and returns self for chaining. -func new_line() -> GdUnitCSIMessageWriter: - prints() - return self - - -## Saves the current cursor position.[br] -## Returns self for chaining. -func save_cursor() -> GdUnitCSIMessageWriter: - printraw("") - return self - - -## Restores previously saved cursor position.[br] -## Returns self for chaining. -func restore_cursor() -> GdUnitCSIMessageWriter: - printraw("") - return self - - -## Clears screen content and resets cursor position. -func clear() -> void: - printraw("") # Clear screen and move cursor to home - _current_pos = 0 - - -## Debug method to display the available color table.[br] -## Shows both 6x6x6 color cube and RGB color modes. -@warning_ignore("return_value_discarded") -func _print_color_table() -> void: - color(Color.ANTIQUE_WHITE).println_message("Color Table 6x6x6") - _debug_show_color_codes = true - for green in range(0, 6): - for red in range(0, 6): - for blue in range(0, 6): - color(Color8(red * 42, green * 42, blue * 42)).println_message("████████ ") - new_line() - new_line() - - color(Color.ANTIQUE_WHITE).println_message("Color Table RGB") - _color_mode = COLOR_RGB - for green in range(0, 6): - for red in range(0, 6): - for blue in range(0, 6): - color(Color8(red * 42, green * 42, blue * 42)).println_message("████████ ") - new_line() - new_line() - _color_mode = COLOR_TABLE - _debug_show_color_codes = false diff --git a/addons/gdUnit4/src/core/writers/GdUnitCSIMessageWriter.gd.uid b/addons/gdUnit4/src/core/writers/GdUnitCSIMessageWriter.gd.uid deleted file mode 100644 index 7f20e9d1..00000000 --- a/addons/gdUnit4/src/core/writers/GdUnitCSIMessageWriter.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bgk5ubygmpous diff --git a/addons/gdUnit4/src/core/writers/GdUnitMessageWriter.gd b/addons/gdUnit4/src/core/writers/GdUnitMessageWriter.gd deleted file mode 100644 index 886c7347..00000000 --- a/addons/gdUnit4/src/core/writers/GdUnitMessageWriter.gd +++ /dev/null @@ -1,214 +0,0 @@ -@tool -class_name GdUnitMessageWriter -extends RefCounted -## Base interface class for writing formatted messages to different outputs.[br] -## [br] -## This class defines the interface and common functionality for writing formatted messages.[br] -## It provides a fluent API for message formatting and supports different output targets.[br] -## [br] -## The class provides formatting options for:[br] -## - Text colors[br] -## - Text styles (bold, italic, underline)[br] -## - Text effects (e.g., wave)[br] -## - Text alignment[br] -## - Indentation[br] -## [br] -## Two concrete implementations are available:[br] -## - [GdUnitRichTextMessageWriter] writing to a [RichTextLabel][br] -## - [GdUnitCSIMessageWriter] writing to console using CSI codes[br] -## [br] -## Example usage:[br] -## [codeblock] -## writer.color(Color.RED).style(BOLD).println_message("Test failed!") -## writer.color(Color.GREEN).align(Align.RIGHT).print_at("Success", 80) -## [/codeblock] - - -## Text style flag for bold formatting -const BOLD = 0x1 -## Text style flag for italic formatting -const ITALIC = 0x2 -## Text style flag for underline formatting -const UNDERLINE = 0x4 - - -## Represents special text effects that can be applied to the output -enum Effect { - ## No special effect applied - NONE, - ## Applies a wave animation to the text - WAVE -} - - -## Controls text alignment at the specified cursor position -enum Align { - ## Aligns text to the left of the cursor position - LEFT, - ## Aligns text to the right of the cursor position, accounting for text length - RIGHT -} - - -## The current text color to be used for the next output operation -var _current_color := Color.WHITE - -## The current indentation level to be used for the next output operation.[br] -## Each level represents two spaces of indentation. -var _current_indent := 0 - -## The current text style flags (BOLD, ITALIC, UNDERLINE) to be used for the next output operation -var _current_flags := 0 - -## The current text alignment to be used for the next output operation -var _current_align := Align.LEFT - -## The current text effect to be used for the next output operation -var _current_effect := Effect.NONE - - -## Sets the text color for the next output operation.[br] -## [br] -## [param value] The color to be used for the text. -## Returns self for method chaining. -func color(value: Color) -> GdUnitMessageWriter: - _current_color = value - return self - - -## Sets the indentation level for the next output operation.[br] -## [br] -## [param value] The number of indentation levels, where each level equals two spaces. -## Returns self for method chaining. -func indent(value: int) -> GdUnitMessageWriter: - _current_indent = value - return self - - -## Sets text style flags for the next output operation.[br] -## [br] -## [param value] A combination of style flags (BOLD, ITALIC, UNDERLINE). -## Returns self for method chaining. -func style(value: int) -> GdUnitMessageWriter: - _current_flags = value - return self - - -## Sets text effect for the next output operation.[br] -## [br] -## [param value] The effect to apply to the text (NONE, WAVE). -## Returns self for method chaining. -func effect(value: Effect) -> GdUnitMessageWriter: - _current_effect = value - return self - - -## Sets text alignment for the next output operation.[br] -## [br] -## [param value] The alignment to use (LEFT, RIGHT). -## Returns self for method chaining. -func align(value: Align) -> GdUnitMessageWriter: - _current_align = value - return self - - -## Resets all formatting options to their default values.[br] -## [br] -## Defaults:[br] -## - color: Color.WHITE[br] -## - indent: 0[br] -## - flags: 0[br] -## - align: LEFT[br] -## - effect: NONE[br] -## Returns self for method chaining. -func reset() -> GdUnitMessageWriter: - _current_color = Color.WHITE - _current_indent = 0 - _current_flags = 0 - _current_align = Align.LEFT - _current_effect = Effect.NONE - return self - - -## Prints a warning message in golden color.[br] -## [br] -## [param message] The warning message to print. -func prints_warning(message: String) -> void: - color(Color.GOLDENROD).println_message(message) - - -## Prints an error message in crimson color.[br] -## [br] -## [param message] The error message to print. -func prints_error(message: String) -> void: - color(Color.CRIMSON).println_message(message) - - -## Prints a message with current formatting settings.[br] -## [br] -## [param message] The text to print. -func print_message(message: String) -> void: - _print_message(message, _current_color, _current_indent, _current_flags) - reset() - - -## Prints a message with current formatting settings followed by a newline.[br] -## [br] -## [param message] The text to print. -func println_message(message: String) -> void: - _println_message(message, _current_color, _current_indent, _current_flags) - reset() - - -## Prints a message at a specific column position with current formatting settings.[br] -## [br] -## [param message] The text to print.[br] -## [param cursor_pos] The column position where the text should start. -func print_at(message: String, cursor_pos: int) -> void: - _print_at(message, cursor_pos, _current_color, _current_effect, _current_align, _current_flags) - reset() - - -## Internal implementation of print_message.[br] -## [br] -## To be overridden by concrete formatters.[br] -## [br] -## [param message] The text to print.[br] -## [param color] The color to use.[br] -## [param indent] The indentation level.[br] -## [param flags] The style flags to apply. -func _print_message(_message: String, _color: Color, _indent: int, _flags: int) -> void: - pass - - -## Internal implementation of println_message.[br] -## [br] -## To be overridden by concrete formatters.[br] -## [br] -## [param message] The text to print.[br] -## [param color] The color to use.[br] -## [param indent] The indentation level.[br] -## [param flags] The style flags to apply. -func _println_message(_message: String, _color: Color, _indent: int, _flags: int) -> void: - pass - - -## Internal implementation of print_at.[br] -## [br] -## To be overridden by concrete formatters.[br] -## [br] -## [param message] The text to print.[br] -## [param cursor_pos] The column position.[br] -## [param color] The color to use.[br] -## [param effect] The effect to apply.[br] -## [param align] The text alignment.[br] -## [param flags] The style flags to apply. -func _print_at(_message: String, _cursor_pos: int, _color: Color, _effect: Effect, _align: Align, _flags: int) -> void: - pass - - -## Clears all output content.[br] -## [br] -## To be overridden by concrete formatters. -func clear() -> void: - pass diff --git a/addons/gdUnit4/src/core/writers/GdUnitMessageWriter.gd.uid b/addons/gdUnit4/src/core/writers/GdUnitMessageWriter.gd.uid deleted file mode 100644 index 63b470db..00000000 --- a/addons/gdUnit4/src/core/writers/GdUnitMessageWriter.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dlf6gid7myugk diff --git a/addons/gdUnit4/src/core/writers/GdUnitRichTextMessageWriter.gd b/addons/gdUnit4/src/core/writers/GdUnitRichTextMessageWriter.gd deleted file mode 100644 index 37b6e39d..00000000 --- a/addons/gdUnit4/src/core/writers/GdUnitRichTextMessageWriter.gd +++ /dev/null @@ -1,115 +0,0 @@ -@tool -class_name GdUnitRichTextMessageWriter -extends GdUnitMessageWriter -## A message writer implementation using [RichTextLabel] for the test report UI.[br] -## [br] -## This writer implementation writes formatted messages to a [RichTextLabel] using BBCode.[br] -## It supports:[br] -## - Text formatting using BBCode (bold, italic, underline)[br] -## - Text coloring using push colors[br] -## - Text indentation using push indent[br] -## - Text effects like wave[br] -## - Basic cursor positioning[br] -## [br] -## Used to format test reports in the editor UI. - - -## The [RichTextLabel] instance to write formatted messages -var _output: RichTextLabel - -## Tracks current position in characters from line start -var _current_pos := 0 - - -## Creates a new message writer for the given [RichTextLabel].[br] -## [br] -## [param output] The [RichTextLabel] used for output. -func _init(output: RichTextLabel) -> void: - _output = output - - -## Applies text style flags by wrapping text in BBCode tags.[br] -## [br] -## Available styles:[br] -## - BOLD: [b]text[/b][br] -## - ITALIC: [i]text[/i][br] -## - UNDERLINE: [u]text[/u][br] -## [br] -## [param message] The text to format.[br] -## [param flags] The text style flags to apply. -func _apply_flags(message: String, flags: int) -> String: - if flags & BOLD: - message = "[b]%s[/b]" % message - if flags & ITALIC: - message = "[i]%s[/i]" % message - if flags & UNDERLINE: - message = "[u]%s[/u]" % message - return message - - -## Writes a message with formatting.[br] -## [br] -## [param message] The text to write.[br] -## [param _color] The color to use.[br] -## [param _indent] The indentation level.[br] -## [param flags] The text style flags to apply. -func _print_message(message: String, _color: Color, _indent: int, flags: int) -> void: - for i in _indent: - _output.push_indent(1) - _output.push_color(_color) - message = _apply_flags(message, flags) - _output.append_text(message) - _output.pop() - for i in _indent: - _output.pop() - _current_pos += _indent * 2 + message.length() - - -## Writes a message with formatting followed by a line break.[br] -## [br] -## [param message] The text to write.[br] -## [param _color] The color to use.[br] -## [param _indent] The indentation level.[br] -## [param flags] The text style flags to apply. -func _println_message(message: String, _color: Color, _indent: int, flags: int) -> void: - _print_message(message, _color, _indent, flags) - _output.newline() - _current_pos = 0 - - -## Writes a message at a specific column position.[br] -## [br] -## [param message] The text to write.[br] -## [param cursor_pos] The column position from line start.[br] -## [param _color] The color to use.[br] -## [param _effect] The text effect to apply (e.g. wave).[br] -## [param _align] The text alignment (left or right).[br] -## [param flags] The text style flags to apply. -func _print_at(message: String, cursor_pos: int, _color: Color, _effect: Effect, _align: Align, flags: int) -> void: - if _align == Align.RIGHT: - cursor_pos = cursor_pos - message.length() - - var spaces := cursor_pos - _current_pos - if spaces > 0: - _output.append_text("".lpad(spaces)) - _current_pos += spaces - else: - _output.append_text(" ") - _current_pos += 1 - - _output.push_color(_color) - message = _apply_flags(message, flags) - match _effect: - Effect.NONE: - pass - Effect.WAVE: - message = "[wave]%s[/wave]" % message - _output.append_text(message) - _output.pop() - _current_pos += message.length() - - -## Clears all written content from the [RichTextLabel]. -func clear() -> void: - _output.clear() - _current_pos = 0 diff --git a/addons/gdUnit4/src/core/writers/GdUnitRichTextMessageWriter.gd.uid b/addons/gdUnit4/src/core/writers/GdUnitRichTextMessageWriter.gd.uid deleted file mode 100644 index bd375f58..00000000 --- a/addons/gdUnit4/src/core/writers/GdUnitRichTextMessageWriter.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dasu47qjmnlks diff --git a/addons/gdUnit4/src/dotnet/GdUnit4CSharpApi.cs b/addons/gdUnit4/src/dotnet/GdUnit4CSharpApi.cs deleted file mode 100644 index 096e83c7..00000000 --- a/addons/gdUnit4/src/dotnet/GdUnit4CSharpApi.cs +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright (c) 2025 Mike Schulze -// MIT License - See LICENSE file in the repository root for full license text -#pragma warning disable IDE1006 -namespace gdUnit4.addons.gdUnit4.src.dotnet; -#pragma warning restore IDE1006 - -#if GDUNIT4NET_API_V5 -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -using GdUnit4; -using GdUnit4.Api; - -using Godot; -using Godot.Collections; - -/// -/// The GdUnit4 GDScript - C# API wrapper. -/// -public partial class GdUnit4CSharpApi : RefCounted -{ - /// - /// The signal to be emitted when the execution is completed. - /// - [Signal] -#pragma warning disable CA1711 - public delegate void ExecutionCompletedEventHandler(); -#pragma warning restore CA1711 - -#pragma warning disable CA2213, SA1201 - private CancellationTokenSource? executionCts; -#pragma warning restore CA2213, SA1201 - - /// - /// Indicates if the API loaded. - /// - /// Returns true if the API already loaded. - public static bool IsApiLoaded() - => true; - - /// - /// Runs test discovery on the given script. - /// - /// The script to be scanned. - /// The list of tests discovered as dictionary. - public static Array DiscoverTests(CSharpScript sourceScript) - { - try - { - // Get the list of test case descriptors from the API - var testCaseDescriptors = GdUnit4NetApiGodotBridge.DiscoverTestsFromScript(sourceScript); - - // Convert each TestCaseDescriptor to a Dictionary - return testCaseDescriptors - .Select(descriptor => new Dictionary - { - ["guid"] = descriptor.Id.ToString(), - ["managed_type"] = descriptor.ManagedType, - ["test_name"] = descriptor.ManagedMethod, - ["source_file"] = sourceScript.ResourcePath, - ["line_number"] = descriptor.LineNumber, - ["attribute_index"] = descriptor.AttributeIndex, - ["require_godot_runtime"] = descriptor.RequireRunningGodotEngine, - ["code_file_path"] = descriptor.CodeFilePath ?? string.Empty, - ["simple_name"] = descriptor.SimpleName, - ["fully_qualified_name"] = descriptor.FullyQualifiedName, - ["assembly_location"] = descriptor.AssemblyPath - }) - .Aggregate( - new Array(), - (array, dict) => - { - array.Add(dict); - return array; - }); - } -#pragma warning disable CA1031 - catch (Exception e) -#pragma warning restore CA1031 - { - GD.PrintErr($"Error discovering tests: {e.Message}\n{e.StackTrace}"); -#pragma warning disable IDE0028 // Do not catch general exception types - return new Array(); -#pragma warning restore IDE0028 // Do not catch general exception types - } - } - - /// - /// Creates a test suite based on the specified source path and line number. - /// - /// The path to the source file from which to create the test suite. - /// The line number in the source file where the method to test is defined. - /// The path where the test suite should be created. - /// A dictionary containing information about the created test suite. - public static Dictionary CreateTestSuite(string sourcePath, int lineNumber, string testSuitePath) - => GdUnit4NetApiGodotBridge.CreateTestSuite(sourcePath, lineNumber, testSuitePath); - - /// - /// Gets the version of the GdUnit4 assembly. - /// - /// The version string of the GdUnit4 assembly. - public static string Version() - => GdUnit4NetApiGodotBridge.Version(); - - /// - public override void _Notification(int what) - { - if (what != NotificationPredelete) - return; - executionCts?.Dispose(); - executionCts = null; - } - - /// - /// Executes the tests and using the listener for reporting the results. - /// - /// A list of tests to be executed. - /// The listener to report the results. - public void ExecuteAsync(Array tests, Callable listener) - { - try - { - // Cancel any ongoing execution - executionCts?.Cancel(); - executionCts?.Dispose(); - - // Create new cancellation token source - executionCts = new CancellationTokenSource(); - - Debug.Assert(tests != null, nameof(tests) + " != null"); - var testSuiteNodes = new List { BuildTestSuiteNodeFrom(tests) }; - GdUnit4NetApiGodotBridge.ExecuteAsync(testSuiteNodes, listener, executionCts.Token) - .GetAwaiter() - .OnCompleted(() => EmitSignal(SignalName.ExecutionCompleted)); - } -#pragma warning disable CA1031 - catch (Exception e) -#pragma warning restore CA1031 - { - GD.PrintErr($"Error executing tests: {e.Message}\n{e.StackTrace}"); - Task.Run(() => { }).GetAwaiter().OnCompleted(() => EmitSignal(SignalName.ExecutionCompleted)); - } - } - - /// - /// Will cancel the current test execution. - /// - public void CancelExecution() - { - try - { - executionCts?.Cancel(); - } -#pragma warning disable CA1031 - catch (Exception e) -#pragma warning restore CA1031 - { - GD.PrintErr($"Error cancelling execution: {e.Message}"); - } - } - - // Convert a set of Tests stored as Dictionaries to TestSuiteNode - // all tests are assigned to a single test suit - internal static TestSuiteNode BuildTestSuiteNodeFrom(Array tests) - { - if (tests.Count == 0) - throw new InvalidOperationException("Cant build 'TestSuiteNode' from an empty test set."); - - // Create a suite ID - var suiteId = Guid.NewGuid(); - var firstTest = tests[0]; - var managedType = firstTest["managed_type"].AsString(); - var assemblyLocation = firstTest["assembly_location"].AsString(); - var sourceFile = firstTest["source_file"].AsString(); - - // Create TestCaseNodes for each test in the suite - var testCaseNodes = tests - .Select(test => new TestCaseNode - { - Id = Guid.Parse(test["guid"].AsString()), - ParentId = suiteId, - ManagedMethod = test["test_name"].AsString(), - LineNumber = test["line_number"].AsInt32(), - AttributeIndex = test["attribute_index"].AsInt32(), - RequireRunningGodotEngine = test["require_godot_runtime"].AsBool() - }) - .ToList(); - - return new TestSuiteNode - { - Id = suiteId, - ParentId = Guid.Empty, - ManagedType = managedType, - AssemblyPath = assemblyLocation, - SourceFile = sourceFile, - Tests = testCaseNodes - }; - } -} -#else -using Godot; -using Godot.Collections; - -public partial class GdUnit4CSharpApi : RefCounted -{ - [Signal] - public delegate void ExecutionCompletedEventHandler(); - - public static bool IsApiLoaded() - { - GD.PushWarning("No `gdunit4.api` dependency found, check your project dependencies."); - return false; - } - - - public static string Version() - => "Unknown"; - - public static Array DiscoverTests(CSharpScript sourceScript) => new(); - - public void ExecuteAsync(Array tests, Callable listener) - { - } - - public static bool IsTestSuite(CSharpScript script) - => false; - - public static Dictionary CreateTestSuite(string sourcePath, int lineNumber, string testSuitePath) - => new(); -} -#endif diff --git a/addons/gdUnit4/src/dotnet/GdUnit4CSharpApi.cs.uid b/addons/gdUnit4/src/dotnet/GdUnit4CSharpApi.cs.uid deleted file mode 100644 index 6e1eeb71..00000000 --- a/addons/gdUnit4/src/dotnet/GdUnit4CSharpApi.cs.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cr0wgxnfgottx diff --git a/addons/gdUnit4/src/dotnet/GdUnit4CSharpApiLoader.gd b/addons/gdUnit4/src/dotnet/GdUnit4CSharpApiLoader.gd deleted file mode 100644 index 3d8ba25f..00000000 --- a/addons/gdUnit4/src/dotnet/GdUnit4CSharpApiLoader.gd +++ /dev/null @@ -1,114 +0,0 @@ -## GdUnit4CSharpApiLoader -## -## A bridge class that handles communication between GDScript and C# for the GdUnit4 testing framework. -## This loader acts as a compatibility layer to safely access the .NET API and ensure that calls -## only proceed when the .NET environment is properly configured and available. -## [br] -## The class handles: -## - Verification of .NET runtime availability -## - Loading the C# wrapper script -## - Checking for the GdUnit4Api assembly -## - Providing proxy methods to access GdUnit4 functionality in C# -@static_unload -class_name GdUnit4CSharpApiLoader -extends RefCounted - -## Cached reference to the loaded C# wrapper script -static var _gdUnit4NetWrapper: Script - -## Cached instance of the API (singleton pattern) -static var _api_instance: RefCounted - - -class TestEventListener extends RefCounted: - - func publish_event(event: Dictionary) -> void: - var test_event := GdUnitEvent.new().deserialize(event) - GdUnitSignals.instance().gdunit_event.emit(test_event) - -static var _test_event_listener := TestEventListener.new() - - -## Returns an instance of the GdUnit4CSharpApi wrapper.[br] -## @return Script: The loaded C# wrapper or null if .NET is not supported -static func instance() -> Script: - if not GdUnit4CSharpApiLoader.is_api_loaded(): - return null - - return _gdUnit4NetWrapper - - -## Returns or creates a single instance of the API [br] -## This improves performance by reusing the same object -static func api_instance() -> RefCounted: - if _api_instance == null and is_api_loaded(): - @warning_ignore("unsafe_method_access") - _api_instance = instance().new() - return _api_instance - - -static func is_engine_version_supported(engine_version: int = Engine.get_version_info().hex) -> bool: - return engine_version >= 0x40200 - - -## Checks if the .NET environment is properly configured and available.[br] -## @return bool: True if .NET is fully supported and the assembly is found -static func is_api_loaded() -> bool: - # If the wrapper is already loaded we don't need to check again - if _gdUnit4NetWrapper != null: - return true - - # First we check if this is a Godot .NET runtime instance - if not ClassDB.class_exists("CSharpScript") or not is_engine_version_supported(): - return false - # Second we check the C# project file exists - var assembly_name: String = ProjectSettings.get_setting("dotnet/project/assembly_name") - if assembly_name.is_empty() or not FileAccess.file_exists("res://%s.csproj" % assembly_name): - return false - - # Finally load the wrapper and check if the GdUnit4 assembly can be found - _gdUnit4NetWrapper = load("res://addons/gdUnit4/src/dotnet/GdUnit4CSharpApi.cs") - @warning_ignore("unsafe_method_access") - return _gdUnit4NetWrapper.call("IsApiLoaded") - - -## Returns the version of the GdUnit4 .NET assembly.[br] -## @return String: The version string or "unknown" if .NET is not supported -static func version() -> String: - if not GdUnit4CSharpApiLoader.is_api_loaded(): - return "unknown" - @warning_ignore("unsafe_method_access") - return instance().Version() - - -static func discover_tests(source_script: Script) -> Array[GdUnitTestCase]: - var tests: Array = _gdUnit4NetWrapper.call("DiscoverTests", source_script) - - return Array(tests.map(GdUnitTestCase.from_dict), TYPE_OBJECT, "RefCounted", GdUnitTestCase) - - -static func execute(tests: Array[GdUnitTestCase]) -> void: - var net_api := api_instance() - if net_api == null: - push_warning("Execute C# tests not supported!") - return - var tests_as_dict: Array[Dictionary] = Array(tests.map(GdUnitTestCase.to_dict), TYPE_DICTIONARY, "", null) - - net_api.call("ExecuteAsync", tests_as_dict, _test_event_listener.publish_event) - @warning_ignore("unsafe_property_access") - await net_api.ExecutionCompleted - - -static func create_test_suite(source_path: String, line_number: int, test_suite_path: String) -> GdUnitResult: - if not GdUnit4CSharpApiLoader.is_api_loaded(): - return GdUnitResult.error("Can't create test suite. No .NET support found.") - @warning_ignore("unsafe_method_access") - var result: Dictionary = instance().CreateTestSuite(source_path, line_number, test_suite_path) - if result.has("error"): - return GdUnitResult.error(str(result.get("error"))) - return GdUnitResult.success(result) - - -static func is_csharp_file(resource_path: String) -> bool: - var ext := resource_path.get_extension() - return ext == "cs" and GdUnit4CSharpApiLoader.is_api_loaded() diff --git a/addons/gdUnit4/src/dotnet/GdUnit4CSharpApiLoader.gd.uid b/addons/gdUnit4/src/dotnet/GdUnit4CSharpApiLoader.gd.uid deleted file mode 100644 index bea59385..00000000 --- a/addons/gdUnit4/src/dotnet/GdUnit4CSharpApiLoader.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://d4du2nsrdreck diff --git a/addons/gdUnit4/src/doubler/CallableDoubler.gd b/addons/gdUnit4/src/doubler/CallableDoubler.gd deleted file mode 100644 index 1bc78a1a..00000000 --- a/addons/gdUnit4/src/doubler/CallableDoubler.gd +++ /dev/null @@ -1,156 +0,0 @@ -## The helper class to allow to double Callable -## Is just a wrapper to the original callable with the same function signature. -## -## Due to interface conflicts between 'Callable' and 'Object', -## it is not possible to stub the 'call' and 'call_deferred' methods. -## -## The Callable interface and the Object class have overlapping method signatures, -## which causes conflicts when attempting to stub these methods. -## As a result, you cannot create stubs for 'call' and 'call_deferred' methods. - -class_name CallableDoubler - - -const doubler_script :Script = preload("res://addons/gdUnit4/src/doubler/CallableDoubler.gd") - -var _cb: Callable - - -func _init(cb: Callable) -> void: - assert(cb!=null, "Invalid argument must not be null") - _cb = cb - -## --- helpers ----------------------------------------------------------------------------------------------------------------------------- -static func map_func_name(method_info: Dictionary) -> String: - return method_info["name"] - - -## We do not want to double all functions based on Object for this class -## Is used on SpyBuilder to excluding functions to be doubled for Callable -static func excluded_functions() -> PackedStringArray: - return ClassDB.class_get_method_list("Object")\ - .map(CallableDoubler.map_func_name)\ - .filter(func (name: String) -> bool: - return !CallableDoubler.callable_functions().has(name)) - - -static func non_callable_functions(name: String) -> bool: - return ![ - # we allow "_init", is need to construct it, - "excluded_functions", - "non_callable_functions", - "callable_functions", - "map_func_name" - ].has(name) - - -## Returns the list of supported Callable functions -static func callable_functions() -> PackedStringArray: - var supported_functions :Array = doubler_script.get_script_method_list()\ - .map(CallableDoubler.map_func_name)\ - .filter(CallableDoubler.non_callable_functions) - # We manually add these functions that we cannot/may not overwrite in this class - supported_functions.append_array(["call_deferred", "callv"]) - return supported_functions - - -## ----------------------------------------------------------------------------------------------------------------------------------------- -## Callable functions stubing -## ----------------------------------------------------------------------------------------------------------------------------------------- - -func bind(...varargs: Array) -> Callable: - _cb = _cb.bindv(varargs) - return _cb - - -func bindv(caller_args: Array) -> Callable: - _cb = _cb.bindv(caller_args) - return _cb - - -@warning_ignore("native_method_override") -func call(...varargs: Array) -> Variant: - return _cb.callv(varargs) - - -# Is not supported, see class description -#func call_deferred(...varargs: Array) -> void: -# return _cb.call_deferred(varargs) - - -# Is not supported, see class description -#func callv(arguments: Array) -> Variant: -# return _cb.callv(arguments) - - -func get_bound_arguments() -> Array: - return _cb.get_bound_arguments() - - -func get_bound_arguments_count() -> int: - return _cb.get_bound_arguments_count() - - -func get_method() -> StringName: - return _cb.get_method() - - -func get_object() -> Object: - return _cb.get_object() - - -func get_object_id() -> int: - return _cb.get_object_id() - - -func hash() -> int: - return _cb.hash() - - -func is_custom() -> bool: - return _cb.is_custom() - - -func is_null() -> bool: - return _cb.is_null() - - -func is_standard() -> bool: - return _cb.is_standard() - - -func is_valid() -> bool: - return _cb.is_valid() - - -func rpc(...varargs: Array) -> void: - match varargs.size(): - 0: _cb.rpc() - 1: _cb.rpc(varargs[0]) - 2: _cb.rpc(varargs[0], varargs[1]) - 3: _cb.rpc(varargs[0], varargs[1], varargs[2]) - 4: _cb.rpc(varargs[0], varargs[1], varargs[2], varargs[3], varargs[4]) - 5: _cb.rpc(varargs[0], varargs[1], varargs[2], varargs[3], varargs[4], varargs[5]) - 6: _cb.rpc(varargs[0], varargs[1], varargs[2], varargs[3], varargs[4], varargs[5], varargs[6]) - 7: _cb.rpc(varargs[0], varargs[1], varargs[2], varargs[3], varargs[4], varargs[5], varargs[6], varargs[7]) - 8: _cb.rpc(varargs[0], varargs[1], varargs[2], varargs[3], varargs[4], varargs[5], varargs[6], varargs[7], varargs[8]) - 9: _cb.rpc(varargs[0], varargs[1], varargs[2], varargs[3], varargs[4], varargs[5], varargs[6], varargs[7], varargs[8], varargs[9]) - - -@warning_ignore("untyped_declaration") -func rpc_id(peer_id: int, ...varargs: Array) -> void: - match varargs.size(): - 0: _cb.rpc_id(peer_id ) - 1: _cb.rpc_id(peer_id, varargs[0]) - 2: _cb.rpc_id(peer_id, varargs[0], varargs[1]) - 3: _cb.rpc_id(peer_id, varargs[0], varargs[1], varargs[2]) - 4: _cb.rpc_id(peer_id, varargs[0], varargs[1], varargs[2], varargs[3], varargs[4]) - 5: _cb.rpc_id(peer_id, varargs[0], varargs[1], varargs[2], varargs[3], varargs[4], varargs[5]) - 6: _cb.rpc_id(peer_id, varargs[0], varargs[1], varargs[2], varargs[3], varargs[4], varargs[5], varargs[6]) - 7: _cb.rpc_id(peer_id, varargs[0], varargs[1], varargs[2], varargs[3], varargs[4], varargs[5], varargs[6], varargs[7]) - 8: _cb.rpc_id(peer_id, varargs[0], varargs[1], varargs[2], varargs[3], varargs[4], varargs[5], varargs[6], varargs[7], varargs[8]) - 9: _cb.rpc_id(peer_id, varargs[0], varargs[1], varargs[2], varargs[3], varargs[4], varargs[5], varargs[6], varargs[7], varargs[8], varargs[9]) - -func unbind(argcount: int) -> Callable: - _cb = _cb.unbind(argcount) - return _cb diff --git a/addons/gdUnit4/src/doubler/CallableDoubler.gd.uid b/addons/gdUnit4/src/doubler/CallableDoubler.gd.uid deleted file mode 100644 index f29cf556..00000000 --- a/addons/gdUnit4/src/doubler/CallableDoubler.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dh3830b0e71kh diff --git a/addons/gdUnit4/src/doubler/GdFunctionDoubler.gd b/addons/gdUnit4/src/doubler/GdFunctionDoubler.gd deleted file mode 100644 index d9459dc3..00000000 --- a/addons/gdUnit4/src/doubler/GdFunctionDoubler.gd +++ /dev/null @@ -1,4 +0,0 @@ -@abstract class_name GdFunctionDoubler -extends RefCounted - -@abstract func double(func_descriptor: GdFunctionDescriptor) -> PackedStringArray diff --git a/addons/gdUnit4/src/doubler/GdFunctionDoubler.gd.uid b/addons/gdUnit4/src/doubler/GdFunctionDoubler.gd.uid deleted file mode 100644 index 9b7e3cb7..00000000 --- a/addons/gdUnit4/src/doubler/GdFunctionDoubler.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bdwnfd8fqrube diff --git a/addons/gdUnit4/src/doubler/GdUnitClassDoubler.gd b/addons/gdUnit4/src/doubler/GdUnitClassDoubler.gd deleted file mode 100644 index 31aa06bc..00000000 --- a/addons/gdUnit4/src/doubler/GdUnitClassDoubler.gd +++ /dev/null @@ -1,119 +0,0 @@ -# A class doubler used to mock and spy checked implementations -class_name GdUnitClassDoubler -extends RefCounted - -const DOUBLER_INSTANCE_ID_PREFIX := "gdunit_doubler_instance_id_" -const EXCLUDE_VIRTUAL_FUNCTIONS = [ - # we have to exclude notifications because NOTIFICATION_PREDELETE is try - # to delete already freed spy/mock resources and will result in a conflict - "_notification", - "notification", - # https://github.com/godotengine/godot/issues/67461 - "get_name", - "get_path", - "duplicate", - ] -# define functions to be exclude when spy or mock checked a scene -const EXLCUDE_SCENE_FUNCTIONS = [ - # needs to exclude get/set script functions otherwise it endsup in recursive endless loop - "set_script", - "get_script", - # needs to exclude otherwise verify fails checked collection arguments checked calling to string - "_to_string", -] -const EXCLUDE_FUNCTIONS = ["new", "free", "get_instance_id", "get_tree"] - - -static func check_leaked_instances() -> void: - ## we check that all registered spy/mock instances are removed from the engine meta data - for key in Engine.get_meta_list(): - if key.begins_with(DOUBLER_INSTANCE_ID_PREFIX): - var instance: Variant = Engine.get_meta(key) - push_error("GdUnit internal error: an spy/mock instance '%s', class:'%s' is not removed from the engine and will lead in a leaked instance!" % [instance, instance.__SOURCE_CLASS]) - await (Engine.get_main_loop() as SceneTree).process_frame - - -# loads the doubler template -# class_info = { "class_name": <>, "class_path" : <>} -static func load_template(template: String, class_info: Dictionary) -> PackedStringArray: - var clazz_name: String = class_info.get("class_name") - var source_code := template\ - .replace("${source_class}", clazz_name)\ - # Replace template class_name DoubledClass with source class name - .replace("SourceClassName", clazz_name.replace(".", "_")) - var lines := GdScriptParser.to_unix_format(source_code).split("\n") - @warning_ignore("return_value_discarded") - lines.insert(1, extends_clazz(class_info)) - lines.insert(0, "@warning_ignore_start('unsafe_call_argument', 'shadowed_variable', 'untyped_declaration', 'native_method_override', 'int_as_enum_without_cast')") - return lines - - -static func extends_clazz(class_info: Dictionary) -> String: - var clazz_name: String = class_info.get("class_name") - var clazz_path: PackedStringArray = class_info.get("class_path", []) - # is inner class? - if clazz_path.size() > 1: - return "extends %s" % clazz_name - if clazz_path.size() == 1 and clazz_path[0].ends_with(".gd"): - return "extends '%s'" % clazz_path[0] - return "extends %s" % clazz_name - - -# double all functions of given instance -static func double_functions(instance: Object, clazz_name: String, clazz_path: PackedStringArray, func_doubler: GdFunctionDoubler, exclude_functions: Array) -> PackedStringArray: - var doubled_source := PackedStringArray() - var parser := GdScriptParser.new() - var exclude_override_functions := EXCLUDE_VIRTUAL_FUNCTIONS + EXCLUDE_FUNCTIONS + exclude_functions - var functions := Array() - - # double script functions - if not ClassDB.class_exists(clazz_name): - var result := parser.parse(clazz_name, clazz_path) - if result.is_error(): - push_error(result.error_message()) - return PackedStringArray() - var class_descriptor: GdClassDescriptor = result.value() - for func_descriptor in class_descriptor.functions(): - if instance != null and not instance.has_method(func_descriptor.name()): - #prints("no virtual func implemented",clazz_name, func_descriptor.name() ) - continue - if functions.has(func_descriptor.name()) or exclude_override_functions.has(func_descriptor.name()): - continue - doubled_source += func_doubler.double(func_descriptor) - functions.append(func_descriptor.name()) - - # double regular class functions - var clazz_functions := GdObjects.extract_class_functions(clazz_name, clazz_path) - for method: Dictionary in clazz_functions: - var func_descriptor := GdFunctionDescriptor.extract_from(method) - # exclude private core functions - if func_descriptor.is_private(): - continue - if functions.has(func_descriptor.name()) or exclude_override_functions.has(func_descriptor.name()): - continue - # GD-110: Hotfix do not double invalid engine functions - if is_invalid_method_descriptior(method): - #prints("'%s': invalid method descriptor found! %s" % [clazz_name, method]) - continue - # do not double on not implemented virtual functions - if instance != null and not instance.has_method(func_descriptor.name()): - #prints("no virtual func implemented",clazz_name, func_descriptor.name() ) - continue - functions.append(func_descriptor.name()) - doubled_source.append_array(func_doubler.double(func_descriptor)) - return doubled_source - - -# GD-110 -static func is_invalid_method_descriptior(method: Dictionary) -> bool: - var return_info: Dictionary = method["return"] - var type: int = return_info["type"] - var usage: int = return_info["usage"] - var clazz_name: String = return_info["class_name"] - # is method returning a type int with a given 'class_name' we have an enum - # and the PROPERTY_USAGE_CLASS_IS_ENUM must be set - if type == TYPE_INT and not clazz_name.is_empty() and not (usage & PROPERTY_USAGE_CLASS_IS_ENUM): - return true - if clazz_name == "Variant.Type": - return true - return false diff --git a/addons/gdUnit4/src/doubler/GdUnitClassDoubler.gd.uid b/addons/gdUnit4/src/doubler/GdUnitClassDoubler.gd.uid deleted file mode 100644 index de295008..00000000 --- a/addons/gdUnit4/src/doubler/GdUnitClassDoubler.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://2y4l1xykubtq diff --git a/addons/gdUnit4/src/doubler/GdUnitFunctionDoublerBuilder.gd b/addons/gdUnit4/src/doubler/GdUnitFunctionDoublerBuilder.gd deleted file mode 100644 index a1a75f11..00000000 --- a/addons/gdUnit4/src/doubler/GdUnitFunctionDoublerBuilder.gd +++ /dev/null @@ -1,336 +0,0 @@ -class_name GdUnitFunctionDoublerBuilder -extends RefCounted - -const TYPE_VOID = GdObjects.TYPE_VOID -const TYPE_VARIANT = GdObjects.TYPE_VARIANT -const TYPE_VARARG = GdObjects.TYPE_VARARG -const TYPE_FUNC = GdObjects.TYPE_FUNC -const TYPE_FUZZER = GdObjects.TYPE_FUZZER -const TYPE_ENUM = GdObjects.TYPE_ENUM - -const DEFAULT_TYPED_RETURN_VALUES := { - TYPE_NIL: "null", - TYPE_BOOL: "false", - TYPE_INT: "0", - TYPE_FLOAT: "0.0", - TYPE_STRING: "\"\"", - TYPE_STRING_NAME: "&\"\"", - TYPE_VECTOR2: "Vector2.ZERO", - TYPE_VECTOR2I: "Vector2i.ZERO", - TYPE_RECT2: "Rect2()", - TYPE_RECT2I: "Rect2i()", - TYPE_VECTOR3: "Vector3.ZERO", - TYPE_VECTOR3I: "Vector3i.ZERO", - TYPE_VECTOR4: "Vector4.ZERO", - TYPE_VECTOR4I: "Vector4i.ZERO", - TYPE_TRANSFORM2D: "Transform2D()", - TYPE_PLANE: "Plane()", - TYPE_QUATERNION: "Quaternion()", - TYPE_AABB: "AABB()", - TYPE_BASIS: "Basis()", - TYPE_TRANSFORM3D: "Transform3D()", - TYPE_PROJECTION: "Projection()", - TYPE_COLOR: "Color()", - TYPE_NODE_PATH: "NodePath()", - TYPE_RID: "RID()", - TYPE_OBJECT: "null", - TYPE_CALLABLE: "Callable()", - TYPE_SIGNAL: "Signal()", - TYPE_DICTIONARY: "Dictionary()", - TYPE_ARRAY: "Array()", - TYPE_PACKED_BYTE_ARRAY: "PackedByteArray()", - TYPE_PACKED_INT32_ARRAY: "PackedInt32Array()", - TYPE_PACKED_INT64_ARRAY: "PackedInt64Array()", - TYPE_PACKED_FLOAT32_ARRAY: "PackedFloat32Array()", - TYPE_PACKED_FLOAT64_ARRAY: "PackedFloat64Array()", - TYPE_PACKED_STRING_ARRAY: "PackedStringArray()", - TYPE_PACKED_VECTOR2_ARRAY: "PackedVector2Array()", - TYPE_PACKED_VECTOR3_ARRAY: "PackedVector3Array()", - TYPE_PACKED_VECTOR4_ARRAY: "PackedVector4Array()", - TYPE_PACKED_COLOR_ARRAY: "PackedColorArray()", - GdObjects.TYPE_VARIANT: "null", - GdObjects.TYPE_ENUM: "0" -} - - -# @GlobalScript enums -# needs to manually map because of https://github.com/godotengine/godot/issues/73835 -const DEFAULT_ENUM_RETURN_VALUES = { - "Side" : "SIDE_LEFT", - "Corner" : "CORNER_TOP_LEFT", - "Orientation" : "HORIZONTAL", - "ClockDirection" : "CLOCKWISE", - "HorizontalAlignment" : "HORIZONTAL_ALIGNMENT_LEFT", - "VerticalAlignment" : "VERTICAL_ALIGNMENT_TOP", - "InlineAlignment" : "INLINE_ALIGNMENT_TOP_TO", - "EulerOrder" : "EULER_ORDER_XYZ", - "Key" : "KEY_NONE", - "KeyModifierMask" : "KEY_CODE_MASK", - "MouseButton" : "MOUSE_BUTTON_NONE", - "MouseButtonMask" : "MOUSE_BUTTON_MASK_LEFT", - "JoyButton" : "JOY_BUTTON_INVALID", - "JoyAxis" : "JOY_AXIS_INVALID", - "MIDIMessage" : "MIDI_MESSAGE_NONE", - "Error" : "OK", - "PropertyHint" : "PROPERTY_HINT_NONE", - "Variant.Type" : "TYPE_NIL", - "Vector2.Axis" : "Vector2.AXIS_X", - "Vector2i.Axis" : "Vector2i.AXIS_X", - "Vector3.Axis" : "Vector3.AXIS_X", - "Vector3i.Axis" : "Vector3i.AXIS_X", - "Vector4.Axis" : "Vector4.AXIS_X", - "Vector4i.Axis" : "Vector4i.AXIS_X", -} - - -static var def_constructor := """ - func _init({constructor_args}) -> void: - __init_doubler() - super({args}) - """.dedent() - - -static var def_verify_block := """ - # verify block - var __verifier := __get_verifier() - if __verifier != null: - if __verifier.is_verify_interactions(): - __verifier.verify_interactions("{func_name}", __args) - {default_return} - else: - __verifier.save_function_interaction("{func_name}", __args) - """.dedent().indent("\t").trim_suffix("\n") - - -static var def_prepare_block := """ - if __is_prepare_return_value(): - __save_function_return_value("{func_name}", __args) - {default_return} - """.dedent().indent("\t").trim_suffix("\n") - - -static var def_void_prepare_block := """ - if __is_prepare_return_value(): - push_error("Mocking functions with return type void is not allowed!") - return - """.dedent().indent("\t").trim_suffix("\n") - - -static var def_mock_return := """ - if __is_do_not_call_real_func("{func_name}", __args): - return __return_mock_value("{func_name}", __args, {default_return}) - """.dedent().indent("\t").trim_suffix("\n") - - -static var def_void_mock_return := """ - if __is_do_not_call_real_func("{func_name}", __args): - return - """.dedent().indent("\t").trim_suffix("\n") - - -var fd: GdFunctionDescriptor -var func_args: Array -var default_return: String -var verify_block: String = "" -var prepare_block: String = "" -var mock_return: String = "" - - -func _init(descriptor: GdFunctionDescriptor) -> void: - # verify all default types are covered - for type_key in TYPE_MAX: - if not DEFAULT_TYPED_RETURN_VALUES.has(type_key): - push_error("missing default definitions! Expexting %d bud is %d" % [DEFAULT_TYPED_RETURN_VALUES.size(), TYPE_MAX]) - prints("missing default definition for type", type_key) - assert(DEFAULT_TYPED_RETURN_VALUES.has(type_key), "Missing Type default definition!") - - fd = descriptor - func_args = argument_names() - default_return = default_return_value() - - -func build_func_signature() -> String: - var return_type := ":" if fd._return_type == TYPE_VARIANT else " -> %s:" % fd.return_type_as_string() - return "{static}func {func_name}({args}){return_type}".format({ - "static" : "static " if fd.is_static() else "", - "func_name": fd.name(), - "args": arguments_full_quilified(), - "return_type": return_type - }) - - -func arguments_full_quilified() -> String: - var collect := PackedStringArray() - for arg in fd.args(): - var name := argument_name(arg) - if arg.has_default(): - var signature := "{argument_name}{arg_typed}={arg_value}".format({ - "argument_name" : name, - "arg_typed" : ":"+GdObjects.type_as_string(arg.type()) if arg.type() == GdObjects.TYPE_VARIANT else "", - "arg_value" : arg.value_as_string() - }) - collect.push_back(signature) - else: - collect.push_back(name) - if fd.is_vararg(): - var arg_descriptor := fd.varargs()[0] - collect.push_back("...%s_: Array" % arg_descriptor.name()) - return ", ".join(collect) - - -func argument_name(arg: GdFunctionArgument) -> String: - return arg.name() + "_" - - -func argument_names() -> PackedStringArray: - return fd.args().map(argument_name) - - -func argument_default(arg :GdFunctionArgument) -> String: - return (arg.value_as_string() - if arg.has_default() - else DEFAULT_TYPED_RETURN_VALUES.get(arg.type(), "null")) - - -func build_constructor_arguments() -> String: - var arguments := PackedStringArray() - for arg in fd.args(): - var default_value := argument_default(arg) - var arg_signature := "{name}:{type}={default}".format({ - "name" : argument_name(arg), - "type" : "Variant" if default_value == "null" else "", - "default" : default_value - }) - arguments.append(arg_signature) - if fd.is_vararg(): - arguments.append("...varargs: Array") - return ", ".join(arguments) - - -func build_arguments() -> String: - return "\tvar __args := [{args}]{varargs}".format({ - "args" : ", ".join(func_args), - "varargs" : " + varargs_" if fd.is_vararg() else "" - }) - - -func build_super_calls() -> String: - if !fd.is_vararg(): - return 'super(%s)\n' % ", ".join(func_args) - - var match_block := "match varargs_.size():\n" - for index in range(0, 11): - match_block += '{index}: super({args})\n'.format({ - "index" : index, - "args" : ", ".join(func_args + build_vararg_list(index)) - }).indent("\t") - match_block += '_: push_error("To many varradic arguments.")\n'.indent("\t") - match_block += "return\n" if is_void_func() else "return %s\n" % default_return - return match_block - - -func build_vararg_list(count: int) -> Array: - var arg_list := [] - for index in count: - arg_list.append("varargs_[%d]" % index) - return arg_list - - -func default_return_value() -> String: - var return_type: Variant = fd.return_type() - if return_type == GdObjects.TYPE_ENUM: - var enum_class := fd._return_class - if DEFAULT_ENUM_RETURN_VALUES.has(enum_class): - return DEFAULT_ENUM_RETURN_VALUES.get(fd._return_class, "0") - - var enum_path := enum_class.split(".") - if enum_path.size() >= 2: - var keys := ClassDB.class_get_enum_constants(enum_path[0], enum_path[1]) - if not keys.is_empty(): - return "%s.%s" % [enum_path[0], keys[0]] - var enum_value: Variant = get_enum_default(enum_class) - if enum_value != null: - return str(enum_value) - # we need fallback for @GlobalScript enums, - return DEFAULT_ENUM_RETURN_VALUES.get(fd._return_class, "0") - return DEFAULT_TYPED_RETURN_VALUES.get(return_type, "invalid") - - -# Determine the enum default by reflection -func get_enum_default(value: String) -> Variant: - var script := GDScript.new() - script.source_code = """ - extends RefCounted - - static func get_enum_default() -> Variant: - return %s.values()[0] - - """.dedent() % value - var err := script.reload() - if err != OK: - push_error("Cant get enum values form '%s', %s" % [value, error_string(err)]) - return 0 - @warning_ignore("unsafe_method_access") - return script.new().call("get_enum_default") - - -func is_void_func() -> bool: - return fd.return_type() == TYPE_NIL or fd.return_type() == TYPE_VOID - - -func with_verify_block() -> GdUnitFunctionDoublerBuilder: - verify_block = def_verify_block.format({ - "func_name" : fd.name(), - "default_return" : "return" if is_void_func() else "return " + default_return - }) - return self - - -func with_prepare_block() -> GdUnitFunctionDoublerBuilder: - if fd.return_type() == TYPE_NIL or fd.return_type() == GdObjects.TYPE_VOID: - prepare_block = def_void_prepare_block - return self - - prepare_block = def_prepare_block.format({ - "func_name" : fd.name(), - "default_return" : "return" if is_void_func() else "return " + default_return - }) - return self - - -func with_mocked_return_value() -> GdUnitFunctionDoublerBuilder: - if is_void_func(): - mock_return = def_void_mock_return.format({ - "func_name" : fd.name(), - }) - else: - mock_return = def_mock_return.format({ - "func_name" : fd.name(), - "default_return" : '"no_arg"' if is_void_func() else default_return - }) - return self - - -func build() -> PackedStringArray: - if fd.name() == "_init": - return [def_constructor.format({ - "constructor_args" : build_constructor_arguments(), - "args" : ", ".join(func_args) - })] - - var func_body: PackedStringArray = [] - func_body.append(build_func_signature()) - func_body.append(build_arguments()) - if not prepare_block.is_empty(): - func_body.append(prepare_block) - func_body.append(verify_block) - if not mock_return.is_empty(): - func_body.append(mock_return) - func_body.append("") - var super_calls := build_super_calls() - if not is_void_func(): - super_calls = super_calls.replace("super(", "return super(" ) - if fd.is_coroutine(): - super_calls = super_calls.replace("super(", "await super(" ) - func_body.append(super_calls.indent("\t")) - return func_body diff --git a/addons/gdUnit4/src/doubler/GdUnitFunctionDoublerBuilder.gd.uid b/addons/gdUnit4/src/doubler/GdUnitFunctionDoublerBuilder.gd.uid deleted file mode 100644 index 6e05ecf9..00000000 --- a/addons/gdUnit4/src/doubler/GdUnitFunctionDoublerBuilder.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://kt1awdql6r3j diff --git a/addons/gdUnit4/src/doubler/GdUnitMockFunctionDoubler.gd b/addons/gdUnit4/src/doubler/GdUnitMockFunctionDoubler.gd deleted file mode 100644 index d735bc56..00000000 --- a/addons/gdUnit4/src/doubler/GdUnitMockFunctionDoubler.gd +++ /dev/null @@ -1,10 +0,0 @@ -class_name GdUnitMockFunctionDoubler -extends GdFunctionDoubler - - -func double(func_descriptor: GdFunctionDescriptor) -> PackedStringArray: - return GdUnitFunctionDoublerBuilder.new(func_descriptor)\ - .with_prepare_block()\ - .with_verify_block()\ - .with_mocked_return_value()\ - .build() diff --git a/addons/gdUnit4/src/doubler/GdUnitMockFunctionDoubler.gd.uid b/addons/gdUnit4/src/doubler/GdUnitMockFunctionDoubler.gd.uid deleted file mode 100644 index f0b9ae11..00000000 --- a/addons/gdUnit4/src/doubler/GdUnitMockFunctionDoubler.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bvr3yq1djn4af diff --git a/addons/gdUnit4/src/doubler/GdUnitObjectInteractions.gd b/addons/gdUnit4/src/doubler/GdUnitObjectInteractions.gd deleted file mode 100644 index 789eb327..00000000 --- a/addons/gdUnit4/src/doubler/GdUnitObjectInteractions.gd +++ /dev/null @@ -1,53 +0,0 @@ -class_name GdUnitObjectInteractions -extends RefCounted - - -static func verify(interaction_object: Object, interactions_times: int) -> Variant: - if not _is_mock_or_spy(interaction_object): - return interaction_object - - _get_verifier(interaction_object).do_verify_interactions(interactions_times) - return interaction_object - - -static func verify_no_interactions(interaction_object: Object) -> GdUnitAssert: - var assert_tool := GdUnitAssertImpl.new("") - if not _is_mock_or_spy(interaction_object): - return assert_tool.report_success() - - var summary := _get_verifier(interaction_object).verify_no_interactions() - if summary.is_empty(): - return assert_tool.report_success() - return assert_tool.report_error(GdAssertMessages.error_no_more_interactions(summary)) - - -static func verify_no_more_interactions(interaction_object: Object) -> GdUnitAssert: - var assert_tool := GdUnitAssertImpl.new("") - if not _is_mock_or_spy(interaction_object): - return assert_tool - - var summary := _get_verifier(interaction_object).verify_no_more_interactions() - if summary.is_empty(): - return assert_tool - return assert_tool.report_error(GdAssertMessages.error_no_more_interactions(summary)) - - -static func reset(interaction_object: Object) -> Object: - if not _is_mock_or_spy(interaction_object): - return interaction_object - - _get_verifier(interaction_object).reset_interactions() - return interaction_object - - -static func _is_mock_or_spy(instance: Object) -> bool: - if instance != null and instance.has_method("__get_verifier"): - return true - - push_error("Error: The given object '%s' is not a mock or spy instance!" % instance) - return false - - -static func _get_verifier(interaction_object: Object) -> GdUnitObjectInteractionsVerifier: - @warning_ignore("unsafe_method_access") - return interaction_object.__get_verifier() diff --git a/addons/gdUnit4/src/doubler/GdUnitObjectInteractions.gd.uid b/addons/gdUnit4/src/doubler/GdUnitObjectInteractions.gd.uid deleted file mode 100644 index 2eec03e9..00000000 --- a/addons/gdUnit4/src/doubler/GdUnitObjectInteractions.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b1jlomyn5tf7t diff --git a/addons/gdUnit4/src/doubler/GdUnitObjectInteractionsVerifier.gd b/addons/gdUnit4/src/doubler/GdUnitObjectInteractionsVerifier.gd deleted file mode 100644 index 36aa9783..00000000 --- a/addons/gdUnit4/src/doubler/GdUnitObjectInteractionsVerifier.gd +++ /dev/null @@ -1,84 +0,0 @@ -class_name GdUnitObjectInteractionsVerifier - -var expected_interactions: int = -1 -var saved_interactions := Dictionary() -var verified_interactions := Array() - - -func save_function_interaction(func_name: String, args :Array[Variant]) -> void: - var function_args := [func_name] + args - var matcher := GdUnitArgumentMatchers.to_matcher(function_args, true) - for index in saved_interactions.keys().size(): - var key: Variant = saved_interactions.keys()[index] - if matcher.is_match(key): - saved_interactions[key] += 1 - return - saved_interactions[function_args] = 1 - - -func is_verify_interactions() -> bool: - return expected_interactions != -1 - - -func do_verify_interactions(interactions_times: int = 1) -> void: - expected_interactions = interactions_times - - -func verify_interactions(func_name: String, args: Array[Variant]) -> void: - var summary := Dictionary() - var total_interactions := 0 - var function_args := [func_name] + args - var matcher := GdUnitArgumentMatchers.to_matcher(function_args, true) - for index in saved_interactions.keys().size(): - var key: Variant = saved_interactions.keys()[index] - if matcher.is_match(key): - var interactions: int = saved_interactions.get(key, 0) - total_interactions += interactions - summary[key] = interactions - # add as verified - verified_interactions.append(key) - - var assert_tool := GdUnitAssertImpl.new("") - if total_interactions != expected_interactions: - var __expected_summary := {function_args : expected_interactions} - var error_message: String - # if no interactions macht collect not verified interactions for failure report - if summary.is_empty(): - var __current_summary := verify_no_more_interactions() - error_message = GdAssertMessages.error_validate_interactions(__current_summary, __expected_summary) - else: - error_message = GdAssertMessages.error_validate_interactions(summary, __expected_summary) - @warning_ignore("return_value_discarded") - assert_tool.report_error(error_message) - else: - @warning_ignore("return_value_discarded") - assert_tool.report_success() - expected_interactions = -1 - - -func verify_no_interactions() -> Dictionary: - var summary := Dictionary() - if not saved_interactions.is_empty(): - for index in saved_interactions.keys().size(): - var func_call: Variant = saved_interactions.keys()[index] - summary[func_call] = saved_interactions[func_call] - return summary - - -func verify_no_more_interactions() -> Dictionary: - var summary := Dictionary() - var called_functions: Array[Variant] = saved_interactions.keys() - if called_functions != verified_interactions: - # collect the not verified functions - var called_but_not_verified := called_functions.duplicate() - for index in verified_interactions.size(): - called_but_not_verified.erase(verified_interactions[index]) - - for index in called_but_not_verified.size(): - var not_verified: Variant = called_but_not_verified[index] - summary[not_verified] = saved_interactions[not_verified] - return summary - - -func reset_interactions() -> void: - saved_interactions.clear() diff --git a/addons/gdUnit4/src/doubler/GdUnitObjectInteractionsVerifier.gd.uid b/addons/gdUnit4/src/doubler/GdUnitObjectInteractionsVerifier.gd.uid deleted file mode 100644 index b53e17aa..00000000 --- a/addons/gdUnit4/src/doubler/GdUnitObjectInteractionsVerifier.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cjwrb8kjh55bh diff --git a/addons/gdUnit4/src/doubler/GdUnitSpyFunctionDoubler.gd b/addons/gdUnit4/src/doubler/GdUnitSpyFunctionDoubler.gd deleted file mode 100644 index 091241da..00000000 --- a/addons/gdUnit4/src/doubler/GdUnitSpyFunctionDoubler.gd +++ /dev/null @@ -1,8 +0,0 @@ -class_name GdUnitSpyFunctionDoubler -extends GdFunctionDoubler - - -func double(func_descriptor: GdFunctionDescriptor) -> PackedStringArray: - return GdUnitFunctionDoublerBuilder.new(func_descriptor)\ - .with_verify_block()\ - .build() diff --git a/addons/gdUnit4/src/doubler/GdUnitSpyFunctionDoubler.gd.uid b/addons/gdUnit4/src/doubler/GdUnitSpyFunctionDoubler.gd.uid deleted file mode 100644 index e41989b0..00000000 --- a/addons/gdUnit4/src/doubler/GdUnitSpyFunctionDoubler.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b2uheqy6cfcn2 diff --git a/addons/gdUnit4/src/extractors/GdUnitFuncValueExtractor.gd b/addons/gdUnit4/src/extractors/GdUnitFuncValueExtractor.gd deleted file mode 100644 index 124d3d4e..00000000 --- a/addons/gdUnit4/src/extractors/GdUnitFuncValueExtractor.gd +++ /dev/null @@ -1,73 +0,0 @@ -# This class defines a value extractor by given function name and args -class_name GdUnitFuncValueExtractor -extends GdUnitValueExtractor - -var _func_names :PackedStringArray -var _args :Array - -func _init(func_name :String, p_args :Array) -> void: - _func_names = func_name.split(".") - _args = p_args - - -func func_names() -> PackedStringArray: - return _func_names - - -func args() -> Array: - return _args - - -# Extracts a value by given `func_name` and `args`, -# Allows to use a chained list of functions setarated ba a dot. -# e.g. "func_a.func_b.name" -# do calls instance.func_a().func_b().name() and returns finally the name -# If a function returns an array, all elements will by collected in a array -# e.g. "get_children.get_name" checked a node -# do calls node.get_children() for all childs get_name() and returns all names in an array -# -# if the value not a Object or not accesible be `func_name` the value is converted to `"n.a."` -# expecing null values -func extract_value(value: Variant) -> Variant: - if value == null: - return null - for func_name in func_names(): - if GdArrayTools.is_array_type(value): - var values := Array() - @warning_ignore("unsafe_cast") - for element: Variant in (value as Array): - values.append(_call_func(element, func_name)) - value = values - else: - value = _call_func(value, func_name) - var type := typeof(value) - if type == TYPE_STRING_NAME: - return str(value) - if type == TYPE_STRING and value == "n.a.": - return value - return value - - -func _call_func(value :Variant, func_name :String) -> Variant: - # for array types we need to call explicit by function name, using funcref is only supported for Objects - # TODO extend to all array functions - if GdArrayTools.is_array_type(value) and func_name == "empty": - @warning_ignore("unsafe_cast") - return (value as Array).is_empty() - - if is_instance_valid(value): - # extract from function - var obj_value: Object = value - if obj_value.has_method(func_name): - var extract := Callable(obj_value, func_name) - if extract.is_valid(): - return obj_value.call(func_name) if args().is_empty() else obj_value.callv(func_name, args()) - else: - # if no function exists than try to extract form parmeters - var parameter: Variant = obj_value.get(func_name) - if parameter != null: - return parameter - # nothing found than return 'n.a.' - if GdUnitSettings.is_verbose_assert_warnings(): - push_warning("Extracting value from element '%s' by func '%s' failed! Converting to \"n.a.\"" % [value, func_name]) - return "n.a." diff --git a/addons/gdUnit4/src/extractors/GdUnitFuncValueExtractor.gd.uid b/addons/gdUnit4/src/extractors/GdUnitFuncValueExtractor.gd.uid deleted file mode 100644 index f576491b..00000000 --- a/addons/gdUnit4/src/extractors/GdUnitFuncValueExtractor.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dcaqmjqxw1urv diff --git a/addons/gdUnit4/src/fuzzers/BoolFuzzer.gd b/addons/gdUnit4/src/fuzzers/BoolFuzzer.gd deleted file mode 100644 index 906ee2c5..00000000 --- a/addons/gdUnit4/src/fuzzers/BoolFuzzer.gd +++ /dev/null @@ -1,24 +0,0 @@ -## A fuzzer that generates random boolean values for testing.[br] -## -## This is useful for testing code paths that -## depend on boolean conditions, flags, or toggle states.[br] -## -## [b]Usage example:[/b] -## [codeblock] -## func test_toggle_feature(fuzzer := BoolFuzzer.new(), _fuzzer_iterations = 100): -## var enabled := fuzzer.next_value() -## my_feature.set_enabled(enabled) -## assert_bool(my_feature.is_enabled()),is_equal(enabled) -## [/codeblock] -class_name BoolFuzzer -extends Fuzzer - - -## Generates a random boolean value.[br] -## -## Returns either [code]true[/code] or [code]false[/code] with equal probability. -## This method is called automatically during fuzz testing iterations.[br] -## -## @returns A randomly generated boolean value ([code]true[/code] or [code]false[/code]). -func next_value() -> bool: - return randi() % 2 diff --git a/addons/gdUnit4/src/fuzzers/BoolFuzzer.gd.uid b/addons/gdUnit4/src/fuzzers/BoolFuzzer.gd.uid deleted file mode 100644 index 5e31e4ba..00000000 --- a/addons/gdUnit4/src/fuzzers/BoolFuzzer.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://crq46j53dic2o diff --git a/addons/gdUnit4/src/fuzzers/FloatFuzzer.gd b/addons/gdUnit4/src/fuzzers/FloatFuzzer.gd deleted file mode 100644 index 5da1a777..00000000 --- a/addons/gdUnit4/src/fuzzers/FloatFuzzer.gd +++ /dev/null @@ -1,37 +0,0 @@ -## A fuzzer that generates random floating-point values within a specified range.[br] -## -## This is particularly useful for testing numerical calculations, -## physics simulations, shader parameters, or any code that processes floating-point -## values.[br] -## -## [b]Usage example:[/b] -## [codeblock] -## func test_calculate_damage(fuzzer := FloatFuzzer.new(0.0, 100.0), _fuzzer_iterations := 500): -## var damage := fuzzer.next_value() -## var result = calculate_damage_reduction(damage) -## assert_float(result).is_between(0.0, damage) -## [/codeblock] -## [br] -## [b]Note:[/b] The range is inclusive on both ends, and values are uniformly distributed. -class_name FloatFuzzer -extends Fuzzer - -## Minimum value (inclusive) for generated floats. -var _from: float = 0 -## Maximum value (inclusive) for generated floats. -var _to: float = 0 - -func _init(from: float, to: float) -> void: - assert(from <= to, "Invalid range!") - _from = from - _to = to - - -## Generates a random float value within the configured range.[br] -## -## Returns a uniformly distributed random float between [member _from] and -## [member _to] (inclusive). Each call produces a new random value.[br] -## -## @returns A random float value within the specified range. -func next_value() -> float: - return randf_range(_from, _to) diff --git a/addons/gdUnit4/src/fuzzers/FloatFuzzer.gd.uid b/addons/gdUnit4/src/fuzzers/FloatFuzzer.gd.uid deleted file mode 100644 index c03fe9fe..00000000 --- a/addons/gdUnit4/src/fuzzers/FloatFuzzer.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://drahq5ep3dw4s diff --git a/addons/gdUnit4/src/fuzzers/Fuzzer.gd b/addons/gdUnit4/src/fuzzers/Fuzzer.gd deleted file mode 100644 index e4e597d0..00000000 --- a/addons/gdUnit4/src/fuzzers/Fuzzer.gd +++ /dev/null @@ -1,80 +0,0 @@ -## Base interface for fuzz testing.[br] -## -## Fuzzer is an abstract base class that provides the foundation for creating -## custom fuzzers used in automated testing. Fuzz testing (fuzzing) is a software -## testing technique that involves providing invalid, unexpected, or random data -## as inputs to a program to find bugs and potential security vulnerabilities. -## [br][br] -## To use a fuzzer in your test cases, add optional parameters to your test function: -## [codeblock] -## func test_foo(fuzzer := Fuzzers.randomInt(), _fuzzer_iterations := 10, _fuzzer_seed := 12345): -## var value := fuzzer.next_value() -## # Test logic using the fuzzed value -## [/codeblock] -## [br] -## @tutorial(Fuzzing on Wikipedia): https://en.wikipedia.org/wiki/Fuzzing -@abstract -class_name Fuzzer -extends RefCounted - -## Default number of iterations for fuzz testing when not specified. -const ITERATION_DEFAULT_COUNT := 1000 -## Parameter name for passing the fuzzer instance to test functions. -const ARGUMENT_FUZZER_INSTANCE := "fuzzer" -## Parameter name for specifying the number of iterations in test functions. -const ARGUMENT_ITERATIONS := "fuzzer_iterations" -## Parameter name for specifying the random seed in test functions. -const ARGUMENT_SEED := "fuzzer_seed" - -## Current iteration index during fuzzing execution. -var _iteration_index := 0 -## Maximum number of iterations to run for this fuzzer. -var _iteration_limit := ITERATION_DEFAULT_COUNT - - -## Generates the next fuzz value.[br] -## -## This abstract method must be implemented by derived classes to provide -## the specific fuzzing logic for generating test values.[br] -## -## [b]Example implementation:[/b] -## [codeblock] -## func next_value() -> int: -## return randi_range(0, 100) -## [/codeblock] -## -## @returns The next generated fuzz value. The type depends on the specific fuzzer implementation. -@abstract -func next_value() -> Variant - - -## Returns the current iteration index.[br] -## -## Useful for tracking progress during fuzzing or for debugging purposes -## when a specific iteration causes a failure.[br] -## -## [b]Example:[/b] -## [codeblock] -## if fuzzer.iteration_index() % 100 == 0: -## print("Processed %d iterations" % fuzzer.iteration_index()) -## [/codeblock] -## -## @returns The current iteration index, starting from 0. -func iteration_index() -> int: - return _iteration_index - - -## Returns the maximum number of iterations for this fuzzer.[br] -## -## This value determines how many times the fuzzer will generate values -## during a test run. It can be overridden by the [code]fuzzer_iterations[/code] -## parameter in test functions.[br] -## -## [b]Example:[/b] -## [codeblock] -## print("Running %d fuzzing iterations" % fuzzer.iteration_limit()) -## [/codeblock] -## -## @returns The maximum number of iterations to be executed. -func iteration_limit() -> int: - return _iteration_limit diff --git a/addons/gdUnit4/src/fuzzers/Fuzzer.gd.uid b/addons/gdUnit4/src/fuzzers/Fuzzer.gd.uid deleted file mode 100644 index e1b39247..00000000 --- a/addons/gdUnit4/src/fuzzers/Fuzzer.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://1aff57gewcrx diff --git a/addons/gdUnit4/src/fuzzers/IntFuzzer.gd b/addons/gdUnit4/src/fuzzers/IntFuzzer.gd deleted file mode 100644 index 4100d514..00000000 --- a/addons/gdUnit4/src/fuzzers/IntFuzzer.gd +++ /dev/null @@ -1,77 +0,0 @@ -## A fuzzer that generates random integer values with optional even/odd constraints.[br] -## -## It supports three modes: normal (any integer), even-only, -## and odd-only generation. This is useful for testing array indices, loop counters, -## enumeration values, or any code that processes integer values.[br] -## -## [b]Usage example:[/b] -## [codeblock] -## # Test with any integer in range -## func test_array_access(fuzzer = IntFuzzer.new(0, 99), fuzzer_iterations = 100): -## var index = fuzzer.next_value() -## var array = create_array(100) -## assert(array[index] != null) -## -## # Test with only even numbers -## func test_even_processing(fuzzer := IntFuzzer.new(0, 100, IntFuzzer.EVEN)): -## var even_num := fuzzer.next_value() -## assert_int(even_num % 2).is_equal(0) -## [/codeblock] -class_name IntFuzzer -extends Fuzzer - - -## Generates any integer within the range. -enum { - NORMAL, ## Generate any integer within the specified range. - EVEN, ## Generate only even integers within the specified range. - ODD ## Generate only odd integers within the specified range. -} - - -## Minimum value (inclusive) for generated integers. -var _from: int = 0 -## Maximum value (inclusive) for generated integers. -var _to: int = 0 -## Generation mode: NORMAL, EVEN, or ODD. -var _mode: int = NORMAL - - -func _init(from: int, to: int, mode: int = NORMAL) -> void: - assert(from <= to, "Invalid range!") - _from = from - _to = to - _mode = mode - - -## Generates a random integer value based on the configured mode.[br] -## -## Returns a random integer between [member _from] and [member _to] (inclusive).[br] -## The value will be constrained according to the [member _mode]:[br] -## - [constant NORMAL]: Any integer in the range[br] -## - [constant EVEN]: Only even integers[br] -## - [constant ODD]: Only odd integers[br] -## -## [b]Example:[/b] -## [codeblock] -## var normal_fuzzer = IntFuzzer.new(1, 10, IntFuzzer.NORMAL) -## var even_fuzzer = IntFuzzer.new(1, 10, IntFuzzer.EVEN) -## var odd_fuzzer = IntFuzzer.new(1, 10, IntFuzzer.ODD) -## -## print(normal_fuzzer.next_value()) # Could be any: 1, 2, 3, ..., 10 -## print(even_fuzzer.next_value()) # Only even: 2, 4, 6, 8, 10 -## print(odd_fuzzer.next_value()) # Only odd: 1, 3, 5, 7, 9 -## [/codeblock] -## -## @returns A random integer value within the specified range and mode -func next_value() -> int: - var value := randi_range(_from, _to) - match _mode: - NORMAL: - return value - EVEN: - return int((value / 2.0) * 2) - ODD: - return int((value / 2.0) * 2 + 1) - _: - return value diff --git a/addons/gdUnit4/src/fuzzers/IntFuzzer.gd.uid b/addons/gdUnit4/src/fuzzers/IntFuzzer.gd.uid deleted file mode 100644 index 27a2f4ef..00000000 --- a/addons/gdUnit4/src/fuzzers/IntFuzzer.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ckj3hkhc86176 diff --git a/addons/gdUnit4/src/fuzzers/StringFuzzer.gd b/addons/gdUnit4/src/fuzzers/StringFuzzer.gd deleted file mode 100644 index 277b4ac6..00000000 --- a/addons/gdUnit4/src/fuzzers/StringFuzzer.gd +++ /dev/null @@ -1,112 +0,0 @@ -## A fuzzer that generates random strings with configurable length and character sets.[br] -## -## It supports custom character sets defined by patterns or ranges, -## making it ideal for testing input validation, text processing, parsers, or any -## code that handles string data.[br] -## -## The fuzzer uses a pattern syntax to define allowed characters:[br] -## - Single characters: [code]abc[/code] allows 'a', 'b', 'c'[br] -## - Ranges: [code]a-z[/code] allows lowercase letters[br] -## - Special patterns: [code]\\w[/code] (word chars), [code]\\p{L}[/code] (letters), [code]\\p{N}[/code] (numbers)[br] -## -## [b]Usage example:[/b] -## [codeblock] -## # Test with alphanumeric strings -## func test_username(fuzzer := StringFuzzer.new(3, 20, "a-zA-Z0-9"), _fuzzer_iterations := 100): -## var username _= fuzzer.next_value() -## assert_bool(validate_username(username)).is_true() -## -## # Test with special characters -## func test_password(fuzzer := StringFuzzer.new(8, 32, "a-zA-Z0-9!@#$%"), _fuzzer_iterations := 100) -> void: -## var password := fuzzer.next_value() -## assert_str(password).has_length(8, Comparator.GREATER_EQUAL).has_length(32, Comparator.LESS_EQUAL) -## [/codeblock] -class_name StringFuzzer -extends Fuzzer - -## Default character set pattern including word characters, letters, numbers, and common symbols.[br] -## Includes: word characters (\\w), Unicode letters (\\p{L}), Unicode numbers (\\p{N}), -## and the characters: +, -, _, ' -const DEFAULT_CHARSET = "\\w\\p{L}\\p{N}+-_'" - -## Minimum length for generated strings (inclusive). -var _min_length: int -## Maximum length for generated strings (inclusive). -var _max_length: int -## Array of character codes that can be used in generated strings. -var _charset: PackedInt32Array - - -func _init(min_length: int, max_length: int, pattern: String = DEFAULT_CHARSET) -> void: - _min_length = min_length - _max_length = max_length + 1 # +1 for inclusive - assert(not null or not pattern.is_empty()) - assert(_min_length > 0 and _min_length < _max_length) - _charset = _extract_charset(pattern) - - -## Generates a random string based on configured parameters.[br] -## -## Creates a string with random length between [member _min_length] and -## [member _max_length], using only characters from the configured charset. -## Each character is selected randomly and independently.[br] -## -## [b]Example:[/b] -## [codeblock] -## var fuzzer = StringFuzzer.new(5, 10, "ABC") -## for i in range(5): -## var str = fuzzer.next_value() -## print("Generated: ", str) -## # Possible outputs: "ABCAB", "BCAABCA", "CCCBAA", etc. -## assert(str.length() >= 5 and str.length() <= 10) -## for c in str: -## assert(c in ["A", "B", "C"]) -## [/codeblock] -## -## @returns A random string matching the configured constraints. -func next_value() -> String: - var value := PackedInt32Array() - var max_char := len(_charset) - var length: int = max(_min_length, randi() % _max_length) - for i in length: - @warning_ignore("return_value_discarded") - value.append(_charset[randi() % max_char]) - return value.to_byte_array().get_string_from_utf32() - - -static func _extract_charset(pattern: String) -> PackedInt32Array: - var reg := RegEx.new() - if reg.compile(pattern) != OK: - push_error("Invalid pattern to generate Strings! Use e.g '\\w\\p{L}\\p{N}+-_'") - return PackedInt32Array() - - var charset := PackedInt32Array() - var char_before := -1 - var index := 0 - while index < pattern.length(): - var char_current := pattern.unicode_at(index) - # - range token at first or last pos? - if char_current == 45 and (index == 0 or index == pattern.length()-1): - charset.append(char_current) - index += 1 - continue - index += 1 - # range starts - if char_current == 45 and char_before != -1: - var char_next := pattern.unicode_at(index) - var characters := _build_chars(char_before, char_next) - for character in characters: - charset.append(character) - char_before = -1 - index += 1 - continue - char_before = char_current - charset.append(char_current) - return charset - - -static func _build_chars(from: int, to: int) -> PackedInt32Array: - var characters := PackedInt32Array() - for character in range(from+1, to+1): - characters.append(character) - return characters diff --git a/addons/gdUnit4/src/fuzzers/StringFuzzer.gd.uid b/addons/gdUnit4/src/fuzzers/StringFuzzer.gd.uid deleted file mode 100644 index ca1b1198..00000000 --- a/addons/gdUnit4/src/fuzzers/StringFuzzer.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cowpncn3c1e3j diff --git a/addons/gdUnit4/src/fuzzers/Vector2Fuzzer.gd b/addons/gdUnit4/src/fuzzers/Vector2Fuzzer.gd deleted file mode 100644 index 70ef31b7..00000000 --- a/addons/gdUnit4/src/fuzzers/Vector2Fuzzer.gd +++ /dev/null @@ -1,45 +0,0 @@ -## A fuzzer that generates random Vector2 values within a specified rectangular range.[br] -## -## This is particularly useful for testing 2D physics, movement -## systems, UI positioning, sprite coordinates, or any code that processes 2D vectors.[br] -## -## The fuzzer generates vectors where each component (x, y) is independently randomized -## within its respective range, creating a uniform distribution over the rectangular area.[br] -## -## [b]Usage example:[/b] -## [codeblock] -## # Test 2D movement within screen bounds -## func test_movement(fuzzer := Vector2Fuzzer.new(Vector2.ZERO, Vector2(1920, 1080)), _fuzzer_iterations := 200) -> void: -## var position := fuzzer.next_value() -## player.set_position(position) -## -## [/codeblock] -class_name Vector2Fuzzer -extends Fuzzer - - -## Minimum bounds for the generated vectors (inclusive for both x and y). -var _from: Vector2 -## Maximum bounds for the generated vectors (inclusive for both x and y). -var _to: Vector2 - - -func _init(from: Vector2, to: Vector2) -> void: - assert(from <= to, "Invalid range!") - _from = from - _to = to - - -## Generates a random Vector2 within the configured rectangular range.[br] -## -## Returns a Vector2 where each component is independently randomized:[br] -## - x: random float between [code]_from.x[/code] and [code]_to.x[/code][br] -## - y: random float between [code]_from.y[/code] and [code]_to.y[/code][br] -## -## The distribution is uniform over the rectangular area defined by the bounds.[br] -## -## @returns A random Vector2 within the specified range. -func next_value() -> Vector2: - var x := randf_range(_from.x, _to.x) - var y := randf_range(_from.y, _to.y) - return Vector2(x, y) diff --git a/addons/gdUnit4/src/fuzzers/Vector2Fuzzer.gd.uid b/addons/gdUnit4/src/fuzzers/Vector2Fuzzer.gd.uid deleted file mode 100644 index 38157ad5..00000000 --- a/addons/gdUnit4/src/fuzzers/Vector2Fuzzer.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://d1rqf80tw6mye diff --git a/addons/gdUnit4/src/fuzzers/Vector3Fuzzer.gd b/addons/gdUnit4/src/fuzzers/Vector3Fuzzer.gd deleted file mode 100644 index b54870d1..00000000 --- a/addons/gdUnit4/src/fuzzers/Vector3Fuzzer.gd +++ /dev/null @@ -1,48 +0,0 @@ -## A fuzzer that generates random Vector3 values within a specified box range.[br] -## -## This is particularly useful for testing 3D physics, spatial -## positioning, camera systems, particle effects, or any code that processes 3D vectors.[br] -## -## The fuzzer generates vectors where each component (x, y, z) is independently -## randomized within its respective range, creating a uniform distribution over the -## 3D box volume.[br] -## -## [b]Usage example:[/b] -## [codeblock] -## # Test 3D object placement within world bounds -## func test_spawn_position(fuzzer := Vector3Fuzzer.new(Vector3(-100, 0, -100), Vector3(100, 50, 100)), _fuzzer_iterations := 300): -## var position := fuzzer.next_value() -## var object = spawn_object(position) -## -## [/codeblock] -class_name Vector3Fuzzer -extends Fuzzer - - -## Minimum bounds for the generated vectors (inclusive for x, y, and z). -var _from: Vector3 -## Maximum bounds for the generated vectors (inclusive for x, y, and z). -var _to: Vector3 - - -func _init(from: Vector3, to: Vector3) -> void: - assert(from <= to, "Invalid range!") - _from = from - _to = to - - -## Generates a random Vector3 within the configured box range.[br] -## -## Returns a Vector3 where each component is independently randomized:[br] -## - x: random float between [code]_from.x[/code] and [code]_to.x[/code][br] -## - y: random float between [code]_from.y[/code] and [code]_to.y[/code][br] -## - z: random float between [code]_from.z[/code] and [code]_to.z[/code][br] -## -## The distribution is uniform over the 3D box volume defined by the bounds.[br] -## -## @returns A random Vector3 within the specified range. -func next_value() -> Vector3: - var x := randf_range(_from.x, _to.x) - var y := randf_range(_from.y, _to.y) - var z := randf_range(_from.z, _to.z) - return Vector3(x, y, z) diff --git a/addons/gdUnit4/src/fuzzers/Vector3Fuzzer.gd.uid b/addons/gdUnit4/src/fuzzers/Vector3Fuzzer.gd.uid deleted file mode 100644 index 8a09af7d..00000000 --- a/addons/gdUnit4/src/fuzzers/Vector3Fuzzer.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c14v7yn5r6b8f diff --git a/addons/gdUnit4/src/matchers/AnyArgumentMatcher.gd b/addons/gdUnit4/src/matchers/AnyArgumentMatcher.gd deleted file mode 100644 index bd503130..00000000 --- a/addons/gdUnit4/src/matchers/AnyArgumentMatcher.gd +++ /dev/null @@ -1,11 +0,0 @@ -class_name AnyArgumentMatcher -extends GdUnitArgumentMatcher - - -@warning_ignore("unused_parameter") -func is_match(value :Variant) -> bool: - return true - - -func _to_string() -> String: - return "any()" diff --git a/addons/gdUnit4/src/matchers/AnyArgumentMatcher.gd.uid b/addons/gdUnit4/src/matchers/AnyArgumentMatcher.gd.uid deleted file mode 100644 index a131d485..00000000 --- a/addons/gdUnit4/src/matchers/AnyArgumentMatcher.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dx684y48ctd3n diff --git a/addons/gdUnit4/src/matchers/AnyBuildInTypeArgumentMatcher.gd b/addons/gdUnit4/src/matchers/AnyBuildInTypeArgumentMatcher.gd deleted file mode 100644 index ba34431c..00000000 --- a/addons/gdUnit4/src/matchers/AnyBuildInTypeArgumentMatcher.gd +++ /dev/null @@ -1,50 +0,0 @@ -class_name AnyBuildInTypeArgumentMatcher -extends GdUnitArgumentMatcher - -var _type : PackedInt32Array = [] - - -func _init(type :PackedInt32Array) -> void: - _type = type - - -func is_match(value :Variant) -> bool: - return _type.has(typeof(value)) - - -func _to_string() -> String: - match _type[0]: - TYPE_BOOL: return "any_bool()" - TYPE_STRING, TYPE_STRING_NAME: return "any_string()" - TYPE_INT: return "any_int()" - TYPE_FLOAT: return "any_float()" - TYPE_COLOR: return "any_color()" - TYPE_VECTOR2: return "any_vector2()" if _type.size() == 1 else "any_vector()" - TYPE_VECTOR2I: return "any_vector2i()" - TYPE_VECTOR3: return "any_vector3()" - TYPE_VECTOR3I: return "any_vector3i()" - TYPE_VECTOR4: return "any_vector4()" - TYPE_VECTOR4I: return "any_vector4i()" - TYPE_RECT2: return "any_rect2()" - TYPE_RECT2I: return "any_rect2i()" - TYPE_PLANE: return "any_plane()" - TYPE_QUATERNION: return "any_quat()" - TYPE_AABB: return "any_aabb()" - TYPE_BASIS: return "any_basis()" - TYPE_TRANSFORM2D: return "any_transform_2d()" - TYPE_TRANSFORM3D: return "any_transform_3d()" - TYPE_NODE_PATH: return "any_node_path()" - TYPE_RID: return "any_rid()" - TYPE_OBJECT: return "any_object()" - TYPE_DICTIONARY: return "any_dictionary()" - TYPE_ARRAY: return "any_array()" - TYPE_PACKED_BYTE_ARRAY: return "any_packed_byte_array()" - TYPE_PACKED_INT32_ARRAY: return "any_packed_int32_array()" - TYPE_PACKED_INT64_ARRAY: return "any_packed_int64_array()" - TYPE_PACKED_FLOAT32_ARRAY: return "any_packed_float32_array()" - TYPE_PACKED_FLOAT64_ARRAY: return "any_packed_float64_array()" - TYPE_PACKED_STRING_ARRAY: return "any_packed_string_array()" - TYPE_PACKED_VECTOR2_ARRAY: return "any_packed_vector2_array()" - TYPE_PACKED_VECTOR3_ARRAY: return "any_packed_vector3_array()" - TYPE_PACKED_COLOR_ARRAY: return "any_packed_color_array()" - _: return "any()" diff --git a/addons/gdUnit4/src/matchers/AnyBuildInTypeArgumentMatcher.gd.uid b/addons/gdUnit4/src/matchers/AnyBuildInTypeArgumentMatcher.gd.uid deleted file mode 100644 index f496acb5..00000000 --- a/addons/gdUnit4/src/matchers/AnyBuildInTypeArgumentMatcher.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ba1akty5ih1xe diff --git a/addons/gdUnit4/src/matchers/AnyClazzArgumentMatcher.gd b/addons/gdUnit4/src/matchers/AnyClazzArgumentMatcher.gd deleted file mode 100644 index b5e3de3a..00000000 --- a/addons/gdUnit4/src/matchers/AnyClazzArgumentMatcher.gd +++ /dev/null @@ -1,32 +0,0 @@ -class_name AnyClazzArgumentMatcher -extends GdUnitArgumentMatcher - -var _clazz :Object - - -func _init(clazz :Object) -> void: - _clazz = clazz - - -func is_match(value :Variant) -> bool: - if typeof(value) != TYPE_OBJECT: - return false - if is_instance_valid(value) and GdObjects.is_script(_clazz): - @warning_ignore("unsafe_cast") - return (value as Object).get_script() == _clazz - return is_instance_of(value, _clazz) - - -func _to_string() -> String: - if (_clazz as Object).is_class("GDScriptNativeClass"): - @warning_ignore("unsafe_method_access") - var instance :Object = _clazz.new() - var clazz_name := instance.get_class() - if not instance is RefCounted: - instance.free() - return "any_class(<"+clazz_name+">)"; - if _clazz is GDScript: - var result := GdObjects.extract_class_name(_clazz) - if result.is_success(): - return "any_class(<"+ result.value() + ">)" - return "any_class()" diff --git a/addons/gdUnit4/src/matchers/AnyClazzArgumentMatcher.gd.uid b/addons/gdUnit4/src/matchers/AnyClazzArgumentMatcher.gd.uid deleted file mode 100644 index 3424f142..00000000 --- a/addons/gdUnit4/src/matchers/AnyClazzArgumentMatcher.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bieqh1kv1i6e4 diff --git a/addons/gdUnit4/src/matchers/ChainedArgumentMatcher.gd b/addons/gdUnit4/src/matchers/ChainedArgumentMatcher.gd deleted file mode 100644 index f779bd79..00000000 --- a/addons/gdUnit4/src/matchers/ChainedArgumentMatcher.gd +++ /dev/null @@ -1,22 +0,0 @@ -class_name ChainedArgumentMatcher -extends GdUnitArgumentMatcher - -var _matchers :Array - - -func _init(matchers :Array) -> void: - _matchers = matchers - - -func is_match(arguments :Variant) -> bool: - var arg_array: Array = arguments - if arg_array == null or arg_array.size() != _matchers.size(): - return false - - for index in arg_array.size(): - var arg: Variant = arg_array[index] - var matcher: GdUnitArgumentMatcher = _matchers[index] - - if not matcher.is_match(arg): - return false - return true diff --git a/addons/gdUnit4/src/matchers/ChainedArgumentMatcher.gd.uid b/addons/gdUnit4/src/matchers/ChainedArgumentMatcher.gd.uid deleted file mode 100644 index 7f366826..00000000 --- a/addons/gdUnit4/src/matchers/ChainedArgumentMatcher.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cdqv8eh1coshc diff --git a/addons/gdUnit4/src/matchers/EqualsArgumentMatcher.gd b/addons/gdUnit4/src/matchers/EqualsArgumentMatcher.gd deleted file mode 100644 index 2d387edc..00000000 --- a/addons/gdUnit4/src/matchers/EqualsArgumentMatcher.gd +++ /dev/null @@ -1,22 +0,0 @@ -class_name EqualsArgumentMatcher -extends GdUnitArgumentMatcher - -var _current :Variant -var _auto_deep_check_mode :bool - - -func _init(current :Variant, auto_deep_check_mode := false) -> void: - _current = current - _auto_deep_check_mode = auto_deep_check_mode - - -func is_match(value :Variant) -> bool: - var case_sensitive_check := true - return GdObjects.equals(_current, value, case_sensitive_check, compare_mode(value)) - - -func compare_mode(value :Variant) -> GdObjects.COMPARE_MODE: - if _auto_deep_check_mode and is_instance_valid(value): - # we do deep check on all InputEvent's - return GdObjects.COMPARE_MODE.PARAMETER_DEEP_TEST if value is InputEvent else GdObjects.COMPARE_MODE.OBJECT_REFERENCE - return GdObjects.COMPARE_MODE.OBJECT_REFERENCE diff --git a/addons/gdUnit4/src/matchers/EqualsArgumentMatcher.gd.uid b/addons/gdUnit4/src/matchers/EqualsArgumentMatcher.gd.uid deleted file mode 100644 index 25a33c8f..00000000 --- a/addons/gdUnit4/src/matchers/EqualsArgumentMatcher.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://7iihl6fyxqtq diff --git a/addons/gdUnit4/src/matchers/GdUnitArgumentMatcher.gd b/addons/gdUnit4/src/matchers/GdUnitArgumentMatcher.gd deleted file mode 100644 index d5adc4bb..00000000 --- a/addons/gdUnit4/src/matchers/GdUnitArgumentMatcher.gd +++ /dev/null @@ -1,13 +0,0 @@ -## The base class of all argument matchers -class_name GdUnitArgumentMatcher -extends RefCounted - - -@warning_ignore("unused_parameter") -func is_match(value: Variant) -> bool: - return true - - -func _to_string() -> String: - assert(false, "`_to_string()` Is not implemented!") - return "" diff --git a/addons/gdUnit4/src/matchers/GdUnitArgumentMatcher.gd.uid b/addons/gdUnit4/src/matchers/GdUnitArgumentMatcher.gd.uid deleted file mode 100644 index 400e1aeb..00000000 --- a/addons/gdUnit4/src/matchers/GdUnitArgumentMatcher.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bhwuperdcf2n8 diff --git a/addons/gdUnit4/src/matchers/GdUnitArgumentMatchers.gd b/addons/gdUnit4/src/matchers/GdUnitArgumentMatchers.gd deleted file mode 100644 index 6a70cc15..00000000 --- a/addons/gdUnit4/src/matchers/GdUnitArgumentMatchers.gd +++ /dev/null @@ -1,42 +0,0 @@ -class_name GdUnitArgumentMatchers -extends RefCounted - -const TYPE_ANY = TYPE_MAX + 100 - - -static func to_matcher(arguments: Array[Variant], auto_deep_check_mode := false) -> ChainedArgumentMatcher: - var matchers: Array[Variant] = [] - for arg: Variant in arguments: - # argument is already a matcher - if arg is GdUnitArgumentMatcher: - matchers.append(arg) - else: - # pass argument into equals matcher - matchers.append(EqualsArgumentMatcher.new(arg, auto_deep_check_mode)) - return ChainedArgumentMatcher.new(matchers) - - -static func any() -> GdUnitArgumentMatcher: - return AnyArgumentMatcher.new() - - -static func by_type(type: int) -> GdUnitArgumentMatcher: - return AnyBuildInTypeArgumentMatcher.new([type]) - - -static func by_types(types: PackedInt32Array) -> GdUnitArgumentMatcher: - return AnyBuildInTypeArgumentMatcher.new(types) - - -static func any_class(clazz: Object) -> GdUnitArgumentMatcher: - return AnyClazzArgumentMatcher.new(clazz) - - -static func is_variant_string_matching(value: Variant) -> GdUnitResult: - if value is String or value is StringName: - return GdUnitResult.success() - if value is GdUnitArgumentMatcher: - if str(value) == "any()" or str(value) == "any_string()": - return GdUnitResult.success() - return GdUnitResult.error("Only 'any()' and 'any_string()' argument matchers are allowed!") - return GdUnitResult.error("Only String or StringName types are allowed!") diff --git a/addons/gdUnit4/src/matchers/GdUnitArgumentMatchers.gd.uid b/addons/gdUnit4/src/matchers/GdUnitArgumentMatchers.gd.uid deleted file mode 100644 index d651605d..00000000 --- a/addons/gdUnit4/src/matchers/GdUnitArgumentMatchers.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dji6lqxoelm5j diff --git a/addons/gdUnit4/src/mocking/GdUnitMock.gd b/addons/gdUnit4/src/mocking/GdUnitMock.gd deleted file mode 100644 index c520d922..00000000 --- a/addons/gdUnit4/src/mocking/GdUnitMock.gd +++ /dev/null @@ -1,45 +0,0 @@ -class_name GdUnitMock -extends RefCounted - -## do call the real implementation -const CALL_REAL_FUNC = "CALL_REAL_FUNC" -## do return a default value for primitive types or null -const RETURN_DEFAULTS = "RETURN_DEFAULTS" -## do return a default value for primitive types and a fully mocked value for Object types -## builds full deep mocked object -const RETURN_DEEP_STUB = "RETURN_DEEP_STUB" - -var _value: Variant - - -func _init(value: Variant) -> void: - _value = value - - -## Selects the mock to work on, used in combination with [method GdUnitTestSuite.do_return][br] -## Example: -## [codeblock] -## do_return(false).on(myMock).is_selected() -## [/codeblock] -func on(obj: Variant) -> Variant: - if not GdUnitMock._is_mock_or_spy(obj, "__do_return"): - return obj - @warning_ignore("unsafe_method_access") - return obj.__do_return(_value) - - -## [color=yellow]`checked` is obsolete, use `on` instead [/color] -func checked(obj :Object) -> Object: - push_warning("Using a deprecated function 'checked' use `on` instead") - return on(obj) - - -static func _is_mock_or_spy(obj: Variant, func_sig: String) -> bool: - if obj is Object and not as_object(obj).has_method(func_sig): - push_error("Error: You try to use a non mock or spy!") - return false - return true - - -static func as_object(value: Variant) -> Object: - return value diff --git a/addons/gdUnit4/src/mocking/GdUnitMock.gd.uid b/addons/gdUnit4/src/mocking/GdUnitMock.gd.uid deleted file mode 100644 index 35329e78..00000000 --- a/addons/gdUnit4/src/mocking/GdUnitMock.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://obuiauaajequ diff --git a/addons/gdUnit4/src/mocking/GdUnitMockBuilder.gd b/addons/gdUnit4/src/mocking/GdUnitMockBuilder.gd deleted file mode 100644 index 537e9239..00000000 --- a/addons/gdUnit4/src/mocking/GdUnitMockBuilder.gd +++ /dev/null @@ -1,186 +0,0 @@ -class_name GdUnitMockBuilder -extends GdUnitClassDoubler - -const GdUnitTools := preload("res://addons/gdUnit4/src/core/GdUnitTools.gd") -const MOCK_TEMPLATE :GDScript = preload("res://addons/gdUnit4/src/mocking/GdUnitMockImpl.gd") - - -static func is_push_errors() -> bool: - return GdUnitSettings.is_report_push_errors() - - -static func build(clazz :Variant, mock_mode :String, debug_write := false) -> Variant: - var push_errors := is_push_errors() - if not is_mockable(clazz, push_errors): - return null - # mocking a scene? - if GdObjects.is_scene(clazz): - var packed_scene: PackedScene = clazz - return mock_on_scene(packed_scene, debug_write) - elif typeof(clazz) == TYPE_STRING and str(clazz).ends_with(".tscn"): - var packed_scene: PackedScene = load(str(clazz)) - return mock_on_scene(packed_scene, debug_write) - # mocking a script - var instance := create_instance(clazz) - if instance == null: - push_error("Can't create instance of class %s" % clazz) - var mock := mock_on_script(instance, clazz, [ "get_script"], debug_write) - if not instance is RefCounted: - instance.free() - if mock == null: - return null - var mock_instance: Object = mock.new() - @warning_ignore("unsafe_method_access") - mock_instance.__init(mock, mock_mode) - return register_auto_free(mock_instance) - - -static func create_instance(clazz: Variant) -> Object: - match typeof(clazz): - TYPE_OBJECT: - var obj: Object = clazz - if clazz is GDScript: - var script: GDScript = clazz - var args := GdObjects.build_function_default_arguments(script, "_init") - return script.callv("new", args) - elif obj.is_class("GDScriptNativeClass"): - @warning_ignore("unsafe_method_access") - return obj.new() - TYPE_STRING: - var clazz_name: String = clazz - if clazz_name.ends_with(".gd"): - var script: GDScript = load(clazz_name) - var args := GdObjects.build_function_default_arguments(script, "_init") - return script.callv("new", args) - elif ClassDB.can_instantiate(clazz_name): - return ClassDB.instantiate(clazz_name) - - push_error("Can't create a mock validation instance from class: `%s`" % clazz) - return null - - -static func mock_on_scene(scene: PackedScene, debug_write: bool) -> Variant: - var push_errors := is_push_errors() - if not scene.can_instantiate(): - if push_errors: - push_error("Can't instanciate scene '%s'" % scene.resource_path) - return null - var scene_instance := scene.instantiate() - # we can only mock checked a scene with attached script - var scene_script: Script = scene_instance.get_script() - if scene_script == null: - if push_errors: - push_error("Can't create a mockable instance for a scene without script '%s'" % scene.resource_path) - @warning_ignore("return_value_discarded") - GdUnitTools.free_instance(scene_instance) - return null - - var script_path := scene_script.get_path() - var mock := mock_on_script(scene_instance, script_path, GdUnitClassDoubler.EXLCUDE_SCENE_FUNCTIONS, debug_write) - if mock == null: - return null - scene_instance.set_script(mock) - @warning_ignore("unsafe_method_access") - scene_instance.__init(mock, GdUnitMock.CALL_REAL_FUNC) - return register_auto_free(scene_instance) - - -static func get_class_info(clazz :Variant) -> Dictionary: - var clazz_name :String = GdObjects.extract_class_name(clazz).value() - var clazz_path := GdObjects.extract_class_path(clazz) - return { - "class_name" : clazz_name, - "class_path" : clazz_path - } - - -static func mock_on_script(instance :Object, clazz :Variant, function_excludes :PackedStringArray, debug_write :bool) -> GDScript: - var function_doubler := GdUnitMockFunctionDoubler.new() - var class_info := get_class_info(clazz) - var clazz_name :String = class_info.get("class_name") - var clazz_path :PackedStringArray = class_info.get("class_path", [clazz_name]) - var mock_template := MOCK_TEMPLATE.source_code.format({ - "instance_id" : abs(instance.get_instance_id()), - "gdunit_source_class": clazz_name if clazz_path.is_empty() else clazz_path[0] - }) - var lines := load_template(mock_template, class_info) - lines += double_functions(instance, clazz_name, clazz_path, function_doubler, function_excludes) - # We disable warning/errors for inferred_declaration - if Engine.get_version_info().hex >= 0x40400: - lines.insert(0, '@warning_ignore_start("inferred_declaration")') - lines.append('@warning_ignore_restore("inferred_declaration")') - - var mock := GDScript.new() - mock.source_code = "\n".join(lines) - mock.resource_name = "Mock%s_%d.gd" % [clazz_name, Time.get_ticks_msec()] - mock.resource_path = "%s/%s" % [GdUnitFileAccess.create_temp_dir("mock"), mock.resource_name] - - if debug_write: - @warning_ignore("return_value_discarded") - DirAccess.remove_absolute(mock.resource_path) - @warning_ignore("return_value_discarded") - ResourceSaver.save(mock, mock.resource_path) - var error := mock.reload(true) - if error != OK: - push_error("Critical!!!, MockBuilder error, please contact the developer.") - return null - return mock - - -static func is_mockable(clazz :Variant, push_errors :bool=false) -> bool: - var clazz_type := typeof(clazz) - if clazz_type != TYPE_OBJECT and clazz_type != TYPE_STRING: - push_error("Invalid clazz type is used") - return false - # is PackedScene - if GdObjects.is_scene(clazz): - return true - if GdObjects.is_native_class(clazz): - return true - # verify class type - if GdObjects.is_object(clazz): - if GdObjects.is_instance(clazz): - if push_errors: - push_error("It is not allowed to mock an instance '%s', use class name instead, Read 'Mocker' documentation for details" % clazz) - return false - - if not GdObjects.can_be_instantiate(clazz): - if push_errors: - push_error("Can't create a mockable instance for class '%s'" % clazz) - return false - return true - # verify by class name checked registered classes - var clazz_name: String = clazz - if ClassDB.class_exists(clazz_name): - if Engine.has_singleton(clazz_name): - if push_errors: - push_error("Mocking a singelton class '%s' is not allowed! Read 'Mocker' documentation for details" % clazz_name) - return false - if not ClassDB.can_instantiate(clazz_name): - if push_errors: - push_error("Mocking class '%s' is not allowed it cannot be instantiated!" % clazz_name) - return false - # exclude classes where name starts with a underscore - if clazz_name.find("_") == 0: - if push_errors: - push_error("Can't create a mockable instance for protected class '%s'" % clazz_name) - return false - return true - # at least try to load as a script - var clazz_path := clazz_name - if not FileAccess.file_exists(clazz_path): - if push_errors: - push_error("'%s' cannot be mocked for the specified resource path, the resource does not exist" % clazz_name) - return false - # finally verify is a script resource - var resource := load(clazz_path) - if resource == null: - if push_errors: - push_error("'%s' cannot be mocked the script cannot be loaded." % clazz_name) - return false - # finally check is extending from script - return GdObjects.is_script(resource) or GdObjects.is_scene(resource) - - -static func register_auto_free(obj :Variant) -> Variant: - return GdUnitThreadManager.get_current_context().get_execution_context().register_auto_free(obj) diff --git a/addons/gdUnit4/src/mocking/GdUnitMockBuilder.gd.uid b/addons/gdUnit4/src/mocking/GdUnitMockBuilder.gd.uid deleted file mode 100644 index 905bb14a..00000000 --- a/addons/gdUnit4/src/mocking/GdUnitMockBuilder.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dwvulgg5xpwid diff --git a/addons/gdUnit4/src/mocking/GdUnitMockImpl.gd b/addons/gdUnit4/src/mocking/GdUnitMockImpl.gd deleted file mode 100644 index 774ca3e3..00000000 --- a/addons/gdUnit4/src/mocking/GdUnitMockImpl.gd +++ /dev/null @@ -1,143 +0,0 @@ -class_name DoubledMockClassSourceClassName - -################################################################################ -# internal mocking stuff -################################################################################ - -const __INSTANCE_ID := "gdunit_doubler_instance_id_{instance_id}" - - -class GdUnitMockDoublerState: - const __SOURCE_CLASS := "{gdunit_source_class}" - - var excluded_methods := PackedStringArray() - var working_mode := GdUnitMock.RETURN_DEFAULTS - var is_prepare_return := false - var return_values := Dictionary() - var return_value: Variant = null - - - func _init(working_mode_ := GdUnitMock.RETURN_DEFAULTS) -> void: - working_mode = working_mode_ - - -var __mock_state := GdUnitMockDoublerState.new() -@warning_ignore("unused_private_class_variable") -var __verifier_instance := GdUnitObjectInteractionsVerifier.new() - - -func __init(__script: GDScript, mock_working_mode: String) -> void: - super.set_script(__script) - __init_doubler() - __mock_state.working_mode = mock_working_mode - - -static func __doubler_state() -> GdUnitMockDoublerState: - if Engine.has_meta(__INSTANCE_ID): - return Engine.get_meta(__INSTANCE_ID).__mock_state - return null - - -func __init_doubler() -> void: - Engine.set_meta(__INSTANCE_ID, self) - - -func _notification(what: int) -> void: - if what == NOTIFICATION_PREDELETE and Engine.has_meta(__INSTANCE_ID): - Engine.remove_meta(__INSTANCE_ID) - - -static func __get_verifier() -> GdUnitObjectInteractionsVerifier: - return Engine.get_meta(__INSTANCE_ID).__verifier_instance - - -static func __is_prepare_return_value() -> bool: - return __doubler_state().is_prepare_return - - -static func __sort_by_argument_matcher(__left_args: Array, __right_args: Array) -> bool: - for __index in __left_args.size(): - var __larg: Variant = __left_args[__index] - if __larg is GdUnitArgumentMatcher: - return false - return true - - -# we need to sort by matcher arguments so that they are all at the end of the list -static func __sort_dictionary(__unsorted_args: Dictionary) -> Dictionary: - # only need to sort if contains more than one entry - if __unsorted_args.size() <= 1: - return __unsorted_args - var __sorted_args: Array = __unsorted_args.keys() - __sorted_args.sort_custom(__sort_by_argument_matcher) - var __sorted_result := {} - for __index in __sorted_args.size(): - var key :Variant = __sorted_args[__index] - __sorted_result[key] = __unsorted_args[key] - return __sorted_result - - -static func __save_function_return_value(__func_name: String, __func_args: Array) -> void: - var doubler_state := __doubler_state() - var mocked_return_value_by_args: Dictionary = doubler_state.return_values.get(__func_name, {}) - - mocked_return_value_by_args[__func_args] = doubler_state.return_value - doubler_state.return_values[__func_name] = __sort_dictionary(mocked_return_value_by_args) - doubler_state.return_value = null - doubler_state.is_prepare_return = false - - -static func __is_mocked_args_match(__func_args: Array, __mocked_args: Array) -> bool: - var __is_matching := false - for __index in __mocked_args.size(): - var __fuction_args: Array = __mocked_args[__index] - if __func_args.size() != __fuction_args.size(): - continue - __is_matching = true - for __arg_index in __func_args.size(): - var __func_arg: Variant = __func_args[__arg_index] - var __mock_arg: Variant = __fuction_args[__arg_index] - if __mock_arg is GdUnitArgumentMatcher: - @warning_ignore("unsafe_method_access") - __is_matching = __is_matching and __mock_arg.is_match(__func_arg) - else: - __is_matching = __is_matching and typeof(__func_arg) == typeof(__mock_arg) and __func_arg == __mock_arg - if not __is_matching: - break - if __is_matching: - break - return __is_matching - - -static func __return_mock_value(__func_name: String, __func_args: Array, __default_return_value: Variant) -> Variant: - var doubler_state := __doubler_state() - if not doubler_state.return_values.has(__func_name): - return __default_return_value - @warning_ignore("unsafe_method_access") - var __mocked_args: Array = doubler_state.return_values.get(__func_name).keys() - for __index in __mocked_args.size(): - var __margs: Variant = __mocked_args[__index] - if __is_mocked_args_match(__func_args, [__margs]): - return doubler_state.return_values[__func_name][__margs] - return __default_return_value - - -static func __is_do_not_call_real_func(__func_name: String, __func_args := []) -> bool: - var doubler_state := __doubler_state() - var __is_call_real_func: bool = doubler_state.working_mode == GdUnitMock.CALL_REAL_FUNC and not doubler_state.excluded_methods.has(__func_name) - # do not call real funcions for mocked functions - if __is_call_real_func and doubler_state.return_values.has(__func_name): - @warning_ignore("unsafe_method_access") - var __mocked_args: Array = doubler_state.return_values.get(__func_name).keys() - return __is_mocked_args_match(__func_args, __mocked_args) - return !__is_call_real_func - - -func __exclude_method_call(exluded_methods: PackedStringArray) -> void: - __doubler_state().excluded_methods.append_array(exluded_methods) - - -func __do_return(mock_do_return_value: Variant) -> Object: - __doubler_state().return_value = mock_do_return_value - __doubler_state().is_prepare_return = true - return self diff --git a/addons/gdUnit4/src/mocking/GdUnitMockImpl.gd.uid b/addons/gdUnit4/src/mocking/GdUnitMockImpl.gd.uid deleted file mode 100644 index b6a81409..00000000 --- a/addons/gdUnit4/src/mocking/GdUnitMockImpl.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cw0dphkuu3a63 diff --git a/addons/gdUnit4/src/monitor/ErrorLogEntry.gd b/addons/gdUnit4/src/monitor/ErrorLogEntry.gd deleted file mode 100644 index 5ee14878..00000000 --- a/addons/gdUnit4/src/monitor/ErrorLogEntry.gd +++ /dev/null @@ -1,72 +0,0 @@ -extends RefCounted -class_name ErrorLogEntry - - -enum TYPE { - SCRIPT_ERROR, - PUSH_ERROR, - PUSH_WARNING -} - - -const GdUnitTools := preload("res://addons/gdUnit4/src/core/GdUnitTools.gd") - -const PATTERN_SCRIPT_ERROR := "USER SCRIPT ERROR:" -const PATTERN_PUSH_ERROR := "USER ERROR:" -const PATTERN_PUSH_WARNING := "USER WARNING:" -# With Godot 4.4 the pattern has changed -const PATTERN_4x4_SCRIPT_ERROR := "SCRIPT ERROR:" -const PATTERN_4x4_PUSH_ERROR := "ERROR:" -const PATTERN_4x4_PUSH_WARNING := "WARNING:" - -static var _regex_parse_error_line_number: RegEx - -var _type: TYPE -var _line: int -var _message: String -var _details: String - - -func _init(type: TYPE, line: int, message: String, details: String) -> void: - _type = type - _line = line - _message = message - _details = details - - -static func is_godot4x4() -> bool: - return Engine.get_version_info().hex >= 0x40400 - - -static func extract_push_warning(records: PackedStringArray, index: int) -> ErrorLogEntry: - var pattern := PATTERN_4x4_PUSH_WARNING if is_godot4x4() else PATTERN_PUSH_WARNING - return _extract(records, index, TYPE.PUSH_WARNING, pattern) - - -static func extract_push_error(records: PackedStringArray, index: int) -> ErrorLogEntry: - var pattern := PATTERN_4x4_PUSH_ERROR if is_godot4x4() else PATTERN_PUSH_ERROR - return _extract(records, index, TYPE.PUSH_ERROR, pattern) - - -static func extract_error(records: PackedStringArray, index: int) -> ErrorLogEntry: - var pattern := PATTERN_4x4_SCRIPT_ERROR if is_godot4x4() else PATTERN_SCRIPT_ERROR - return _extract(records, index, TYPE.SCRIPT_ERROR, pattern) - - -static func _extract(records: PackedStringArray, index: int, type: TYPE, pattern: String) -> ErrorLogEntry: - var message := records[index] - if message.begins_with(pattern): - var error := message.replace(pattern, "").strip_edges() - var details := records[index+1].strip_edges() - var line := _parse_error_line_number(details) - return ErrorLogEntry.new(type, line, error, details) - return null - - -static func _parse_error_line_number(record: String) -> int: - if _regex_parse_error_line_number == null: - _regex_parse_error_line_number = GdUnitTools.to_regex("at: .*res://.*:(\\d+)") - var matches := _regex_parse_error_line_number.search(record) - if matches != null: - return matches.get_string(1).to_int() - return -1 diff --git a/addons/gdUnit4/src/monitor/ErrorLogEntry.gd.uid b/addons/gdUnit4/src/monitor/ErrorLogEntry.gd.uid deleted file mode 100644 index cf5d4ca2..00000000 --- a/addons/gdUnit4/src/monitor/ErrorLogEntry.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://8kjgr8gyjg5f diff --git a/addons/gdUnit4/src/monitor/GdUnitMonitor.gd b/addons/gdUnit4/src/monitor/GdUnitMonitor.gd deleted file mode 100644 index b6429cad..00000000 --- a/addons/gdUnit4/src/monitor/GdUnitMonitor.gd +++ /dev/null @@ -1,24 +0,0 @@ -# GdUnit Monitoring Base Class -class_name GdUnitMonitor -extends RefCounted - -var _id :String - -# constructs new Monitor with given id -func _init(p_id :String) -> void: - _id = p_id - - -# Returns the id of the monitor to uniqe identify -func id() -> String: - return _id - - -# starts monitoring -func start() -> void: - pass - - -# stops monitoring -func stop() -> void: - pass diff --git a/addons/gdUnit4/src/monitor/GdUnitMonitor.gd.uid b/addons/gdUnit4/src/monitor/GdUnitMonitor.gd.uid deleted file mode 100644 index 30cef024..00000000 --- a/addons/gdUnit4/src/monitor/GdUnitMonitor.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://gq08i83yup2g diff --git a/addons/gdUnit4/src/monitor/GdUnitOrphanNodesMonitor.gd b/addons/gdUnit4/src/monitor/GdUnitOrphanNodesMonitor.gd deleted file mode 100644 index 725dd1fb..00000000 --- a/addons/gdUnit4/src/monitor/GdUnitOrphanNodesMonitor.gd +++ /dev/null @@ -1,27 +0,0 @@ -class_name GdUnitOrphanNodesMonitor -extends GdUnitMonitor - -var _initial_count := 0 -var _orphan_count := 0 -var _orphan_detection_enabled :bool - - -func _init(name :String = "") -> void: - super("OrphanNodesMonitor:" + name) - _orphan_detection_enabled = GdUnitSettings.is_verbose_orphans() - - -func start() -> void: - _initial_count = _orphans() - - -func stop() -> void: - _orphan_count = max(0, _orphans() - _initial_count) - - -func _orphans() -> int: - return Performance.get_monitor(Performance.OBJECT_ORPHAN_NODE_COUNT) as int - - -func orphan_nodes() -> int: - return _orphan_count if _orphan_detection_enabled else 0 diff --git a/addons/gdUnit4/src/monitor/GdUnitOrphanNodesMonitor.gd.uid b/addons/gdUnit4/src/monitor/GdUnitOrphanNodesMonitor.gd.uid deleted file mode 100644 index 862b5113..00000000 --- a/addons/gdUnit4/src/monitor/GdUnitOrphanNodesMonitor.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cufv71udymwm5 diff --git a/addons/gdUnit4/src/monitor/GodotGdErrorMonitor.gd b/addons/gdUnit4/src/monitor/GodotGdErrorMonitor.gd deleted file mode 100644 index 16db4582..00000000 --- a/addons/gdUnit4/src/monitor/GodotGdErrorMonitor.gd +++ /dev/null @@ -1,103 +0,0 @@ -class_name GodotGdErrorMonitor -extends GdUnitMonitor - -var _godot_log_file: String -var _eof: int -var _report_enabled := false -var _entries: Array[ErrorLogEntry] = [] - - -func _init() -> void: - super("GodotGdErrorMonitor") - _godot_log_file = GdUnitSettings.get_log_path() - _report_enabled = _is_reporting_enabled() - - -func start() -> void: - var file := FileAccess.open(_godot_log_file, FileAccess.READ) - if file: - file.seek_end(0) - _eof = file.get_length() - - -func stop() -> void: - pass - - -func to_reports() -> Array[GdUnitReport]: - var reports_: Array[GdUnitReport] = [] - if _report_enabled: - reports_.assign(_entries.map(_to_report)) - _entries.clear() - return reports_ - - -static func _to_report(errorLog: ErrorLogEntry) -> GdUnitReport: - var failure := "%s\n\t%s\n%s %s" % [ - GdAssertMessages._error("Godot Runtime Error !"), - GdAssertMessages._colored_value(errorLog._details), - GdAssertMessages._error("Error:"), - GdAssertMessages._colored_value(errorLog._message)] - return GdUnitReport.new().create(GdUnitReport.ABORT, errorLog._line, failure) - - -func scan(force_collect_reports := false) -> Array[ErrorLogEntry]: - await (Engine.get_main_loop() as SceneTree).process_frame - await (Engine.get_main_loop() as SceneTree).physics_frame - _entries.append_array(_collect_log_entries(force_collect_reports)) - return _entries - - -func erase_log_entry(entry: ErrorLogEntry) -> void: - _entries.erase(entry) - - -func collect_full_logs() -> PackedStringArray: - await (Engine.get_main_loop() as SceneTree).process_frame - await (Engine.get_main_loop() as SceneTree).physics_frame - - var file := FileAccess.open(_godot_log_file, FileAccess.READ) - file.seek(_eof) - var records := PackedStringArray() - while not file.eof_reached(): - @warning_ignore("return_value_discarded") - records.append(file.get_line()) - - return records - - -func _collect_log_entries(force_collect_reports: bool) -> Array[ErrorLogEntry]: - var file := FileAccess.open(_godot_log_file, FileAccess.READ) - if not file: - # Log file might not be available. - return [] - file.seek(_eof) - var records := PackedStringArray() - while not file.eof_reached(): - @warning_ignore("return_value_discarded") - records.append(file.get_line()) - file.seek_end(0) - _eof = file.get_length() - var log_entries: Array[ErrorLogEntry]= [] - var is_report_errors := force_collect_reports or _is_report_push_errors() - var is_report_script_errors := force_collect_reports or _is_report_script_errors() - for index in records.size(): - if force_collect_reports: - log_entries.append(ErrorLogEntry.extract_push_warning(records, index)) - if is_report_errors: - log_entries.append(ErrorLogEntry.extract_push_error(records, index)) - if is_report_script_errors: - log_entries.append(ErrorLogEntry.extract_error(records, index)) - return log_entries.filter(func(value: ErrorLogEntry) -> bool: return value != null ) - - -func _is_reporting_enabled() -> bool: - return _is_report_script_errors() or _is_report_push_errors() - - -func _is_report_push_errors() -> bool: - return GdUnitSettings.is_report_push_errors() - - -func _is_report_script_errors() -> bool: - return GdUnitSettings.is_report_script_errors() diff --git a/addons/gdUnit4/src/monitor/GodotGdErrorMonitor.gd.uid b/addons/gdUnit4/src/monitor/GodotGdErrorMonitor.gd.uid deleted file mode 100644 index 56a51e9a..00000000 --- a/addons/gdUnit4/src/monitor/GodotGdErrorMonitor.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://de86ibngfhvf5 diff --git a/addons/gdUnit4/src/network/GdUnitServer.gd b/addons/gdUnit4/src/network/GdUnitServer.gd deleted file mode 100644 index 6d878a01..00000000 --- a/addons/gdUnit4/src/network/GdUnitServer.gd +++ /dev/null @@ -1,42 +0,0 @@ -@tool -extends Node - -@onready var _server :GdUnitTcpServer = $TcpServer - - -@warning_ignore("return_value_discarded") -func _ready() -> void: - var result := _server.start() - if result.is_error(): - push_error(result.error_message()) - return - var server_port :int = result.value() - Engine.set_meta("gdunit_server_port", server_port) - _server.client_connected.connect(_on_client_connected) - _server.client_disconnected.connect(_on_client_disconnected) - _server.rpc_data.connect(_receive_rpc_data) - GdUnitCommandHandler.instance().gdunit_runner_stop.connect(_on_gdunit_runner_stop) - - -func _on_client_connected(client_id: int) -> void: - GdUnitSignals.instance().gdunit_client_connected.emit(client_id) - - -func _on_client_disconnected(client_id: int) -> void: - GdUnitSignals.instance().gdunit_client_disconnected.emit(client_id) - - -func _on_gdunit_runner_stop(client_id: int) -> void: - if _server: - _server.disconnect_client(client_id) - - -func _receive_rpc_data(p_rpc: RPC) -> void: - if p_rpc is RPCMessage: - var rpc_message: RPCMessage = p_rpc - GdUnitSignals.instance().gdunit_message.emit(rpc_message.message()) - return - if p_rpc is RPCGdUnitEvent: - var rpc_event: RPCGdUnitEvent = p_rpc - GdUnitSignals.instance().gdunit_event.emit(rpc_event.event()) - return diff --git a/addons/gdUnit4/src/network/GdUnitServer.gd.uid b/addons/gdUnit4/src/network/GdUnitServer.gd.uid deleted file mode 100644 index 55005223..00000000 --- a/addons/gdUnit4/src/network/GdUnitServer.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://2pr0fvtay8vf diff --git a/addons/gdUnit4/src/network/GdUnitServer.tscn b/addons/gdUnit4/src/network/GdUnitServer.tscn deleted file mode 100644 index 4dbe8c49..00000000 --- a/addons/gdUnit4/src/network/GdUnitServer.tscn +++ /dev/null @@ -1,10 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://cn5mp3tmi2gb1"] - -[ext_resource type="Script" path="res://addons/gdUnit4/src/network/GdUnitServer.gd" id="1"] -[ext_resource type="Script" path="res://addons/gdUnit4/src/network/GdUnitTcpServer.gd" id="2"] - -[node name="Control" type="Node"] -script = ExtResource("1") - -[node name="TcpServer" type="Node" parent="."] -script = ExtResource("2") diff --git a/addons/gdUnit4/src/network/GdUnitServerConstants.gd b/addons/gdUnit4/src/network/GdUnitServerConstants.gd deleted file mode 100644 index d31eee77..00000000 --- a/addons/gdUnit4/src/network/GdUnitServerConstants.gd +++ /dev/null @@ -1,6 +0,0 @@ -class_name GdUnitServerConstants -extends RefCounted - -const DEFAULT_SERVER_START_RETRY_TIMES :int = 5 -const GD_TEST_SERVER_PORT :int = 31002 -const JSON_RESPONSE_DELIMITER :String = "<>" diff --git a/addons/gdUnit4/src/network/GdUnitServerConstants.gd.uid b/addons/gdUnit4/src/network/GdUnitServerConstants.gd.uid deleted file mode 100644 index 6c70d8c1..00000000 --- a/addons/gdUnit4/src/network/GdUnitServerConstants.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://eobp360ofaq5 diff --git a/addons/gdUnit4/src/network/GdUnitTask.gd b/addons/gdUnit4/src/network/GdUnitTask.gd deleted file mode 100644 index e0188a04..00000000 --- a/addons/gdUnit4/src/network/GdUnitTask.gd +++ /dev/null @@ -1,25 +0,0 @@ -class_name GdUnitTask -extends RefCounted - -const TASK_NAME = "task_name" -const TASK_ARGS = "task_args" - -var _task_name :String -var _fref :Callable - - -func _init(task_name :String,instance :Object,func_name :String) -> void: - _task_name = task_name - if not instance.has_method(func_name): - push_error("Can't create GdUnitTask, Invalid func name '%s' for instance '%s'" % [instance, func_name]) - _fref = Callable(instance, func_name) - - -func name() -> String: - return _task_name - - -func execute(args :Array) -> GdUnitResult: - if args.is_empty(): - return _fref.call() - return _fref.callv(args) diff --git a/addons/gdUnit4/src/network/GdUnitTask.gd.uid b/addons/gdUnit4/src/network/GdUnitTask.gd.uid deleted file mode 100644 index 1b73e3b0..00000000 --- a/addons/gdUnit4/src/network/GdUnitTask.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://t6wuy7w6nlve diff --git a/addons/gdUnit4/src/network/GdUnitTcpClient.gd b/addons/gdUnit4/src/network/GdUnitTcpClient.gd deleted file mode 100644 index 2cf32a37..00000000 --- a/addons/gdUnit4/src/network/GdUnitTcpClient.gd +++ /dev/null @@ -1,124 +0,0 @@ -class_name GdUnitTcpClient -extends GdUnitTcpNode - -signal connection_succeeded(message: String) -signal connection_failed(message: String) - - -var _client_name: String -var _debug := false -var _host: String -var _port: int -var _client_id: int -var _connected: bool -var _stream: StreamPeerTCP - - -func _init(client_name := "GdUnit4 TCP Client", debug := false) -> void: - _client_name = client_name - _debug = debug - - -func _ready() -> void: - _connected = false - _stream = StreamPeerTCP.new() - #_stream.set_big_endian(true) - - -func stop() -> void: - console("Disconnecting from server") - if _stream != null: - rpc_send(_stream, RPCClientDisconnect.new().with_id(_client_id)) - if _stream != null: - _stream.disconnect_from_host() - _connected = false - - -func start(host: String, port: int) -> GdUnitResult: - _host = host - _port = port - if _connected: - return GdUnitResult.warn("Client already connected ... %s:%d" % [_host, _port]) - - # Connect client to server - if _stream.get_status() != StreamPeerTCP.STATUS_CONNECTED: - var err := _stream.connect_to_host(host, port) - #prints("connect_to_host", host, port, err) - if err != OK: - return GdUnitResult.error("GdUnit4: Can't establish client, error code: %s" % err) - return GdUnitResult.success("GdUnit4: Client connected checked port %d" % port) - - -func _process(_delta: float) -> void: - match _stream.get_status(): - StreamPeerTCP.STATUS_NONE: - return - - StreamPeerTCP.STATUS_CONNECTING: - set_process(false) - # wait until client is connected to server - for retry in 10: - @warning_ignore("return_value_discarded") - _stream.poll() - console("Waiting to connect ..") - if _stream.get_status() == StreamPeerTCP.STATUS_CONNECTING: - await get_tree().create_timer(0.500).timeout - if _stream.get_status() == StreamPeerTCP.STATUS_CONNECTED: - set_process(true) - return - set_process(true) - _stream.disconnect_from_host() - console("Connection failed") - connection_failed.emit("Connect to TCP Server %s:%d faild!" % [_host, _port]) - - StreamPeerTCP.STATUS_CONNECTED: - if not _connected: - var rpc_data :RPC = null - set_process(false) - while rpc_data == null: - await get_tree().create_timer(0.500).timeout - rpc_data = rpc_receive() - set_process(true) - _client_id = (rpc_data as RPCClientConnect).client_id() - console("Connected to Server: %d" % _client_id) - connection_succeeded.emit("Connect to TCP Server %s:%d success." % [_host, _port]) - _connected = true - process_rpc() - - StreamPeerTCP.STATUS_ERROR: - console("Connection failed") - _stream.disconnect_from_host() - connection_failed.emit("Connect to TCP Server %s:%d faild!" % [_host, _port]) - return - - -func is_client_connected() -> bool: - return _connected - - -func process_rpc() -> void: - if _stream.get_available_bytes() > 0: - var rpc_data := rpc_receive() - if rpc_data is RPCClientDisconnect: - stop() - - -func send(data: RPC) -> void: - rpc_send(_stream, data) - - -func rpc_receive() -> RPC: - return receive_packages(_stream).front() - - -func console(value: Variant) -> void: - if _debug: - print(_client_name, ": ", value) - - -func _on_connection_failed(message: String) -> void: - console("Connection faild by: " + message) - - -func _on_connection_succeeded(message: String) -> void: - console("Connected: " + message) diff --git a/addons/gdUnit4/src/network/GdUnitTcpClient.gd.uid b/addons/gdUnit4/src/network/GdUnitTcpClient.gd.uid deleted file mode 100644 index 0aa42a04..00000000 --- a/addons/gdUnit4/src/network/GdUnitTcpClient.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c5dwxfihc8jwp diff --git a/addons/gdUnit4/src/network/GdUnitTcpNode.gd b/addons/gdUnit4/src/network/GdUnitTcpNode.gd deleted file mode 100644 index 156c764b..00000000 --- a/addons/gdUnit4/src/network/GdUnitTcpNode.gd +++ /dev/null @@ -1,73 +0,0 @@ -class_name GdUnitTcpNode -extends Node - - -func rpc_send(stream: StreamPeerTCP, data: RPC) -> void: - var package_buffer := StreamPeerBuffer.new() - var buffer := data.serialize().to_utf16_buffer() - package_buffer.put_u32(0xDEADBEEF) - package_buffer.put_u32(buffer.size()) - var status_code := package_buffer.put_data(buffer) - if status_code != OK: - push_error("'rpc_send:' Can't put_data(), error: %s" % error_string(status_code)) - return - stream.put_data(package_buffer.data_array) - - -func receive_packages(stream: StreamPeerTCP, rpc_cb: Callable = noop) -> Array[RPC]: - var received_packages: Array[RPC] = [] - var package_buffer := StreamPeerBuffer.new() - if stream.get_status() != StreamPeerTCP.STATUS_CONNECTED: - return received_packages - - while stream.get_status() == StreamPeerTCP.STATUS_CONNECTED and stream.get_available_bytes() > 0: - var buffer := stream.get_data(8) - var status_code: int = buffer[0] - if status_code != OK: - push_error("'receive_packages:' Can't get_data(%d) for available_bytes, error: %s" - % [stream.get_available_bytes(), error_string(status_code)]) - return received_packages - - var data_package: PackedByteArray - package_buffer.data_array = buffer[1] - package_buffer.seek(0) - - if package_buffer.get_u32() == 0xDEADBEEF: - var size := package_buffer.get_u32() - if stream.get_status() != StreamPeerTCP.STATUS_CONNECTED: - return received_packages - if stream.get_available_bytes() < size: - prints("size check:", - package_buffer.get_size(), ":", - package_buffer.get_position(), - "to read:", - size, - "available size:", - stream.get_available_bytes()) - push_error("'receive_packages:' Can't receive data get_data(%d) for package, error: %s" % [size, error_string(status_code)]) - return received_packages - - buffer = stream.get_data(size) - package_buffer.data_array = buffer[1] - - var rpc_data := package_buffer.get_data(size) - status_code = rpc_data[0] - if status_code != OK: - push_error("'receive_packages:' Can't get_data(%d) for package, error: %s" % [size, error_string(status_code)]) - continue - data_package = rpc_data[1] - else: - data_package = buffer[1] - - var json := data_package.get_string_from_utf16() - if json.is_empty(): - push_warning("json is empty, can't process data") - continue - var data := RPC.deserialize(json) - received_packages.append(data) - rpc_cb.call(data) - return received_packages - - -static func noop(_rpc_data: RPC) -> void: - pass diff --git a/addons/gdUnit4/src/network/GdUnitTcpNode.gd.uid b/addons/gdUnit4/src/network/GdUnitTcpNode.gd.uid deleted file mode 100644 index c5f90ee4..00000000 --- a/addons/gdUnit4/src/network/GdUnitTcpNode.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bcywbsdfcc88k diff --git a/addons/gdUnit4/src/network/GdUnitTcpServer.gd b/addons/gdUnit4/src/network/GdUnitTcpServer.gd deleted file mode 100644 index 4687ac19..00000000 --- a/addons/gdUnit4/src/network/GdUnitTcpServer.gd +++ /dev/null @@ -1,129 +0,0 @@ -@tool -class_name GdUnitTcpServer -extends Node - -signal client_connected(client_id: int) -signal client_disconnected(client_id: int) -@warning_ignore("unused_signal") -signal rpc_data(rpc_data: RPC) - -var _server: TCPServer -var _server_name: String - -class TcpConnection extends GdUnitTcpNode: - var _id: int - var _stream: StreamPeerTCP - - - func _init(tcp_server: TCPServer) -> void: - _stream = tcp_server.take_connection() - #_stream.set_big_endian(true) - _id = _stream.get_instance_id() - rpc_send(_stream, RPCClientConnect.new().with_id(_id)) - - - func _ready() -> void: - server().client_connected.emit(_id) - - - func close() -> void: - if _stream != null and _stream.get_status() == StreamPeerTCP.STATUS_CONNECTED: - _stream.disconnect_from_host() - queue_free() - - - func id() -> int: - return _id - - - func server() -> GdUnitTcpServer: - return get_parent() - - - func _process(_delta: float) -> void: - if _stream == null or _stream.get_status() != StreamPeerTCP.STATUS_CONNECTED: - return - receive_packages(_stream, func(rpc_data: RPC) -> void: - server().rpc_data.emit(rpc_data) - # is client disconnecting we close the server after a timeout of 1 second - if rpc_data is RPCClientDisconnect: - close() - ) - - - func console(_value: Variant) -> void: - #print_debug("TCP Server: ", value) - pass - - -func _init(server_name := "GdUnit4 TCP Server") -> void: - _server_name = server_name - - -func _ready() -> void: - _server = TCPServer.new() - client_connected.connect(_on_client_connected) - client_disconnected.connect(_on_client_disconnected) - - -func _notification(what: int) -> void: - if what == NOTIFICATION_PREDELETE: - stop() - - -func start(server_port := GdUnitServerConstants.GD_TEST_SERVER_PORT) -> GdUnitResult: - var err := OK - for retry in GdUnitServerConstants.DEFAULT_SERVER_START_RETRY_TIMES: - err = _server.listen(server_port, "127.0.0.1") - if err != OK: - prints("GdUnit4: Can't establish server checked port: %d, Error: %s" % [server_port, error_string(err)]) - server_port += 1 - prints("GdUnit4: Retry (%d) ..." % retry) - else: - break - if err != OK: - if err == ERR_ALREADY_IN_USE: - return GdUnitResult.error("GdUnit4: Can't establish server, the server is already in use. Error: %s, " % error_string(err)) - return GdUnitResult.error("GdUnit4: Can't establish server. Error: %s." % error_string(err)) - console("Successfully started checked port: %d" % server_port) - return GdUnitResult.success(server_port) - - -func stop() -> void: - if _server: - _server.stop() - for connection in get_children(): - if connection is TcpConnection: - @warning_ignore("unsafe_method_access") - connection.close() - remove_child(connection) - _server = null - - -func disconnect_client(client_id: int) -> void: - client_disconnected.emit(client_id) - - -func _process(_delta: float) -> void: - if _server != null and not _server.is_listening(): - return - # check if connection is ready to be used - if _server != null and _server.is_connection_available(): - add_child(TcpConnection.new(_server)) - - -func _on_client_connected(client_id: int) -> void: - console("Client connected %d" % client_id) - - -func _on_client_disconnected(client_id: int) -> void: - for connection in get_children(): - @warning_ignore("unsafe_method_access") - if connection is TcpConnection and connection.id() == client_id: - @warning_ignore("unsafe_method_access") - connection.close() - remove_child(connection) - - -func console(value: Variant) -> void: - print(_server_name, ": ", value) diff --git a/addons/gdUnit4/src/network/GdUnitTcpServer.gd.uid b/addons/gdUnit4/src/network/GdUnitTcpServer.gd.uid deleted file mode 100644 index 15c8cd19..00000000 --- a/addons/gdUnit4/src/network/GdUnitTcpServer.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dkxh0mktjia50 diff --git a/addons/gdUnit4/src/network/rpc/RPC.gd b/addons/gdUnit4/src/network/rpc/RPC.gd deleted file mode 100644 index 6569cb1c..00000000 --- a/addons/gdUnit4/src/network/rpc/RPC.gd +++ /dev/null @@ -1,37 +0,0 @@ -class_name RPC -extends RefCounted - - -var _data: Dictionary = {} - - -func _init(obj: Object = null) -> void: - if obj != null: - if obj.has_method("serialize"): - _data = obj.call("serialize") - else: - _data = inst_to_dict(obj) - - -func get_data() -> Object: - return dict_to_inst(_data) - - -func serialize() -> String: - return JSON.stringify(inst_to_dict(self)) - - -# using untyped version see comments below -static func deserialize(json_value: String) -> Object: - var json := JSON.new() - var err := json.parse(json_value) - if err != OK: - push_error("Can't deserialize JSON, error at line %d:\n error: %s \n json: '%s'" - % [json.get_error_line(), json.get_error_message(), json_value]) - return null - var result: Dictionary = json.get_data() - if not typeof(result) == TYPE_DICTIONARY: - push_error("Can't deserialize JSON. Expecting dictionary, error at line %d:\n error: %s \n json: '%s'" - % [result.error_line, result.error_string, json_value]) - return null - return dict_to_inst(result) diff --git a/addons/gdUnit4/src/network/rpc/RPC.gd.uid b/addons/gdUnit4/src/network/rpc/RPC.gd.uid deleted file mode 100644 index e69cd9c8..00000000 --- a/addons/gdUnit4/src/network/rpc/RPC.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cop588f5ov5ul diff --git a/addons/gdUnit4/src/network/rpc/RPCClientConnect.gd b/addons/gdUnit4/src/network/rpc/RPCClientConnect.gd deleted file mode 100644 index 6b494cfe..00000000 --- a/addons/gdUnit4/src/network/rpc/RPCClientConnect.gd +++ /dev/null @@ -1,13 +0,0 @@ -class_name RPCClientConnect -extends RPC - -var _client_id: int - - -func with_id(id: int) -> RPCClientConnect: - _client_id = id - return self - - -func client_id() -> int: - return _client_id diff --git a/addons/gdUnit4/src/network/rpc/RPCClientConnect.gd.uid b/addons/gdUnit4/src/network/rpc/RPCClientConnect.gd.uid deleted file mode 100644 index ce9bbef4..00000000 --- a/addons/gdUnit4/src/network/rpc/RPCClientConnect.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c0nqfpo3y6lkk diff --git a/addons/gdUnit4/src/network/rpc/RPCClientDisconnect.gd b/addons/gdUnit4/src/network/rpc/RPCClientDisconnect.gd deleted file mode 100644 index 7445b9de..00000000 --- a/addons/gdUnit4/src/network/rpc/RPCClientDisconnect.gd +++ /dev/null @@ -1,13 +0,0 @@ -class_name RPCClientDisconnect -extends RPC - -var _client_id: int - - -func with_id(id: int) -> RPCClientDisconnect: - _client_id = id - return self - - -func client_id() -> int: - return _client_id diff --git a/addons/gdUnit4/src/network/rpc/RPCClientDisconnect.gd.uid b/addons/gdUnit4/src/network/rpc/RPCClientDisconnect.gd.uid deleted file mode 100644 index 29edb9ae..00000000 --- a/addons/gdUnit4/src/network/rpc/RPCClientDisconnect.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cos6yegplfqxr diff --git a/addons/gdUnit4/src/network/rpc/RPCGdUnitEvent.gd b/addons/gdUnit4/src/network/rpc/RPCGdUnitEvent.gd deleted file mode 100644 index dbf55c63..00000000 --- a/addons/gdUnit4/src/network/rpc/RPCGdUnitEvent.gd +++ /dev/null @@ -1,14 +0,0 @@ -class_name RPCGdUnitEvent -extends RPC - - -static func of(p_event: GdUnitEvent) -> RPCGdUnitEvent: - return RPCGdUnitEvent.new(p_event) - - -func event() -> GdUnitEvent: - return GdUnitEvent.new().deserialize(_data) - - -func _to_string() -> String: - return "RPCGdUnitEvent: " + str(_data) diff --git a/addons/gdUnit4/src/network/rpc/RPCGdUnitEvent.gd.uid b/addons/gdUnit4/src/network/rpc/RPCGdUnitEvent.gd.uid deleted file mode 100644 index 03816ea7..00000000 --- a/addons/gdUnit4/src/network/rpc/RPCGdUnitEvent.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b1ocmn5c833kt diff --git a/addons/gdUnit4/src/network/rpc/RPCMessage.gd b/addons/gdUnit4/src/network/rpc/RPCMessage.gd deleted file mode 100644 index 1db0470d..00000000 --- a/addons/gdUnit4/src/network/rpc/RPCMessage.gd +++ /dev/null @@ -1,18 +0,0 @@ -class_name RPCMessage -extends RPC - -var _message: String - - -static func of(msg :String) -> RPCMessage: - var rpc := RPCMessage.new() - rpc._message = msg - return rpc - - -func message() -> String: - return _message - - -func _to_string() -> String: - return "RPCMessage: " + _message diff --git a/addons/gdUnit4/src/network/rpc/RPCMessage.gd.uid b/addons/gdUnit4/src/network/rpc/RPCMessage.gd.uid deleted file mode 100644 index 8f9cdee4..00000000 --- a/addons/gdUnit4/src/network/rpc/RPCMessage.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://0mpkrrxtbgao diff --git a/addons/gdUnit4/src/reporters/GdUnitReportSummary.gd b/addons/gdUnit4/src/reporters/GdUnitReportSummary.gd deleted file mode 100644 index b55b964f..00000000 --- a/addons/gdUnit4/src/reporters/GdUnitReportSummary.gd +++ /dev/null @@ -1,202 +0,0 @@ -class_name GdUnitReportSummary -extends RefCounted - -var _resource_path: String -var _name: String -var _test_count := 0 -var _failure_count := 0 -var _error_count := 0 -var _orphan_count := 0 -var _skipped_count := 0 -var _flaky_count := 0 -var _duration := 0 -var _reports: Array[GdUnitReportSummary] = [] -var _text_formatter: Callable - - -func _init(text_formatter: Callable) -> void: - _text_formatter = text_formatter - - -func name() -> String: - return _name - - -func path() -> String: - return _resource_path.get_base_dir().replace("res://", "") - - -func get_resource_path() -> String: - return _resource_path - - -func suite_count() -> int: - return _reports.size() - - -func suite_executed_count() -> int: - var executed := _reports.size() - for report in _reports: - if report.test_count() == report.skipped_count(): - executed -= 1 - return executed - - -func test_count() -> int: - var count := _test_count - for report in _reports: - count += report.test_count() - return count - - -func test_executed_count() -> int: - return test_count() - skipped_count() - - -func success_count() -> int: - return test_count() - error_count() - failure_count() - flaky_count() - skipped_count() - - -func error_count() -> int: - return _error_count - - -func failure_count() -> int: - return _failure_count - - -func skipped_count() -> int: - return _skipped_count - - -func flaky_count() -> int: - return _flaky_count - - -func orphan_count() -> int: - return _orphan_count - - -func duration() -> int: - return _duration - - -func get_reports() -> Array: - return _reports - - -func add_report(report: GdUnitReportSummary) -> void: - _reports.append(report) - - -func report_state() -> String: - return calculate_state(error_count(), failure_count(), orphan_count(), flaky_count(), skipped_count()) - - -func succes_rate() -> String: - return calculate_succes_rate(test_count(), error_count(), failure_count()) - - -@warning_ignore("shadowed_variable") -func add_testcase(resource_path: String, suite_name: String, test_name: String) -> void: - for report: GdUnitTestSuiteReport in _reports: - if report.get_resource_path() == resource_path: - var test_report := GdUnitTestCaseReport.new(resource_path, suite_name, test_name, _text_formatter) - report.add_or_create_test_report(test_report) - - -func add_reports( - p_resource_path: String, - p_test_name: String, - p_reports: Array[GdUnitReport]) -> void: - - for report:GdUnitTestSuiteReport in _reports: - if report.get_resource_path() == p_resource_path: - report.add_testcase_reports(p_test_name, p_reports) - - -func add_testsuite_report(p_resource_path: String, p_suite_name: String, p_test_count: int) -> void: - _reports.append(GdUnitTestSuiteReport.new(p_resource_path, p_suite_name, p_test_count, _text_formatter)) - - -func add_testsuite_reports( - p_resource_path: String, - p_reports: Array = []) -> void: - - for report:GdUnitTestSuiteReport in _reports: - if report.get_resource_path() == p_resource_path: - report.set_reports(p_reports) - - -func set_counters( - p_resource_path: String, - p_test_name: String, - p_error_count: int, - p_failure_count: int, - p_orphan_count: int, - p_is_skipped: bool, - p_is_flaky: bool, - p_duration: int) -> void: - - for report: GdUnitTestSuiteReport in _reports: - if report.get_resource_path() == p_resource_path: - report.set_testcase_counters(p_test_name, p_error_count, p_failure_count, p_orphan_count, - p_is_skipped, p_is_flaky, p_duration) - - -func update_testsuite_counters( - p_resource_path: String, - p_error_count: int, - p_failure_count: int, - p_orphan_count: int, - p_skipped_count: int, - p_flaky_count: int, - p_duration: int) -> void: - - for report:GdUnitTestSuiteReport in _reports: - if report.get_resource_path() == p_resource_path: - report._update_testsuite_counters(p_error_count, p_failure_count, p_orphan_count, p_skipped_count, p_flaky_count, p_duration) - _update_summary_counters(p_error_count, p_failure_count, p_orphan_count, p_skipped_count, p_flaky_count, 0) - - -func _update_summary_counters( - p_error_count: int, - p_failure_count: int, - p_orphan_count: int, - p_skipped_count: int, - p_flaky_count: int, - p_duration: int) -> void: - - _error_count += p_error_count - _failure_count += p_failure_count - _orphan_count += p_orphan_count - _skipped_count += p_skipped_count - _flaky_count += p_flaky_count - _duration += p_duration - - -func calculate_state(p_error_count :int, p_failure_count :int, p_orphan_count :int, p_flaky_count: int, p_skipped_count: int) -> String: - if p_error_count > 0: - return "ERROR" - if p_failure_count > 0: - return "FAILED" - if p_flaky_count > 0: - return "FLAKY" - if p_orphan_count > 0: - return "WARNING" - if p_skipped_count > 0: - return "SKIPPED" - return "PASSED" - - -func calculate_succes_rate(p_test_count :int, p_error_count :int, p_failure_count :int) -> String: - if p_failure_count == 0: - return "100%" - var count := p_test_count-p_failure_count-p_error_count - if count < 0: - return "0%" - return "%d" % (( 0 if count < 0 else count) * 100.0 / p_test_count) + "%" - - -func create_summary(_report_dir :String) -> String: - return "" diff --git a/addons/gdUnit4/src/reporters/GdUnitReportSummary.gd.uid b/addons/gdUnit4/src/reporters/GdUnitReportSummary.gd.uid deleted file mode 100644 index 7e46ff44..00000000 --- a/addons/gdUnit4/src/reporters/GdUnitReportSummary.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://meit1uha85vb diff --git a/addons/gdUnit4/src/reporters/GdUnitReportWriter.gd b/addons/gdUnit4/src/reporters/GdUnitReportWriter.gd deleted file mode 100644 index bf4c96ea..00000000 --- a/addons/gdUnit4/src/reporters/GdUnitReportWriter.gd +++ /dev/null @@ -1,12 +0,0 @@ -class_name GdUnitReportWriter -extends RefCounted - - -func write(_report_path: String, _report: GdUnitReportSummary) -> String: - assert(false, "'write' is not implemented!") - return "" - - -func output_format() -> String: - assert(false, "'output_format' is not implemented!") - return "" diff --git a/addons/gdUnit4/src/reporters/GdUnitReportWriter.gd.uid b/addons/gdUnit4/src/reporters/GdUnitReportWriter.gd.uid deleted file mode 100644 index 49724c0b..00000000 --- a/addons/gdUnit4/src/reporters/GdUnitReportWriter.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bapou3o42rua2 diff --git a/addons/gdUnit4/src/reporters/GdUnitTestCaseReport.gd b/addons/gdUnit4/src/reporters/GdUnitTestCaseReport.gd deleted file mode 100644 index 2801696c..00000000 --- a/addons/gdUnit4/src/reporters/GdUnitTestCaseReport.gd +++ /dev/null @@ -1,47 +0,0 @@ -class_name GdUnitTestCaseReport -extends GdUnitReportSummary - - -var _suite_name: String -var _failure_reports: Array[GdUnitReport] = [] - - -func _init(p_resource_path: String, p_suite_name: String, p_test_name: String, text_formatter: Callable) -> void: - _resource_path = p_resource_path - _suite_name = p_suite_name - _name = p_test_name - _text_formatter = text_formatter - - -func suite_name() -> String: - return _suite_name - - -func failure_report() -> String: - var report_message := "" - for report in get_test_reports(): - report_message += _text_formatter.call(str(report)) + "\n" - return report_message - - -func add_testcase_reports(reports: Array[GdUnitReport]) -> void: - _failure_reports.append_array(reports) - - -func set_testcase_counters( - p_error_count: int, - p_failure_count: int, - p_orphan_count: int, - p_is_skipped: bool, - p_is_flaky: bool, - p_duration: int) -> void: - _error_count = p_error_count - _failure_count = p_failure_count - _orphan_count = p_orphan_count - _skipped_count = p_is_skipped - _flaky_count = p_is_flaky as int - _duration = p_duration - - -func get_test_reports() -> Array[GdUnitReport]: - return _failure_reports diff --git a/addons/gdUnit4/src/reporters/GdUnitTestCaseReport.gd.uid b/addons/gdUnit4/src/reporters/GdUnitTestCaseReport.gd.uid deleted file mode 100644 index 467772e2..00000000 --- a/addons/gdUnit4/src/reporters/GdUnitTestCaseReport.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://d34dh6aril014 diff --git a/addons/gdUnit4/src/reporters/GdUnitTestReporter.gd b/addons/gdUnit4/src/reporters/GdUnitTestReporter.gd deleted file mode 100644 index 46b81931..00000000 --- a/addons/gdUnit4/src/reporters/GdUnitTestReporter.gd +++ /dev/null @@ -1,112 +0,0 @@ -class_name GdUnitTestReporter -extends RefCounted - - -var _statistics := {} -var _summary := {} - - -func init_summary() -> void: - _summary["suite_count"] = 0 - _summary["total_count"] = 0 - _summary["error_count"] = 0 - _summary["failed_count"] = 0 - _summary["skipped_count"] = 0 - _summary["flaky_count"] = 0 - _summary["orphan_nodes"] = 0 - _summary["elapsed_time"] = 0 - - -func init_statistics() -> void: - _statistics.clear() - - -func add_test_statistics(event: GdUnitEvent) -> void: - _statistics[event.guid()] = { - "error_count" : event.error_count(), - "failed_count" : event.failed_count(), - "skipped_count" : event.skipped_count(), - "flaky_count" : event.is_flaky() as int, - "orphan_nodes" : event.orphan_nodes() - } - - -func build_test_suite_statisitcs(event: GdUnitEvent) -> Dictionary: - var statistic := { - "total_count" : _statistics.size(), - "error_count" : event.error_count(), - "failed_count" : event.failed_count(), - "skipped_count" : event.skipped_count(), - "flaky_count" : 0, - "orphan_nodes" : event.orphan_nodes() - } - _summary["suite_count"] += 1 - _summary["total_count"] += _statistics.size() - _summary["error_count"] += event.error_count() - _summary["failed_count"] += event.failed_count() - _summary["skipped_count"] += event.skipped_count() - _summary["orphan_nodes"] += event.orphan_nodes() - _summary["elapsed_time"] += event.elapsed_time() - - for key: String in ["error_count", "failed_count", "skipped_count", "flaky_count", "orphan_nodes"]: - var value: int = _statistics.values().reduce(get_value.bind(key), 0 ) - statistic[key] += value - _summary[key] += value - - return statistic - - -func get_value(acc: int, value: Dictionary, key: String) -> int: - return acc + value[key] - - -func processed_suite_count() -> int: - return _summary["suite_count"] - - -func total_test_count() -> int: - return _summary["total_count"] - - -func total_flaky_count() -> int: - return _summary["flaky_count"] - - -func total_error_count() -> int: - return _summary["error_count"] - - -func total_failure_count() -> int: - return _summary["failed_count"] - - -func total_skipped_count() -> int: - return _summary["skipped_count"] - - -func total_orphan_count() -> int: - return _summary["orphan_nodes"] - - -func elapsed_time() -> int: - return _summary["elapsed_time"] - - -func error_count(statistics: Dictionary) -> int: - return statistics["error_count"] - - -func failed_count(statistics: Dictionary) -> int: - return statistics["failed_count"] - - -func orphan_nodes(statistics: Dictionary) -> int: - return statistics["orphan_nodes"] - - -func skipped_count(statistics: Dictionary) -> int: - return statistics["skipped_count"] - - -func flaky_count(statistics: Dictionary) -> int: - return statistics["flaky_count"] diff --git a/addons/gdUnit4/src/reporters/GdUnitTestReporter.gd.uid b/addons/gdUnit4/src/reporters/GdUnitTestReporter.gd.uid deleted file mode 100644 index 52e61aed..00000000 --- a/addons/gdUnit4/src/reporters/GdUnitTestReporter.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cd8snijgldveh diff --git a/addons/gdUnit4/src/reporters/GdUnitTestSuiteReport.gd b/addons/gdUnit4/src/reporters/GdUnitTestSuiteReport.gd deleted file mode 100644 index 9be06825..00000000 --- a/addons/gdUnit4/src/reporters/GdUnitTestSuiteReport.gd +++ /dev/null @@ -1,96 +0,0 @@ -class_name GdUnitTestSuiteReport -extends GdUnitReportSummary - -var _time_stamp: int -var _failure_reports: Array[GdUnitReport] = [] - - -func _init(p_resource_path: String, p_name: String, p_test_count: int, text_formatter: Callable) -> void: - _resource_path = p_resource_path - _name = p_name - _test_count = p_test_count - _time_stamp = Time.get_unix_time_from_system() as int - _text_formatter = text_formatter - - -func failure_report() -> String: - var report_message := "" - for report in _failure_reports: - report_message += _text_formatter.call(str(report)) - return report_message - - -func set_duration(p_duration :int) -> void: - _duration = p_duration - - -func time_stamp() -> int: - return _time_stamp - - -func duration() -> int: - return _duration - - -func set_skipped(skipped :int) -> void: - _skipped_count += skipped - - -func set_orphans(orphans :int) -> void: - _orphan_count = orphans - - -func set_failed(count :int) -> void: - _failure_count += count - - -func set_reports(failure_reports :Array[GdUnitReport]) -> void: - _failure_reports = failure_reports - - -func add_or_create_test_report(test_report: GdUnitTestCaseReport) -> void: - _reports.append(test_report) - - -func _update_testsuite_counters( - p_error_count: int, - p_failure_count: int, - p_orphan_count: int, - p_skipped_count: int, - p_flaky_count: int, - p_duration: int) -> void: - _error_count += p_error_count - _failure_count += p_failure_count - _orphan_count += p_orphan_count - _skipped_count += p_skipped_count - _flaky_count += p_flaky_count - _duration += p_duration - - -func set_testcase_counters( - test_name: String, - p_error_count: int, - p_failure_count: int, - p_orphan_count: int, - p_is_skipped: bool, - p_is_flaky: bool, - p_duration: int) -> void: - if _reports.is_empty(): - return - var test_report: GdUnitTestCaseReport = _reports.filter(func (report: GdUnitTestCaseReport) -> bool: - return report.name() == test_name - ).back() - if test_report: - test_report.set_testcase_counters(p_error_count, p_failure_count, p_orphan_count, p_is_skipped, p_is_flaky, p_duration) - - -func add_testcase_reports(test_name: String, reports: Array[GdUnitReport]) -> void: - if reports.is_empty(): - return - # we lookup to latest matching report because of flaky tests could be retry the tests - # and resultis in multipe report entries with the same name - var test_report: GdUnitTestCaseReport = _reports.filter(func (report: GdUnitTestCaseReport) -> bool: - return report.name() == test_name - ).back() - if test_report: - test_report.add_testcase_reports(reports) diff --git a/addons/gdUnit4/src/reporters/GdUnitTestSuiteReport.gd.uid b/addons/gdUnit4/src/reporters/GdUnitTestSuiteReport.gd.uid deleted file mode 100644 index 12986589..00000000 --- a/addons/gdUnit4/src/reporters/GdUnitTestSuiteReport.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://buoo3f5s15ptt diff --git a/addons/gdUnit4/src/reporters/console/GdUnitConsoleTestReporter.gd b/addons/gdUnit4/src/reporters/console/GdUnitConsoleTestReporter.gd deleted file mode 100644 index 05d4b1d7..00000000 --- a/addons/gdUnit4/src/reporters/console/GdUnitConsoleTestReporter.gd +++ /dev/null @@ -1,234 +0,0 @@ -@tool -class_name GdUnitConsoleTestReporter - - -var test_session: GdUnitTestSession: - get: - return test_session - set(value): - # disconnect first possible connected listener - if test_session != null: - test_session.test_event.disconnect(on_gdunit_event) - # add listening to current session - test_session = value - if test_session != null: - test_session.test_event.connect(on_gdunit_event) - - -var _writer: GdUnitMessageWriter -var _reporter: GdUnitTestReporter = GdUnitTestReporter.new() -var _status_indent := 86 -var _detailed: bool -var _text_color: Color = Color.ANTIQUE_WHITE -var _function_color: Color = Color.ANTIQUE_WHITE -var _engine_type_color: Color = Color.ANTIQUE_WHITE - - -func _init(writer: GdUnitMessageWriter, detailed := false) -> void: - _writer = writer - _writer.clear() - _detailed = detailed - if _detailed: - _status_indent = 20 - init_colors() - - -func init_colors() -> void: - if Engine.is_editor_hint(): - var settings := EditorInterface.get_editor_settings() - _text_color = settings.get_setting("text_editor/theme/highlighting/text_color") - _function_color = settings.get_setting("text_editor/theme/highlighting/function_color") - _engine_type_color = settings.get_setting("text_editor/theme/highlighting/engine_type_color") - - -func clear() -> void: - _writer.clear() - - -func on_gdunit_event(event: GdUnitEvent) -> void: - match event.type(): - GdUnitEvent.INIT: - _reporter.init_summary() - - GdUnitEvent.STOP: - _print_summary() - println_message(build_executed_test_suite_msg(processed_suite_count(), processed_suite_count()), Color.DARK_SALMON) - println_message(build_executed_test_case_msg(total_test_count(), total_skipped_count()), Color.DARK_SALMON) - println_message("Total execution time: %s" % LocalTime.elapsed(elapsed_time()), Color.DARK_SALMON) - # We need finally to set the wave effect to enable the animations - _writer.effect(GdUnitMessageWriter.Effect.WAVE).print_at("", 0) - - GdUnitEvent.TESTSUITE_BEFORE: - _reporter.init_statistics() - print_message("Run Test Suite: ", Color.DARK_TURQUOISE) - println_message(event.resource_path(), _engine_type_color) - - GdUnitEvent.TESTSUITE_AFTER: - if not event.reports().is_empty(): - _writer.color(Color.DARK_SALMON) \ - .style(GdUnitMessageWriter.BOLD) \ - .println_message(event.suite_name() + ":finalze") - _print_failure_report(event.reports()) - _print_statistics(_reporter.build_test_suite_statisitcs(event)) - _print_status(event) - println_message("") - if _detailed: - println_message("") - - GdUnitEvent.TESTCASE_BEFORE: - var test := test_session.find_test_by_id(event.guid()) - _print_test_path(test, event.guid()) - if _detailed: - _writer.color(Color.FOREST_GREEN).print_at("STARTED", _status_indent) - println_message("") - - GdUnitEvent.TESTCASE_AFTER: - _reporter.add_test_statistics(event) - if _detailed: - var test := test_session.find_test_by_id(event.guid()) - _print_test_path(test, event.guid()) - _print_status(event) - _print_failure_report(event.reports()) - if _detailed: - println_message("") - - -func _print_test_path(test: GdUnitTestCase, uid: GdUnitGUID) -> void: - if test == null: - prints_warning("Can't print full test info, the test by uid: '%s' was not discovered." % uid) - _writer.indent(1).color(_engine_type_color).print_message("Test ID: %s" % uid) - return - - var suite_name := test.source_file if _detailed else test.suite_name - _writer.indent(1).color(_engine_type_color).print_message(suite_name) - print_message(" > ") - print_message(test.display_name, _function_color) - - -func _print_status(event: GdUnitEvent) -> void: - if event.is_flaky() and event.is_success(): - var retries: int = event.statistic(GdUnitEvent.RETRY_COUNT) - _writer.color(Color.GREEN_YELLOW) \ - .style(GdUnitMessageWriter.ITALIC) \ - .print_at("FLAKY (%d retries)" % retries, _status_indent) - elif event.is_success(): - _writer.color(Color.FOREST_GREEN).print_at("PASSED", _status_indent) - elif event.is_skipped(): - _writer.color(Color.GOLDENROD).style(GdUnitMessageWriter.ITALIC).print_at("SKIPPED", _status_indent) - elif event.is_failed() or event.is_error(): - var retries: int = event.statistic(GdUnitEvent.RETRY_COUNT) - var message := "FAILED (retry %d)" % retries if retries > 1 else "FAILED" - _writer.color(Color.FIREBRICK) \ - .style(GdUnitMessageWriter.BOLD) \ - .effect(GdUnitMessageWriter.Effect.WAVE) \ - .print_at(message, _status_indent) - elif event.is_warning(): - _writer.color(Color.GOLDENROD) \ - .style(GdUnitMessageWriter.UNDERLINE) \ - .print_at("WARNING", _status_indent) - - println_message(" %s" % LocalTime.elapsed(event.elapsed_time()), Color.CORNFLOWER_BLUE) - - -func _print_failure_report(reports: Array[GdUnitReport]) -> void: - for report in reports: - if ( - report.is_failure() - or report.is_error() - or report.is_warning() - or report.is_skipped() - ): - _writer.indent(1) \ - .color(Color.DARK_TURQUOISE) \ - .style(GdUnitMessageWriter.BOLD | GdUnitMessageWriter.UNDERLINE) \ - .println_message("Report:") - var text := str(report) - for line in text.split("\n", false): - _writer.indent(2).color(Color.DARK_TURQUOISE).println_message(line) - - if not reports.is_empty(): - println_message("") - - -func _print_statistics(statistics: Dictionary) -> void: - print_message("Statistics:", Color.DODGER_BLUE) - print_message(" %d test cases | %d errors | %d failures | %d flaky | %d skipped | %d orphans |" % \ - [statistics["total_count"], - statistics["error_count"], - statistics["failed_count"], - statistics["flaky_count"], - statistics["skipped_count"], - statistics["orphan_nodes"]]) - - -func _print_summary() -> void: - print_message("Overall Summary:", Color.DODGER_BLUE) - _writer \ - .println_message(" %d test cases | %d errors | %d failures | %d flaky | %d skipped | %d orphans |" % [ - total_test_count(), - total_error_count(), - total_failure_count(), - total_flaky_count(), - total_skipped_count(), - total_orphan_count() - ]) - - -func build_executed_test_suite_msg(executed_count: int, total_count: int) -> String: - if executed_count == total_count: - return "Executed test suites: (%d/%d)" % [executed_count, total_count] - return "Executed test suites: (%d/%d), %d skipped" % [executed_count, total_count, (total_count - executed_count)] - - -func build_executed_test_case_msg(total_count: int, p_skipped_count: int) -> String: - if p_skipped_count == 0: - return "Executed test cases : (%d/%d)" % [total_count, total_count] - return "Executed test cases : (%d/%d), %d skipped" % [total_count - p_skipped_count, total_count, p_skipped_count] - - -func print_message(message: String, color: Color = _text_color) -> void: - _writer.color(color).print_message(message) - - -func println_message(message: String, color: Color = _text_color) -> void: - _writer.color(color).println_message(message) - - -func prints_warning(message: String) -> void: - _writer.prints_warning(message) - - -func prints_error(message: String) -> void: - _writer.prints_error(message) - - -func total_test_count() -> int: - return _reporter.total_test_count() - - -func total_error_count() -> int: - return _reporter.total_error_count() - - -func total_failure_count() -> int: - return _reporter.total_failure_count() - - -func total_flaky_count() -> int: - return _reporter.total_flaky_count() - - -func total_skipped_count() -> int: - return _reporter.total_skipped_count() - - -func total_orphan_count() -> int: - return _reporter.total_orphan_count() - - -func processed_suite_count() -> int: - return _reporter.processed_suite_count() - - -func elapsed_time() -> int: - return _reporter.elapsed_time() diff --git a/addons/gdUnit4/src/reporters/console/GdUnitConsoleTestReporter.gd.uid b/addons/gdUnit4/src/reporters/console/GdUnitConsoleTestReporter.gd.uid deleted file mode 100644 index ca3a3c5a..00000000 --- a/addons/gdUnit4/src/reporters/console/GdUnitConsoleTestReporter.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cnc3bdrbur61g diff --git a/addons/gdUnit4/src/reporters/html/GdUnitByPathReport.gd b/addons/gdUnit4/src/reporters/html/GdUnitByPathReport.gd deleted file mode 100644 index 74b961b4..00000000 --- a/addons/gdUnit4/src/reporters/html/GdUnitByPathReport.gd +++ /dev/null @@ -1,60 +0,0 @@ -class_name GdUnitByPathReport -extends GdUnitReportSummary - - -func _init(p_path :String, report_summaries :Array[GdUnitReportSummary]) -> void: - _resource_path = p_path - _reports = report_summaries - - -# -> Dictionary[String, Array[GdUnitReportSummary]] -static func sort_reports_by_path(report_summaries :Array[GdUnitReportSummary]) -> Dictionary: - var by_path := Dictionary() - for report in report_summaries: - var suite_path :String = ProjectSettings.localize_path(report.path()) - var suite_report :Array[GdUnitReportSummary] = by_path.get(suite_path, [] as Array[GdUnitReportSummary]) - suite_report.append(report) - by_path[suite_path] = suite_report - return by_path - - -func path() -> String: - return _resource_path.replace("res://", "").trim_suffix("/") - - -func create_record(report_link :String) -> String: - return GdUnitHtmlPatterns.build(GdUnitHtmlPatterns.TABLE_RECORD_PATH, self, report_link) - - -func write(report_dir :String) -> String: - calculate_summary() - var template := GdUnitHtmlPatterns.load_template("res://addons/gdUnit4/src/reporters/html/template/folder_report.html") - var path_report := GdUnitHtmlPatterns.build(template, self, "") - path_report = apply_testsuite_reports(report_dir, path_report, _reports) - - var output_path := "%s/path/%s.html" % [report_dir, path().replace("/", ".")] - var dir := output_path.get_base_dir() - if not DirAccess.dir_exists_absolute(dir): - @warning_ignore("return_value_discarded") - DirAccess.make_dir_recursive_absolute(dir) - FileAccess.open(output_path, FileAccess.WRITE).store_string(path_report) - return output_path - - -func apply_testsuite_reports(report_dir :String, template :String, test_suite_reports :Array[GdUnitReportSummary]) -> String: - var table_records := PackedStringArray() - for report:GdUnitTestSuiteReport in test_suite_reports: - var report_link := GdUnitHtmlReportWriter.create_output_path(report_dir, report.path(), report.name()).replace(report_dir, "..") - @warning_ignore("return_value_discarded") - table_records.append(GdUnitHtmlPatterns.create_suite_record(report_link, report)) - return template.replace(GdUnitHtmlPatterns.TABLE_BY_TESTSUITES, "\n".join(table_records)) - - -func calculate_summary() -> void: - for report:GdUnitTestSuiteReport in get_reports(): - _error_count += report.error_count() - _failure_count += report.failure_count() - _orphan_count += report.orphan_count() - _skipped_count += report.skipped_count() - _flaky_count += report.flaky_count() - _duration += report.duration() diff --git a/addons/gdUnit4/src/reporters/html/GdUnitByPathReport.gd.uid b/addons/gdUnit4/src/reporters/html/GdUnitByPathReport.gd.uid deleted file mode 100644 index 495496cc..00000000 --- a/addons/gdUnit4/src/reporters/html/GdUnitByPathReport.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://byxm8mid1s1ev diff --git a/addons/gdUnit4/src/reporters/html/GdUnitHtmlPatterns.gd b/addons/gdUnit4/src/reporters/html/GdUnitHtmlPatterns.gd deleted file mode 100644 index b8be904f..00000000 --- a/addons/gdUnit4/src/reporters/html/GdUnitHtmlPatterns.gd +++ /dev/null @@ -1,199 +0,0 @@ -class_name GdUnitHtmlPatterns -extends RefCounted - -const TABLE_RECORD_TESTSUITE = """ - - ${testsuite_name} - ${report_state_label} - ${test_count} - ${skipped_count} - ${flaky_count} - ${failure_count} - ${orphan_count} - ${duration} - -
-
-
-
-
-
-
-
- - -""" - -const TABLE_RECORD_PATH = """ - - ${path} - ${report_state_label} - ${test_count} - ${skipped_count} - ${flaky_count} - ${failure_count} - ${orphan_count} - ${duration} - -
-
-
-
-
-
-
-
- - -""" - - -const TABLE_REPORT_TESTSUITE = """ - - TestSuite hooks - n/a - ${orphan_count} - ${duration} - -
-${failure-report}
-										
- - -""" - - -const TABLE_RECORD_TESTCASE = """ - - ${testcase_name} - ${report_state_label} - ${skipped_count} - ${orphan_count} - ${duration} - -
-${failure-report}
-										
- - -""" - -const CHARACTERS_TO_ENCODE := { - '<' : '<', - '>' : '>' -} - -const TABLE_BY_PATHS = "${report_table_paths}" -const TABLE_BY_TESTSUITES = "${report_table_testsuites}" -const TABLE_BY_TESTCASES = "${report_table_tests}" - -# the report state success, error, warning -const REPORT_STATE = "${report_state}" -const REPORT_STATE_LABEL = "${report_state_label}" -const PATH = "${path}" -const RESOURCE_PATH = "${resource_path}" -const TESTSUITE_COUNT = "${suite_count}" -const TESTCASE_COUNT = "${test_count}" -const FAILURE_COUNT = "${failure_count}" -const FLAKY_COUNT = "${flaky_count}" -const SKIPPED_COUNT = "${skipped_count}" -const ORPHAN_COUNT = "${orphan_count}" -const DURATION = "${duration}" -const FAILURE_REPORT = "${failure-report}" -const SUCCESS_PERCENT = "${success_percent}" - - -const QUICK_STATE_SKIPPED = "${skipped-percent}" -const QUICK_STATE_PASSED = "${passed-percent}" -const QUICK_STATE_FLAKY = "${flaky-percent}" -const QUICK_STATE_ERROR = "${error-percent}" -const QUICK_STATE_FAILED = "${failed-percent}" -const QUICK_STATE_WARNING = "${warning-percent}" - -const TESTSUITE_NAME = "${testsuite_name}" -const TESTCASE_NAME = "${testcase_name}" -const REPORT_LINK = "${report_link}" -const BREADCRUMP_PATH_LINK = "${breadcrumb_path_link}" -const BUILD_DATE = "${buid_date}" - - -static func current_date() -> String: - return Time.get_datetime_string_from_system(true, true) - - -static func build(template: String, report: GdUnitReportSummary, report_link: String) -> String: - return template\ - .replace(PATH, get_report_path(report))\ - .replace(BREADCRUMP_PATH_LINK, get_path_as_link(report))\ - .replace(RESOURCE_PATH, report.get_resource_path())\ - .replace(TESTSUITE_NAME, html_encoded(report.name()))\ - .replace(TESTSUITE_COUNT, str(report.suite_count()))\ - .replace(TESTCASE_COUNT, str(report.test_count()))\ - .replace(FAILURE_COUNT, str(report.error_count() + report.failure_count()))\ - .replace(FLAKY_COUNT, str(report.flaky_count()))\ - .replace(SKIPPED_COUNT, str(report.skipped_count()))\ - .replace(ORPHAN_COUNT, str(report.orphan_count()))\ - .replace(DURATION, LocalTime.elapsed(report.duration()))\ - .replace(SUCCESS_PERCENT, report.calculate_succes_rate(report.test_count(), report.error_count(), report.failure_count()))\ - .replace(REPORT_STATE, report.report_state().to_lower())\ - .replace(REPORT_STATE_LABEL, report.report_state())\ - .replace(QUICK_STATE_SKIPPED, calculate_percentage(report.test_count(), report.skipped_count()))\ - .replace(QUICK_STATE_PASSED, calculate_percentage(report.test_count(), report.success_count()))\ - .replace(QUICK_STATE_FLAKY, calculate_percentage(report.test_count(), report.flaky_count()))\ - .replace(QUICK_STATE_ERROR, calculate_percentage(report.test_count(), report.error_count()))\ - .replace(QUICK_STATE_FAILED, calculate_percentage(report.test_count(), report.failure_count()))\ - .replace(QUICK_STATE_WARNING, calculate_percentage(report.test_count(), 0))\ - .replace(REPORT_LINK, report_link)\ - .replace(BUILD_DATE, current_date()) - - -static func load_template(template_name :String) -> String: - return FileAccess.open(template_name, FileAccess.READ).get_as_text() - - -static func get_path_as_link(report: GdUnitReportSummary) -> String: - return "../path/%s.html" % report.path().replace("/", ".") - - -static func get_report_path(report: GdUnitReportSummary) -> String: - var path := report.path() - if path.is_empty(): - return "/" - return path - - -static func calculate_percentage(p_test_count: int, count: int) -> String: - if count <= 0: - return "0%" - return "%d" % (( 0 if count < 0 else count) * 100.0 / p_test_count) + "%" - - -static func html_encoded(value: String) -> String: - for key: String in CHARACTERS_TO_ENCODE.keys(): - @warning_ignore("unsafe_cast") - value = value.replace(key, CHARACTERS_TO_ENCODE[key] as String) - return value - - -static func create_suite_record(report_link: String, report: GdUnitTestSuiteReport) -> String: - return GdUnitHtmlPatterns.build(GdUnitHtmlPatterns.TABLE_RECORD_TESTSUITE, report, report_link) - - -static func create_test_failure_report(_report_dir :String, report: GdUnitTestCaseReport) -> String: - return GdUnitHtmlPatterns.TABLE_RECORD_TESTCASE\ - .replace(GdUnitHtmlPatterns.REPORT_STATE, report.report_state().to_lower())\ - .replace(GdUnitHtmlPatterns.REPORT_STATE_LABEL, report.report_state())\ - .replace(GdUnitHtmlPatterns.TESTCASE_NAME, report.name())\ - .replace(GdUnitHtmlPatterns.SKIPPED_COUNT, str(report.skipped_count()))\ - .replace(GdUnitHtmlPatterns.ORPHAN_COUNT, str(report.orphan_count()))\ - .replace(GdUnitHtmlPatterns.DURATION, LocalTime.elapsed(report._duration))\ - .replace(GdUnitHtmlPatterns.FAILURE_REPORT, report.failure_report()) - - -static func create_suite_failure_report(report: GdUnitTestSuiteReport) -> String: - return GdUnitHtmlPatterns.TABLE_REPORT_TESTSUITE\ - .replace(GdUnitHtmlPatterns.REPORT_STATE, report.report_state().to_lower())\ - .replace(GdUnitHtmlPatterns.REPORT_STATE_LABEL, report.report_state())\ - .replace(GdUnitHtmlPatterns.ORPHAN_COUNT, str(report.orphan_count()))\ - .replace(GdUnitHtmlPatterns.DURATION, LocalTime.elapsed(report._duration))\ - .replace(GdUnitHtmlPatterns.FAILURE_REPORT, report.failure_report()) diff --git a/addons/gdUnit4/src/reporters/html/GdUnitHtmlPatterns.gd.uid b/addons/gdUnit4/src/reporters/html/GdUnitHtmlPatterns.gd.uid deleted file mode 100644 index 74abfe25..00000000 --- a/addons/gdUnit4/src/reporters/html/GdUnitHtmlPatterns.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dndrqodnpdtx0 diff --git a/addons/gdUnit4/src/reporters/html/GdUnitHtmlReportWriter.gd b/addons/gdUnit4/src/reporters/html/GdUnitHtmlReportWriter.gd deleted file mode 100644 index a3d2bfff..00000000 --- a/addons/gdUnit4/src/reporters/html/GdUnitHtmlReportWriter.gd +++ /dev/null @@ -1,72 +0,0 @@ -class_name GdUnitHtmlReportWriter -extends GdUnitReportWriter - - -func output_format() -> String: - return "HTML" - - -func write(report_path: String, report: GdUnitReportSummary) -> String: - var template := GdUnitHtmlPatterns.load_template("res://addons/gdUnit4/src/reporters/html/template/index.html") - var to_write := GdUnitHtmlPatterns.build(template, report, "") - to_write = _apply_path_reports(report_path, to_write, report.get_reports()) - to_write = _apply_testsuite_reports(report_path, to_write, report.get_reports()) - # write report - DirAccess.make_dir_recursive_absolute(report_path) - var html_report_file := "%s/index.html" % report_path - FileAccess.open(html_report_file, FileAccess.WRITE).store_string(to_write) - @warning_ignore("return_value_discarded") - GdUnitFileAccess.copy_directory("res://addons/gdUnit4/src/reporters/html/template/css/", report_path + "/css") - return html_report_file - - -func _apply_path_reports(report_dir: String, template: String, report_summaries: Array) -> String: - #Dictionary[String, Array[GdUnitReportSummary]] - var path_report_mapping := GdUnitByPathReport.sort_reports_by_path(report_summaries) - var table_records := PackedStringArray() - var paths: Array[String] = [] - paths.append_array(path_report_mapping.keys()) - paths.sort() - for report_at_path in paths: - var reports: Array[GdUnitReportSummary] = path_report_mapping.get(report_at_path) - var report := GdUnitByPathReport.new(report_at_path, reports) - var report_link: String = report.write(report_dir).replace(report_dir, ".") - @warning_ignore("return_value_discarded") - table_records.append(report.create_record(report_link)) - return template.replace(GdUnitHtmlPatterns.TABLE_BY_PATHS, "\n".join(table_records)) - - -func _apply_testsuite_reports(report_dir: String, template: String, test_suite_reports: Array[GdUnitReportSummary]) -> String: - var table_records := PackedStringArray() - for report: GdUnitTestSuiteReport in test_suite_reports: - var report_link: String = _write(report_dir, report).replace(report_dir, ".") - @warning_ignore("return_value_discarded") - table_records.append(GdUnitHtmlPatterns.create_suite_record(report_link, report)) - return template.replace(GdUnitHtmlPatterns.TABLE_BY_TESTSUITES, "\n".join(table_records)) - - -func _write(report_dir :String, report: GdUnitTestSuiteReport) -> String: - var template := GdUnitHtmlPatterns.load_template("res://addons/gdUnit4/src/reporters/html/template/suite_report.html") - template = GdUnitHtmlPatterns.build(template, report, "") - - var report_output_path := create_output_path(report_dir, report.path(), report.name()) - var test_report_table := PackedStringArray() - if not report._failure_reports.is_empty(): - @warning_ignore("return_value_discarded") - test_report_table.append(GdUnitHtmlPatterns.create_suite_failure_report(report)) - for test_report: GdUnitTestCaseReport in report._reports: - @warning_ignore("return_value_discarded") - test_report_table.append(GdUnitHtmlPatterns.create_test_failure_report(report_output_path, test_report)) - - template = template.replace(GdUnitHtmlPatterns.TABLE_BY_TESTCASES, "\n".join(test_report_table)) - - var dir := report_output_path.get_base_dir() - if not DirAccess.dir_exists_absolute(dir): - @warning_ignore("return_value_discarded") - DirAccess.make_dir_recursive_absolute(dir) - FileAccess.open(report_output_path, FileAccess.WRITE).store_string(template) - return report_output_path - - -static func create_output_path(report_dir :String, path: String, name: String) -> String: - return "%s/test_suites/%s.%s.html" % [report_dir, path.replace("/", "."), name] diff --git a/addons/gdUnit4/src/reporters/html/GdUnitHtmlReportWriter.gd.uid b/addons/gdUnit4/src/reporters/html/GdUnitHtmlReportWriter.gd.uid deleted file mode 100644 index dedbb39f..00000000 --- a/addons/gdUnit4/src/reporters/html/GdUnitHtmlReportWriter.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dc1daqsf13p2m diff --git a/addons/gdUnit4/src/reporters/html/template/.gdignore b/addons/gdUnit4/src/reporters/html/template/.gdignore deleted file mode 100644 index e69de29b..00000000 diff --git a/addons/gdUnit4/src/reporters/html/template/css/breadcrumb.css b/addons/gdUnit4/src/reporters/html/template/css/breadcrumb.css deleted file mode 100644 index 17215ff2..00000000 --- a/addons/gdUnit4/src/reporters/html/template/css/breadcrumb.css +++ /dev/null @@ -1,66 +0,0 @@ -.breadcrumb { - display: flex; - border-radius: 6px; - overflow: hidden; - height: 45px; - z-index: 1; - background-color: #9d73eb; - margin-top: 0px; - margin-bottom: 10px; - box-shadow: 0 0 3px black; -} - -.breadcrumb a { - position: relative; - display: flex; - -ms-flex-positive: 1; - flex-grow: 1; - text-decoration: none; - margin: auto; - height: 100%; - color: white; -} - -.breadcrumb a:first-child { - padding-left: 5.2px; -} - -.breadcrumb a:last-child { - padding-right: 5.2px; -} - -.breadcrumb a:after { - content: ""; - position: absolute; - display: inline-block; - width: 45px; - height: 45px; - top: 0; - right: -20px; - background-color: #9d73eb; - border-top-right-radius: 5px; - transform: scale(0.707) rotate(45deg); - box-shadow: 2px -2px rgba(0, 0, 0, 0.25); - z-index: 1; -} - -.breadcrumb a:last-child:after { - content: none; -} - -.breadcrumb a.active, -.breadcrumb a:hover { - background: #b899f2; - color: white; - text-decoration: underline; -} - -.breadcrumb a.active:after, -.breadcrumb a:hover:after { - background: #b899f2; -} - -.breadcrumb span { - margin: inherit; - z-index: 2; -} diff --git a/addons/gdUnit4/src/reporters/html/template/css/logo.png b/addons/gdUnit4/src/reporters/html/template/css/logo.png deleted file mode 100644 index c1db2242..00000000 --- a/addons/gdUnit4/src/reporters/html/template/css/logo.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ed176306a061dff6c2a97c76e572bbbdee50cb7f5a496ba10d6898721f198351 -size 49775 diff --git a/addons/gdUnit4/src/reporters/html/template/css/styles.css b/addons/gdUnit4/src/reporters/html/template/css/styles.css deleted file mode 100644 index e92d59b7..00000000 --- a/addons/gdUnit4/src/reporters/html/template/css/styles.css +++ /dev/null @@ -1,475 +0,0 @@ -html, -body { - display: flex; - flex-direction: column; - margin: 0; - padding: 0; - font-family: sans-serif; - background-color: white; - height: 100%; -} - -main { - flex-grow: 1; - overflow: auto; - margin: 0 10em; -} - - -header { - color: white; - padding: 1px; - position: relative; - background-image: linear-gradient(to bottom right, #8058e3, #9d73eb); -} - -.logo { - position: fixed; - top: 20px; - left: 20px; - display: flex; - align-items: center; - z-index: 1000; - filter: grayscale(1); - mix-blend-mode: plus-lighter; -} - -.logo img { - width: 64px; - height: 64px; -} - -.logo span { - font-size: 1.2em; - color: lightslategray; -} - -.report-container { - margin: 0 15em; - text-align: center; - margin-top: 60px; - flex-grow: 0; -} - -h1 { - margin: 0 0 20px 0; - font-size: 2.5em; - font-weight: normal; -} - -.summary { - display: inline-flex; - justify-content: center; - flex-wrap: nowrap; - margin-bottom: 20px; - align-items: baseline; - max-width: 960px; -} - -.summary-item { - flex: 1; - min-width: 80px; -} - -.label { - font-size: 1em; - flex-wrap: nowrap; -} - -.value { - font-size: 0.9em; - display: block; - padding-top: 10px; - color: lightgray; -} - -.success-rate { - padding-left: 40px; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; -} - -.check-icon { - background-color: #34c538; - color: white; - width: 48px; - height: 48px; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - font-size: 1.4em; -} - -.rate-text { - text-align: center; - flex-wrap: nowrap; -} - -.percentage { - font-size: 1.2em; - font-weight: bold; -} - - -nav { - padding: 20px 0px; - font-family: monospace; -} - -nav ul { - list-style-type: none; - padding: 0; - margin: 0; - display: flex; - justify-content: flex-start; - border-bottom: 1px solid lightgray; -} - -nav li { - cursor: pointer; - padding: 5px 20px; - font-size: 1.1em; - color: lightslategray; -} - -nav li.active { - color: darkslategray; - border-bottom: 1px solid darkslategray; - font-weight: bold; -} - -div#content { - height: calc(100vh - 400px); -} - - -table { - width: 100%; - height: 100%; - border-collapse: collapse; - overflow: hidden; -} - -thead th { - position: sticky; - top: 0; - background-color: white; - z-index: 1; - border-bottom: 2px solid #ddd; -} - -tbody { - display: block; - /* Limit the height of the table body */ - max-height: calc(100vh - 400px); - /* Enable scrolling on the table body */ - overflow-y: auto; -} - -thead, -tbody tr { - display: table; - width: 100%; - table-layout: fixed; -} - -tbody td { - overflow: hidden; -} - -/* Ensure scrollbar visibility */ -tbody::-webkit-scrollbar { - height: 4px; - width: 14px; -} - -tbody::-webkit-scrollbar-thumb { - background-color: #aaa6a6; - border-radius: 4px; -} - -tbody::-webkit-scrollbar-track { - background-color: #f1f1f1; -} - -th, -td { - font-size: .9em; - padding: 5px 0px; - border-bottom: 1px solid #eee; - color: lightslategrey; - text-align: left; - text-wrap: nowrap; - /* Default max and min width for all columns */ - max-width: 150px; - min-width: 80px; - width: 80px; -} - -th { - font-size: 1em; - font-weight: normal; - padding-top: 20px; - color: gray; - text-wrap: nowrap; -} - -.tab-report { - display: grid; - grid-template-columns: 100%; - margin-bottom: 20px; -} - -.tab-report-grid { - display: grid; - grid-template-columns: 70% 30%; - margin-bottom: 20px; -} - - -/* Specific styling for the first column (Testcase) */ -th:first-child, -td:first-child { - padding-left: 5px; - text-align: left; - /* Max width for the first column */ - min-width: 249px; - width: 250px; - /* Enable scrollbar if content exceeds max-width */ - white-space: nowrap; - overflow: auto; -} - -/* Scrollbar styles for first column */ -td:first-child { - overflow-x: auto; - text-overflow: initial; -} - -/* Scrollbar appearance */ -td:first-child::-webkit-scrollbar { - height: 6px; -} - -td:first-child::-webkit-scrollbar-thumb { - background-color: #888; - border-radius: 10px; -} - -td:first-child::-webkit-scrollbar-track { - background-color: #f1f1f1; -} - -/* Max width for Result column */ -th:nth-child(2), -td:nth-child(2) { - max-width: 140px; - min-width: 140px; - width: 140px; -} - -/* Max width for Quick Results column */ -th:nth-child(9), -td:nth-child(9) { - max-width: 140px; - min-width: 140px; - width: 140px; - padding-right: 10px; -} - -/* Background color for alternating groups */ -.group-bg-1 { - background-color: #f1f1f1; -} - -.group-bg-2 { - background-color: #e0e0e0; -} - -.grid-item { - overflow: auto; - padding-left: 20px; - color: lightslategrey; - max-height: calc(100vh - 350px); -} - -div.tab td.report-column, -th.report-column { - display: none; -} - -/* Result status styles */ -.status { - padding: 2px 40px; - border-radius: 6px; - color: black; - width: 40px; - display: flex; - align-content: center; - align-items: center; -} - -.status-bar { - display: flex; - border-radius: 8px; - overflow: hidden; - height: 20px; - flex-wrap: nowrap; - justify-content: space-evenly; -} - -.status-bar-column { - margin: -2px; - color: black; - display: flex; - align-content: center; - align-items: center; - transition: width 0.3s ease; -} - -.status-skipped { - background-color: #888888; -} - -.status-passed { - background-color: #63bb38; -} - -.status-error { - background-color: #fd1100; -} - -.status-failed { - background-color: #ed594f; -} - -.status-flaky { - background-color: #1d9a1f; -} - -.status-warning { - background-color: #fdda3f; -} - -div.tab tr:hover { - background-color: #d9e7fa; - box-shadow: 0 0 5px black; -} - -div.tab tr.selected { - background-color: #d9e7fa; -} - -div.report-column { - margin-top: 10px; - width: 100%; - text-align: left; -} - -.logging-container { - width: 100%; - height: 100%; -} - -div.godot-report-frame { - margin: 10px; - font-family: monospace; - height: 100%; - background-color: #eee; -} - -div.include-footer { - position: fixed; - bottom: 0; - width: 100%; - display: flex; -} - -footer { - position: static; - left: 0; - bottom: 0; - width: 100%; - white-space: nowrap; - color: lightgray; - font-size: 12px; - background-image: linear-gradient(to bottom right, #8058e3, #9d73eb); - display: flex; - justify-content: space-between; - align-items: center; -} - -footer p { - padding-left: 10em; -} - -footer .status-legend { - display: flex; - gap: 15px; - width: 500px; -} - -footer a { - color: lightgray; -} - -footer a:hover { - color: whitesmoke; -} - -footer a:visited { - color: whitesmoke; -} - -.status-legend-item { - display: flex; - align-items: center; - gap: 5px; -} - -.status-box { - width: 15px; - height: 15px; - border-radius: 3px; - display: inline-block; -} - -/* Normal link */ -a { - color: lightslategrey; -} - -/* Link when hovered */ -a:hover { - color: #9d73eb; -} - -/* Visited link */ -a:visited { - color: #8058e3; -} - -/* Active link (while being clicked) */ -a:active { - color: #8058e3; - /* Custom color when link is clicked */ -} - - -@media (max-width: 1024px) { - .summary { - flex-direction: column; - } - - nav ul { - flex-wrap: wrap; - } - - nav li { - margin-right: 10px; - margin-bottom: 5px; - } -} diff --git a/addons/gdUnit4/src/reporters/html/template/folder_report.html b/addons/gdUnit4/src/reporters/html/template/folder_report.html deleted file mode 100644 index 2cdca675..00000000 --- a/addons/gdUnit4/src/reporters/html/template/folder_report.html +++ /dev/null @@ -1,122 +0,0 @@ - - - - - - - - - GdUnit4 Testsuite - - - - - -
- -
-

Report by Paths

-
- ${resource_path} -
-
-
- TestSuites - ${suite_count} -
-
- Tests - ${test_count} -
-
- Skipped - ${skipped_count} -
-
- Flaky - ${flaky_count} -
-
- Failures - ${failure_count} -
-
- Orphans - ${orphan_count} -
-
- Duration - ${duration} -
-
-
✓
-
- Success Rate - ${success_percent} -
-
-
-
- -
- -
-
-
-
- - - - - - - - - - - - - - - - ${report_table_testsuites} - -
TestSuitesResultTestsSkippedFlakyFailuresOrphansDurationSuccess rate
-
-
-
-
- -
-

Generated by GdUnit4 at ${buid_date}

-
- - Skipped - - - Passed - - - Flaky - - - Warning - - - Failed - - - Error - -
-
- - - diff --git a/addons/gdUnit4/src/reporters/html/template/index.html b/addons/gdUnit4/src/reporters/html/template/index.html deleted file mode 100644 index 342c8f25..00000000 --- a/addons/gdUnit4/src/reporters/html/template/index.html +++ /dev/null @@ -1,164 +0,0 @@ - - - - - - - GdUnit4 Report - - - - -
- -
-

Summary Report

-
-
- Test Suites - ${suite_count} -
-
- Tests - ${test_count} -
-
- Skipped - ${skipped_count} -
-
- Flaky - ${flaky_count} -
-
- Failures - ${failure_count} -
-
- Orphans - ${orphan_count} -
-
- Duration - ${duration} -
-
-
✓
-
- Success Rate - ${success_percent} -
-
-
-
-
-
- -
- -
-
- -
-

Generated by GdUnit4 at ${buid_date}

-
- - Skipped - - - Passed - - - Flaky - - - Warning - - - Failed - - - Error - -
-
- - - - - diff --git a/addons/gdUnit4/src/reporters/html/template/suite_report.html b/addons/gdUnit4/src/reporters/html/template/suite_report.html deleted file mode 100644 index 47468410..00000000 --- a/addons/gdUnit4/src/reporters/html/template/suite_report.html +++ /dev/null @@ -1,177 +0,0 @@ - - - - - - - - - GdUnit4 Testsuite - - - - - - - - -
- -
-

Testsuite Report

-
- ${resource_path} -
-
-
- Tests - ${test_count} -
-
- Skipped - ${skipped_count} -
-
- Flaky - ${flaky_count} -
-
- Failures - ${failure_count} -
-
- Orphans - ${orphan_count} -
-
- Duration - ${duration} -
-
-
✓
-
- Success Rate - ${success_percent} -
-
-
-
- -
- -
-
-
- - - - - - - - - - - - - ${report_table_tests} - -
TestcaseResultSkippedOrphansDurationReport
-
-
-

Failure Report

-
-
-
-
- -
-

Generated by GdUnit4 at ${buid_date}

-
- - Skipped - - - Passed - - - Flaky - - - Warning - - - Failed - - - Error - -
-
- - - - - diff --git a/addons/gdUnit4/src/reporters/xml/JUnitXmlReportWriter.gd b/addons/gdUnit4/src/reporters/xml/JUnitXmlReportWriter.gd deleted file mode 100644 index 0b9674f3..00000000 --- a/addons/gdUnit4/src/reporters/xml/JUnitXmlReportWriter.gd +++ /dev/null @@ -1,143 +0,0 @@ -# This class implements the JUnit XML file format -# based checked https://github.com/windyroad/JUnit-Schema/blob/master/JUnit.xsd -class_name JUnitXmlReportWriter -extends GdUnitReportWriter - -const GdUnitTools := preload("res://addons/gdUnit4/src/core/GdUnitTools.gd") - -const ATTR_CLASSNAME := "classname" -const ATTR_ERRORS := "errors" -const ATTR_FAILURES := "failures" -const ATTR_HOST := "hostname" -const ATTR_ID := "id" -const ATTR_MESSAGE := "message" -const ATTR_NAME := "name" -const ATTR_PACKAGE := "package" -const ATTR_SKIPPED := "skipped" -const ATTR_FLAKY := "flaky" -const ATTR_TESTS := "tests" -const ATTR_TIME := "time" -const ATTR_TIMESTAMP := "timestamp" -const ATTR_TYPE := "type" - -const HEADER := '\n' - - -func output_format() -> String: - return "XML" - - -func write(report_path: String, report: GdUnitReportSummary) -> String: - var result_file: String = "%s/results.xml" % report_path - DirAccess.make_dir_recursive_absolute(report_path) - var file := FileAccess.open(result_file, FileAccess.WRITE) - if file == null: - push_warning("Can't saving the result to '%s'\n Error: %s" % [result_file, error_string(FileAccess.get_open_error())]) - else: - file.store_string(build_junit_report(report_path, report)) - return result_file - - -func build_junit_report(report_path: String, report: GdUnitReportSummary) -> String: - var iso8601_datetime := Time.get_date_string_from_system() - var test_suites := XmlElement.new("testsuites")\ - .attribute(ATTR_ID, iso8601_datetime)\ - .attribute(ATTR_NAME, report_path.get_file())\ - .attribute(ATTR_TESTS, report.test_count())\ - .attribute(ATTR_FAILURES, report.failure_count())\ - .attribute(ATTR_SKIPPED, report.skipped_count())\ - .attribute(ATTR_FLAKY, report.flaky_count())\ - .attribute(ATTR_TIME, JUnitXmlReportWriter.to_time(report.duration()))\ - .add_childs(build_test_suites(report)) - var as_string := test_suites.to_xml() - test_suites.dispose() - return HEADER + as_string - - -func build_test_suites(summary: GdUnitReportSummary) -> Array: - var test_suites: Array[XmlElement] = [] - for index in summary.get_reports().size(): - var suite_report :GdUnitTestSuiteReport = summary.get_reports()[index] - var iso8601_datetime := Time.get_datetime_string_from_unix_time(suite_report.time_stamp()) - test_suites.append(XmlElement.new("testsuite")\ - .attribute(ATTR_ID, index)\ - .attribute(ATTR_NAME, suite_report.name())\ - .attribute(ATTR_PACKAGE, suite_report.path())\ - .attribute(ATTR_TIMESTAMP, iso8601_datetime)\ - .attribute(ATTR_HOST, "localhost")\ - .attribute(ATTR_TESTS, suite_report.test_count())\ - .attribute(ATTR_FAILURES, suite_report.failure_count())\ - .attribute(ATTR_ERRORS, suite_report.error_count())\ - .attribute(ATTR_SKIPPED, suite_report.skipped_count())\ - .attribute(ATTR_FLAKY, suite_report.flaky_count())\ - .attribute(ATTR_TIME, JUnitXmlReportWriter.to_time(suite_report.duration()))\ - .add_childs(build_test_cases(suite_report))) - return test_suites - - -func build_test_cases(suite_report: GdUnitTestSuiteReport) -> Array: - var test_cases: Array[XmlElement] = [] - for index in suite_report.get_reports().size(): - var report :GdUnitTestCaseReport = suite_report.get_reports()[index] - test_cases.append( XmlElement.new("testcase")\ - .attribute(ATTR_NAME, JUnitXmlReportWriter.encode_xml(report.name()))\ - .attribute(ATTR_CLASSNAME, report.suite_name())\ - .attribute(ATTR_TIME, JUnitXmlReportWriter.to_time(report.duration()))\ - .add_childs(build_reports(report))) - return test_cases - - -func build_reports(test_report: GdUnitTestCaseReport) -> Array: - var failure_reports: Array[XmlElement] = [] - - for report: GdUnitReport in test_report.get_test_reports(): - if report.is_failure(): - failure_reports.append(XmlElement.new("failure")\ - .attribute(ATTR_MESSAGE, "FAILED: %s:%d" % [test_report.get_resource_path(), report.line_number()])\ - .attribute(ATTR_TYPE, JUnitXmlReportWriter.to_type(report.type()))\ - .text(convert_rtf_to_text(report.message()))) - elif report.is_error(): - failure_reports.append(XmlElement.new("error")\ - .attribute(ATTR_MESSAGE, "ERROR: %s:%d" % [test_report.get_resource_path(), report.line_number()])\ - .attribute(ATTR_TYPE, JUnitXmlReportWriter.to_type(report.type()))\ - .text(convert_rtf_to_text(report.message()))) - elif report.is_skipped(): - failure_reports.append(XmlElement.new("skipped")\ - .attribute(ATTR_MESSAGE, "SKIPPED: %s:%d" % [test_report.get_resource_path(), report.line_number()])\ - .text(convert_rtf_to_text(report.message()))) - return failure_reports - - -func convert_rtf_to_text(bbcode: String) -> String: - return GdUnitTools.richtext_normalize(bbcode) - - -static func to_type(type: int) -> String: - match type: - GdUnitReport.SUCCESS: - return "SUCCESS" - GdUnitReport.WARN: - return "WARN" - GdUnitReport.FAILURE: - return "FAILURE" - GdUnitReport.ORPHAN: - return "ORPHAN" - GdUnitReport.TERMINATED: - return "TERMINATED" - GdUnitReport.INTERUPTED: - return "INTERUPTED" - GdUnitReport.ABORT: - return "ABORT" - return "UNKNOWN" - - -static func to_time(duration: int) -> String: - return "%4.03f" % (duration / 1000.0) - - -static func encode_xml(value: String) -> String: - return value.xml_escape(true) - - -#static func to_ISO8601_datetime() -> String: - #return "%04d-%02d-%02dT%02d:%02d:%02d" % [date["year"], date["month"], date["day"], date["hour"], date["minute"], date["second"]] diff --git a/addons/gdUnit4/src/reporters/xml/JUnitXmlReportWriter.gd.uid b/addons/gdUnit4/src/reporters/xml/JUnitXmlReportWriter.gd.uid deleted file mode 100644 index daf0f5a2..00000000 --- a/addons/gdUnit4/src/reporters/xml/JUnitXmlReportWriter.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bxwmuqci2eaj1 diff --git a/addons/gdUnit4/src/reporters/xml/XmlElement.gd b/addons/gdUnit4/src/reporters/xml/XmlElement.gd deleted file mode 100644 index 86c74212..00000000 --- a/addons/gdUnit4/src/reporters/xml/XmlElement.gd +++ /dev/null @@ -1,69 +0,0 @@ -class_name XmlElement -extends RefCounted - -var _name :String -# Dictionary[String, String] -var _attributes :Dictionary = {} -var _childs :Array[XmlElement] = [] -var _parent :XmlElement = null -var _text :String = "" - - -func _init(name :String) -> void: - _name = name - - -func dispose() -> void: - for child in _childs: - child.dispose() - _childs.clear() - _attributes.clear() - _parent = null - - -func attribute(name :String, value :Variant) -> XmlElement: - _attributes[name] = str(value) - return self - - -func text(p_text :String) -> XmlElement: - _text = p_text if p_text.ends_with("\n") else p_text + "\n" - return self - - -func add_child(child :XmlElement) -> XmlElement: - _childs.append(child) - child._parent = self - return self - - -func add_childs(childs :Array[XmlElement]) -> XmlElement: - for child in childs: - @warning_ignore("return_value_discarded") - add_child(child) - return self - - -func indentation() -> String: - return "" if _parent == null else _parent.indentation() + " " - - -func to_xml() -> String: - var attributes := "" - for key in _attributes.keys() as Array[String]: - attributes += ' {attr}="{value}"'.format({"attr": key, "value": _attributes.get(key)}) - - var childs := "" - for child in _childs: - childs += child.to_xml() - - return "{_indentation}<{name}{attributes}>\n{childs}{text}{_indentation}\n"\ - .format({"name": _name, - "attributes": attributes, - "childs": childs, - "_indentation": indentation(), - "text": cdata(_text)}) - - -func cdata(p_text :String) -> String: - return "" if p_text.is_empty() else "\n".format({"text" : p_text}) diff --git a/addons/gdUnit4/src/reporters/xml/XmlElement.gd.uid b/addons/gdUnit4/src/reporters/xml/XmlElement.gd.uid deleted file mode 100644 index 16bc6f0f..00000000 --- a/addons/gdUnit4/src/reporters/xml/XmlElement.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://byogn2u5815e0 diff --git a/addons/gdUnit4/src/spy/GdUnitSpyBuilder.gd b/addons/gdUnit4/src/spy/GdUnitSpyBuilder.gd deleted file mode 100644 index 5d8b6318..00000000 --- a/addons/gdUnit4/src/spy/GdUnitSpyBuilder.gd +++ /dev/null @@ -1,154 +0,0 @@ -class_name GdUnitSpyBuilder -extends GdUnitClassDoubler - -const GdUnitTools := preload("res://addons/gdUnit4/src/core/GdUnitTools.gd") -const SPY_TEMPLATE :GDScript = preload("res://addons/gdUnit4/src/spy/GdUnitSpyImpl.gd") -const EXCLUDE_PROPERTIES_TO_COPY = ["script", "type"] - - -static func build(to_spy: Variant, debug_write := false) -> Variant: - if GdObjects.is_singleton(to_spy): - @warning_ignore("unsafe_cast") - push_error("Spy on a Singleton is not allowed! '%s'" % (to_spy as Object).get_class()) - return null - - # if resource path load it before - if GdObjects.is_scene_resource_path(to_spy): - var scene_resource_path :String = to_spy - if not FileAccess.file_exists(scene_resource_path): - push_error("Can't build spy on scene '%s'! The given resource not exists!" % scene_resource_path) - return null - var scene_to_spy: PackedScene = load(scene_resource_path) - return spy_on_scene(scene_to_spy.instantiate() as Node, debug_write) - # spy checked PackedScene - if GdObjects.is_scene(to_spy): - var scene_to_spy: PackedScene = to_spy - return spy_on_scene(scene_to_spy.instantiate() as Node, debug_write) - # spy checked a scene instance - if GdObjects.is_instance_scene(to_spy): - @warning_ignore("unsafe_cast") - return spy_on_scene(to_spy as Node, debug_write) - - var excluded_functions := [] - if to_spy is Callable: - @warning_ignore("unsafe_cast") - to_spy = CallableDoubler.new(to_spy as Callable) - excluded_functions = CallableDoubler.excluded_functions() - - var spy := spy_on_script(to_spy, excluded_functions, debug_write) - if spy == null: - return null - var spy_instance: Object = spy.new() - @warning_ignore("unsafe_method_access") - # we do not call the original implementation for _ready and all input function, this is actualy done by the engine - spy_instance.__init(["_input", "_gui_input", "_input_event", "_unhandled_input"]) - @warning_ignore("unsafe_cast") - copy_properties(to_spy as Object, spy_instance) - @warning_ignore("return_value_discarded") - GdUnitObjectInteractions.reset(spy_instance) - return register_auto_free(spy_instance) - - -static func get_class_info(clazz :Variant) -> Dictionary: - var clazz_path := GdObjects.extract_class_path(clazz) - var clazz_name :String = GdObjects.extract_class_name(clazz).value() - return { - "class_name" : clazz_name, - "class_path" : clazz_path - } - - -static func spy_on_script(instance: Variant, function_excludes: PackedStringArray, debug_write: bool) -> GDScript: - if GdArrayTools.is_array_type(instance): - if GdUnitSettings.is_verbose_assert_errors(): - push_error("Can't build spy checked type '%s'! Spy checked Container Built-In Type not supported!" % type_string(typeof(instance))) - return null - var class_info := get_class_info(instance) - var clazz_name :String = class_info.get("class_name") - var clazz_path :PackedStringArray = class_info.get("class_path", [clazz_name]) - if not GdObjects.is_instance(instance): - if GdUnitSettings.is_verbose_assert_errors(): - push_error("Can't build spy for class type '%s'! Using an instance instead e.g. 'spy()'" % [clazz_name]) - return null - - @warning_ignore("unsafe_method_access") - var spy_template := SPY_TEMPLATE.source_code.format({ - "instance_id" : abs(instance.get_instance_id()), - "gdunit_source_class": clazz_name if clazz_path.is_empty() else clazz_path[0] - }) - @warning_ignore("unsafe_cast") - var lines := load_template(spy_template, class_info) - @warning_ignore("unsafe_cast") - lines += double_functions(instance as Object, clazz_name, clazz_path, GdUnitSpyFunctionDoubler.new(), function_excludes) - # We disable warning/errors for inferred_declaration - if Engine.get_version_info().hex >= 0x40400: - lines.insert(0, '@warning_ignore_start("inferred_declaration")') - lines.append('@warning_ignore_restore("inferred_declaration")') - - var spy := GDScript.new() - spy.source_code = "\n".join(lines) - spy.resource_name = "Spy%s.gd" % clazz_name - spy.resource_path = GdUnitFileAccess.create_temp_dir("spy") + "/Spy%s_%d.gd" % [clazz_name, Time.get_ticks_msec()] - - if debug_write: - @warning_ignore("return_value_discarded") - DirAccess.remove_absolute(spy.resource_path) - @warning_ignore("return_value_discarded") - ResourceSaver.save(spy, spy.resource_path) - var error := spy.reload(true) - if error != OK: - push_error("Unexpected Error!, SpyBuilder error, please contact the developer.") - return null - return spy - - -static func spy_on_scene(scene :Node, debug_write :bool) -> Object: - if scene.get_script() == null: - if GdUnitSettings.is_verbose_assert_errors(): - push_error("Can't create a spy checked a scene without script '%s'" % scene.get_scene_file_path()) - return null - # buils spy checked original script - @warning_ignore("unsafe_cast") - var scene_script :Object = (scene.get_script() as GDScript).new() - var spy := spy_on_script(scene_script, GdUnitClassDoubler.EXLCUDE_SCENE_FUNCTIONS, debug_write) - scene_script.free() - if spy == null: - return null - - # we need to restore the original script properties to apply after script exchange - var original_properties := {} - for p in scene.get_property_list(): - var property_name: String = p["name"] - var usage: int = p["usage"] - if (usage & PROPERTY_USAGE_SCRIPT_VARIABLE) == PROPERTY_USAGE_SCRIPT_VARIABLE: - original_properties[property_name] = scene.get(property_name) - - # exchage with spy - scene.set_script(spy) - # apply original script properties to the spy - for property_name: String in original_properties.keys(): - scene.set(property_name, original_properties[property_name]) - - @warning_ignore("unsafe_method_access") - scene.__init() - return register_auto_free(scene) - - -static func copy_properties(source :Object, dest :Object) -> void: - for property in source.get_property_list(): - var property_name :String = property["name"] - var property_value :Variant = source.get(property_name) - if EXCLUDE_PROPERTIES_TO_COPY.has(property_name): - continue - #if dest.get(property_name) == null: - # prints("|%s|" % property_name, source.get(property_name)) - - # check for invalid name property - if property_name == "name" and property_value == "": - dest.set(property_name, ""); - continue - dest.set(property_name, property_value) - - -static func register_auto_free(obj :Variant) -> Variant: - return GdUnitThreadManager.get_current_context().get_execution_context().register_auto_free(obj) diff --git a/addons/gdUnit4/src/spy/GdUnitSpyBuilder.gd.uid b/addons/gdUnit4/src/spy/GdUnitSpyBuilder.gd.uid deleted file mode 100644 index 70544a25..00000000 --- a/addons/gdUnit4/src/spy/GdUnitSpyBuilder.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c02xkecgmjjk5 diff --git a/addons/gdUnit4/src/spy/GdUnitSpyImpl.gd b/addons/gdUnit4/src/spy/GdUnitSpyImpl.gd deleted file mode 100644 index e0bcaf2b..00000000 --- a/addons/gdUnit4/src/spy/GdUnitSpyImpl.gd +++ /dev/null @@ -1,46 +0,0 @@ -class_name DoubledSpyClassSourceClassName - -const __INSTANCE_ID := "gdunit_doubler_instance_id_{instance_id}" - - -class GdUnitSpyDoublerState: - const __SOURCE_CLASS := "{gdunit_source_class}" - - var excluded_methods := PackedStringArray() - - func _init(excluded_methods__ := PackedStringArray()) -> void: - excluded_methods = excluded_methods__ - - -var __spy_state := GdUnitSpyDoublerState.new() -@warning_ignore("unused_private_class_variable") -var __verifier_instance := GdUnitObjectInteractionsVerifier.new() - - -func __init(__excluded_methods := PackedStringArray()) -> void: - __init_doubler() - __spy_state.excluded_methods = __excluded_methods - - -static func __doubler_state() -> GdUnitSpyDoublerState: - if Engine.has_meta(__INSTANCE_ID): - return Engine.get_meta(__INSTANCE_ID).__spy_state - return null - - -func __init_doubler() -> void: - Engine.set_meta(__INSTANCE_ID, self) - - -func _notification(what: int) -> void: - if what == NOTIFICATION_PREDELETE and Engine.has_meta(__INSTANCE_ID): - Engine.remove_meta(__INSTANCE_ID) - - -static func __get_verifier() -> GdUnitObjectInteractionsVerifier: - return Engine.get_meta(__INSTANCE_ID).__verifier_instance - - -static func __do_call_real_func(__func_name: String) -> bool: - @warning_ignore("unsafe_method_access") - return not __doubler_state().excluded_methods.has(__func_name) diff --git a/addons/gdUnit4/src/spy/GdUnitSpyImpl.gd.uid b/addons/gdUnit4/src/spy/GdUnitSpyImpl.gd.uid deleted file mode 100644 index 11183e5e..00000000 --- a/addons/gdUnit4/src/spy/GdUnitSpyImpl.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://n4vkvuk2dwgt diff --git a/addons/gdUnit4/src/ui/GdUnitConsole.gd b/addons/gdUnit4/src/ui/GdUnitConsole.gd deleted file mode 100644 index eb1e6254..00000000 --- a/addons/gdUnit4/src/ui/GdUnitConsole.gd +++ /dev/null @@ -1,91 +0,0 @@ -@tool -extends Control - -const GdUnitUpdateClient = preload("res://addons/gdUnit4/src/update/GdUnitUpdateClient.gd") -const TITLE = "gdUnit4 ${version} Console" - -@onready var header := $VBoxContainer/Header -@onready var title: RichTextLabel = $VBoxContainer/Header/header_title -@onready var output: RichTextLabel = $VBoxContainer/Console/TextEdit - - -var _test_reporter: GdUnitConsoleTestReporter - - -@warning_ignore("return_value_discarded") -func _ready() -> void: - GdUnitFonts.init_fonts(output) - GdUnit4Version.init_version_label(title) - GdUnitSignals.instance().gdunit_event.connect(_on_gdunit_event) - GdUnitSignals.instance().gdunit_message.connect(_on_gdunit_message) - GdUnitSignals.instance().gdunit_client_connected.connect(_on_gdunit_client_connected) - GdUnitSignals.instance().gdunit_client_disconnected.connect(_on_gdunit_client_disconnected) - _test_reporter = GdUnitConsoleTestReporter.new(GdUnitRichTextMessageWriter.new(output)) - - -func _notification(what: int) -> void: - if what == EditorSettings.NOTIFICATION_EDITOR_SETTINGS_CHANGED: - _test_reporter.init_colors() - if what == NOTIFICATION_PREDELETE: - var instance := GdUnitSignals.instance() - if instance.gdunit_event.is_connected(_on_gdunit_event): - instance.gdunit_event.disconnect(_on_gdunit_event) - if instance.gdunit_message.is_connected(_on_gdunit_event): - instance.gdunit_message.disconnect(_on_gdunit_message) - if instance.gdunit_client_connected.is_connected(_on_gdunit_event): - instance.gdunit_client_connected.disconnect(_on_gdunit_client_connected) - if instance.gdunit_client_disconnected.is_connected(_on_gdunit_event): - instance.gdunit_client_disconnected.disconnect(_on_gdunit_client_disconnected) - - -func setup_update_notification(control: Button) -> void: - if not GdUnitSettings.is_update_notification_enabled(): - _test_reporter.println_message("The search for updates is deactivated.", Color.CORNFLOWER_BLUE) - return - - _test_reporter.print_message("Searching for updates... ", Color.CORNFLOWER_BLUE) - var update_client := GdUnitUpdateClient.new() - add_child(update_client) - var response :GdUnitUpdateClient.HttpResponse = await update_client.request_latest_version() - if response.status() != 200: - _test_reporter.println_message("Information cannot be retrieved from GitHub!", Color.INDIAN_RED) - _test_reporter.println_message("Error: %s" % response.response(), Color.INDIAN_RED) - return - var latest_version := update_client.extract_latest_version(response) - if not latest_version.is_greater(GdUnit4Version.current()): - _test_reporter.println_message("GdUnit4 is up-to-date.", Color.FOREST_GREEN) - return - - _test_reporter.println_message("A new update is available %s" % latest_version, Color.YELLOW) - _test_reporter.println_message("Open the GdUnit4 settings and check the update tab.", Color.YELLOW) - - control.icon = GdUnitUiTools.get_icon("Notification", Color.YELLOW) - var tween := create_tween() - tween.tween_property(control, "self_modulate", Color.VIOLET, .2).set_trans(Tween.TransitionType.TRANS_LINEAR) - tween.tween_property(control, "self_modulate", Color.YELLOW, .2).set_trans(Tween.TransitionType.TRANS_BOUNCE) - tween.parallel() - tween.tween_property(control, "scale", Vector2.ONE*1.05, .4).set_trans(Tween.TransitionType.TRANS_LINEAR) - tween.tween_property(control, "scale", Vector2.ONE, .4).set_trans(Tween.TransitionType.TRANS_BOUNCE) - tween.set_loops(-1) - tween.play() - - -func _on_gdunit_event(event: GdUnitEvent) -> void: - match event.type(): - GdUnitEvent.SESSION_START: - _test_reporter.test_session = GdUnitTestSession.new(GdUnitTestDiscoverGuard.instance().get_discovered_tests(), "") - GdUnitEvent.SESSION_CLOSE: - _test_reporter.test_session = null - - -func _on_gdunit_client_connected(client_id: int) -> void: - _test_reporter.clear() - _test_reporter.println_message("GdUnit Test Client connected with id: %d" % client_id, Color.hex(0x9887c4)) - - -func _on_gdunit_client_disconnected(client_id: int) -> void: - _test_reporter.println_message("GdUnit Test Client disconnected with id: %d" % client_id, Color.hex(0x9887c4)) - - -func _on_gdunit_message(message: String) -> void: - _test_reporter.println_message(message, Color.CORNFLOWER_BLUE) diff --git a/addons/gdUnit4/src/ui/GdUnitConsole.gd.uid b/addons/gdUnit4/src/ui/GdUnitConsole.gd.uid deleted file mode 100644 index d2090024..00000000 --- a/addons/gdUnit4/src/ui/GdUnitConsole.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://sohxcxmk1j diff --git a/addons/gdUnit4/src/ui/GdUnitConsole.tscn b/addons/gdUnit4/src/ui/GdUnitConsole.tscn deleted file mode 100644 index c3c7e29f..00000000 --- a/addons/gdUnit4/src/ui/GdUnitConsole.tscn +++ /dev/null @@ -1,64 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://dm0wvfyeew7vd"] - -[ext_resource type="Script" path="res://addons/gdUnit4/src/ui/GdUnitConsole.gd" id="1"] - -[node name="Control" type="Control"] -use_parent_material = true -clip_contents = true -custom_minimum_size = Vector2(0, 200) -layout_mode = 3 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 -script = ExtResource("1") - -[node name="VBoxContainer" type="VBoxContainer" parent="."] -use_parent_material = true -clip_contents = true -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="Header" type="PanelContainer" parent="VBoxContainer"] -auto_translate_mode = 2 -custom_minimum_size = Vector2(0, 32) -layout_mode = 2 -localize_numeral_system = false -mouse_filter = 2 - -[node name="header_title" type="RichTextLabel" parent="VBoxContainer/Header"] -auto_translate_mode = 2 -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 -localize_numeral_system = false -mouse_filter = 2 -bbcode_enabled = true -scroll_active = false -autowrap_mode = 0 -shortcut_keys_enabled = false - -[node name="Console" type="ScrollContainer" parent="VBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="TextEdit" type="RichTextLabel" parent="VBoxContainer/Console"] -use_parent_material = true -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 -focus_mode = 2 -bbcode_enabled = true -scroll_following = true -context_menu_enabled = true -selection_enabled = true diff --git a/addons/gdUnit4/src/ui/GdUnitFonts.gd b/addons/gdUnit4/src/ui/GdUnitFonts.gd deleted file mode 100644 index 0cb0f5d5..00000000 --- a/addons/gdUnit4/src/ui/GdUnitFonts.gd +++ /dev/null @@ -1,36 +0,0 @@ -@tool -class_name GdUnitFonts -extends RefCounted - - -static func init_fonts(item: CanvasItem) -> float: - # set default size - item.set("theme_override_font_sizes/font_size", 16) - - if Engine.is_editor_hint(): - var base_control := EditorInterface.get_base_control() - # source modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs - # https://github.com/godotengine/godot/blob/9ee1873ae1e09c217ac24a5800007f63cb895615/editor/editor_log.cpp#L65 - var output_source_mono := base_control.get_theme_font("output_source_mono", "EditorFonts") - var output_source_bold_italic := base_control.get_theme_font("output_source_bold_italic", "EditorFonts") - var output_source_italic := base_control.get_theme_font("output_source_italic", "EditorFonts") - var output_source_bold := base_control.get_theme_font("output_source_bold", "EditorFonts") - var output_source := base_control.get_theme_font("output_source", "EditorFonts") - var settings := EditorInterface.get_editor_settings() - var scale_factor := EditorInterface.get_editor_scale() - var font_size: float = settings.get_setting("interface/editor/main_font_size") - - font_size *= scale_factor - item.set("theme_override_fonts/normal_font", output_source) - item.set("theme_override_fonts/bold_font", output_source_bold) - item.set("theme_override_fonts/italics_font", output_source_italic) - item.set("theme_override_fonts/bold_italics_font", output_source_bold_italic) - item.set("theme_override_fonts/mono_font", output_source_mono) - item.set("theme_override_font_sizes/font_size", font_size) - item.set("theme_override_font_sizes/normal_font_size", font_size) - item.set("theme_override_font_sizes/bold_font_size", font_size) - item.set("theme_override_font_sizes/italics_font_size", font_size) - item.set("theme_override_font_sizes/bold_italics_font_size", font_size) - item.set("theme_override_font_sizes/mono_font_size", font_size) - return font_size - return 16.0 diff --git a/addons/gdUnit4/src/ui/GdUnitFonts.gd.uid b/addons/gdUnit4/src/ui/GdUnitFonts.gd.uid deleted file mode 100644 index ae4a8839..00000000 --- a/addons/gdUnit4/src/ui/GdUnitFonts.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bmclcx5f2s1hx diff --git a/addons/gdUnit4/src/ui/GdUnitInspector.gd b/addons/gdUnit4/src/ui/GdUnitInspector.gd deleted file mode 100644 index a6d53f9b..00000000 --- a/addons/gdUnit4/src/ui/GdUnitInspector.gd +++ /dev/null @@ -1,31 +0,0 @@ -@tool -class_name GdUnitInspecor -extends Panel - - -var _command_handler := GdUnitCommandHandler.instance() - - -func _ready() -> void: - @warning_ignore("return_value_discarded") - GdUnitCommandHandler.instance().gdunit_runner_start.connect(func() -> void: - var control :Control = get_parent_control() - # if the tab is floating we dont need to set as current - if control is TabContainer: - var tab_container :TabContainer = control - for tab_index in tab_container.get_tab_count(): - if tab_container.get_tab_title(tab_index) == "GdUnit": - tab_container.set_current_tab(tab_index) - ) - - # propagete the test_counters_changed signal to the progress bar - @warning_ignore("unsafe_property_access", "unsafe_method_access") - %MainPanel.test_counters_changed.connect(%ProgressBar._on_test_counter_changed) - -func _process(_delta: float) -> void: - _command_handler._do_process() - - -@warning_ignore("redundant_await") -func _on_status_bar_request_discover_tests() -> void: - await _command_handler.cmd_discover_tests() diff --git a/addons/gdUnit4/src/ui/GdUnitInspector.gd.uid b/addons/gdUnit4/src/ui/GdUnitInspector.gd.uid deleted file mode 100644 index 0cecf540..00000000 --- a/addons/gdUnit4/src/ui/GdUnitInspector.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bf82ceb5733id diff --git a/addons/gdUnit4/src/ui/GdUnitInspector.tscn b/addons/gdUnit4/src/ui/GdUnitInspector.tscn deleted file mode 100644 index 2dcb9505..00000000 --- a/addons/gdUnit4/src/ui/GdUnitInspector.tscn +++ /dev/null @@ -1,71 +0,0 @@ -[gd_scene load_steps=8 format=3 uid="uid://mpo5o6d4uybu"] - -[ext_resource type="PackedScene" path="res://addons/gdUnit4/src/ui/parts/InspectorToolBar.tscn" id="1"] -[ext_resource type="PackedScene" path="res://addons/gdUnit4/src/ui/parts/InspectorProgressBar.tscn" id="2"] -[ext_resource type="PackedScene" path="res://addons/gdUnit4/src/ui/parts/InspectorStatusBar.tscn" id="3"] -[ext_resource type="PackedScene" path="res://addons/gdUnit4/src/ui/parts/InspectorMonitor.tscn" id="4"] -[ext_resource type="Script" path="res://addons/gdUnit4/src/ui/GdUnitInspector.gd" id="5"] -[ext_resource type="PackedScene" path="res://addons/gdUnit4/src/ui/parts/InspectorTreePanel.tscn" id="7"] -[ext_resource type="PackedScene" path="res://addons/gdUnit4/src/network/GdUnitServer.tscn" id="7_721no"] - -[node name="GdUnit" type="Panel"] -use_parent_material = true -clip_contents = true -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -size_flags_horizontal = 11 -size_flags_vertical = 3 -focus_mode = 2 -script = ExtResource("5") - -[node name="VBoxContainer" type="VBoxContainer" parent="."] -use_parent_material = true -clip_contents = true -layout_mode = 0 -anchor_right = 1.0 -anchor_bottom = 1.0 -size_flags_vertical = 11 -theme_override_constants/separation = 0 - -[node name="Header" type="VBoxContainer" parent="VBoxContainer"] -use_parent_material = true -clip_contents = true -layout_mode = 2 -size_flags_horizontal = 9 -size_flags_vertical = 0 - -[node name="ToolBar" parent="VBoxContainer/Header" instance=ExtResource("1")] -layout_mode = 2 -size_flags_vertical = 1 - -[node name="ProgressBar" parent="VBoxContainer/Header" instance=ExtResource("2")] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 5 -max_value = 0.0 - -[node name="StatusBar" parent="VBoxContainer/Header" instance=ExtResource("3")] -layout_mode = 2 -size_flags_horizontal = 11 - -[node name="MainPanel" parent="VBoxContainer" instance=ExtResource("7")] -unique_name_in_owner = true -layout_mode = 2 - -[node name="Monitor" parent="VBoxContainer" instance=ExtResource("4")] -layout_mode = 2 - -[node name="event_server" parent="." instance=ExtResource("7_721no")] - -[connection signal="request_discover_tests" from="VBoxContainer/Header/StatusBar" to="." method="_on_status_bar_request_discover_tests"] -[connection signal="select_error_next" from="VBoxContainer/Header/StatusBar" to="VBoxContainer/MainPanel" method="_on_select_next_item_by_state" binds= [7]] -[connection signal="select_error_prevous" from="VBoxContainer/Header/StatusBar" to="VBoxContainer/MainPanel" method="_on_select_previous_item_by_state" binds= [7]] -[connection signal="select_failure_next" from="VBoxContainer/Header/StatusBar" to="VBoxContainer/MainPanel" method="_on_select_next_item_by_state" binds= [6]] -[connection signal="select_failure_prevous" from="VBoxContainer/Header/StatusBar" to="VBoxContainer/MainPanel" method="_on_select_previous_item_by_state" binds= [6]] -[connection signal="select_flaky_next" from="VBoxContainer/Header/StatusBar" to="VBoxContainer/MainPanel" method="_on_select_next_item_by_state" binds= [5]] -[connection signal="select_flaky_prevous" from="VBoxContainer/Header/StatusBar" to="VBoxContainer/MainPanel" method="_on_select_previous_item_by_state" binds= [5]] -[connection signal="select_skipped_next" from="VBoxContainer/Header/StatusBar" to="VBoxContainer/MainPanel" method="_on_select_next_item_by_state" binds= [2]] -[connection signal="select_skipped_prevous" from="VBoxContainer/Header/StatusBar" to="VBoxContainer/MainPanel" method="_on_select_previous_item_by_state" binds= [2]] -[connection signal="tree_view_mode_changed" from="VBoxContainer/Header/StatusBar" to="VBoxContainer/MainPanel" method="_on_status_bar_tree_view_mode_changed"] -[connection signal="jump_to_orphan_nodes" from="VBoxContainer/Monitor" to="VBoxContainer/MainPanel" method="select_first_orphan"] diff --git a/addons/gdUnit4/src/ui/GdUnitInspectorTreeConstants.gd b/addons/gdUnit4/src/ui/GdUnitInspectorTreeConstants.gd deleted file mode 100644 index 8dd0265d..00000000 --- a/addons/gdUnit4/src/ui/GdUnitInspectorTreeConstants.gd +++ /dev/null @@ -1,31 +0,0 @@ -class_name GdUnitInspectorTreeConstants -extends RefCounted - - -# the inspector panel presantation -enum TREE_VIEW_MODE { - TREE, - FLAT -} - - -# The inspector sort modes -enum SORT_MODE { - UNSORTED, - NAME_ASCENDING, - NAME_DESCENDING, - EXECUTION_TIME -} - - -enum STATE { - INITIAL, - RUNNING, - SKIPPED, - SUCCESS, - WARNING, - FLAKY, - FAILED, - ERROR, - ABORDED, -} diff --git a/addons/gdUnit4/src/ui/GdUnitInspectorTreeConstants.gd.uid b/addons/gdUnit4/src/ui/GdUnitInspectorTreeConstants.gd.uid deleted file mode 100644 index 16a06986..00000000 --- a/addons/gdUnit4/src/ui/GdUnitInspectorTreeConstants.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://d11pldsm6rcbm diff --git a/addons/gdUnit4/src/ui/GdUnitUiTools.gd b/addons/gdUnit4/src/ui/GdUnitUiTools.gd deleted file mode 100644 index 0bcdb1d2..00000000 --- a/addons/gdUnit4/src/ui/GdUnitUiTools.gd +++ /dev/null @@ -1,151 +0,0 @@ -class_name GdUnitUiTools -extends RefCounted - - -static var _spinner: AnimatedTexture - - -enum ImageFlipMode { - HORIZONTAl, - VERITCAL -} - - -## Returns the icon by name, if it exists. -static func get_icon(icon_name: String, color: = Color.BLACK) -> Texture2D: - if not Engine.is_editor_hint(): - return null - var icon := EditorInterface.get_base_control().get_theme_icon(icon_name, "EditorIcons") - if icon == null: - return null - if color != Color.BLACK: - icon = _modulate_texture(icon, color) - return icon - - -## Returns the icon flipped -static func get_flipped_icon(icon_name: String, mode: = ImageFlipMode.HORIZONTAl) -> Texture2D: - if not Engine.is_editor_hint(): - return null - var icon := EditorInterface.get_base_control().get_theme_icon(icon_name, "EditorIcons") - if icon == null: - return null - return ImageTexture.create_from_image(_flip_image(icon, mode)) - - -static func get_spinner() -> AnimatedTexture: - if _spinner != null: - return _spinner - _spinner = AnimatedTexture.new() - _spinner.frames = 8 - _spinner.speed_scale = 2.5 - for frame in _spinner.frames: - _spinner.set_frame_texture(frame, get_icon("Progress%d" % (frame+1))) - _spinner.set_frame_duration(frame, 0.2) - return _spinner - - -static func get_color_animated_icon(icon_name :String, from :Color, to :Color) -> AnimatedTexture: - if not Engine.is_editor_hint(): - return null - var texture := AnimatedTexture.new() - texture.frames = 8 - texture.speed_scale = 2.5 - var color := from - for frame in texture.frames: - color = lerp(color, to, .2) - texture.set_frame_texture(frame, get_icon(icon_name, color)) - texture.set_frame_duration(frame, 0.2) - return texture - - -static func get_run_overall_icon() -> Texture2D: - if not Engine.is_editor_hint(): - return null - var icon := EditorInterface.get_base_control().get_theme_icon("Play", "EditorIcons") - var image := _merge_images(icon.get_image(), Vector2i(-2, 0), icon.get_image(), Vector2i(3, 0)) - return ImageTexture.create_from_image(image) - - -static func get_GDScript_icon(status: String, color: Color) -> Texture2D: - if not Engine.is_editor_hint(): - return null - var icon_a := EditorInterface.get_base_control().get_theme_icon("GDScript", "EditorIcons") - var icon_b := EditorInterface.get_base_control().get_theme_icon(status, "EditorIcons") - var overlay_image := _modulate_image(icon_b.get_image(), color) - var image := _merge_images_scaled(icon_a.get_image(), Vector2i(0, 0), overlay_image, Vector2i(5, 5)) - return ImageTexture.create_from_image(image) - - -static func get_CSharpScript_icon(status: String, color: Color) -> Texture2D: - if not Engine.is_editor_hint(): - return null - var icon_a := EditorInterface.get_base_control().get_theme_icon("CSharpScript", "EditorIcons") - var icon_b := EditorInterface.get_base_control().get_theme_icon(status, "EditorIcons") - var overlay_image := _modulate_image(icon_b.get_image(), color) - var image := _merge_images_scaled(icon_a.get_image(), Vector2i(0, 0), overlay_image, Vector2i(5, 5)) - return ImageTexture.create_from_image(image) - - -static func _modulate_texture(texture: Texture2D, color: Color) -> Texture2D: - var image := _modulate_image(texture.get_image(), color) - return ImageTexture.create_from_image(image) - - -static func _modulate_image(image: Image, color: Color) -> Image: - var data: PackedByteArray = image.data["data"] - for pixel in range(0, data.size(), 4): - var pixel_a := _to_color(data, pixel) - if pixel_a.a8 != 0: - pixel_a = pixel_a.lerp(color, .9) - data[pixel + 0] = pixel_a.r8 - data[pixel + 1] = pixel_a.g8 - data[pixel + 2] = pixel_a.b8 - data[pixel + 3] = pixel_a.a8 - var output_image := Image.new() - output_image.set_data(image.get_width(), image.get_height(), image.has_mipmaps(), image.get_format(), data) - return output_image - - -static func _merge_images(image1: Image, offset1: Vector2i, image2: Image, offset2: Vector2i) -> Image: - ## we need to fix the image to have the same size to avoid merge conflicts - if image1.get_height() < image2.get_height(): - image1.resize(image2.get_width(), image2.get_height()) - # Create a new Image for the merged result - var merged_image := Image.create(image1.get_width(), image1.get_height(), false, Image.FORMAT_RGBA8) - merged_image.blit_rect_mask(image1, image2, Rect2(Vector2.ZERO, image1.get_size()), offset1) - merged_image.blit_rect_mask(image1, image2, Rect2(Vector2.ZERO, image2.get_size()), offset2) - return merged_image - - -@warning_ignore("narrowing_conversion") -static func _merge_images_scaled(image1: Image, offset1: Vector2i, image2: Image, offset2: Vector2i) -> Image: - ## we need to fix the image to have the same size to avoid merge conflicts - if image1.get_height() < image2.get_height(): - image1.resize(image2.get_width(), image2.get_height()) - # Create a new Image for the merged result - var merged_image := Image.create(image1.get_width(), image1.get_height(), false, image1.get_format()) - merged_image.blend_rect(image1, Rect2(Vector2.ZERO, image1.get_size()), offset1) - @warning_ignore("narrowing_conversion") - image2.resize(image2.get_width()/1.3, image2.get_height()/1.3) - merged_image.blend_rect(image2, Rect2(Vector2.ZERO, image2.get_size()), offset2) - return merged_image - - -static func _flip_image(texture: Texture2D, mode: ImageFlipMode) -> Image: - var flipped_image := Image.new() - flipped_image.copy_from(texture.get_image()) - if mode == ImageFlipMode.VERITCAL: - flipped_image.flip_x() - else: - flipped_image.flip_y() - return flipped_image - - -static func _to_color(data: PackedByteArray, position: int) -> Color: - var pixel_a := Color() - pixel_a.r8 = data[position + 0] - pixel_a.g8 = data[position + 1] - pixel_a.b8 = data[position + 2] - pixel_a.a8 = data[position + 3] - return pixel_a diff --git a/addons/gdUnit4/src/ui/GdUnitUiTools.gd.uid b/addons/gdUnit4/src/ui/GdUnitUiTools.gd.uid deleted file mode 100644 index 5ddad466..00000000 --- a/addons/gdUnit4/src/ui/GdUnitUiTools.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dtcpngc82r2xb diff --git a/addons/gdUnit4/src/ui/ScriptEditorControls.gd b/addons/gdUnit4/src/ui/ScriptEditorControls.gd deleted file mode 100644 index 5e07fe15..00000000 --- a/addons/gdUnit4/src/ui/ScriptEditorControls.gd +++ /dev/null @@ -1,100 +0,0 @@ -# A tool to provide extended script editor functionallity -class_name ScriptEditorControls -extends RefCounted - -# https://github.com/godotengine/godot/blob/master/editor/plugins/script_editor_plugin.h -# the Editor menu popup items -enum { - FILE_NEW, - FILE_NEW_TEXTFILE, - FILE_OPEN, - FILE_REOPEN_CLOSED, - FILE_OPEN_RECENT, - FILE_SAVE, - FILE_SAVE_AS, - FILE_SAVE_ALL, - FILE_THEME, - FILE_RUN, - FILE_CLOSE, - CLOSE_DOCS, - CLOSE_ALL, - CLOSE_OTHER_TABS, - TOGGLE_SCRIPTS_PANEL, - SHOW_IN_FILE_SYSTEM, - FILE_COPY_PATH, - FILE_TOOL_RELOAD_SOFT, - SEARCH_IN_FILES, - REPLACE_IN_FILES, - SEARCH_HELP, - SEARCH_WEBSITE, - HELP_SEARCH_FIND, - HELP_SEARCH_FIND_NEXT, - HELP_SEARCH_FIND_PREVIOUS, - WINDOW_MOVE_UP, - WINDOW_MOVE_DOWN, - WINDOW_NEXT, - WINDOW_PREV, - WINDOW_SORT, - WINDOW_SELECT_BASE = 100 -} - - -# Saves the given script and closes if requested by -# The script is saved when is opened in the editor. -# The script is closed when is set to true. -static func save_an_open_script(script_path: String, close:=false) -> bool: - #prints("save_an_open_script", script_path, close) - if !Engine.is_editor_hint(): - return false - var editor := EditorInterface.get_script_editor() - var editor_popup := _menu_popup() - # search for the script in all opened editor scrips - for open_script in editor.get_open_scripts(): - if open_script.resource_path == script_path: - # select the script in the editor - EditorInterface.edit_script(open_script, 0); - # save and close - editor_popup.id_pressed.emit(FILE_SAVE) - if close: - editor_popup.id_pressed.emit(FILE_CLOSE) - return true - return false - - -# Saves all opened script -static func save_all_open_script() -> void: - if Engine.is_editor_hint(): - _menu_popup().id_pressed.emit(FILE_SAVE_ALL) - - -static func close_open_editor_scripts() -> void: - if Engine.is_editor_hint(): - _menu_popup().id_pressed.emit(CLOSE_ALL) - - -# Edits the given script. -# The script is openend in the current editor and selected in the file system dock. -# The line and column on which to open the script can also be specified. -# The script will be open with the user-configured editor for the script's language which may be an external editor. -static func edit_script(script_path: String, line_number := -1) -> void: - var file_system := EditorInterface.get_resource_filesystem() - file_system.update_file(script_path) - var file_system_dock := EditorInterface.get_file_system_dock() - file_system_dock.navigate_to_path(script_path) - EditorInterface.select_file(script_path) - var script: GDScript = load(script_path) - EditorInterface.edit_script(script, line_number) - - -static func _menu_popup() -> PopupMenu: - @warning_ignore("unsafe_method_access") - return EditorInterface.get_script_editor().get_child(0).get_child(0).get_child(0).get_popup() - - -static func _print_menu(popup: PopupMenu) -> void: - for itemIndex in popup.item_count: - prints("get_item_id", popup.get_item_id(itemIndex)) - prints("get_item_accelerator", popup.get_item_accelerator(itemIndex)) - prints("get_item_shortcut", popup.get_item_shortcut(itemIndex)) - prints("get_item_text", popup.get_item_text(itemIndex)) - prints() diff --git a/addons/gdUnit4/src/ui/ScriptEditorControls.gd.uid b/addons/gdUnit4/src/ui/ScriptEditorControls.gd.uid deleted file mode 100644 index c5864627..00000000 --- a/addons/gdUnit4/src/ui/ScriptEditorControls.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://gpsfvph81sx8 diff --git a/addons/gdUnit4/src/ui/menu/EditorFileSystemContextMenuHandler.gd b/addons/gdUnit4/src/ui/menu/EditorFileSystemContextMenuHandler.gd deleted file mode 100644 index 044b9efc..00000000 --- a/addons/gdUnit4/src/ui/menu/EditorFileSystemContextMenuHandler.gd +++ /dev/null @@ -1,79 +0,0 @@ -@tool -extends Control - -var _context_menus := Dictionary() -var _command_handler := GdUnitCommandHandler.instance() - - -func _init() -> void: - set_name("EditorFileSystemContextMenuHandler") - - var is_test_suite := func is_visible(script: Script, is_ts: bool) -> bool: - if script == null: - return false - return GdUnitTestSuiteScanner.is_test_suite(script) == is_ts - var context_menus :Array[GdUnitContextMenuItem] = [ - GdUnitContextMenuItem.new(GdUnitContextMenuItem.MENU_ID.TEST_RUN, "Run Testsuites", "Play", is_test_suite.bind(true), _command_handler.command(GdUnitCommandHandler.CMD_RUN_TESTSUITE)), - GdUnitContextMenuItem.new(GdUnitContextMenuItem.MENU_ID.TEST_DEBUG, "Debug Testsuites", "PlayStart", is_test_suite.bind(true), _command_handler.command(GdUnitCommandHandler.CMD_RUN_TESTSUITE_DEBUG)), - ] - for menu in context_menus: - _context_menus[menu.id] = menu - var popup := _menu_popup() - var file_tree := _file_tree() - @warning_ignore("return_value_discarded") - popup.about_to_popup.connect(on_context_menu_show.bind(popup, file_tree)) - @warning_ignore("return_value_discarded") - popup.id_pressed.connect(on_context_menu_pressed.bind(file_tree)) - - -func on_context_menu_show(context_menu: PopupMenu, file_tree: Tree) -> void: - context_menu.add_separator() - var current_index := context_menu.get_item_count() - - for menu_id: int in _context_menus.keys(): - var menu_item: GdUnitContextMenuItem = _context_menus[menu_id] - - context_menu.add_item(menu_item.name, menu_id) - #context_menu.set_item_icon_modulate(current_index, Color.MEDIUM_PURPLE) - context_menu.set_item_disabled(current_index, !menu_item.is_enabled(null)) - context_menu.set_item_icon(current_index, GdUnitUiTools.get_icon(menu_item.icon)) - current_index += 1 - - -func on_context_menu_pressed(id: int, file_tree: Tree) -> void: - if !_context_menus.has(id): - return - var menu_item: GdUnitContextMenuItem = _context_menus[id] - var test_suites := collect_testsuites(menu_item, file_tree) - - menu_item.execute([test_suites]) - - -func collect_testsuites(_menu_item: GdUnitContextMenuItem, file_tree: Tree) -> Array[Script]: - var file_system := EditorInterface.get_resource_filesystem() - var selected_item := file_tree.get_selected() - var selected_test_suites: Array[Script] = [] - var suite_scaner := GdUnitTestSuiteScanner.new() - - while selected_item: - var resource_path: String = selected_item.get_metadata(0) - var file_type := file_system.get_file_type(resource_path) - var is_dir := DirAccess.dir_exists_absolute(resource_path) - if is_dir: - selected_test_suites.append_array(suite_scaner.scan_directory(resource_path)) - elif is_dir or file_type == "GDScript" or file_type == "CSharpScript": - # find a performant way to check if the selected item a testsuite - var resource: Script = ResourceLoader.load(resource_path, "Script", ResourceLoader.CACHE_MODE_REUSE) - if _menu_item.is_visible(resource): - @warning_ignore("return_value_discarded") - selected_test_suites.append(resource) - selected_item = file_tree.get_next_selected(selected_item) - return selected_test_suites - - -func _file_tree() -> Tree: - return GdObjects.find_nodes_by_class(EditorInterface.get_file_system_dock(), "Tree", true)[-1] - - -func _menu_popup() -> PopupMenu: - return GdObjects.find_nodes_by_class(EditorInterface.get_file_system_dock(), "PopupMenu")[-1] diff --git a/addons/gdUnit4/src/ui/menu/EditorFileSystemContextMenuHandler.gd.uid b/addons/gdUnit4/src/ui/menu/EditorFileSystemContextMenuHandler.gd.uid deleted file mode 100644 index d50bd88d..00000000 --- a/addons/gdUnit4/src/ui/menu/EditorFileSystemContextMenuHandler.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://njdp45y5pnap diff --git a/addons/gdUnit4/src/ui/menu/EditorFileSystemContextMenuHandlerV44.gdx b/addons/gdUnit4/src/ui/menu/EditorFileSystemContextMenuHandlerV44.gdx deleted file mode 100644 index 108450e5..00000000 --- a/addons/gdUnit4/src/ui/menu/EditorFileSystemContextMenuHandlerV44.gdx +++ /dev/null @@ -1,47 +0,0 @@ -@tool -extends EditorContextMenuPlugin - -var _context_menus := Dictionary() -var _command_handler := GdUnitCommandHandler.instance() - - -func _init() -> void: - var is_test_suite := func is_visible(script: Script, is_ts: bool) -> bool: - if script == null: - return false - return GdUnitTestSuiteScanner.is_test_suite(script) == is_ts - _context_menus[GdUnitContextMenuItem.MENU_ID.TEST_RUN] = GdUnitContextMenuItem.new(GdUnitContextMenuItem.MENU_ID.TEST_RUN, "Run Testsuites", "Play", is_test_suite.bind(true), _command_handler.command(GdUnitCommandHandler.CMD_RUN_TESTSUITE)) - _context_menus[GdUnitContextMenuItem.MENU_ID.TEST_DEBUG] = GdUnitContextMenuItem.new(GdUnitContextMenuItem.MENU_ID.TEST_DEBUG, "Debug Testsuites", "PlayStart", is_test_suite.bind(true), _command_handler.command(GdUnitCommandHandler.CMD_RUN_TESTSUITE_DEBUG)) - - # setup shortcuts - for menu_item: GdUnitContextMenuItem in _context_menus.values(): - var cb := func call(files: Array) -> void: - menu_item.execute([files]) - add_menu_shortcut(menu_item.shortcut(), cb) - - -func _popup_menu(paths: PackedStringArray) -> void: - var test_suites: Array[Script] = [] - var suite_scaner := GdUnitTestSuiteScanner.new() - - for resource_path in paths: - # directories and test-suites are valid to enable the menu - if DirAccess.dir_exists_absolute(resource_path): - test_suites.append_array(suite_scaner.scan_directory(resource_path)) - continue - - var file_type := resource_path.get_extension() - if file_type == "gd" or file_type == "cs": - var script: Script = ResourceLoader.load(resource_path, "Script", ResourceLoader.CACHE_MODE_REUSE) - if GdUnitTestSuiteScanner.is_test_suite(script): - test_suites.append(script) - - # no direcory or test-suites selected? - if test_suites.is_empty(): - return - - for menu_item: GdUnitContextMenuItem in _context_menus.values(): - @warning_ignore("unused_parameter") - var cb := func call(files: Array) -> void: - menu_item.execute([test_suites]) - add_context_menu_item(menu_item.name, cb, GdUnitUiTools.get_icon(menu_item.icon)) diff --git a/addons/gdUnit4/src/ui/menu/GdUnitContextMenuItem.gd b/addons/gdUnit4/src/ui/menu/GdUnitContextMenuItem.gd deleted file mode 100644 index 2f89c61e..00000000 --- a/addons/gdUnit4/src/ui/menu/GdUnitContextMenuItem.gd +++ /dev/null @@ -1,69 +0,0 @@ -class_name GdUnitContextMenuItem - -enum MENU_ID { - UNDEFINED = 0, - TEST_RUN = 1000, - TEST_DEBUG = 1001, - TEST_RERUN = 1002, - CREATE_TEST = 1010, -} - -var id: MENU_ID = MENU_ID.UNDEFINED: - set(value): - id = value - get: - return id - -var name: StringName: - set(value): - name = value - get: - return name - -var command: GdUnitCommand: - set(value): - command = value - get: - return command - -var visible: Callable: - set(value): - visible = value - get: - return visible - -var icon: String: - set(value): - icon = value - get: - return icon - - -func _init(p_id: MENU_ID, p_name: StringName, p_icon :String, p_is_visible: Callable, p_command: GdUnitCommand) -> void: - assert(p_id != null, "(%s) missing parameter 'MENU_ID'" % p_name) - assert(p_is_visible != null, "(%s) missing parameter 'GdUnitCommand'" % p_name) - assert(p_command != null, "(%s) missing parameter 'GdUnitCommand'" % p_name) - self.id = p_id - self.name = p_name - self.icon = p_icon - self.command = p_command - self.visible = p_is_visible - - -func shortcut() -> Shortcut: - return GdUnitCommandHandler.instance().get_shortcut(command.shortcut) - - -func is_enabled(script: Script) -> bool: - return command.is_enabled.call(script) - - -func is_visible(script: Script) -> bool: - return visible.call(script) - - -func execute(arguments:=[]) -> void: - if arguments.is_empty(): - command.runnable.call() - else: - command.runnable.callv(arguments) diff --git a/addons/gdUnit4/src/ui/menu/GdUnitContextMenuItem.gd.uid b/addons/gdUnit4/src/ui/menu/GdUnitContextMenuItem.gd.uid deleted file mode 100644 index 855f4797..00000000 --- a/addons/gdUnit4/src/ui/menu/GdUnitContextMenuItem.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bla1g2ce6t53i diff --git a/addons/gdUnit4/src/ui/menu/ScriptEditorContextMenuHandler.gd b/addons/gdUnit4/src/ui/menu/ScriptEditorContextMenuHandler.gd deleted file mode 100644 index 550c6d61..00000000 --- a/addons/gdUnit4/src/ui/menu/ScriptEditorContextMenuHandler.gd +++ /dev/null @@ -1,81 +0,0 @@ -@tool -extends Control - -var _context_menus := Dictionary() -var _editor: ScriptEditor -var _command_handler := GdUnitCommandHandler.instance() - - -func _init() -> void: - set_name("ScriptEditorContextMenuHandler") - - var is_test_suite := func is_visible(script: Script, is_ts: bool) -> bool: - return GdUnitTestSuiteScanner.is_test_suite(script) == is_ts - var context_menus :Array[GdUnitContextMenuItem] = [ - GdUnitContextMenuItem.new(GdUnitContextMenuItem.MENU_ID.TEST_RUN, "Run Tests", "Play", is_test_suite.bind(true), _command_handler.command(GdUnitCommandHandler.CMD_RUN_TESTCASE)), - GdUnitContextMenuItem.new(GdUnitContextMenuItem.MENU_ID.TEST_DEBUG, "Debug Tests", "PlayStart", is_test_suite.bind(true), _command_handler.command(GdUnitCommandHandler.CMD_RUN_TESTCASE_DEBUG)), - GdUnitContextMenuItem.new(GdUnitContextMenuItem.MENU_ID.CREATE_TEST, "Create Test", "New", is_test_suite.bind(false), _command_handler.command(GdUnitCommandHandler.CMD_CREATE_TESTCASE)) - ] - for menu in context_menus: - _context_menus[menu.id] = menu - _editor = EditorInterface.get_script_editor() - @warning_ignore("return_value_discarded") - _editor.editor_script_changed.connect(on_script_changed) - on_script_changed(active_script()) - - -func _input(event: InputEvent) -> void: - if event is InputEventKey and event.is_pressed(): - for action: GdUnitContextMenuItem in _context_menus.values(): - if action.shortcut().matches_event(event) and action.is_visible(active_script()): - #if not has_editor_focus(): - # return - action.execute() - accept_event() - return - - -func has_editor_focus() -> bool: - return (Engine.get_main_loop() as SceneTree).root.gui_get_focus_owner() == active_base_editor() - - -func on_script_changed(script: Script) -> void: - if script is Script: - var popups: Array[Node] = GdObjects.find_nodes_by_class(active_editor(), "PopupMenu", true) - for popup: PopupMenu in popups: - if not popup.about_to_popup.is_connected(on_context_menu_show): - popup.about_to_popup.connect(on_context_menu_show.bind(script, popup)) - if not popup.id_pressed.is_connected(on_context_menu_pressed): - popup.id_pressed.connect(on_context_menu_pressed) - - -func on_context_menu_show(script: Script, context_menu: PopupMenu) -> void: - #prints("on_context_menu_show", _context_menus.keys(), context_menu, self) - context_menu.add_separator() - var current_index := context_menu.get_item_count() - for menu_id: int in _context_menus.keys(): - var menu_item: GdUnitContextMenuItem = _context_menus[menu_id] - if menu_item.is_visible(script): - context_menu.add_item(menu_item.name, menu_id) - context_menu.set_item_disabled(current_index, !menu_item.is_enabled(script)) - context_menu.set_item_shortcut(current_index, menu_item.shortcut(), true) - current_index += 1 - - -func on_context_menu_pressed(id: int) -> void: - if !_context_menus.has(id): - return - var menu_item: GdUnitContextMenuItem = _context_menus[id] - menu_item.execute() - - -func active_editor() -> ScriptEditorBase: - return _editor.get_current_editor() - - -func active_base_editor() -> TextEdit: - return active_editor().get_base_editor() - - -func active_script() -> Script: - return _editor.get_current_script() diff --git a/addons/gdUnit4/src/ui/menu/ScriptEditorContextMenuHandler.gd.uid b/addons/gdUnit4/src/ui/menu/ScriptEditorContextMenuHandler.gd.uid deleted file mode 100644 index 8f0e9e84..00000000 --- a/addons/gdUnit4/src/ui/menu/ScriptEditorContextMenuHandler.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cy5cblh8psm0a diff --git a/addons/gdUnit4/src/ui/menu/ScriptEditorContextMenuHandlerV44.gdx b/addons/gdUnit4/src/ui/menu/ScriptEditorContextMenuHandlerV44.gdx deleted file mode 100644 index a879e378..00000000 --- a/addons/gdUnit4/src/ui/menu/ScriptEditorContextMenuHandlerV44.gdx +++ /dev/null @@ -1,33 +0,0 @@ -@tool -extends EditorContextMenuPlugin - -var _context_menus := Dictionary() -var _editor: ScriptEditor -var _command_handler := GdUnitCommandHandler.instance() - - -func _init() -> void: - var is_test_suite := func is_visible(script: Script, is_ts: bool) -> bool: - return GdUnitTestSuiteScanner.is_test_suite(script) == is_ts - var context_menus :Array[GdUnitContextMenuItem] = [ - GdUnitContextMenuItem.new(GdUnitContextMenuItem.MENU_ID.TEST_RUN, "Run Tests", "Play", is_test_suite.bind(true), _command_handler.command(GdUnitCommandHandler.CMD_RUN_TESTCASE)), - GdUnitContextMenuItem.new(GdUnitContextMenuItem.MENU_ID.TEST_DEBUG, "Debug Tests", "PlayStart", is_test_suite.bind(true), _command_handler.command(GdUnitCommandHandler.CMD_RUN_TESTCASE_DEBUG)), - GdUnitContextMenuItem.new(GdUnitContextMenuItem.MENU_ID.CREATE_TEST, "Create Test", "New", is_test_suite.bind(false), _command_handler.command(GdUnitCommandHandler.CMD_CREATE_TESTCASE)) - ] - for menu in context_menus: - _context_menus[menu.id] = menu - _editor = EditorInterface.get_script_editor() - @warning_ignore("return_value_discarded") - - -func _popup_menu(paths: PackedStringArray) -> void: - var script_path := paths[0] - var script: Script = ResourceLoader.load(script_path, "Script", ResourceLoader.CACHE_MODE_REUSE) - - for menu_id: int in _context_menus.keys(): - var menu_item: GdUnitContextMenuItem = _context_menus[menu_id] - if menu_item.is_visible(script): - add_context_menu_item(menu_item.name, - func call(files: Array) -> void: - menu_item.execute([script_path]), - GdUnitUiTools.get_icon(menu_item.icon)) diff --git a/addons/gdUnit4/src/ui/parts/InspectorMonitor.gd b/addons/gdUnit4/src/ui/parts/InspectorMonitor.gd deleted file mode 100644 index c36b3ecb..00000000 --- a/addons/gdUnit4/src/ui/parts/InspectorMonitor.gd +++ /dev/null @@ -1,54 +0,0 @@ -@tool -extends PanelContainer - -signal jump_to_orphan_nodes() - -@onready var ICON_GREEN := GdUnitUiTools.get_icon("Unlinked", Color.WEB_GREEN) -@onready var ICON_RED := GdUnitUiTools.get_color_animated_icon("Unlinked", Color.YELLOW, Color.ORANGE_RED) - -@onready var _button_time: Button = %btn_time -@onready var _time: Label = %time_value -@onready var _orphans: Label = %orphan_value -@onready var _orphan_button: Button = %btn_orphan - -var total_elapsed_time := 0 -var total_orphans := 0 - - -func _ready() -> void: - @warning_ignore("return_value_discarded") - GdUnitSignals.instance().gdunit_event.connect(_on_gdunit_event) - _time.text = "" - _orphans.text = "0" - _button_time.icon = GdUnitUiTools.get_icon("Time") - _orphan_button.icon = ICON_GREEN - - -func status_changed(elapsed_time: int, orphan_nodes: int) -> void: - total_elapsed_time += elapsed_time - total_orphans += orphan_nodes - _time.text = LocalTime.elapsed(total_elapsed_time) - _orphans.text = str(total_orphans) - if total_orphans > 0: - _orphan_button.icon = ICON_RED - - -func _on_gdunit_event(event: GdUnitEvent) -> void: - match event.type(): - GdUnitEvent.INIT: - _orphan_button.icon = ICON_GREEN - total_elapsed_time = 0 - total_orphans = 0 - status_changed(0, 0) - GdUnitEvent.TESTCASE_BEFORE: - pass - GdUnitEvent.TESTCASE_AFTER: - status_changed(0, event.orphan_nodes()) - GdUnitEvent.TESTSUITE_BEFORE: - pass - GdUnitEvent.TESTSUITE_AFTER: - status_changed(event.elapsed_time(), event.orphan_nodes()) - - -func _on_ToolButton_pressed() -> void: - jump_to_orphan_nodes.emit() diff --git a/addons/gdUnit4/src/ui/parts/InspectorMonitor.gd.uid b/addons/gdUnit4/src/ui/parts/InspectorMonitor.gd.uid deleted file mode 100644 index 93762004..00000000 --- a/addons/gdUnit4/src/ui/parts/InspectorMonitor.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bor3tq32bx7ss diff --git a/addons/gdUnit4/src/ui/parts/InspectorMonitor.tscn b/addons/gdUnit4/src/ui/parts/InspectorMonitor.tscn deleted file mode 100644 index 0262b8cd..00000000 --- a/addons/gdUnit4/src/ui/parts/InspectorMonitor.tscn +++ /dev/null @@ -1,94 +0,0 @@ -[gd_scene load_steps=6 format=3 uid="uid://djp8ait0bxpsc"] - -[ext_resource type="Script" path="res://addons/gdUnit4/src/ui/parts/InspectorMonitor.gd" id="3"] - -[sub_resource type="Image" id="Image_sx31i"] -data = { -"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 4, 227, 227, 227, 36, 227, 227, 227, 36, 255, 255, 255, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 131, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 5, 225, 225, 225, 76, 224, 224, 224, 255, 224, 224, 224, 255, 226, 226, 226, 77, 255, 255, 255, 5, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 99, 224, 224, 224, 232, 224, 224, 224, 244, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 244, 224, 224, 224, 233, 224, 224, 224, 97, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 135, 224, 224, 224, 247, 224, 224, 224, 115, 234, 234, 234, 12, 224, 224, 224, 130, 224, 224, 224, 130, 234, 234, 234, 12, 225, 225, 225, 116, 224, 224, 224, 248, 224, 224, 224, 132, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 226, 226, 226, 77, 224, 224, 224, 251, 224, 224, 224, 64, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 66, 224, 224, 224, 252, 225, 225, 225, 75, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 201, 224, 224, 224, 146, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 2, 224, 224, 224, 146, 224, 224, 224, 106, 255, 255, 255, 0, 225, 225, 225, 150, 224, 224, 224, 195, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 24, 224, 224, 224, 255, 226, 226, 226, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 233, 233, 233, 23, 225, 225, 225, 166, 224, 224, 224, 237, 228, 228, 228, 47, 255, 255, 255, 0, 225, 225, 225, 51, 224, 224, 224, 255, 224, 224, 224, 16, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 67, 224, 224, 224, 255, 225, 225, 225, 215, 227, 227, 227, 9, 255, 255, 255, 0, 255, 255, 255, 0, 223, 223, 223, 239, 224, 224, 224, 253, 224, 224, 224, 49, 255, 255, 255, 0, 230, 230, 230, 30, 224, 224, 224, 230, 224, 224, 224, 255, 224, 224, 224, 49, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 41, 224, 224, 224, 255, 225, 225, 225, 101, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 139, 224, 224, 224, 139, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 5, 225, 225, 225, 117, 224, 224, 224, 255, 224, 224, 224, 33, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 6, 224, 224, 224, 240, 226, 226, 226, 87, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 96, 224, 224, 224, 236, 255, 255, 255, 3, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 143, 224, 224, 224, 211, 224, 224, 224, 8, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 232, 232, 232, 11, 224, 224, 224, 216, 225, 225, 225, 141, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 238, 238, 238, 15, 224, 224, 224, 220, 224, 224, 224, 178, 238, 238, 238, 15, 255, 255, 255, 0, 225, 225, 225, 51, 225, 225, 225, 51, 255, 255, 255, 0, 227, 227, 227, 18, 224, 224, 224, 184, 224, 224, 224, 218, 238, 238, 238, 15, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 36, 224, 224, 224, 212, 224, 224, 224, 232, 225, 225, 225, 133, 224, 224, 224, 251, 224, 224, 224, 240, 225, 225, 225, 135, 224, 224, 224, 234, 224, 224, 224, 208, 225, 225, 225, 34, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 230, 230, 230, 10, 224, 224, 224, 107, 224, 224, 224, 197, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 196, 224, 224, 224, 104, 224, 224, 224, 8, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_ugpqy"] -image = SubResource("Image_sx31i") - -[sub_resource type="Image" id="Image_gkq5u"] -data = { -"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 22, 138, 22, 251, 255, 255, 255, 0, 255, 255, 255, 0, 22, 138, 22, 234, 22, 138, 22, 247, 22, 138, 22, 253, 22, 138, 22, 253, 22, 138, 22, 247, 22, 138, 22, 233, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 22, 138, 22, 251, 22, 138, 22, 236, 255, 255, 255, 0, 22, 138, 22, 255, 255, 255, 255, 0, 23, 138, 23, 233, 22, 138, 22, 254, 22, 138, 22, 255, 22, 138, 22, 255, 22, 138, 22, 255, 22, 138, 22, 255, 22, 138, 22, 253, 23, 138, 23, 233, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 22, 138, 22, 236, 22, 138, 22, 253, 22, 138, 22, 236, 22, 138, 22, 251, 255, 255, 255, 0, 22, 138, 22, 247, 22, 138, 22, 255, 22, 138, 22, 248, 22, 138, 22, 233, 23, 138, 23, 233, 22, 138, 22, 249, 22, 138, 22, 255, 22, 138, 22, 246, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 22, 138, 22, 236, 22, 138, 22, 251, 255, 255, 255, 0, 255, 255, 255, 0, 22, 138, 22, 249, 22, 138, 22, 253, 23, 138, 23, 232, 255, 255, 255, 0, 255, 255, 255, 0, 22, 138, 22, 234, 22, 138, 22, 255, 22, 138, 22, 253, 255, 255, 255, 0, 255, 255, 255, 0, 22, 138, 22, 251, 22, 138, 22, 255, 22, 138, 22, 251, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 24, 139, 24, 231, 23, 138, 23, 231, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 23, 138, 23, 234, 22, 138, 22, 255, 22, 138, 22, 253, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 23, 138, 23, 231, 23, 138, 23, 234, 22, 138, 22, 249, 22, 138, 22, 255, 22, 138, 22, 246, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 23, 138, 23, 233, 22, 138, 22, 247, 22, 138, 22, 249, 24, 139, 24, 231, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 23, 138, 23, 245, 22, 138, 22, 255, 22, 138, 22, 255, 22, 138, 22, 255, 22, 138, 22, 253, 23, 138, 23, 233, 255, 255, 255, 0, 255, 255, 255, 0, 22, 138, 22, 234, 22, 138, 22, 254, 22, 138, 22, 255, 22, 138, 22, 253, 23, 138, 23, 231, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 23, 138, 23, 241, 22, 138, 22, 253, 22, 138, 22, 253, 22, 138, 22, 246, 22, 138, 22, 233, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 22, 138, 22, 247, 22, 138, 22, 255, 22, 138, 22, 248, 23, 138, 23, 232, 255, 255, 255, 0, 255, 255, 255, 0, 23, 138, 23, 245, 23, 138, 23, 241, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 22, 138, 22, 253, 22, 138, 22, 255, 22, 138, 22, 233, 255, 255, 255, 0, 255, 255, 255, 0, 23, 138, 23, 231, 22, 138, 22, 255, 22, 138, 22, 253, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 22, 138, 22, 253, 22, 138, 22, 255, 23, 138, 23, 233, 255, 255, 255, 0, 255, 255, 255, 0, 23, 138, 23, 234, 22, 138, 22, 255, 22, 138, 22, 253, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 22, 138, 22, 247, 22, 138, 22, 255, 22, 138, 22, 249, 22, 138, 22, 234, 23, 138, 23, 234, 22, 138, 22, 249, 22, 138, 22, 255, 22, 138, 22, 246, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 22, 138, 22, 233, 22, 138, 22, 253, 22, 138, 22, 255, 22, 138, 22, 255, 22, 138, 22, 255, 22, 138, 22, 255, 22, 138, 22, 253, 22, 138, 22, 233, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 23, 138, 23, 233, 22, 138, 22, 246, 22, 138, 22, 253, 22, 138, 22, 253, 22, 138, 22, 246, 23, 138, 23, 233, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_nj5du"] -image = SubResource("Image_gkq5u") - -[node name="Monitor" type="PanelContainer"] -clip_contents = true -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_right = -793.0 -offset_bottom = -564.0 -size_flags_horizontal = 9 -size_flags_vertical = 9 -script = ExtResource("3") - -[node name="HBoxContainer" type="HBoxContainer" parent="."] -layout_mode = 2 -size_flags_vertical = 4 - -[node name="timer" type="HBoxContainer" parent="HBoxContainer"] -layout_mode = 2 - -[node name="btn_time" type="Button" parent="HBoxContainer/timer"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 4 -auto_translate = false -localize_numeral_system = false -tooltip_text = "Shows the total elapsed time of test execution." -mouse_force_pass_scroll_events = false -button_mask = 0 -shortcut_feedback = false -shortcut_in_tooltip = false -text = "Time" -icon = SubResource("ImageTexture_ugpqy") -flat = true - -[node name="time_value" type="Label" parent="HBoxContainer/timer"] -unique_name_in_owner = true -use_parent_material = true -layout_mode = 2 -size_flags_horizontal = 3 -auto_translate = false -localize_numeral_system = false -max_lines_visible = 1 - -[node name="orphan" type="HBoxContainer" parent="HBoxContainer/timer"] -layout_mode = 2 - -[node name="btn_orphan" type="Button" parent="HBoxContainer/timer/orphan"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 4 -auto_translate = false -localize_numeral_system = false -tooltip_text = "Shows the total orphan nodes detected." -text = "Orphans" -icon = SubResource("ImageTexture_nj5du") - -[node name="orphan_value" type="Label" parent="HBoxContainer/timer/orphan"] -unique_name_in_owner = true -use_parent_material = true -layout_mode = 2 -size_flags_horizontal = 3 -auto_translate = false -localize_numeral_system = false -text = "0" -max_lines_visible = 1 diff --git a/addons/gdUnit4/src/ui/parts/InspectorProgressBar.gd b/addons/gdUnit4/src/ui/parts/InspectorProgressBar.gd deleted file mode 100644 index d368ed3f..00000000 --- a/addons/gdUnit4/src/ui/parts/InspectorProgressBar.gd +++ /dev/null @@ -1,49 +0,0 @@ -@tool -extends ProgressBar - - -@onready var status: Label = $Label -@onready var style: StyleBoxFlat = get("theme_override_styles/fill") - -var _state: GdUnitInspectorTreeConstants.STATE - -func _ready() -> void: - style.bg_color = Color.DARK_GREEN - value = 0 - max_value = 0 - update_text() - - -func update_text() -> void: - status.text = "%d:%d" % [value, max_value] - - -func _on_test_counter_changed(index: int, total: int, state: GdUnitInspectorTreeConstants.STATE) -> void: - value = index - max_value = total - update_text() - - # inital state - if index == 0: - style.bg_color = Color.DARK_GREEN - - # do only update the state is higher prio than current state - if state <= _state: - return - _state = state - - if is_flaky(state): - style.bg_color = Color.WEB_GREEN - if is_failed(state): - style.bg_color = Color.DARK_RED - - -func is_failed(state: GdUnitInspectorTreeConstants.STATE) -> bool: - return state in [ - GdUnitInspectorTreeConstants.STATE.FAILED, - GdUnitInspectorTreeConstants.STATE.ERROR, - GdUnitInspectorTreeConstants.STATE.ABORDED] - - -func is_flaky(state: GdUnitInspectorTreeConstants.STATE) -> bool: - return state == GdUnitInspectorTreeConstants.STATE.FLAKY diff --git a/addons/gdUnit4/src/ui/parts/InspectorProgressBar.gd.uid b/addons/gdUnit4/src/ui/parts/InspectorProgressBar.gd.uid deleted file mode 100644 index 32e2c281..00000000 --- a/addons/gdUnit4/src/ui/parts/InspectorProgressBar.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cs8fqgtcum3s5 diff --git a/addons/gdUnit4/src/ui/parts/InspectorProgressBar.tscn b/addons/gdUnit4/src/ui/parts/InspectorProgressBar.tscn deleted file mode 100644 index 1824230a..00000000 --- a/addons/gdUnit4/src/ui/parts/InspectorProgressBar.tscn +++ /dev/null @@ -1,33 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://dva3tonxsxrlk"] - -[ext_resource type="Script" path="res://addons/gdUnit4/src/ui/parts/InspectorProgressBar.gd" id="1"] - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ayfir"] -bg_color = Color(0, 0.392157, 0, 1) - -[node name="ProgressBar" type="ProgressBar"] -custom_minimum_size = Vector2(0, 20) -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -size_flags_vertical = 9 -theme_override_styles/fill = SubResource("StyleBoxFlat_ayfir") -rounded = true -allow_greater = true -show_percentage = false -script = ExtResource("1") - -[node name="Label" type="Label" parent="."] -use_parent_material = true -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -size_flags_vertical = 3 -horizontal_alignment = 1 -vertical_alignment = 1 -max_lines_visible = 1 diff --git a/addons/gdUnit4/src/ui/parts/InspectorStatusBar.gd b/addons/gdUnit4/src/ui/parts/InspectorStatusBar.gd deleted file mode 100644 index dfed5204..00000000 --- a/addons/gdUnit4/src/ui/parts/InspectorStatusBar.gd +++ /dev/null @@ -1,216 +0,0 @@ -@tool -extends PanelContainer - -signal select_failure_next() -signal select_failure_prevous() -signal select_error_next() -signal select_error_prevous() -signal select_flaky_next() -signal select_flaky_prevous() -signal select_skipped_next() -signal select_skipped_prevous() -signal request_discover_tests() - -@warning_ignore("unused_signal") -signal tree_view_mode_changed(flat :bool) - -@onready var _errors: Label = %error_value -@onready var _failures: Label = %failure_value -@onready var _flaky_value: Label = %flaky_value -@onready var _skipped_value: Label = %skipped_value -#@onready var _button_failure_up: Button = %btn_failure_up -#@onready var _button_failure_down: Button = %btn_failure_down -@onready var _button_sync: Button = %btn_tree_sync -@onready var _button_view_mode: MenuButton = %btn_tree_mode -@onready var _button_sort_mode: MenuButton = %btn_tree_sort - -@onready var _icon_errors: TextureRect = %icon_errors -@onready var _icon_failures: TextureRect = %icon_failures -@onready var _icon_flaky: TextureRect = %icon_flaky -@onready var _icon_skipped: TextureRect = %icon_skipped - -var total_failed := 0 -var total_errors := 0 -var total_flaky := 0 -var total_skipped := 0 - - -var icon_mappings := { - # tree sort modes - 0x100 + GdUnitInspectorTreeConstants.SORT_MODE.UNSORTED : GdUnitUiTools.get_icon("TripleBar"), - 0x100 + GdUnitInspectorTreeConstants.SORT_MODE.NAME_ASCENDING : GdUnitUiTools.get_icon("Sort"), - 0x100 + GdUnitInspectorTreeConstants.SORT_MODE.NAME_DESCENDING : GdUnitUiTools.get_flipped_icon("Sort"), - 0x100 + GdUnitInspectorTreeConstants.SORT_MODE.EXECUTION_TIME : GdUnitUiTools.get_icon("History"), - # tree view modes - 0x200 + GdUnitInspectorTreeConstants.TREE_VIEW_MODE.TREE : GdUnitUiTools.get_icon("Tree", Color.GHOST_WHITE), - 0x200 + GdUnitInspectorTreeConstants.TREE_VIEW_MODE.FLAT : GdUnitUiTools.get_icon("AnimationTrackGroup", Color.GHOST_WHITE) -} - - -@warning_ignore("return_value_discarded") -func _ready() -> void: - _failures.text = "0" - _errors.text = "0" - _flaky_value.text = "0" - _skipped_value.text = "0" - _icon_failures.texture = GdUnitUiTools.get_icon("StatusError", Color.SKY_BLUE) - _icon_errors.texture = GdUnitUiTools.get_icon("StatusError", Color.DARK_RED) - _icon_flaky.texture = GdUnitUiTools.get_icon("CheckBox", Color.GREEN_YELLOW) - _icon_skipped.texture = GdUnitUiTools.get_icon("CheckBox", Color.WEB_GRAY) - - #_button_failure_up.icon = GdUnitUiTools.get_icon("ArrowUp") - #_button_failure_down.icon = GdUnitUiTools.get_icon("ArrowDown") - _button_sync.icon = GdUnitUiTools.get_icon("Loop") - _set_sort_mode_menu_options() - _set_view_mode_menu_options() - GdUnitSignals.instance().gdunit_event.connect(_on_gdunit_event) - GdUnitSignals.instance().gdunit_settings_changed.connect(_on_settings_changed) - var command_handler := GdUnitCommandHandler.instance() - command_handler.gdunit_runner_start.connect(_on_gdunit_runner_start) - command_handler.gdunit_runner_stop.connect(_on_gdunit_runner_stop) - - - -func _set_sort_mode_menu_options() -> void: - _button_sort_mode.icon = GdUnitUiTools.get_icon("Sort") - # construct context sort menu according to the available modes - var context_menu :PopupMenu = _button_sort_mode.get_popup() - context_menu.clear() - - if not context_menu.index_pressed.is_connected(_on_sort_mode_changed): - @warning_ignore("return_value_discarded") - context_menu.index_pressed.connect(_on_sort_mode_changed) - - var configured_sort_mode := GdUnitSettings.get_inspector_tree_sort_mode() - for sort_mode: String in GdUnitInspectorTreeConstants.SORT_MODE.keys(): - var enum_value :int = GdUnitInspectorTreeConstants.SORT_MODE.get(sort_mode) - var icon :Texture2D = icon_mappings[0x100 + enum_value] - context_menu.add_icon_check_item(icon, normalise(sort_mode), enum_value) - context_menu.set_item_checked(enum_value, configured_sort_mode == enum_value) - - -func _set_view_mode_menu_options() -> void: - _button_view_mode.icon = GdUnitUiTools.get_icon("Tree", Color.GHOST_WHITE) - # construct context tree view menu according to the available modes - var context_menu :PopupMenu = _button_view_mode.get_popup() - context_menu.clear() - - if not context_menu.index_pressed.is_connected(_on_tree_view_mode_changed): - @warning_ignore("return_value_discarded") - context_menu.index_pressed.connect(_on_tree_view_mode_changed) - - var configured_tree_view_mode := GdUnitSettings.get_inspector_tree_view_mode() - for tree_view_mode: String in GdUnitInspectorTreeConstants.TREE_VIEW_MODE.keys(): - var enum_value :int = GdUnitInspectorTreeConstants.TREE_VIEW_MODE.get(tree_view_mode) - var icon :Texture2D = icon_mappings[0x200 + enum_value] - context_menu.add_icon_check_item(icon, normalise(tree_view_mode), enum_value) - context_menu.set_item_checked(enum_value, configured_tree_view_mode == enum_value) - - -func normalise(value: String) -> String: - var parts := value.to_lower().split("_") - parts[0] = parts[0].capitalize() - return " ".join(parts) - - -func status_changed(errors: int, failed: int, flaky: int, skipped: int) -> void: - total_failed += failed - total_errors += errors - total_flaky += flaky - total_skipped += skipped - _failures.text = str(total_failed) - _errors.text = str(total_errors) - _flaky_value.text = str(total_flaky) - _skipped_value.text = str(total_skipped) - - -func disable_buttons(value :bool) -> void: - _button_sync.set_disabled(value) - _button_sort_mode.set_disabled(value) - _button_view_mode.set_disabled(value) - - -func _on_gdunit_event(event: GdUnitEvent) -> void: - match event.type(): - GdUnitEvent.DISCOVER_START: - disable_buttons(true) - - GdUnitEvent.DISCOVER_END: - disable_buttons(false) - - GdUnitEvent.INIT: - total_errors = 0 - total_failed = 0 - total_flaky = 0 - total_skipped = 0 - status_changed(total_errors, total_failed, total_flaky, total_skipped) - - GdUnitEvent.TESTCASE_AFTER: - status_changed(event.error_count(), event.failed_count(), event.is_flaky(), event.is_skipped()) - - GdUnitEvent.TESTSUITE_AFTER: - status_changed(event.error_count(), event.failed_count(), event.is_flaky(), 0) - - -func _on_btn_error_up_pressed() -> void: - select_error_prevous.emit() - - -func _on_btn_error_down_pressed() -> void: - select_error_next.emit() - - -func _on_failure_up_pressed() -> void: - select_failure_prevous.emit() - - -func _on_failure_down_pressed() -> void: - select_failure_next.emit() - - -func _on_btn_flaky_up_pressed() -> void: - select_flaky_prevous.emit() - - -func _on_btn_flaky_down_pressed() -> void: - select_flaky_next.emit() - - -func _on_btn_skipped_up_pressed() -> void: - select_skipped_prevous.emit() - - -func _on_btn_skipped_down_pressed() -> void: - select_skipped_next.emit() - - -func _on_tree_sync_pressed() -> void: - request_discover_tests.emit() - - -func _on_sort_mode_changed(index: int) -> void: - var selected_sort_mode :GdUnitInspectorTreeConstants.SORT_MODE = GdUnitInspectorTreeConstants.SORT_MODE.values()[index] - GdUnitSettings.set_inspector_tree_sort_mode(selected_sort_mode) - - -func _on_tree_view_mode_changed(index: int) ->void: - var selected_tree_mode :GdUnitInspectorTreeConstants.TREE_VIEW_MODE = GdUnitInspectorTreeConstants.TREE_VIEW_MODE.values()[index] - GdUnitSettings.set_inspector_tree_view_mode(selected_tree_mode) - - -################################################################################ -# external signal receiver -################################################################################ -func _on_gdunit_runner_start() -> void: - disable_buttons(true) - - -func _on_gdunit_runner_stop(_client_id: int) -> void: - disable_buttons(false) - - -func _on_settings_changed(property :GdUnitProperty) -> void: - if property.name() == GdUnitSettings.INSPECTOR_TREE_SORT_MODE: - _set_sort_mode_menu_options() - if property.name() == GdUnitSettings.INSPECTOR_TREE_VIEW_MODE: - _set_view_mode_menu_options() diff --git a/addons/gdUnit4/src/ui/parts/InspectorStatusBar.gd.uid b/addons/gdUnit4/src/ui/parts/InspectorStatusBar.gd.uid deleted file mode 100644 index b0245bed..00000000 --- a/addons/gdUnit4/src/ui/parts/InspectorStatusBar.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bhkahqvjp7rto diff --git a/addons/gdUnit4/src/ui/parts/InspectorStatusBar.tscn b/addons/gdUnit4/src/ui/parts/InspectorStatusBar.tscn deleted file mode 100644 index baf6a9fb..00000000 --- a/addons/gdUnit4/src/ui/parts/InspectorStatusBar.tscn +++ /dev/null @@ -1,477 +0,0 @@ -[gd_scene load_steps=30 format=3 uid="uid://c22l4odk7qesc"] - -[ext_resource type="Script" path="res://addons/gdUnit4/src/ui/parts/InspectorStatusBar.gd" id="3"] - -[sub_resource type="Image" id="Image_mb3ih"] -data = { -"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 160, 230, 230, 230, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 213, 225, 225, 225, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 225, 225, 75, 224, 224, 224, 188, 224, 224, 224, 238, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 245, 224, 224, 224, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 225, 225, 133, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 245, 226, 226, 226, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 226, 226, 226, 77, 224, 224, 224, 255, 224, 224, 224, 253, 225, 225, 225, 117, 224, 224, 224, 32, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 212, 225, 225, 225, 42, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 129, 226, 226, 226, 70, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 189, 224, 224, 224, 255, 224, 224, 224, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 225, 225, 159, 230, 230, 230, 10, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 73, 224, 224, 224, 255, 224, 224, 224, 185, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 242, 224, 224, 224, 255, 224, 224, 224, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 225, 225, 25, 224, 224, 224, 255, 224, 224, 224, 238, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 243, 224, 224, 224, 254, 233, 233, 233, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 229, 229, 229, 29, 224, 224, 224, 255, 224, 224, 224, 236, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 189, 224, 224, 224, 255, 225, 225, 225, 68, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 10, 224, 224, 224, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 121, 224, 224, 224, 255, 224, 224, 224, 181, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 72, 224, 224, 224, 121, 0, 0, 0, 0, 0, 0, 0, 0, 226, 226, 226, 43, 224, 224, 224, 213, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 227, 227, 227, 36, 225, 225, 225, 124, 224, 224, 224, 254, 224, 224, 224, 255, 226, 226, 226, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 96, 224, 224, 224, 245, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 226, 226, 226, 95, 224, 224, 224, 245, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 237, 224, 224, 224, 185, 226, 226, 226, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 225, 225, 42, 224, 224, 224, 213, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 10, 225, 225, 225, 159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_wo03e"] -image = SubResource("Image_mb3ih") - -[sub_resource type="Image" id="Image_ixycx"] -data = { -"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 233, 233, 233, 23, 224, 224, 224, 198, 224, 224, 224, 201, 224, 224, 224, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 233, 233, 233, 23, 224, 224, 224, 213, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 215, 224, 224, 224, 24, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 196, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 171, 224, 224, 224, 195, 224, 224, 224, 253, 224, 224, 224, 255, 224, 224, 224, 195, 225, 225, 225, 175, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 252, 224, 224, 224, 255, 255, 255, 255, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 252, 224, 224, 224, 255, 255, 255, 255, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 252, 224, 224, 224, 255, 255, 255, 255, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 252, 224, 224, 224, 255, 255, 255, 255, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 252, 224, 224, 224, 255, 255, 255, 255, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 252, 224, 224, 224, 255, 255, 255, 255, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 176, 224, 224, 224, 200, 224, 224, 224, 253, 224, 224, 224, 255, 225, 225, 225, 199, 224, 224, 224, 179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 194, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 197, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231, 231, 231, 21, 224, 224, 224, 210, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 212, 232, 232, 232, 22, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231, 231, 231, 21, 224, 224, 224, 194, 224, 224, 224, 196, 232, 232, 232, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_c80wp"] -image = SubResource("Image_ixycx") - -[sub_resource type="Image" id="Image_eis20"] -data = { -"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_t2qd7"] -image = SubResource("Image_eis20") - -[sub_resource type="Image" id="Image_jh28t"] -data = { -"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231, 231, 231, 21, 224, 224, 224, 194, 224, 224, 224, 196, 232, 232, 232, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231, 231, 231, 21, 224, 224, 224, 210, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 212, 232, 232, 232, 22, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 194, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 197, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 176, 224, 224, 224, 200, 224, 224, 224, 253, 224, 224, 224, 255, 225, 225, 225, 199, 224, 224, 224, 179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 252, 224, 224, 224, 255, 255, 255, 255, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 252, 224, 224, 224, 255, 255, 255, 255, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 252, 224, 224, 224, 255, 255, 255, 255, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 252, 224, 224, 224, 255, 255, 255, 255, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 252, 224, 224, 224, 255, 255, 255, 255, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 252, 224, 224, 224, 255, 255, 255, 255, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 171, 224, 224, 224, 195, 224, 224, 224, 253, 224, 224, 224, 255, 224, 224, 224, 195, 225, 225, 225, 175, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 196, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 233, 233, 233, 23, 224, 224, 224, 213, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 215, 224, 224, 224, 24, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 233, 233, 233, 23, 224, 224, 224, 198, 224, 224, 224, 201, 224, 224, 224, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_1mh1t"] -image = SubResource("Image_jh28t") - -[sub_resource type="Image" id="Image_lpjla"] -data = { -"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 3, 224, 224, 224, 105, 224, 224, 224, 192, 224, 224, 224, 244, 224, 224, 224, 238, 224, 224, 224, 197, 224, 224, 224, 105, 255, 255, 255, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 233, 233, 233, 23, 225, 225, 225, 207, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 198, 226, 226, 226, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 6, 224, 224, 224, 205, 224, 224, 224, 255, 224, 224, 224, 218, 225, 225, 225, 83, 237, 237, 237, 14, 237, 237, 237, 14, 224, 224, 224, 82, 224, 224, 224, 220, 224, 224, 224, 255, 224, 224, 224, 197, 255, 255, 255, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 225, 225, 102, 224, 224, 224, 255, 224, 224, 224, 218, 227, 227, 227, 18, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 224, 224, 224, 16, 224, 224, 224, 221, 224, 224, 224, 255, 225, 225, 225, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 198, 224, 224, 224, 255, 225, 225, 225, 84, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 226, 226, 226, 86, 224, 224, 224, 255, 224, 224, 224, 194, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 1, 255, 255, 255, 4, 224, 224, 224, 238, 224, 224, 224, 255, 227, 227, 227, 18, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 229, 229, 229, 19, 224, 224, 224, 255, 224, 224, 224, 233, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 160, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 159, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 230, 230, 230, 20, 224, 224, 224, 255, 224, 224, 224, 237, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 10, 224, 224, 224, 213, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 212, 230, 230, 230, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 90, 224, 224, 224, 255, 224, 224, 224, 185, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 225, 225, 42, 224, 224, 224, 245, 224, 224, 224, 245, 225, 225, 225, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 232, 232, 22, 224, 224, 224, 224, 224, 224, 224, 255, 224, 224, 224, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 96, 226, 226, 226, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 20, 224, 224, 224, 88, 224, 224, 224, 221, 224, 224, 224, 255, 225, 225, 225, 199, 255, 255, 255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 200, 227, 227, 227, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 236, 224, 224, 224, 195, 224, 224, 224, 96, 255, 255, 255, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_bq8kn"] -image = SubResource("Image_lpjla") - -[sub_resource type="Image" id="Image_bwbka"] -data = { -"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 248, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 248, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_8lbfl"] -image = SubResource("Image_bwbka") - -[sub_resource type="Image" id="Image_ki3oo"] -data = { -"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 248, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 237, 247, 245, 248, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 237, 247, 245, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_ivm1h"] -image = SubResource("Image_ki3oo") - -[sub_resource type="Image" id="Image_uqb0l"] -data = { -"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 249, 249, 255, 230, 246, 246, 252, 230, 249, 249, 255, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 246, 246, 252, 237, 246, 246, 252, 255, 246, 246, 252, 248, 0, 0, 0, 0, 246, 246, 252, 254, 246, 246, 252, 255, 246, 246, 252, 255, 246, 246, 252, 255, 246, 246, 252, 255, 246, 246, 252, 255, 246, 246, 252, 255, 246, 246, 252, 255, 246, 246, 252, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 246, 246, 252, 236, 246, 246, 252, 254, 246, 246, 252, 247, 0, 0, 0, 0, 246, 246, 252, 254, 246, 246, 252, 255, 246, 246, 252, 255, 246, 246, 252, 255, 246, 246, 252, 255, 246, 246, 252, 255, 246, 246, 252, 255, 246, 246, 252, 255, 246, 246, 252, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 246, 246, 253, 231, 246, 246, 253, 232, 246, 246, 252, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 246, 246, 252, 243, 246, 246, 252, 255, 246, 246, 252, 242, 246, 246, 252, 230, 246, 246, 252, 255, 246, 246, 252, 255, 246, 246, 252, 255, 246, 246, 252, 255, 246, 246, 252, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 246, 246, 252, 242, 246, 246, 252, 253, 246, 246, 252, 241, 246, 246, 252, 230, 246, 246, 252, 255, 246, 246, 252, 255, 246, 246, 252, 255, 246, 246, 252, 255, 246, 246, 252, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 246, 246, 252, 244, 246, 246, 252, 255, 246, 246, 252, 241, 246, 246, 252, 230, 246, 246, 252, 255, 246, 246, 252, 255, 246, 246, 252, 255, 246, 246, 252, 255, 246, 246, 252, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 246, 246, 252, 244, 246, 246, 252, 255, 246, 246, 252, 241, 246, 246, 252, 230, 246, 246, 252, 255, 246, 246, 252, 255, 246, 246, 252, 255, 246, 246, 252, 255, 246, 246, 252, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_j00vj"] -image = SubResource("Image_uqb0l") - -[sub_resource type="Image" id="Image_0oden"] -data = { -"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 151, 12, 11, 232, 151, 12, 11, 242, 151, 12, 11, 250, 151, 12, 11, 254, 151, 12, 11, 254, 151, 12, 11, 250, 151, 12, 11, 242, 151, 12, 10, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 151, 12, 10, 238, 151, 12, 11, 254, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 253, 151, 12, 11, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 151, 12, 11, 237, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 254, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 254, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 10, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 151, 12, 10, 232, 151, 12, 11, 253, 151, 12, 11, 255, 151, 12, 11, 240, 151, 12, 10, 234, 151, 12, 11, 253, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 253, 151, 12, 11, 234, 151, 12, 11, 241, 151, 12, 11, 255, 151, 12, 11, 253, 151, 11, 10, 232, 0, 0, 0, 0, 0, 0, 0, 0, 151, 12, 11, 242, 151, 12, 11, 255, 151, 12, 11, 254, 151, 12, 10, 234, 0, 0, 0, 0, 151, 12, 10, 234, 151, 12, 11, 253, 151, 12, 11, 253, 151, 12, 11, 234, 0, 0, 0, 0, 151, 12, 11, 234, 151, 12, 11, 254, 151, 12, 11, 255, 151, 12, 11, 241, 0, 0, 0, 0, 0, 0, 0, 0, 151, 12, 11, 250, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 253, 151, 12, 10, 234, 0, 0, 0, 0, 151, 12, 10, 234, 151, 12, 10, 234, 0, 0, 0, 0, 151, 12, 11, 234, 151, 12, 11, 253, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 250, 0, 0, 0, 0, 0, 0, 0, 0, 151, 12, 11, 254, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 253, 151, 12, 10, 234, 0, 0, 0, 0, 0, 0, 0, 0, 151, 12, 11, 234, 151, 12, 11, 253, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 253, 0, 0, 0, 0, 0, 0, 0, 0, 151, 12, 11, 254, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 253, 151, 12, 10, 234, 0, 0, 0, 0, 0, 0, 0, 0, 151, 12, 10, 234, 151, 12, 11, 253, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 253, 0, 0, 0, 0, 0, 0, 0, 0, 151, 12, 11, 250, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 253, 151, 12, 11, 234, 0, 0, 0, 0, 151, 12, 11, 234, 151, 12, 10, 234, 0, 0, 0, 0, 151, 12, 11, 234, 151, 12, 11, 253, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 250, 0, 0, 0, 0, 0, 0, 0, 0, 151, 12, 11, 242, 151, 12, 11, 255, 151, 12, 11, 254, 151, 12, 11, 234, 0, 0, 0, 0, 151, 12, 11, 234, 151, 12, 11, 253, 151, 12, 11, 253, 151, 12, 11, 234, 0, 0, 0, 0, 151, 12, 11, 234, 151, 12, 11, 254, 151, 12, 11, 255, 151, 12, 10, 241, 0, 0, 0, 0, 0, 0, 0, 0, 151, 12, 10, 232, 151, 12, 11, 253, 151, 12, 11, 255, 151, 12, 11, 241, 151, 12, 11, 234, 151, 12, 11, 253, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 253, 151, 12, 11, 234, 151, 12, 11, 241, 151, 12, 11, 255, 151, 12, 11, 253, 151, 11, 10, 231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 151, 12, 11, 237, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 254, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 254, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 151, 12, 11, 237, 151, 12, 11, 253, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 255, 151, 12, 11, 253, 151, 12, 11, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 151, 12, 11, 232, 151, 12, 11, 242, 151, 12, 11, 250, 151, 12, 11, 253, 151, 12, 11, 253, 151, 12, 11, 250, 151, 12, 11, 241, 151, 11, 10, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_suo5c"] -image = SubResource("Image_0oden") - -[sub_resource type="Image" id="Image_ipq44"] -data = { -"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 231, 231, 231, 21, 224, 224, 224, 255, 224, 224, 224, 255, 231, 231, 231, 21, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 231, 231, 231, 21, 224, 224, 224, 211, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 210, 231, 231, 231, 21, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 231, 231, 231, 21, 224, 224, 224, 211, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 210, 231, 231, 231, 21, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 231, 231, 231, 21, 224, 224, 224, 211, 224, 224, 224, 255, 224, 224, 224, 210, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 210, 224, 224, 224, 255, 224, 224, 224, 210, 231, 231, 231, 21, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 195, 224, 224, 224, 255, 224, 224, 224, 210, 230, 230, 230, 20, 224, 224, 224, 255, 224, 224, 224, 255, 231, 231, 231, 21, 224, 224, 224, 210, 224, 224, 224, 255, 224, 224, 224, 194, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 178, 224, 224, 224, 194, 230, 230, 230, 20, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 231, 231, 231, 21, 224, 224, 224, 194, 224, 224, 224, 179, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 180, 224, 224, 224, 180, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_1oriu"] -image = SubResource("Image_ipq44") - -[sub_resource type="Image" id="Image_d5kq4"] -data = { -"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 181, 224, 224, 224, 180, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 180, 224, 224, 224, 195, 231, 231, 231, 21, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 231, 231, 231, 21, 224, 224, 224, 195, 224, 224, 224, 178, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 195, 224, 224, 224, 255, 224, 224, 224, 210, 231, 231, 231, 21, 224, 224, 224, 255, 224, 224, 224, 255, 231, 231, 231, 21, 224, 224, 224, 211, 224, 224, 224, 255, 224, 224, 224, 194, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 231, 231, 231, 21, 224, 224, 224, 210, 224, 224, 224, 255, 224, 224, 224, 210, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 211, 224, 224, 224, 255, 224, 224, 224, 210, 230, 230, 230, 20, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 231, 231, 231, 21, 224, 224, 224, 210, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 210, 230, 230, 230, 20, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 231, 231, 231, 21, 224, 224, 224, 210, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 210, 230, 230, 230, 20, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 231, 231, 231, 21, 224, 224, 224, 255, 224, 224, 224, 255, 230, 230, 230, 20, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_ikyhk"] -image = SubResource("Image_d5kq4") - -[sub_resource type="Image" id="Image_8d0da"] -data = { -"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 198, 223, 232, 147, 197, 222, 242, 147, 197, 222, 250, 147, 197, 222, 254, 147, 197, 222, 254, 147, 197, 222, 250, 147, 197, 222, 242, 147, 197, 222, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 197, 222, 238, 147, 197, 222, 254, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 253, 147, 197, 222, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 198, 222, 237, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 254, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 254, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 197, 222, 232, 147, 197, 222, 253, 147, 197, 222, 255, 147, 197, 222, 240, 147, 198, 222, 234, 147, 197, 222, 253, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 253, 147, 198, 222, 234, 147, 197, 222, 241, 147, 197, 222, 255, 147, 197, 222, 253, 147, 197, 222, 232, 0, 0, 0, 0, 0, 0, 0, 0, 147, 197, 222, 242, 147, 197, 222, 255, 147, 197, 222, 254, 147, 198, 222, 234, 0, 0, 0, 0, 147, 198, 222, 234, 147, 197, 222, 253, 147, 197, 222, 253, 147, 197, 222, 234, 0, 0, 0, 0, 147, 197, 222, 234, 147, 197, 222, 254, 147, 197, 222, 255, 147, 197, 222, 241, 0, 0, 0, 0, 0, 0, 0, 0, 147, 197, 222, 250, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 253, 147, 198, 222, 234, 0, 0, 0, 0, 147, 198, 222, 234, 147, 198, 222, 234, 0, 0, 0, 0, 147, 197, 222, 234, 147, 197, 222, 253, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 250, 0, 0, 0, 0, 0, 0, 0, 0, 147, 197, 222, 254, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 253, 147, 198, 222, 234, 0, 0, 0, 0, 0, 0, 0, 0, 147, 197, 222, 234, 147, 197, 222, 253, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 253, 0, 0, 0, 0, 0, 0, 0, 0, 147, 197, 222, 254, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 253, 147, 198, 222, 234, 0, 0, 0, 0, 0, 0, 0, 0, 147, 198, 222, 234, 147, 197, 222, 253, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 253, 0, 0, 0, 0, 0, 0, 0, 0, 147, 197, 222, 250, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 253, 147, 197, 222, 234, 0, 0, 0, 0, 147, 197, 222, 234, 147, 198, 222, 234, 0, 0, 0, 0, 147, 197, 222, 234, 147, 197, 222, 253, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 250, 0, 0, 0, 0, 0, 0, 0, 0, 147, 197, 222, 242, 147, 197, 222, 255, 147, 197, 222, 254, 147, 198, 222, 234, 0, 0, 0, 0, 147, 197, 222, 234, 147, 197, 222, 253, 147, 197, 222, 253, 147, 197, 222, 234, 0, 0, 0, 0, 147, 197, 222, 234, 147, 197, 222, 254, 147, 197, 222, 255, 147, 197, 222, 241, 0, 0, 0, 0, 0, 0, 0, 0, 147, 197, 222, 232, 147, 197, 222, 253, 147, 197, 222, 255, 147, 197, 222, 241, 147, 197, 222, 234, 147, 197, 222, 253, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 253, 147, 197, 222, 234, 147, 197, 222, 241, 147, 197, 222, 255, 147, 197, 222, 253, 147, 197, 221, 231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 198, 222, 237, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 254, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 254, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 197, 222, 237, 147, 197, 222, 253, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 255, 147, 197, 222, 253, 147, 197, 222, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 198, 222, 232, 147, 197, 222, 242, 147, 197, 222, 250, 147, 197, 222, 253, 147, 197, 222, 253, 147, 197, 222, 250, 147, 197, 222, 241, 147, 197, 222, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_qagbu"] -image = SubResource("Image_8d0da") - -[sub_resource type="Image" id="Image_oy0ff"] -data = { -"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, 253, 57, 237, 170, 253, 57, 252, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 254, 58, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, 253, 57, 252, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 254, 58, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, 253, 57, 255, 170, 253, 57, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, 253, 58, 234, 170, 253, 57, 247, 171, 255, 57, 231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, 253, 57, 255, 170, 253, 57, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, 253, 58, 234, 170, 253, 57, 253, 170, 253, 57, 255, 170, 254, 57, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, 253, 57, 255, 170, 253, 57, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, 253, 58, 234, 170, 253, 57, 253, 170, 253, 57, 255, 170, 254, 57, 247, 171, 255, 58, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, 253, 57, 255, 170, 253, 57, 255, 0, 0, 0, 0, 0, 0, 0, 0, 170, 254, 58, 232, 170, 254, 57, 232, 0, 0, 0, 0, 170, 253, 58, 234, 170, 253, 57, 253, 170, 253, 57, 255, 170, 254, 57, 247, 171, 255, 58, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, 253, 57, 255, 170, 253, 57, 255, 0, 0, 0, 0, 170, 254, 58, 232, 170, 253, 57, 251, 170, 253, 57, 251, 170, 254, 58, 236, 170, 253, 57, 253, 170, 253, 57, 255, 170, 254, 57, 247, 171, 255, 58, 230, 0, 0, 0, 0, 170, 254, 58, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, 253, 57, 255, 170, 253, 57, 255, 0, 0, 0, 0, 170, 254, 57, 232, 170, 253, 57, 251, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 254, 57, 247, 171, 255, 58, 230, 0, 0, 0, 0, 170, 254, 58, 242, 170, 253, 57, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, 253, 57, 255, 170, 253, 57, 255, 0, 0, 0, 0, 0, 0, 0, 0, 170, 254, 57, 232, 170, 253, 57, 251, 170, 253, 57, 255, 170, 254, 57, 247, 171, 255, 58, 230, 0, 0, 0, 0, 0, 0, 0, 0, 170, 253, 57, 255, 170, 253, 57, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, 253, 57, 255, 170, 253, 57, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, 254, 57, 232, 170, 253, 57, 244, 171, 255, 58, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, 253, 57, 255, 170, 253, 57, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, 253, 57, 255, 170, 253, 57, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, 253, 57, 255, 170, 253, 57, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, 253, 57, 252, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, 254, 57, 237, 170, 253, 57, 252, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 255, 170, 253, 57, 252, 170, 254, 57, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_a4rkr"] -image = SubResource("Image_oy0ff") - -[sub_resource type="Image" id="Image_iahim"] -data = { -"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 139, 130, 237, 129, 139, 130, 252, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 139, 130, 252, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 139, 130, 255, 129, 139, 130, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 139, 131, 234, 129, 139, 130, 247, 130, 141, 130, 231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 139, 130, 255, 129, 139, 130, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 139, 131, 234, 129, 139, 130, 253, 129, 139, 130, 255, 129, 139, 130, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 139, 130, 255, 129, 139, 130, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 139, 131, 234, 129, 139, 130, 253, 129, 139, 130, 255, 129, 139, 130, 247, 131, 141, 131, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 139, 130, 255, 129, 139, 130, 255, 0, 0, 0, 0, 0, 0, 0, 0, 130, 140, 131, 232, 129, 140, 130, 232, 0, 0, 0, 0, 129, 139, 131, 234, 129, 139, 130, 253, 129, 139, 130, 255, 129, 139, 130, 247, 131, 141, 131, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 139, 130, 255, 129, 139, 130, 255, 0, 0, 0, 0, 130, 140, 131, 232, 129, 139, 130, 251, 129, 139, 130, 251, 129, 139, 130, 236, 129, 139, 130, 253, 129, 139, 130, 255, 129, 139, 130, 247, 131, 141, 131, 230, 0, 0, 0, 0, 129, 139, 130, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 139, 130, 255, 129, 139, 130, 255, 0, 0, 0, 0, 129, 140, 130, 232, 129, 139, 130, 251, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 247, 131, 141, 131, 230, 0, 0, 0, 0, 129, 139, 130, 242, 129, 139, 130, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 139, 130, 255, 129, 139, 130, 255, 0, 0, 0, 0, 0, 0, 0, 0, 130, 140, 130, 232, 129, 139, 130, 251, 129, 139, 130, 255, 129, 139, 130, 247, 131, 141, 131, 230, 0, 0, 0, 0, 0, 0, 0, 0, 129, 139, 130, 255, 129, 139, 130, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 139, 130, 255, 129, 139, 130, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 140, 130, 232, 129, 139, 130, 244, 131, 141, 131, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 139, 130, 255, 129, 139, 130, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 139, 130, 255, 129, 139, 130, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 139, 130, 255, 129, 139, 130, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 139, 130, 252, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 139, 130, 237, 129, 139, 130, 252, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 255, 129, 139, 130, 252, 129, 139, 130, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_idt7c"] -image = SubResource("Image_iahim") - -[node name="StatusBar" type="PanelContainer"] -clip_contents = true -anchors_preset = 10 -anchor_right = 1.0 -offset_right = -807.0 -offset_bottom = 31.0 -grow_horizontal = 2 -size_flags_horizontal = 3 -size_flags_vertical = 0 -script = ExtResource("3") - -[node name="VBoxContainer" type="VBoxContainer" parent="."] -layout_mode = 2 -size_flags_vertical = 0 - -[node name="tree_tools" type="HBoxContainer" parent="VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 0 - -[node name="Label" type="Label" parent="VBoxContainer/tree_tools"] -layout_mode = 2 -size_flags_horizontal = 0 -text = "Statistics" - -[node name="tree_buttons" type="HBoxContainer" parent="VBoxContainer/tree_tools"] -layout_mode = 2 -size_flags_horizontal = 10 -size_flags_vertical = 4 -alignment = 2 - -[node name="VSeparator" type="VSeparator" parent="VBoxContainer/tree_tools/tree_buttons"] -layout_mode = 2 - -[node name="btn_tree_sync" type="Button" parent="VBoxContainer/tree_tools/tree_buttons"] -unique_name_in_owner = true -layout_mode = 2 -tooltip_text = "Run discover tests." -icon = SubResource("ImageTexture_wo03e") - -[node name="btn_tree_sort" type="MenuButton" parent="VBoxContainer/tree_tools/tree_buttons"] -unique_name_in_owner = true -layout_mode = 2 -tooltip_text = "Sets tree sorting mode." -icon = SubResource("ImageTexture_c80wp") -flat = false -item_count = 4 -popup/item_0/text = "Unsorted" -popup/item_0/icon = SubResource("ImageTexture_t2qd7") -popup/item_0/checkable = 1 -popup/item_0/id = 0 -popup/item_1/text = "Name ascending" -popup/item_1/icon = SubResource("ImageTexture_c80wp") -popup/item_1/checkable = 1 -popup/item_1/checked = true -popup/item_1/id = 1 -popup/item_2/text = "Name descending" -popup/item_2/icon = SubResource("ImageTexture_1mh1t") -popup/item_2/checkable = 1 -popup/item_2/id = 2 -popup/item_3/text = "Execution time" -popup/item_3/icon = SubResource("ImageTexture_bq8kn") -popup/item_3/checkable = 1 -popup/item_3/id = 3 - -[node name="btn_tree_mode" type="MenuButton" parent="VBoxContainer/tree_tools/tree_buttons"] -unique_name_in_owner = true -layout_mode = 2 -tooltip_text = "Sets tree presentation mode." -icon = SubResource("ImageTexture_8lbfl") -flat = false -item_count = 2 -popup/item_0/text = "Tree" -popup/item_0/icon = SubResource("ImageTexture_ivm1h") -popup/item_0/checkable = 1 -popup/item_0/checked = true -popup/item_0/id = 0 -popup/item_1/text = "Flat" -popup/item_1/icon = SubResource("ImageTexture_j00vj") -popup/item_1/checkable = 1 -popup/item_1/id = 1 - -[node name="HSeparator" type="HSeparator" parent="VBoxContainer"] -layout_mode = 2 -theme_override_constants/separation = 0 - -[node name="status_bar" type="HFlowContainer" parent="VBoxContainer"] -layout_direction = 2 -layout_mode = 2 -size_flags_vertical = 2 - -[node name="error" type="VBoxContainer" parent="VBoxContainer/status_bar"] -custom_minimum_size = Vector2(0, 48) -layout_mode = 2 -size_flags_vertical = 0 -theme_override_constants/separation = -2 - -[node name="icon" type="HBoxContainer" parent="VBoxContainer/status_bar/error"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="icon_errors" type="TextureRect" parent="VBoxContainer/status_bar/error/icon"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 10 -size_flags_vertical = 4 -tooltip_text = "Error Tests" -texture = SubResource("ImageTexture_suo5c") -stretch_mode = 3 - -[node name="btn_up" type="Button" parent="VBoxContainer/status_bar/error/icon"] -layout_mode = 2 -size_flags_horizontal = 10 -size_flags_vertical = 4 -tooltip_text = "Jump to the previous error test" -icon = SubResource("ImageTexture_1oriu") - -[node name="counter" type="HBoxContainer" parent="VBoxContainer/status_bar/error"] -auto_translate_mode = 2 -layout_mode = 2 -localize_numeral_system = false - -[node name="error_value" type="Label" parent="VBoxContainer/status_bar/error/counter"] -unique_name_in_owner = true -use_parent_material = true -custom_minimum_size = Vector2(32, 0) -layout_mode = 2 -size_flags_horizontal = 10 -text = "0" -horizontal_alignment = 2 -justification_flags = 0 -visible_characters = 3 -visible_ratio = 3.0 - -[node name="btn_down" type="Button" parent="VBoxContainer/status_bar/error/counter"] -layout_mode = 2 -size_flags_horizontal = 4 -size_flags_vertical = 4 -tooltip_text = "Jump to the next error test" -icon = SubResource("ImageTexture_ikyhk") - -[node name="VSeparator" type="VSeparator" parent="VBoxContainer/status_bar"] -layout_mode = 2 - -[node name="failure" type="VBoxContainer" parent="VBoxContainer/status_bar"] -custom_minimum_size = Vector2(0, 48) -layout_mode = 2 -theme_override_constants/separation = -2 - -[node name="icon" type="HBoxContainer" parent="VBoxContainer/status_bar/failure"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="icon_failures" type="TextureRect" parent="VBoxContainer/status_bar/failure/icon"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 10 -size_flags_vertical = 4 -tooltip_text = "Failed Tests" -texture = SubResource("ImageTexture_qagbu") -stretch_mode = 3 - -[node name="btn_up" type="Button" parent="VBoxContainer/status_bar/failure/icon"] -layout_mode = 2 -size_flags_horizontal = 10 -size_flags_vertical = 4 -tooltip_text = "Jump to the previous failed test" -icon = SubResource("ImageTexture_1oriu") - -[node name="counter" type="HBoxContainer" parent="VBoxContainer/status_bar/failure"] -auto_translate_mode = 2 -layout_mode = 2 -localize_numeral_system = false - -[node name="failure_value" type="Label" parent="VBoxContainer/status_bar/failure/counter"] -unique_name_in_owner = true -use_parent_material = true -custom_minimum_size = Vector2(32, 0) -layout_mode = 2 -size_flags_horizontal = 10 -text = "0" -horizontal_alignment = 2 -justification_flags = 0 -visible_characters = 3 -visible_ratio = 3.0 - -[node name="btn_down" type="Button" parent="VBoxContainer/status_bar/failure/counter"] -layout_mode = 2 -size_flags_horizontal = 4 -size_flags_vertical = 4 -tooltip_text = "Jump to the next failed test" -icon = SubResource("ImageTexture_ikyhk") - -[node name="VSeparator2" type="VSeparator" parent="VBoxContainer/status_bar"] -layout_mode = 2 - -[node name="flaky" type="VBoxContainer" parent="VBoxContainer/status_bar"] -custom_minimum_size = Vector2(0, 48) -layout_mode = 2 -theme_override_constants/separation = -2 - -[node name="icon" type="HBoxContainer" parent="VBoxContainer/status_bar/flaky"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="icon_flaky" type="TextureRect" parent="VBoxContainer/status_bar/flaky/icon"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 10 -size_flags_vertical = 4 -tooltip_text = "Flaky Tests" -texture = SubResource("ImageTexture_a4rkr") -stretch_mode = 3 - -[node name="btn_up" type="Button" parent="VBoxContainer/status_bar/flaky/icon"] -layout_mode = 2 -size_flags_horizontal = 10 -size_flags_vertical = 4 -tooltip_text = "Jump to the previous flaky test" -icon = SubResource("ImageTexture_1oriu") - -[node name="counter" type="HBoxContainer" parent="VBoxContainer/status_bar/flaky"] -auto_translate_mode = 2 -layout_mode = 2 -localize_numeral_system = false - -[node name="flaky_value" type="Label" parent="VBoxContainer/status_bar/flaky/counter"] -unique_name_in_owner = true -use_parent_material = true -custom_minimum_size = Vector2(32, 0) -layout_mode = 2 -size_flags_horizontal = 10 -text = "0" -horizontal_alignment = 2 -justification_flags = 0 -visible_characters = 3 -visible_ratio = 3.0 - -[node name="btn_down" type="Button" parent="VBoxContainer/status_bar/flaky/counter"] -layout_mode = 2 -size_flags_horizontal = 4 -size_flags_vertical = 4 -tooltip_text = "Jump to the next flaky test" -icon = SubResource("ImageTexture_ikyhk") - -[node name="VSeparator3" type="VSeparator" parent="VBoxContainer/status_bar"] -layout_mode = 2 - -[node name="skipped" type="VBoxContainer" parent="VBoxContainer/status_bar"] -custom_minimum_size = Vector2(0, 48) -layout_mode = 2 -theme_override_constants/separation = -2 - -[node name="icon" type="HBoxContainer" parent="VBoxContainer/status_bar/skipped"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="icon_skipped" type="TextureRect" parent="VBoxContainer/status_bar/skipped/icon"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 10 -size_flags_vertical = 4 -tooltip_text = "Skipped Tests" -texture = SubResource("ImageTexture_idt7c") -stretch_mode = 3 - -[node name="btn_up" type="Button" parent="VBoxContainer/status_bar/skipped/icon"] -layout_mode = 2 -size_flags_horizontal = 10 -size_flags_vertical = 4 -tooltip_text = "Jump to the previous skipped test" -icon = SubResource("ImageTexture_1oriu") - -[node name="counter" type="HBoxContainer" parent="VBoxContainer/status_bar/skipped"] -auto_translate_mode = 2 -layout_mode = 2 -localize_numeral_system = false - -[node name="skipped_value" type="Label" parent="VBoxContainer/status_bar/skipped/counter"] -unique_name_in_owner = true -use_parent_material = true -custom_minimum_size = Vector2(32, 0) -layout_mode = 2 -size_flags_horizontal = 10 -text = "0" -horizontal_alignment = 2 -justification_flags = 0 -visible_characters = 3 -visible_ratio = 3.0 - -[node name="btn_down" type="Button" parent="VBoxContainer/status_bar/skipped/counter"] -layout_mode = 2 -size_flags_horizontal = 4 -size_flags_vertical = 4 -tooltip_text = "Jump to the next skipped test" -icon = SubResource("ImageTexture_ikyhk") - -[connection signal="pressed" from="VBoxContainer/tree_tools/tree_buttons/btn_tree_sync" to="." method="_on_tree_sync_pressed"] -[connection signal="pressed" from="VBoxContainer/status_bar/error/icon/btn_up" to="." method="_on_btn_error_up_pressed"] -[connection signal="pressed" from="VBoxContainer/status_bar/error/counter/btn_down" to="." method="_on_btn_error_down_pressed"] -[connection signal="pressed" from="VBoxContainer/status_bar/failure/icon/btn_up" to="." method="_on_failure_up_pressed"] -[connection signal="pressed" from="VBoxContainer/status_bar/failure/counter/btn_down" to="." method="_on_failure_down_pressed"] -[connection signal="pressed" from="VBoxContainer/status_bar/flaky/icon/btn_up" to="." method="_on_btn_flaky_up_pressed"] -[connection signal="pressed" from="VBoxContainer/status_bar/flaky/counter/btn_down" to="." method="_on_btn_flaky_down_pressed"] -[connection signal="pressed" from="VBoxContainer/status_bar/skipped/icon/btn_up" to="." method="_on_btn_skipped_up_pressed"] -[connection signal="pressed" from="VBoxContainer/status_bar/skipped/counter/btn_down" to="." method="_on_btn_skipped_down_pressed"] diff --git a/addons/gdUnit4/src/ui/parts/InspectorToolBar.gd b/addons/gdUnit4/src/ui/parts/InspectorToolBar.gd deleted file mode 100644 index 0cca901a..00000000 --- a/addons/gdUnit4/src/ui/parts/InspectorToolBar.gd +++ /dev/null @@ -1,130 +0,0 @@ -@tool -extends PanelContainer - -signal run_overall_pressed(debug: bool) -signal run_pressed(debug: bool) -signal stop_pressed() - -const InspectorTreeMainPanel := preload("res://addons/gdUnit4/src/ui/parts/InspectorTreeMainPanel.gd") - -@onready var _version_label: Control = %version -@onready var _button_wiki: Button = %help -@onready var _tool_button: Button = %tool -@onready var _button_run_overall: Button = %run_overall -@onready var _button_run: Button = %run -@onready var _button_run_debug: Button = %debug -@onready var _button_stop: Button = %stop - - -const SETTINGS_SHORTCUT_MAPPING := { - GdUnitSettings.SHORTCUT_INSPECTOR_RERUN_TEST: GdUnitShortcut.ShortCut.RERUN_TESTS, - GdUnitSettings.SHORTCUT_INSPECTOR_RERUN_TEST_DEBUG: GdUnitShortcut.ShortCut.RERUN_TESTS_DEBUG, - GdUnitSettings.SHORTCUT_INSPECTOR_RUN_TEST_OVERALL: GdUnitShortcut.ShortCut.RUN_TESTS_OVERALL, - GdUnitSettings.SHORTCUT_INSPECTOR_RUN_TEST_STOP: GdUnitShortcut.ShortCut.STOP_TEST_RUN, -} - - -func _ready() -> void: - var inspector :InspectorTreeMainPanel = get_parent().get_parent().find_child("MainPanel", false, false) - if inspector == null: - push_error("Internal error, can't connect to the test inspector!") - else: - inspector.tree_item_selected.connect(_on_inspector_selected) - run_pressed.connect(inspector._on_run_pressed) - - GdUnit4Version.init_version_label(_version_label) - var command_handler := GdUnitCommandHandler.instance() - run_overall_pressed.connect(command_handler._on_run_overall_pressed) - stop_pressed.connect(command_handler._on_stop_pressed) - command_handler.gdunit_runner_start.connect(_on_gdunit_runner_start) - command_handler.gdunit_runner_stop.connect(_on_gdunit_runner_stop) - GdUnitSignals.instance().gdunit_settings_changed.connect(_on_gdunit_settings_changed) - init_buttons() - init_shortcuts(command_handler) - - -func init_buttons() -> void: - _button_run_overall.icon = GdUnitUiTools.get_run_overall_icon() - _button_run_overall.visible = GdUnitSettings.is_inspector_toolbar_button_show() - _button_run.icon = GdUnitUiTools.get_icon("Play") - _button_run_debug.icon = GdUnitUiTools.get_icon("PlayStart") - _button_stop.icon = GdUnitUiTools.get_icon("Stop") - _tool_button.icon = GdUnitUiTools.get_icon("Tools") - _button_wiki.icon = GdUnitUiTools.get_icon("HelpSearch") - # Set run buttons initial disabled - _button_run.disabled = true - _button_run_debug.disabled = true - - -func init_shortcuts(command_handler: GdUnitCommandHandler) -> void: - _button_run.shortcut = command_handler.get_shortcut(GdUnitShortcut.ShortCut.RERUN_TESTS) - _button_run_overall.shortcut = command_handler.get_shortcut(GdUnitShortcut.ShortCut.RUN_TESTS_OVERALL) - _button_run_debug.shortcut = command_handler.get_shortcut(GdUnitShortcut.ShortCut.RERUN_TESTS_DEBUG) - _button_stop.shortcut = command_handler.get_shortcut(GdUnitShortcut.ShortCut.STOP_TEST_RUN) - # register for shortcut changes - @warning_ignore("return_value_discarded") - GdUnitSignals.instance().gdunit_settings_changed.connect(_on_settings_changed.bind(command_handler)) - - -func _on_inspector_selected(item: TreeItem) -> void: - var button_disabled := item == null - _button_run.disabled = button_disabled - _button_run_debug.disabled = button_disabled - - -func _on_runoverall_pressed(debug:=false) -> void: - run_overall_pressed.emit(debug) - - -func _on_run_pressed(debug := false) -> void: - run_pressed.emit(debug) - - -func _on_stop_pressed() -> void: - stop_pressed.emit() - - -func _on_gdunit_runner_start() -> void: - _button_run_overall.disabled = true - _button_run.disabled = true - _button_run_debug.disabled = true - _button_stop.disabled = false - - -func _on_gdunit_runner_stop(_client_id: int) -> void: - _button_run_overall.disabled = false - _button_stop.disabled = true - - -func _on_gdunit_settings_changed(_property: GdUnitProperty) -> void: - _button_run_overall.visible = GdUnitSettings.is_inspector_toolbar_button_show() - - -func _on_wiki_pressed() -> void: - var status := OS.shell_open("https://mikeschulze.github.io/gdUnit4/%s" % GdUnit4Version.current().documentation_version()) - if status != OK: - push_error("Can't open GdUnit4 documentaion page: %s" % error_string(status)) - - -func _on_btn_tool_pressed() -> void: - var settings_dlg: Window = EditorInterface.get_base_control().find_child("GdUnitSettingsDialog", false, false) - if settings_dlg == null: - settings_dlg = preload("res://addons/gdUnit4/src/ui/settings/GdUnitSettingsDialog.tscn").instantiate() - EditorInterface.get_base_control().add_child(settings_dlg, true) - settings_dlg.popup_centered_ratio(.60) - - -func _on_settings_changed(property: GdUnitProperty, command_handler: GdUnitCommandHandler) -> void: - # needs to wait a frame to be command handler notified first for settings changes - await get_tree().process_frame - if SETTINGS_SHORTCUT_MAPPING.has(property.name()): - var shortcut: GdUnitShortcut.ShortCut = SETTINGS_SHORTCUT_MAPPING.get(property.name(), GdUnitShortcut.ShortCut.NONE) - match shortcut: - GdUnitShortcut.ShortCut.RERUN_TESTS: - _button_run.shortcut = command_handler.get_shortcut(shortcut) - GdUnitShortcut.ShortCut.RUN_TESTS_OVERALL: - _button_run_overall.shortcut = command_handler.get_shortcut(shortcut) - GdUnitShortcut.ShortCut.RERUN_TESTS_DEBUG: - _button_run_debug.shortcut = command_handler.get_shortcut(shortcut) - GdUnitShortcut.ShortCut.STOP_TEST_RUN: - _button_stop.shortcut = command_handler.get_shortcut(shortcut) diff --git a/addons/gdUnit4/src/ui/parts/InspectorToolBar.gd.uid b/addons/gdUnit4/src/ui/parts/InspectorToolBar.gd.uid deleted file mode 100644 index 696553f4..00000000 --- a/addons/gdUnit4/src/ui/parts/InspectorToolBar.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dy1ierqsfcw8q diff --git a/addons/gdUnit4/src/ui/parts/InspectorToolBar.tscn b/addons/gdUnit4/src/ui/parts/InspectorToolBar.tscn deleted file mode 100644 index 5d75da02..00000000 --- a/addons/gdUnit4/src/ui/parts/InspectorToolBar.tscn +++ /dev/null @@ -1,212 +0,0 @@ -[gd_scene load_steps=22 format=3 uid="uid://dx7xy4dgi3wwb"] - -[ext_resource type="Script" path="res://addons/gdUnit4/src/ui/parts/InspectorToolBar.gd" id="3"] - -[sub_resource type="Image" id="Image_c7rhl"] -data = { -"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 36, 224, 224, 224, 168, 224, 224, 224, 233, 224, 224, 224, 236, 224, 224, 224, 170, 231, 231, 231, 31, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 36, 224, 224, 224, 234, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 239, 230, 230, 230, 30, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 168, 224, 224, 224, 255, 224, 224, 224, 186, 224, 224, 224, 32, 224, 224, 224, 33, 224, 224, 224, 187, 224, 224, 224, 255, 225, 225, 225, 167, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 237, 224, 224, 224, 255, 224, 224, 224, 33, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 36, 224, 224, 224, 255, 224, 224, 224, 234, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 237, 224, 224, 224, 255, 224, 224, 224, 33, 255, 255, 255, 0, 255, 255, 255, 0, 229, 229, 229, 38, 224, 224, 224, 255, 224, 224, 224, 229, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 164, 224, 224, 224, 255, 224, 224, 224, 187, 225, 225, 225, 34, 227, 227, 227, 36, 224, 224, 224, 192, 224, 224, 224, 255, 224, 224, 224, 162, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 24, 225, 225, 225, 215, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 229, 224, 224, 224, 32, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 24, 224, 224, 224, 216, 224, 224, 224, 255, 224, 224, 224, 210, 224, 224, 224, 161, 224, 224, 224, 232, 224, 224, 224, 231, 225, 225, 225, 159, 230, 230, 230, 30, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 107, 224, 224, 224, 255, 224, 224, 224, 210, 230, 230, 230, 20, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 105, 230, 230, 230, 20, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 221, 224, 224, 224, 130, 255, 255, 255, 1, 255, 255, 255, 1, 225, 225, 225, 134, 224, 224, 224, 224, 225, 225, 225, 223, 224, 224, 224, 132, 255, 255, 255, 1, 255, 255, 255, 6, 224, 224, 224, 137, 224, 224, 224, 231, 224, 224, 224, 255, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 130, 225, 225, 225, 133, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 129, 224, 224, 224, 137, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 65, 224, 224, 224, 255, 224, 224, 224, 220, 225, 225, 225, 223, 224, 224, 224, 255, 226, 226, 226, 61, 224, 224, 224, 65, 224, 224, 224, 255, 224, 224, 224, 222, 224, 224, 224, 231, 224, 224, 224, 255, 227, 227, 227, 62, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 67, 224, 224, 224, 255, 224, 224, 224, 219, 224, 224, 224, 222, 224, 224, 224, 255, 227, 227, 227, 63, 225, 225, 225, 67, 224, 224, 224, 255, 224, 224, 224, 219, 224, 224, 224, 230, 224, 224, 224, 255, 227, 227, 227, 63, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 127, 224, 224, 224, 129, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 126, 225, 225, 225, 135, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 221, 225, 225, 225, 127, 255, 255, 255, 0, 255, 255, 255, 1, 224, 224, 224, 128, 224, 224, 224, 220, 224, 224, 224, 219, 225, 225, 225, 127, 255, 255, 255, 0, 255, 255, 255, 5, 225, 225, 225, 134, 224, 224, 224, 229, 224, 224, 224, 255, 255, 255, 255, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_t52y3"] -image = SubResource("Image_c7rhl") - -[sub_resource type="Image" id="Image_3erui"] -data = { -"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 64, 224, 224, 224, 255, 227, 227, 227, 63, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 5, 225, 225, 225, 142, 255, 255, 255, 0, 255, 255, 255, 2, 224, 224, 224, 138, 255, 255, 255, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 192, 224, 224, 224, 255, 225, 225, 225, 191, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 142, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 2, 224, 224, 224, 255, 224, 224, 224, 137, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 192, 224, 224, 224, 255, 225, 225, 225, 191, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 236, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 64, 224, 224, 224, 255, 227, 227, 227, 63, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 235, 224, 224, 224, 255, 224, 224, 224, 65, 225, 225, 225, 67, 224, 224, 224, 255, 224, 224, 224, 230, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 140, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 134, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 4, 224, 224, 224, 137, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 135, 255, 255, 255, 3, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 247, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 246, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 183, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 179, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 231, 231, 231, 21, 224, 224, 224, 179, 224, 224, 224, 237, 224, 224, 224, 179, 230, 230, 230, 20, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 190, 224, 224, 224, 188, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_wip2b"] -image = SubResource("Image_3erui") - -[sub_resource type="InputEventKey" id="InputEventKey_6jdrj"] -ctrl_pressed = true -pressed = true -keycode = 4194338 -physical_keycode = 4194338 - -[sub_resource type="Shortcut" id="Shortcut_t0ytp"] -events = [SubResource("InputEventKey_6jdrj")] - -[sub_resource type="Image" id="Image_p22nw"] -data = { -"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 195, 224, 224, 224, 210, 224, 224, 224, 56, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 195, 224, 224, 224, 210, 224, 224, 224, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 253, 224, 224, 224, 139, 224, 224, 224, 8, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 253, 224, 224, 224, 139, 224, 224, 224, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 215, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 215, 224, 224, 224, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 253, 224, 224, 224, 139, 224, 224, 224, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 183, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 182, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 252, 225, 225, 225, 134, 255, 255, 255, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 212, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 212, 226, 226, 226, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 252, 225, 225, 225, 134, 255, 255, 255, 6, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 252, 225, 225, 225, 134, 255, 255, 255, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 225, 225, 191, 224, 224, 224, 206, 226, 226, 226, 52, 0, 0, 0, 0, 0, 0, 0, 0, 225, 225, 225, 191, 224, 224, 224, 206, 226, 226, 226, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_mggmt"] -image = SubResource("Image_p22nw") - -[sub_resource type="InputEventKey" id="InputEventKey_pl3pi"] -ctrl_pressed = true -pressed = true -keycode = 4194336 -physical_keycode = 4194336 - -[sub_resource type="Shortcut" id="Shortcut_77xhn"] -events = [SubResource("InputEventKey_pl3pi")] - -[sub_resource type="Image" id="Image_3lcek"] -data = { -"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 195, 224, 224, 224, 210, 224, 224, 224, 56, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 253, 224, 224, 224, 139, 224, 224, 224, 8, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 215, 224, 224, 224, 56, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 253, 224, 224, 224, 139, 224, 224, 224, 8, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 183, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 182, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 252, 225, 225, 225, 134, 255, 255, 255, 6, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 212, 226, 226, 226, 52, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 252, 225, 225, 225, 134, 255, 255, 255, 6, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 191, 224, 224, 224, 206, 226, 226, 226, 52, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_q6qbp"] -image = SubResource("Image_3lcek") - -[sub_resource type="InputEventKey" id="InputEventKey_qk8q5"] -ctrl_pressed = true -pressed = true -keycode = 4194337 -physical_keycode = 4194337 - -[sub_resource type="Shortcut" id="Shortcut_ae6em"] -events = [SubResource("InputEventKey_qk8q5")] - -[sub_resource type="Image" id="Image_ndw0i"] -data = { -"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 184, 224, 224, 224, 255, 224, 224, 224, 181, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 184, 224, 224, 224, 202, 228, 228, 228, 37, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 239, 224, 224, 224, 74, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 253, 224, 224, 224, 123, 255, 255, 255, 1, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 173, 234, 234, 234, 12, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 188, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 185, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 168, 230, 230, 230, 10, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 252, 225, 225, 225, 118, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 237, 226, 226, 226, 70, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 181, 224, 224, 224, 255, 224, 224, 224, 180, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 188, 224, 224, 224, 201, 225, 225, 225, 34, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_q0wt0"] -image = SubResource("Image_ndw0i") - -[sub_resource type="InputEventKey" id="InputEventKey_l8obn"] -ctrl_pressed = true -pressed = true -keycode = 4194339 -physical_keycode = 4194339 - -[sub_resource type="Shortcut" id="Shortcut_2mb87"] -events = [SubResource("InputEventKey_l8obn")] - -[sub_resource type="Image" id="Image_eoihf"] -data = { -"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 176, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 177, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 177, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 176, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_1wiyx"] -image = SubResource("Image_eoihf") - -[node name="ToolBar" type="PanelContainer"] -anchors_preset = 10 -anchor_right = 1.0 -offset_right = -894.0 -offset_bottom = 24.0 -grow_horizontal = 2 -size_flags_horizontal = 3 -size_flags_vertical = 4 -script = ExtResource("3") - -[node name="HBoxContainer" type="HBoxContainer" parent="."] -layout_mode = 2 - -[node name="tools" type="HBoxContainer" parent="HBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 0 -size_flags_vertical = 4 - -[node name="help" type="Button" parent="HBoxContainer/tools"] -unique_name_in_owner = true -layout_mode = 2 -icon = SubResource("ImageTexture_t52y3") - -[node name="tool" type="Button" parent="HBoxContainer/tools"] -unique_name_in_owner = true -layout_mode = 2 -tooltip_text = "GdUnit Settings" -icon = SubResource("ImageTexture_wip2b") - -[node name="controls" type="HBoxContainer" parent="HBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 6 -size_flags_vertical = 4 -alignment = 1 - -[node name="VSeparator3" type="VSeparator" parent="HBoxContainer/controls"] -layout_mode = 2 - -[node name="run_overall" type="Button" parent="HBoxContainer/controls"] -unique_name_in_owner = true -visible = false -use_parent_material = true -layout_mode = 2 -tooltip_text = "Run overall tests" -shortcut = SubResource("Shortcut_t0ytp") -icon = SubResource("ImageTexture_mggmt") - -[node name="run" type="Button" parent="HBoxContainer/controls"] -unique_name_in_owner = true -use_parent_material = true -layout_mode = 2 -tooltip_text = "Rerun unit tests" -shortcut = SubResource("Shortcut_77xhn") -icon = SubResource("ImageTexture_q6qbp") - -[node name="debug" type="Button" parent="HBoxContainer/controls"] -unique_name_in_owner = true -use_parent_material = true -layout_mode = 2 -tooltip_text = "Rerun unit tests (Debug)" -shortcut = SubResource("Shortcut_ae6em") -icon = SubResource("ImageTexture_q0wt0") - -[node name="stop" type="Button" parent="HBoxContainer/controls"] -unique_name_in_owner = true -use_parent_material = true -layout_mode = 2 -tooltip_text = "Stops runing unit tests" -disabled = true -shortcut = SubResource("Shortcut_2mb87") -icon = SubResource("ImageTexture_1wiyx") - -[node name="VSeparator4" type="VSeparator" parent="HBoxContainer/controls"] -layout_mode = 2 - -[node name="CenterContainer" type="HBoxContainer" parent="HBoxContainer"] -use_parent_material = true -layout_mode = 2 -size_flags_horizontal = 10 -size_flags_vertical = 4 -alignment = 2 - -[node name="version" type="Label" parent="HBoxContainer/CenterContainer"] -unique_name_in_owner = true -use_parent_material = true -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 13 -auto_translate = false -localize_numeral_system = false -text = "gdUnit4 4.3.0" -horizontal_alignment = 1 -justification_flags = 160 - -[connection signal="pressed" from="HBoxContainer/tools/help" to="." method="_on_wiki_pressed"] -[connection signal="pressed" from="HBoxContainer/tools/tool" to="." method="_on_btn_tool_pressed"] -[connection signal="pressed" from="HBoxContainer/controls/run_overall" to="." method="_on_runoverall_pressed"] -[connection signal="pressed" from="HBoxContainer/controls/run" to="." method="_on_run_pressed"] -[connection signal="pressed" from="HBoxContainer/controls/debug" to="." method="_on_run_pressed" binds= [true]] -[connection signal="pressed" from="HBoxContainer/controls/stop" to="." method="_on_stop_pressed"] diff --git a/addons/gdUnit4/src/ui/parts/InspectorTreeMainPanel.gd b/addons/gdUnit4/src/ui/parts/InspectorTreeMainPanel.gd deleted file mode 100644 index 536fe87f..00000000 --- a/addons/gdUnit4/src/ui/parts/InspectorTreeMainPanel.gd +++ /dev/null @@ -1,1245 +0,0 @@ -@tool -extends VSplitContainer - -## Will be emitted when the test index counter is changed -signal test_counters_changed(index: int, total: int, state: GdUnitInspectorTreeConstants.STATE) -signal tree_item_selected(item: TreeItem) - - -const CONTEXT_MENU_RUN_ID = 0 -const CONTEXT_MENU_DEBUG_ID = 1 -const CONTEXT_MENU_COLLAPSE_ALL = 3 -const CONTEXT_MENU_EXPAND_ALL = 4 - - -@onready var _tree: Tree = $Panel/Tree -@onready var _report_list: Node = $report/ScrollContainer/list -@onready var _report_template: RichTextLabel = $report/report_template -@onready var _context_menu: PopupMenu = $contextMenu -@onready var _discover_hint: Control = %discover_hint -@onready var _spinner: Button = %spinner - -# loading tree icons -@onready var ICON_SPINNER := GdUnitUiTools.get_spinner() -@onready var ICON_FOLDER := GdUnitUiTools.get_icon("Folder") -# gdscript icons -@onready var ICON_GDSCRIPT_TEST_DEFAULT := GdUnitUiTools.get_icon("GDScript", Color.LIGHT_GRAY) -@onready var ICON_GDSCRIPT_TEST_SUCCESS := GdUnitUiTools.get_GDScript_icon("StatusSuccess", Color.DARK_GREEN) -@onready var ICON_GDSCRIPT_TEST_FLAKY := GdUnitUiTools.get_GDScript_icon("CheckBox", Color.GREEN_YELLOW) -@onready var ICON_GDSCRIPT_TEST_FAILED := GdUnitUiTools.get_GDScript_icon("StatusError", Color.SKY_BLUE) -@onready var ICON_GDSCRIPT_TEST_ERROR := GdUnitUiTools.get_GDScript_icon("StatusError", Color.DARK_RED) -@onready var ICON_GDSCRIPT_TEST_SUCCESS_ORPHAN := GdUnitUiTools.get_GDScript_icon("Unlinked", Color.DARK_GREEN) -@onready var ICON_GDSCRIPT_TEST_FAILED_ORPHAN := GdUnitUiTools.get_GDScript_icon("Unlinked", Color.SKY_BLUE) -@onready var ICON_GDSCRIPT_TEST_ERRORS_ORPHAN := GdUnitUiTools.get_GDScript_icon("Unlinked", Color.DARK_RED) -# csharp script icons -@onready var ICON_CSSCRIPT_TEST_DEFAULT := GdUnitUiTools.get_icon("CSharpScript", Color.LIGHT_GRAY) -@onready var ICON_CSSCRIPT_TEST_SUCCESS := GdUnitUiTools.get_CSharpScript_icon("StatusSuccess", Color.DARK_GREEN) -@onready var ICON_CSSCRIPT_TEST_FAILED := GdUnitUiTools.get_CSharpScript_icon("StatusError", Color.SKY_BLUE) -@onready var ICON_CSSCRIPT_TEST_ERROR := GdUnitUiTools.get_CSharpScript_icon("StatusError", Color.DARK_RED) -@onready var ICON_CSSCRIPT_TEST_SUCCESS_ORPHAN := GdUnitUiTools.get_CSharpScript_icon("Unlinked", Color.DARK_GREEN) -@onready var ICON_CSSCRIPT_TEST_FAILED_ORPHAN := GdUnitUiTools.get_CSharpScript_icon("Unlinked", Color.SKY_BLUE) -@onready var ICON_CSSCRIPT_TEST_ERRORS_ORPHAN := GdUnitUiTools.get_CSharpScript_icon("Unlinked", Color.DARK_RED) - - -enum GdUnitType { - FOLDER, - TEST_SUITE, - TEST_CASE, - TEST_GROUP -} - -const META_GDUNIT_PROGRESS_COUNT_MAX := "gdUnit_progress_count_max" -const META_GDUNIT_PROGRESS_INDEX := "gdUnit_progress_index" -const META_TEST_CASE := "gdunit_test_case" -const META_GDUNIT_NAME := "gdUnit_name" -const META_GDUNIT_STATE := "gdUnit_state" -const META_GDUNIT_TYPE := "gdUnit_type" -const META_GDUNIT_SUCCESS_TESTS := "gdUnit_suite_success_tests" -const META_GDUNIT_REPORT := "gdUnit_report" -const META_GDUNIT_ORPHAN := "gdUnit_orphan" -const META_GDUNIT_EXECUTION_TIME := "gdUnit_execution_time" -const META_GDUNIT_ORIGINAL_INDEX = "gdunit_original_index" -const STATE = GdUnitInspectorTreeConstants.STATE - - -var _tree_root: TreeItem -var _current_selected_item: TreeItem = null -var _current_tree_view_mode := GdUnitSettings.get_inspector_tree_view_mode() -var _run_test_recovery := true - - -## Used for debugging purposes only -func print_tree_item_ids(parent: TreeItem) -> TreeItem: - for child in parent.get_children(): - if child.has_meta(META_TEST_CASE): - var test_case: GdUnitTestCase = child.get_meta(META_TEST_CASE) - prints(test_case.guid, test_case.test_name) - - if child.get_child_count() > 0: - print_tree_item_ids(child) - - return null - - -func _find_tree_item(parent: TreeItem, item_name: String) -> TreeItem: - for child in parent.get_children(): - if child.get_meta(META_GDUNIT_NAME) == item_name: - return child - return null - - -func _find_tree_item_by_id(parent: TreeItem, id: GdUnitGUID) -> TreeItem: - for child in parent.get_children(): - if is_test_id(child, id): - return child - if child.get_child_count() > 0: - var item := _find_tree_item_by_id(child, id) - if item != null: - return item - - return null - - -func _find_tree_item_by_test_suite(parent: TreeItem, suite_path: String, suite_name: String) -> TreeItem: - for child in parent.get_children(): - if child.get_meta(META_GDUNIT_TYPE) == GdUnitType.TEST_SUITE: - var test_case: GdUnitTestCase = child.get_meta(META_TEST_CASE) - if test_case.suite_resource_path == suite_path and test_case.suite_name == suite_name: - return child - if child.get_child_count() > 0: - var item := _find_tree_item_by_test_suite(child, suite_path, suite_name) - if item != null: - return item - return null - - -func _find_first_item_by_state(parent: TreeItem, item_state: STATE, reverse := false) -> TreeItem: - var itmes := parent.get_children() - if reverse: - itmes.reverse() - for item in itmes: - if is_test_case(item) and (is_item_state(item, item_state)): - return item - var failure_item := _find_first_item_by_state(item, item_state, reverse) - if failure_item != null: - return failure_item - return null - - -func _find_last_item_by_state(parent: TreeItem, item_state: STATE) -> TreeItem: - return _find_first_item_by_state(parent, item_state, true) - - -func _find_item_by_state(current: TreeItem, item_state: STATE, prev := false) -> TreeItem: - var next := current.get_prev_in_tree() if prev else current.get_next_in_tree() - if next == null or next == _tree_root: - return null - if is_test_case(next) and is_item_state(next, item_state): - return next - return _find_item_by_state(next, item_state, prev) - - -func is_item_state(item: TreeItem, item_state: STATE) -> bool: - return item.has_meta(META_GDUNIT_STATE) and item.get_meta(META_GDUNIT_STATE) == item_state - - -func is_state_running(item: TreeItem) -> bool: - return is_item_state(item, STATE.RUNNING) - - -func is_state_success(item: TreeItem) -> bool: - return is_item_state(item, STATE.SUCCESS) - - -func is_state_warning(item: TreeItem) -> bool: - return is_item_state(item, STATE.WARNING) - - -func is_state_failed(item: TreeItem) -> bool: - return is_item_state(item, STATE.FAILED) - - -func is_state_error(item: TreeItem) -> bool: - return is_item_state(item, STATE.ERROR) or is_item_state(item, STATE.ABORDED) - - -func is_item_state_orphan(item: TreeItem) -> bool: - return item.has_meta(META_GDUNIT_ORPHAN) - - -func is_test_suite(item: TreeItem) -> bool: - return item.has_meta(META_GDUNIT_TYPE) and item.get_meta(META_GDUNIT_TYPE) == GdUnitType.TEST_SUITE - - -func is_test_case(item: TreeItem) -> bool: - return item.has_meta(META_GDUNIT_TYPE) and item.get_meta(META_GDUNIT_TYPE) == GdUnitType.TEST_CASE - - -func is_folder(item: TreeItem) -> bool: - return item.has_meta(META_GDUNIT_TYPE) and item.get_meta(META_GDUNIT_TYPE) == GdUnitType.FOLDER - - -func is_test_id(item: TreeItem, id: GdUnitGUID) -> bool: - if not item.has_meta(META_TEST_CASE): - return false - - var test_case: GdUnitTestCase = item.get_meta(META_TEST_CASE) - return test_case.guid.equals(id) - - -func disable_test_recovery() -> void: - _run_test_recovery = false - - -@warning_ignore("return_value_discarded") -func _ready() -> void: - _context_menu.set_item_icon(CONTEXT_MENU_RUN_ID, GdUnitUiTools.get_icon("Play")) - _context_menu.set_item_icon(CONTEXT_MENU_DEBUG_ID, GdUnitUiTools.get_icon("PlayStart")) - _context_menu.set_item_icon(CONTEXT_MENU_EXPAND_ALL, GdUnitUiTools.get_icon("ExpandTree")) - _context_menu.set_item_icon(CONTEXT_MENU_COLLAPSE_ALL, GdUnitUiTools.get_icon("CollapseTree")) - # do colorize the icons - #for index in _context_menu.item_count: - # _context_menu.set_item_icon_modulate(index, Color.MEDIUM_PURPLE) - - _spinner.icon = GdUnitUiTools.get_spinner() - init_tree() - GdUnitSignals.instance().gdunit_settings_changed.connect(_on_settings_changed) - GdUnitSignals.instance().gdunit_event.connect(_on_gdunit_event) - GdUnitSignals.instance().gdunit_test_discover_added.connect(on_test_case_discover_added) - GdUnitSignals.instance().gdunit_test_discover_deleted.connect(on_test_case_discover_deleted) - GdUnitSignals.instance().gdunit_test_discover_modified.connect(on_test_case_discover_modified) - var command_handler := GdUnitCommandHandler.instance() - command_handler.gdunit_runner_stop.connect(_on_gdunit_runner_stop) - if _run_test_recovery: - GdUnitTestDiscoverer.restore_last_session() - - -# we need current to manually redraw bacause of the animation bug -# https://github.com/godotengine/godot/issues/69330 -func _process(_delta: float) -> void: - if is_visible_in_tree(): - queue_redraw() - - -func init_tree() -> void: - cleanup_tree() - _tree.deselect_all() - _tree.set_hide_root(true) - _tree.ensure_cursor_is_visible() - _tree.set_allow_reselect(true) - _tree.set_allow_rmb_select(true) - _tree.set_columns(2) - _tree.set_column_clip_content(0, true) - _tree.set_column_expand_ratio(0, 1) - _tree.set_column_custom_minimum_width(0, 240) - _tree.set_column_expand_ratio(1, 0) - _tree.set_column_custom_minimum_width(1, 100) - _tree_root = _tree.create_item() - _tree_root.set_text(0, "tree_root") - _tree_root.set_meta(META_GDUNIT_NAME, "tree_root") - _tree_root.set_meta(META_GDUNIT_PROGRESS_COUNT_MAX, 0) - _tree_root.set_meta(META_GDUNIT_PROGRESS_INDEX, 0) - _tree_root.set_meta(META_GDUNIT_STATE, STATE.INITIAL) - _tree_root.set_meta(META_GDUNIT_SUCCESS_TESTS, 0) - # fix tree icon scaling - var scale_factor := EditorInterface.get_editor_scale() if Engine.is_editor_hint() else 1.0 - _tree.set("theme_override_constants/icon_max_width", 16 * scale_factor) - - -func cleanup_tree() -> void: - clear_reports() - if not _tree_root: - return - _free_recursive() - _tree.clear() - _current_selected_item = null - - -func _free_recursive(items:=_tree_root.get_children()) -> void: - for item in items: - _free_recursive(item.get_children()) - item.call_deferred("free") - - -func sort_tree_items(parent: TreeItem) -> void: - _sort_tree_items(parent, GdUnitSettings.get_inspector_tree_sort_mode()) - _tree.queue_redraw() - - -static func _sort_tree_items(parent: TreeItem, sort_mode: GdUnitInspectorTreeConstants.SORT_MODE) -> void: - parent.visible = false - var items := parent.get_children() - # first remove all childs before sorting - for item in items: - parent.remove_child(item) - - # do sort by selected sort mode - match sort_mode: - GdUnitInspectorTreeConstants.SORT_MODE.UNSORTED: - items.sort_custom(sort_items_by_original_index) - - GdUnitInspectorTreeConstants.SORT_MODE.NAME_ASCENDING: - items.sort_custom(sort_items_by_name.bind(true)) - - GdUnitInspectorTreeConstants.SORT_MODE.NAME_DESCENDING: - items.sort_custom(sort_items_by_name.bind(false)) - - GdUnitInspectorTreeConstants.SORT_MODE.EXECUTION_TIME: - items.sort_custom(sort_items_by_execution_time) - - # readding sorted childs - for item in items: - parent.add_child(item) - if item.get_child_count() > 0: - _sort_tree_items(item, sort_mode) - parent.visible = true - - -static func sort_items_by_name(a: TreeItem, b: TreeItem, ascending: bool) -> bool: - var type_a: GdUnitType = a.get_meta(META_GDUNIT_TYPE) - var type_b: GdUnitType = b.get_meta(META_GDUNIT_TYPE) - - # Sort folders to the top - if type_a == GdUnitType.FOLDER and type_b != GdUnitType.FOLDER: - return true - if type_b == GdUnitType.FOLDER and type_a != GdUnitType.FOLDER: - return false - - # sort by name - var name_a: String = a.get_meta(META_GDUNIT_NAME) - var name_b: String = b.get_meta(META_GDUNIT_NAME) - var comparison := name_a.naturalnocasecmp_to(name_b) - - return comparison < 0 if ascending else comparison > 0 - - -static func sort_items_by_execution_time(a: TreeItem, b: TreeItem) -> bool: - var type_a: GdUnitType = a.get_meta(META_GDUNIT_TYPE) - var type_b: GdUnitType = b.get_meta(META_GDUNIT_TYPE) - - # Sort folders to the top - if type_a == GdUnitType.FOLDER and type_b != GdUnitType.FOLDER: - return true - if type_b == GdUnitType.FOLDER and type_a != GdUnitType.FOLDER: - return false - - var execution_time_a :int = a.get_meta(META_GDUNIT_EXECUTION_TIME) - var execution_time_b :int = b.get_meta(META_GDUNIT_EXECUTION_TIME) - # if has same execution time sort by name - if execution_time_a == execution_time_b: - var name_a :String = a.get_meta(META_GDUNIT_NAME) - var name_b :String = b.get_meta(META_GDUNIT_NAME) - return name_a.naturalnocasecmp_to(name_b) > 0 - return execution_time_a > execution_time_b - - -static func sort_items_by_original_index(a: TreeItem, b: TreeItem) -> bool: - var type_a: GdUnitType = a.get_meta(META_GDUNIT_TYPE) - var type_b: GdUnitType = b.get_meta(META_GDUNIT_TYPE) - - # Sort folders to the top - if type_a == GdUnitType.FOLDER and type_b != GdUnitType.FOLDER: - return true - if type_b == GdUnitType.FOLDER and type_a != GdUnitType.FOLDER: - return false - - var index_a :int = a.get_meta(META_GDUNIT_ORIGINAL_INDEX) - var index_b :int = b.get_meta(META_GDUNIT_ORIGINAL_INDEX) - - # Sorting by index - return index_a < index_b - - -func restructure_tree(parent: TreeItem, tree_mode: GdUnitInspectorTreeConstants.TREE_VIEW_MODE) -> void: - _current_tree_view_mode = tree_mode - - match tree_mode: - GdUnitInspectorTreeConstants.TREE_VIEW_MODE.FLAT: - restructure_tree_to_flat(parent) - GdUnitInspectorTreeConstants.TREE_VIEW_MODE.TREE: - restructure_tree_to_tree(parent) - recalculate_counters(_tree_root) - # finally apply actual sort mode - sort_tree_items(_tree_root) - - -# Restructure into flat mode -func restructure_tree_to_flat(parent: TreeItem) -> void: - var folders := flatmap_folders(parent) - # Store current folder paths and their test suites - for folder_path: String in folders: - var test_suites: Array[TreeItem] = folders[folder_path] - if test_suites.is_empty(): - continue - - # Create flat folder and move test suites into it - var folder := _tree.create_item(parent) - folder.set_meta(META_GDUNIT_NAME, folder_path) - update_item_total_counter(folder) - set_state_initial(folder, GdUnitType.FOLDER) - - # Move test suites under the flat folder - for test_suite in test_suites: - var old_parent := test_suite.get_parent() - old_parent.remove_child(test_suite) - folder.add_child(test_suite) - - # Cleanup old folder structure - cleanup_empty_folders(parent) - - -# Restructure into hierarchical tree mode -func restructure_tree_to_tree(parent: TreeItem) -> void: - var items_to_process := parent.get_children().duplicate() - - for item: TreeItem in items_to_process: - if is_folder(item): - var folder_path: String = item.get_meta(META_GDUNIT_NAME) - var parts := folder_path.split("/") - - if parts.size() > 1: - var current_parent := parent - # Build folder hierarchy - for part in parts: - var next := _find_tree_item(current_parent, part) - if not next: - next = _tree.create_item(current_parent) - next.set_meta(META_GDUNIT_NAME, part) - set_state_initial(next, GdUnitType.FOLDER) - current_parent = next - - # Move test suites to deepest folder - var test_suites := item.get_children() - for test_suite in test_suites: - item.remove_child(test_suite) - current_parent.add_child(test_suite) - - # Remove the flat folder - item.get_parent().remove_child(item) - item.free() - - -func flatmap_folders(parent: TreeItem) -> Dictionary: - var folder_map := {} - - for item in parent.get_children(): - if is_folder(item): - var current_path: String = item.get_meta(META_GDUNIT_NAME) - # Get parent folder paths - var parent_path := get_parent_folder_path(item) - if parent_path: - current_path = parent_path + "/" + current_path - - # Collect direct children of this folder - var children: Array[TreeItem] = [] - for child in item.get_children(): - if is_test_suite(child): - children.append(child) - - # Add children to existing path or create new entry - if not children.is_empty(): - if folder_map.has(current_path): - @warning_ignore("unsafe_method_access") - folder_map[current_path].append_array(children) - else: - folder_map[current_path] = children - - # Recursively process subfolders - var sub_folders := flatmap_folders(item) - for path: String in sub_folders.keys(): - if folder_map.has(path): - @warning_ignore("unsafe_method_access") - folder_map[path].append_array(sub_folders[path]) - else: - folder_map[path] = sub_folders[path] - return folder_map - - -func get_parent_folder_path(item: TreeItem) -> String: - var path := "" - var parent := item.get_parent() - - while parent != _tree_root: - if is_folder(parent): - path = parent.get_meta(META_GDUNIT_NAME) + ("/" + path if path else "") - parent = parent.get_parent() - - return path - - -func cleanup_empty_folders(parent: TreeItem) -> void: - var folders: Array[TreeItem] = [] - # First collect all folders to avoid modification during iteration - for item in parent.get_children(): - if is_folder(item): - folders.append(item) - - # Process collected folders - for folder in folders: - cleanup_empty_folders(folder) - # Remove folder if it has no children after cleanup - if folder.get_child_count() == 0: - parent.remove_child(folder) - folder.free() - - -func reset_tree_state(parent: TreeItem) -> void: - if parent == _tree_root: - _tree_root.set_meta(META_GDUNIT_PROGRESS_INDEX, 0) - _tree_root.set_meta(META_GDUNIT_STATE, STATE.INITIAL) - test_counters_changed.emit(0, 0, STATE.INITIAL) - - for item in parent.get_children(): - set_state_initial(item, get_item_type(item)) - reset_tree_state(item) - - -func select_item(item: TreeItem) -> TreeItem: - if item != null: - # enshure the parent is collapsed - do_collapse_parent(item) - item.select(0) - _tree.ensure_cursor_is_visible() - _tree.scroll_to_item(item, true) - return item - - -func do_collapse_parent(item: TreeItem) -> void: - if item != null: - item.collapsed = false - do_collapse_parent(item.get_parent()) - - -func do_collapse_all(collapse: bool, parent := _tree_root) -> void: - for item in parent.get_children(): - item.collapsed = collapse - if not collapse: - do_collapse_all(collapse, item) - - -func set_state_initial(item: TreeItem, type: GdUnitType) -> void: - item.set_text(0, str(item.get_meta(META_GDUNIT_NAME))) - item.set_custom_color(0, Color.LIGHT_GRAY) - item.set_tooltip_text(0, "") - item.set_text_overrun_behavior(0, TextServer.OVERRUN_TRIM_CHAR) - item.set_expand_right(0, true) - - item.set_custom_color(1, Color.LIGHT_GRAY) - item.set_text(1, "") - item.set_expand_right(1, true) - item.set_tooltip_text(1, "") - - item.set_meta(META_GDUNIT_STATE, STATE.INITIAL) - item.set_meta(META_GDUNIT_TYPE, type) - item.set_meta(META_GDUNIT_SUCCESS_TESTS, 0) - item.set_meta(META_GDUNIT_EXECUTION_TIME, 0) - if item.has_meta(META_GDUNIT_PROGRESS_COUNT_MAX) and item.get_meta(META_GDUNIT_PROGRESS_COUNT_MAX) > 0: - item.set_text(0, "(0/%d) %s" % [item.get_meta(META_GDUNIT_PROGRESS_COUNT_MAX), item.get_meta(META_GDUNIT_NAME)]) - item.remove_meta(META_GDUNIT_REPORT) - item.remove_meta(META_GDUNIT_ORPHAN) - - set_item_icon_by_state(item) - - -func set_state_running(item: TreeItem, is_running: bool) -> void: - if is_state_running(item): - return - if is_item_state(item, STATE.INITIAL): - item.set_custom_color(0, Color.DARK_GREEN) - item.set_custom_color(1, Color.DARK_GREEN) - item.set_meta(META_GDUNIT_STATE, STATE.RUNNING) - item.collapsed = false - - if is_running: - item.set_icon(0, ICON_SPINNER) - else: - set_item_icon_by_state(item) - for child in item.get_children(): - set_item_icon_by_state(child) - - var parent := item.get_parent() - if parent != _tree_root: - set_state_running(parent, is_running) - - -func set_state_succeded(item: TreeItem) -> void: - # Do not overwrite higher states - if is_state_error(item) or is_state_failed(item): - return - if item == _tree_root: - return - item.set_custom_color(0, Color.GREEN) - item.set_custom_color(1, Color.GREEN) - item.set_meta(META_GDUNIT_STATE, STATE.SUCCESS) - item.collapsed = GdUnitSettings.is_inspector_node_collapse() - set_item_icon_by_state(item) - - -func set_state_flaky(item: TreeItem, event: GdUnitEvent) -> void: - # Do not overwrite higher states - if is_state_error(item): - return - var retry_count := event.statistic(GdUnitEvent.RETRY_COUNT) - item.set_meta(META_GDUNIT_STATE, STATE.FLAKY) - if retry_count > 1: - var item_text: String = item.get_meta(META_GDUNIT_NAME) - if item.has_meta(META_GDUNIT_PROGRESS_COUNT_MAX): - var success_count: int = item.get_meta(META_GDUNIT_SUCCESS_TESTS) - item_text = "(%d/%d) %s" % [success_count, item.get_meta(META_GDUNIT_PROGRESS_COUNT_MAX), item.get_meta(META_GDUNIT_NAME)] - item.set_text(0, "%s (%s retries)" % [item_text, retry_count]) - item.set_custom_color(0, Color.GREEN_YELLOW) - item.set_custom_color(1, Color.GREEN_YELLOW) - item.collapsed = false - set_item_icon_by_state(item) - - -func set_state_skipped(item: TreeItem) -> void: - item.set_meta(META_GDUNIT_STATE, STATE.SKIPPED) - item.set_text(1, "(skipped)") - item.set_text_alignment(1, HORIZONTAL_ALIGNMENT_RIGHT) - item.set_custom_color(0, Color.DARK_GRAY) - item.set_custom_color(1, Color.DARK_GRAY) - item.collapsed = false - set_item_icon_by_state(item) - - -func set_state_warnings(item: TreeItem) -> void: - # Do not overwrite higher states - if is_state_error(item) or is_state_failed(item): - return - item.set_meta(META_GDUNIT_STATE, STATE.WARNING) - item.set_custom_color(0, Color.YELLOW) - item.set_custom_color(1, Color.YELLOW) - item.collapsed = false - set_item_icon_by_state(item) - - -func set_state_failed(item: TreeItem, event: GdUnitEvent) -> void: - # Do not overwrite higher states - if is_state_error(item): - return - var retry_count := event.statistic(GdUnitEvent.RETRY_COUNT) - if retry_count > 1: - var item_text: String = item.get_meta(META_GDUNIT_NAME) - if item.has_meta(META_GDUNIT_PROGRESS_COUNT_MAX): - var success_count: int = item.get_meta(META_GDUNIT_SUCCESS_TESTS) - item_text = "(%d/%d) %s" % [success_count, item.get_meta(META_GDUNIT_PROGRESS_COUNT_MAX), item.get_meta(META_GDUNIT_NAME)] - item.set_text(0, "%s (%s retries)" % [item_text, retry_count]) - item.set_meta(META_GDUNIT_STATE, STATE.FAILED) - item.set_custom_color(0, Color.LIGHT_BLUE) - item.set_custom_color(1, Color.LIGHT_BLUE) - item.collapsed = false - set_item_icon_by_state(item) - - -func set_state_error(item: TreeItem) -> void: - item.set_meta(META_GDUNIT_STATE, STATE.ERROR) - item.set_custom_color(0, Color.ORANGE_RED) - item.set_custom_color(1, Color.ORANGE_RED) - set_item_icon_by_state(item) - item.collapsed = false - - -func set_state_aborted(item: TreeItem) -> void: - item.set_meta(META_GDUNIT_STATE, STATE.ABORDED) - item.set_custom_color(0, Color.ORANGE_RED) - item.set_custom_color(1, Color.ORANGE_RED) - item.clear_custom_bg_color(0) - item.set_text(1, "(aborted)") - item.set_text_alignment(1, HORIZONTAL_ALIGNMENT_RIGHT) - set_item_icon_by_state(item) - item.collapsed = false - - -func set_state_orphan(item: TreeItem, event: GdUnitEvent) -> void: - var orphan_count := event.statistic(GdUnitEvent.ORPHAN_NODES) - if orphan_count == 0: - return - if item.has_meta(META_GDUNIT_ORPHAN): - orphan_count += item.get_meta(META_GDUNIT_ORPHAN) - item.set_meta(META_GDUNIT_ORPHAN, orphan_count) - if item.get_meta(META_GDUNIT_STATE) != STATE.FAILED: - item.set_custom_color(0, Color.YELLOW) - item.set_custom_color(1, Color.YELLOW) - item.set_tooltip_text(0, "Total <%d> orphan nodes detected." % orphan_count) - set_item_icon_by_state(item) - - -func update_state(item: TreeItem, event: GdUnitEvent, add_reports := true) -> void: - # we do not show the root - if item == null: - return - - if event.is_skipped(): - set_state_skipped(item) - elif event.is_success() and event.is_flaky(): - set_state_flaky(item, event) - elif event.is_success(): - set_state_succeded(item) - elif event.is_error(): - set_state_error(item) - elif event.is_failed(): - set_state_failed(item, event) - elif event.is_warning(): - set_state_warnings(item) - if add_reports: - for report in event.reports(): - add_report(item, report) - set_state_orphan(item, event) - - var parent := item.get_parent() - if parent == null: - return - - var item_state: int = item.get_meta(META_GDUNIT_STATE) - var parent_state: int = parent.get_meta(META_GDUNIT_STATE) - if item_state <= parent_state: - return - update_state(item.get_parent(), event, false) - - -func add_report(item: TreeItem, report: GdUnitReport) -> void: - var reports: Array[GdUnitReport] = [] - if item.has_meta(META_GDUNIT_REPORT): - reports = get_item_reports(item) - reports.append(report) - item.set_meta(META_GDUNIT_REPORT, reports) - - -func abort_running(items:=_tree_root.get_children()) -> void: - for item in items: - if is_state_running(item): - set_state_aborted(item) - abort_running(item.get_children()) - - -func _on_select_next_item_by_state(item_state: int) -> TreeItem: - var current_selected := _tree.get_selected() - # If nothing is selected, the first error is selected or the next one in the vicinity of the current selection is found - current_selected = _find_first_item_by_state(_tree_root, item_state) if current_selected == null else _find_item_by_state(current_selected, item_state) - # If no next failure found, then we try to select first - if current_selected == null: - current_selected = _find_first_item_by_state(_tree_root, item_state) - return select_item(current_selected) - - -func _on_select_previous_item_by_state(item_state: int) -> TreeItem: - var current_selected := _tree.get_selected() - # If nothing is selected, the first error is selected or the next one in the vicinity of the current selection is found - current_selected = _find_last_item_by_state(_tree_root, item_state) if current_selected == null else _find_item_by_state(current_selected, item_state, true) - # If no next failure found, then we try to select first last - if current_selected == null: - current_selected = _find_last_item_by_state(_tree_root, item_state) - return select_item(current_selected) - - -func select_first_orphan() -> void: - for parent in _tree_root.get_children(): - if not is_state_success(parent): - for item in parent.get_children(): - if is_item_state_orphan(item): - parent.set_collapsed(false) - @warning_ignore("return_value_discarded") - select_item(item) - return - - -func clear_reports() -> void: - for child in _report_list.get_children(): - _report_list.remove_child(child) - child.queue_free() - - -func show_failed_report(selected_item: TreeItem) -> void: - clear_reports() - if selected_item == null or not selected_item.has_meta(META_GDUNIT_REPORT): - return - # add new reports - for report in get_item_reports(selected_item): - var reportNode: RichTextLabel = _report_template.duplicate() - _report_list.add_child(reportNode) - reportNode.append_text(report.to_string()) - reportNode.visible = true - - -func update_test_suite(event: GdUnitEvent) -> void: - var item := _find_tree_item_by_test_suite(_tree_root, event.resource_path(), event.suite_name()) - if not item: - push_error("[InspectorTreeMainPanel#update_test_suite] Internal Error: Can't find test suite item '{_suite_name}' for {_resource_path} ".format(event)) - return - if event.type() == GdUnitEvent.TESTSUITE_AFTER: - update_item_elapsed_time_counter(item, event.elapsed_time()) - update_state(item, event) - set_state_running(item, false) - - -func update_test_case(event: GdUnitEvent) -> void: - var item := _find_tree_item_by_id(_tree_root, event.guid()) - if not item: - #push_error("Internal Error: Can't find test id %s" % [event.guid()]) - return - if event.type() == GdUnitEvent.TESTCASE_BEFORE: - set_state_running(item, true) - # force scrolling to current test case - _tree.scroll_to_item(item, true) - return - - if event.type() == GdUnitEvent.TESTCASE_AFTER: - update_item_elapsed_time_counter(item, event.elapsed_time()) - if event.is_success() or event.is_warning(): - update_item_processed_counter(item) - update_state(item, event) - update_progress_counters(item) - - -func create_item(parent: TreeItem, test: GdUnitTestCase, item_name: String, type: GdUnitType) -> TreeItem: - var item := _tree.create_item(parent) - item.collapsed = true - item.set_meta(META_GDUNIT_ORIGINAL_INDEX, item.get_index()) - item.set_text(0, item_name) - match type: - GdUnitType.TEST_CASE: - item.set_meta(META_TEST_CASE, test) - GdUnitType.TEST_GROUP: - # We need to create a copy of the test record meta with a new uniqe guid - item.set_meta(META_TEST_CASE, GdUnitTestCase.from(test.suite_resource_path, test.source_file, test.line_number, test.test_name)) - GdUnitType.TEST_SUITE: - # We need to create a copy of the test record meta with a new uniqe guid - item.set_meta(META_TEST_CASE, GdUnitTestCase.from(test.suite_resource_path, test.source_file, test.line_number, test.suite_name)) - - item.set_meta(META_GDUNIT_NAME, item_name) - set_state_initial(item, type) - update_item_total_counter(item) - return item - - -func set_item_icon_by_state(item :TreeItem) -> void: - if item == _tree_root: - return - var state :STATE = item.get_meta(META_GDUNIT_STATE) - var is_orphan := is_item_state_orphan(item) - var resource_path := get_item_source_file(item) - item.set_icon(0, get_icon_by_file_type(resource_path, state, is_orphan)) - if item.get_meta(META_GDUNIT_TYPE) == GdUnitType.FOLDER: - item.set_icon_modulate(0, Color.SKY_BLUE) - - -func update_item_total_counter(item: TreeItem) -> void: - if item == null: - return - - var child_count := get_total_child_count(item) - if child_count > 0: - item.set_meta(META_GDUNIT_PROGRESS_COUNT_MAX, child_count) - item.set_text(0, "(0/%d) %s" % [child_count, item.get_meta(META_GDUNIT_NAME)]) - - update_item_total_counter(item.get_parent()) - - -func get_total_child_count(item: TreeItem) -> int: - var total_count := 0 - for child in item.get_children(): - total_count += child.get_meta(META_GDUNIT_PROGRESS_COUNT_MAX) if child.has_meta(META_GDUNIT_PROGRESS_COUNT_MAX) else 1 - return total_count - - -func update_item_processed_counter(item: TreeItem, add_count := 1) -> void: - if item == _tree_root: - return - - var success_count: int = item.get_meta(META_GDUNIT_SUCCESS_TESTS) + add_count - item.set_meta(META_GDUNIT_SUCCESS_TESTS, success_count) - if item.has_meta(META_GDUNIT_PROGRESS_COUNT_MAX): - item.set_text(0, "(%d/%d) %s" % [success_count, item.get_meta(META_GDUNIT_PROGRESS_COUNT_MAX), item.get_meta(META_GDUNIT_NAME)]) - - update_item_processed_counter(item.get_parent(), add_count) - - -func update_progress_counters(item: TreeItem) -> void: - var index: int = _tree_root.get_meta(META_GDUNIT_PROGRESS_INDEX) + 1 - var total_test: int = _tree_root.get_meta(META_GDUNIT_PROGRESS_COUNT_MAX) - var state: STATE = item.get_meta(META_GDUNIT_STATE) - test_counters_changed.emit(index, total_test, state) - _tree_root.set_meta(META_GDUNIT_PROGRESS_INDEX, index) - - -func recalculate_counters(parent: TreeItem) -> void: - # Reset the counter first - if parent.has_meta(META_GDUNIT_PROGRESS_COUNT_MAX): - parent.set_meta(META_GDUNIT_PROGRESS_COUNT_MAX, 0) - if parent.has_meta(META_GDUNIT_PROGRESS_INDEX): - parent.set_meta(META_GDUNIT_PROGRESS_INDEX, 0) - if parent.has_meta(META_GDUNIT_SUCCESS_TESTS): - parent.set_meta(META_GDUNIT_SUCCESS_TESTS, 0) - - # Calculate new count based on children - var total_count := 0 - var success_count := 0 - var progress_index := 0 - - for child in parent.get_children(): - if child.get_child_count() > 0: - # Recursively update child counters first - recalculate_counters(child) - # Add child's counters to parent - if child.has_meta(META_GDUNIT_PROGRESS_COUNT_MAX): - total_count += child.get_meta(META_GDUNIT_PROGRESS_COUNT_MAX) - if child.has_meta(META_GDUNIT_SUCCESS_TESTS): - success_count += child.get_meta(META_GDUNIT_SUCCESS_TESTS) - if child.has_meta(META_GDUNIT_PROGRESS_INDEX): - progress_index += child.get_meta(META_GDUNIT_PROGRESS_INDEX) - elif is_test_case(child): - # Count individual test cases - total_count += 1 - # Count completed tests - if is_state_success(child) or is_state_warning(child) or is_state_failed(child) or is_state_error(child): - progress_index += 1 - if is_state_success(child) or is_state_warning(child): - success_count += 1 - - # Update the counters - if total_count > 0: - parent.set_meta(META_GDUNIT_PROGRESS_COUNT_MAX, total_count) - parent.set_meta(META_GDUNIT_PROGRESS_INDEX, progress_index) - parent.set_meta(META_GDUNIT_SUCCESS_TESTS, success_count) - - # Update the display text - parent.set_text(0, "(%d/%d) %s" % [success_count, total_count, parent.get_meta(META_GDUNIT_NAME)]) - - -func update_item_elapsed_time_counter(item: TreeItem, time: int) -> void: - item.set_text(1, "%s" % LocalTime.elapsed(time)) - item.set_text_alignment(1, HORIZONTAL_ALIGNMENT_RIGHT) - item.set_meta(META_GDUNIT_EXECUTION_TIME, time) - - var parent := item.get_parent() - if parent == _tree_root: - return - var elapsed_time :int = parent.get_meta(META_GDUNIT_EXECUTION_TIME) + time - var type :GdUnitType = item.get_meta(META_GDUNIT_TYPE) - match type: - GdUnitType.TEST_CASE: - return - GdUnitType.TEST_SUITE: - update_item_elapsed_time_counter(parent, elapsed_time) - #GdUnitType.FOLDER: - # update_item_elapsed_time_counter(parent, elapsed_time) - - -func get_icon_by_file_type(path: String, state: STATE, orphans: bool) -> Texture2D: - if path.get_extension() == "gd": - match state: - STATE.INITIAL: - return ICON_GDSCRIPT_TEST_DEFAULT - STATE.SUCCESS: - return ICON_GDSCRIPT_TEST_SUCCESS_ORPHAN if orphans else ICON_GDSCRIPT_TEST_SUCCESS - STATE.ERROR: - return ICON_GDSCRIPT_TEST_ERRORS_ORPHAN if orphans else ICON_GDSCRIPT_TEST_ERROR - STATE.FAILED: - return ICON_GDSCRIPT_TEST_FAILED_ORPHAN if orphans else ICON_GDSCRIPT_TEST_FAILED - STATE.WARNING: - return ICON_GDSCRIPT_TEST_SUCCESS_ORPHAN if orphans else ICON_GDSCRIPT_TEST_DEFAULT - STATE.FLAKY: - return ICON_GDSCRIPT_TEST_SUCCESS_ORPHAN if orphans else ICON_GDSCRIPT_TEST_FLAKY - _: - return ICON_GDSCRIPT_TEST_DEFAULT - if path.get_extension() == "cs": - match state: - STATE.INITIAL: - return ICON_CSSCRIPT_TEST_DEFAULT - STATE.SUCCESS: - return ICON_CSSCRIPT_TEST_SUCCESS_ORPHAN if orphans else ICON_CSSCRIPT_TEST_SUCCESS - STATE.ERROR: - return ICON_CSSCRIPT_TEST_ERRORS_ORPHAN if orphans else ICON_CSSCRIPT_TEST_ERROR - STATE.FAILED: - return ICON_CSSCRIPT_TEST_FAILED_ORPHAN if orphans else ICON_CSSCRIPT_TEST_FAILED - STATE.WARNING: - return ICON_CSSCRIPT_TEST_SUCCESS_ORPHAN if orphans else ICON_CSSCRIPT_TEST_DEFAULT - _: - return ICON_CSSCRIPT_TEST_DEFAULT - match state: - STATE.INITIAL: - return ICON_FOLDER - STATE.ERROR: - return ICON_FOLDER - STATE.FAILED: - return ICON_FOLDER - _: - return ICON_FOLDER - - -func on_test_case_discover_added(test_case: GdUnitTestCase) -> void: - var test_root_folder := GdUnitSettings.test_root_folder().replace("res://", "") - var fully_qualified_name := test_case.fully_qualified_name.trim_suffix(test_case.display_name) - var parts := fully_qualified_name.split(".", false) - parts.append(test_case.display_name) - # Skip tree structure until test root folder - var index := parts.find(test_root_folder) - if index != -1: - parts = parts.slice(index+1) - - match _current_tree_view_mode: - GdUnitInspectorTreeConstants.TREE_VIEW_MODE.FLAT: - create_items_tree_mode_flat(test_case, parts) - GdUnitInspectorTreeConstants.TREE_VIEW_MODE.TREE: - create_items_tree_mode_tree(test_case, parts) - - -func create_items_tree_mode_tree(test_case: GdUnitTestCase, parts: PackedStringArray) -> void: - var parent := _tree_root - var is_suite_assigned := false - var suite_name := test_case.suite_name.split(".")[-1] - for item_name in parts: - var next := _find_tree_item(parent, item_name) - if next != null: - parent = next - continue - - if not is_suite_assigned and suite_name == item_name: - next = create_item(parent, test_case, item_name, GdUnitType.TEST_SUITE) - is_suite_assigned = true - elif item_name == test_case.display_name: - next = create_item(parent, test_case, item_name, GdUnitType.TEST_CASE) - # On grouped tests (parameterized tests) - elif item_name == test_case.test_name: - next = create_item(parent, test_case, item_name, GdUnitType.TEST_GROUP) - else: - next = create_item(parent, test_case, item_name, GdUnitType.FOLDER) - parent = next - - -func create_items_tree_mode_flat(test_case: GdUnitTestCase, parts: PackedStringArray) -> void: - # All parts except the last two (suite name and test name/display name) - var slice_index := -2 if parts[-1] == test_case.test_name else -3 - var path_parts := parts.slice(0, slice_index) - var folder_path := "/".join(path_parts) - - # Find or create flat folder - var folder_item: TreeItem - if folder_path.is_empty(): - folder_item = _tree_root - else: - folder_item = _find_tree_item(_tree_root, folder_path) - if folder_item == null: - folder_item = create_item(_tree_root, test_case, folder_path, GdUnitType.FOLDER) - - # Find suite under the flat folder (second to last part) - var suite_item := _find_tree_item(folder_item, test_case.suite_name) - if suite_item == null: - suite_item = create_item(folder_item, test_case, test_case.suite_name, GdUnitType.TEST_SUITE) - - # Add test case or group under the suite - if test_case.test_name != test_case.display_name: - # It's a parameterized test group - var group_item := _find_tree_item(suite_item, test_case.test_name) - if group_item == null: - group_item = create_item(suite_item, test_case, test_case.test_name, GdUnitType.TEST_GROUP) - create_item(group_item, test_case, test_case.display_name, GdUnitType.TEST_CASE) - else: - create_item(suite_item, test_case, test_case.display_name, GdUnitType.TEST_CASE) - - -func on_test_case_discover_deleted(test_case: GdUnitTestCase) -> void: - var item := _find_tree_item_by_id(_tree_root, test_case.guid) - if item != null: - var parent := item.get_parent() - parent.remove_child(item) - - # update the cached counters - var item_success_count: int = item.get_meta(META_GDUNIT_SUCCESS_TESTS) - var item_total_test_count: int = item.get_meta(META_GDUNIT_PROGRESS_COUNT_MAX, 0) - var total_test_count: int = parent.get_meta(META_GDUNIT_PROGRESS_COUNT_MAX, 0) - parent.set_meta(META_GDUNIT_PROGRESS_COUNT_MAX, total_test_count-item_total_test_count) - - # propagate counter update to all parents - update_item_total_counter(parent) - update_item_processed_counter(parent, -item_success_count) - - -func on_test_case_discover_modified(test_case: GdUnitTestCase) -> void: - var item := _find_tree_item_by_id(_tree_root, test_case.guid) - if item != null: - item.set_meta(META_TEST_CASE, test_case) - item.set_text(0, test_case.display_name) - item.set_meta(META_GDUNIT_NAME, test_case.display_name) - - -func get_item_reports(item: TreeItem) -> Array[GdUnitReport]: - return item.get_meta(META_GDUNIT_REPORT) - - -func get_item_test_line_number(item: TreeItem) -> int: - if item == null or not item.has_meta(META_TEST_CASE): - return -1 - - var test_case: GdUnitTestCase = item.get_meta(META_TEST_CASE) - return test_case.line_number - - -func get_item_source_file(item: TreeItem) -> String: - if item == null or not item.has_meta(META_TEST_CASE): - return "" - - var test_case: GdUnitTestCase = item.get_meta(META_TEST_CASE) - return test_case.source_file - - -func get_item_type(item: TreeItem) -> GdUnitType: - if item == null or not item.has_meta(META_GDUNIT_TYPE): - return GdUnitType.FOLDER - return item.get_meta(META_GDUNIT_TYPE) - - -func _dump_tree_as_json(dump_name: String) -> void: - var dict := _to_json(_tree_root) - var file := FileAccess.open("res://%s.json" % dump_name, FileAccess.WRITE) - file.store_string(JSON.stringify(dict, "\t")) - - -func _to_json(parent :TreeItem) -> Dictionary: - var item_as_dict := GdObjects.obj2dict(parent) - item_as_dict["TreeItem"]["childrens"] = parent.get_children().map(func(item: TreeItem) -> Dictionary: - return _to_json(item)) - return item_as_dict - - -func extract_resource_path(event: GdUnitEvent) -> String: - return ProjectSettings.localize_path(event.resource_path()) - - -func collect_test_cases(item: TreeItem, tests: Array[GdUnitTestCase] = []) -> Array[GdUnitTestCase]: - for next in item.get_children(): - collect_test_cases(next, tests) - - if is_test_case(item): - var test: GdUnitTestCase = item.get_meta(META_TEST_CASE) - if not tests.has(test): - tests.append(test) - - return tests - - -################################################################################ -# Tree signal receiver -################################################################################ -func _on_tree_item_mouse_selected(mouse_position: Vector2, mouse_button_index: int) -> void: - if mouse_button_index == MOUSE_BUTTON_RIGHT: - _context_menu.position = get_screen_position() + mouse_position - _context_menu.popup() - - -func _on_run_pressed(run_debug: bool) -> void: - _context_menu.hide() - var item: = _tree.get_selected() - if item == null: - print_rich("[color=GOLDENROD]Abort Testrun, no test suite selected![/color]") - return - - var test_to_execute := collect_test_cases(item) - GdUnitCommandHandler.instance().cmd_run_tests(test_to_execute, run_debug) - - -func _on_Tree_item_selected() -> void: - # only show report checked manual item selection - # we need to check the run mode here otherwise it will be called every selection - if not _context_menu.is_item_disabled(CONTEXT_MENU_RUN_ID): - var selected_item: TreeItem = _tree.get_selected() - show_failed_report(selected_item) - _current_selected_item = _tree.get_selected() - tree_item_selected.emit(_current_selected_item) - - -# Opens the test suite -func _on_Tree_item_activated() -> void: - var selected_item := _tree.get_selected() - var line_number := get_item_test_line_number(selected_item) - if line_number != -1: - var script_path := ProjectSettings.localize_path(get_item_source_file(selected_item)) - var resource: Script = load(script_path) - - if selected_item.has_meta(META_GDUNIT_REPORT): - var reports := get_item_reports(selected_item) - var report_line_number := reports[0].line_number() - # if number -1 we use original stored line number of the test case - # in non debug mode the line number is not available - if report_line_number != -1: - line_number = report_line_number - - EditorInterface.get_file_system_dock().navigate_to_path(script_path) - EditorInterface.edit_script(resource, line_number) - elif selected_item.get_meta(META_GDUNIT_TYPE) == GdUnitType.FOLDER: - # Toggle collapse if dir - selected_item.collapsed = not selected_item.collapsed - - -################################################################################ -# external signal receiver -################################################################################ -func _on_gdunit_runner_start() -> void: - _context_menu.set_item_disabled(CONTEXT_MENU_RUN_ID, true) - _context_menu.set_item_disabled(CONTEXT_MENU_DEBUG_ID, true) - reset_tree_state(_tree_root) - clear_reports() - - -func _on_gdunit_runner_stop(_id: int) -> void: - _context_menu.set_item_disabled(CONTEXT_MENU_RUN_ID, false) - _context_menu.set_item_disabled(CONTEXT_MENU_DEBUG_ID, false) - abort_running() - sort_tree_items(_tree_root) - # wait until the tree redraw - await get_tree().process_frame - var failure_item := _find_first_item_by_state(_tree_root, STATE.FAILED) - select_item( failure_item if failure_item else _current_selected_item) - - -func _on_gdunit_event(event: GdUnitEvent) -> void: - match event.type(): - GdUnitEvent.DISCOVER_START: - _tree_root.visible = false - _discover_hint.visible = true - init_tree() - - GdUnitEvent.DISCOVER_END: - sort_tree_items(_tree_root) - select_item(_tree_root.get_first_child()) - _discover_hint.visible = false - _tree_root.visible = true - #_dump_tree_as_json("tree_example_discovered") - - GdUnitEvent.INIT: - _on_gdunit_runner_start() - - GdUnitEvent.TESTCASE_BEFORE: - update_test_case(event) - - GdUnitEvent.TESTCASE_AFTER: - update_test_case(event) - - GdUnitEvent.TESTSUITE_BEFORE: - update_test_suite(event) - - GdUnitEvent.TESTSUITE_AFTER: - update_test_suite(event) - - -func _on_context_m_index_pressed(index: int) -> void: - match index: - CONTEXT_MENU_DEBUG_ID: - _on_run_pressed(true) - CONTEXT_MENU_RUN_ID: - _on_run_pressed(false) - CONTEXT_MENU_EXPAND_ALL: - do_collapse_all(false) - CONTEXT_MENU_COLLAPSE_ALL: - do_collapse_all(true) - - -func _on_settings_changed(property :GdUnitProperty) -> void: - match property.name(): - GdUnitSettings.INSPECTOR_TREE_SORT_MODE: - sort_tree_items(_tree_root) - #_dump_tree_as_json("tree_sorted_by_%s" % GdUnitInspectorTreeConstants.SORT_MODE.keys()[property.value()]) - - GdUnitSettings.INSPECTOR_TREE_VIEW_MODE: - restructure_tree(_tree_root, GdUnitSettings.get_inspector_tree_view_mode()) diff --git a/addons/gdUnit4/src/ui/parts/InspectorTreeMainPanel.gd.uid b/addons/gdUnit4/src/ui/parts/InspectorTreeMainPanel.gd.uid deleted file mode 100644 index ef9608b1..00000000 --- a/addons/gdUnit4/src/ui/parts/InspectorTreeMainPanel.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cw8355bfvukx diff --git a/addons/gdUnit4/src/ui/parts/InspectorTreePanel.tscn b/addons/gdUnit4/src/ui/parts/InspectorTreePanel.tscn deleted file mode 100644 index a4247706..00000000 --- a/addons/gdUnit4/src/ui/parts/InspectorTreePanel.tscn +++ /dev/null @@ -1,273 +0,0 @@ -[gd_scene load_steps=27 format=3 uid="uid://bqfpidewtpeg0"] - -[ext_resource type="Script" path="res://addons/gdUnit4/src/ui/parts/InspectorTreeMainPanel.gd" id="1"] - -[sub_resource type="Image" id="Image_466oo"] -data = { -"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 4, 226, 226, 226, 26, 224, 224, 224, 41, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 223, 224, 224, 224, 148, 228, 228, 228, 28, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 2, 226, 226, 226, 43, 225, 225, 225, 51, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 211, 255, 255, 255, 5, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 2, 255, 255, 255, 0, 227, 227, 227, 9, 223, 223, 223, 47, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 221, 229, 229, 229, 29, 255, 255, 255, 0, 255, 255, 255, 2, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 4, 226, 226, 226, 43, 227, 227, 227, 9, 255, 255, 255, 0, 227, 227, 227, 9, 225, 225, 225, 17, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 65, 229, 229, 229, 29, 255, 255, 255, 0, 227, 227, 227, 9, 226, 226, 226, 43, 192, 192, 192, 4, 255, 255, 255, 0, 255, 255, 255, 0, 226, 226, 226, 26, 225, 225, 225, 51, 223, 223, 223, 47, 227, 227, 227, 9, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 9, 228, 228, 228, 47, 225, 225, 225, 51, 225, 225, 225, 25, 255, 255, 255, 0, 255, 255, 255, 0, 231, 231, 231, 41, 225, 225, 225, 51, 225, 225, 225, 51, 225, 225, 225, 17, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 18, 225, 225, 225, 51, 225, 225, 225, 51, 224, 224, 224, 40, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 1, 255, 255, 255, 1, 255, 255, 255, 1, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 41, 225, 225, 225, 51, 225, 225, 225, 51, 225, 225, 225, 17, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 18, 225, 225, 225, 51, 225, 225, 225, 51, 229, 229, 229, 39, 255, 255, 255, 0, 255, 255, 255, 0, 226, 226, 226, 26, 225, 225, 225, 51, 223, 223, 223, 47, 255, 255, 255, 8, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 9, 223, 223, 223, 47, 225, 225, 225, 51, 225, 225, 225, 25, 255, 255, 255, 0, 255, 255, 255, 0, 192, 192, 192, 4, 226, 226, 226, 43, 224, 224, 224, 8, 255, 255, 255, 0, 227, 227, 227, 9, 227, 227, 227, 18, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 18, 227, 227, 227, 9, 255, 255, 255, 0, 227, 227, 227, 9, 226, 226, 226, 43, 255, 255, 255, 3, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 1, 255, 255, 255, 0, 227, 227, 227, 9, 228, 228, 228, 47, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 1, 225, 225, 225, 51, 223, 223, 223, 47, 227, 227, 227, 9, 255, 255, 255, 0, 255, 255, 255, 2, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 2, 226, 226, 226, 43, 225, 225, 225, 51, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 1, 225, 225, 225, 51, 225, 225, 225, 51, 226, 226, 226, 43, 255, 255, 255, 2, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 192, 192, 192, 4, 226, 226, 226, 26, 224, 224, 224, 40, 255, 255, 255, 0, 255, 255, 255, 1, 229, 229, 229, 39, 225, 225, 225, 25, 255, 255, 255, 3, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_nwpuj"] -image = SubResource("Image_466oo") - -[sub_resource type="Image" id="Image_o6s0p"] -data = { -"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 4, 226, 226, 226, 26, 224, 224, 224, 41, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 41, 226, 226, 226, 26, 192, 192, 192, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 2, 226, 226, 226, 43, 225, 225, 225, 51, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 51, 225, 225, 225, 51, 226, 226, 226, 43, 255, 255, 255, 1, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 2, 255, 255, 255, 0, 227, 227, 227, 9, 223, 223, 223, 47, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 51, 223, 223, 223, 47, 224, 224, 224, 8, 255, 255, 255, 0, 224, 224, 224, 8, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 4, 226, 226, 226, 43, 227, 227, 227, 9, 255, 255, 255, 0, 227, 227, 227, 9, 225, 225, 225, 17, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 17, 255, 255, 255, 8, 255, 255, 255, 0, 224, 224, 224, 48, 224, 224, 224, 217, 225, 225, 225, 17, 255, 255, 255, 0, 255, 255, 255, 0, 226, 226, 226, 26, 225, 225, 225, 51, 223, 223, 223, 47, 227, 227, 227, 9, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 228, 228, 228, 47, 224, 224, 224, 236, 224, 224, 224, 255, 225, 225, 225, 125, 255, 255, 255, 0, 255, 255, 255, 0, 231, 231, 231, 41, 225, 225, 225, 51, 225, 225, 225, 51, 225, 225, 225, 17, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 226, 226, 226, 86, 224, 224, 224, 252, 224, 224, 224, 252, 224, 224, 224, 194, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 41, 225, 225, 225, 51, 225, 225, 225, 51, 225, 225, 225, 17, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 18, 225, 225, 225, 51, 225, 225, 225, 51, 230, 230, 230, 40, 255, 255, 255, 0, 255, 255, 255, 0, 226, 226, 226, 26, 225, 225, 225, 51, 223, 223, 223, 47, 255, 255, 255, 8, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 9, 223, 223, 223, 47, 225, 225, 225, 51, 225, 225, 225, 25, 255, 255, 255, 0, 255, 255, 255, 0, 192, 192, 192, 4, 226, 226, 226, 43, 224, 224, 224, 8, 255, 255, 255, 0, 227, 227, 227, 9, 227, 227, 227, 18, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 18, 227, 227, 227, 9, 255, 255, 255, 0, 227, 227, 227, 9, 226, 226, 226, 43, 255, 255, 255, 3, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 1, 255, 255, 255, 0, 227, 227, 227, 9, 228, 228, 228, 47, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 51, 223, 223, 223, 47, 227, 227, 227, 9, 255, 255, 255, 0, 255, 255, 255, 2, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 2, 226, 226, 226, 43, 225, 225, 225, 51, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 51, 225, 225, 225, 51, 226, 226, 226, 43, 255, 255, 255, 2, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 192, 192, 192, 4, 225, 225, 225, 25, 230, 230, 230, 40, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 40, 225, 225, 225, 25, 255, 255, 255, 3, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_pdcj5"] -image = SubResource("Image_o6s0p") - -[sub_resource type="Image" id="Image_miuuy"] -data = { -"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 4, 226, 226, 226, 26, 224, 224, 224, 41, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 41, 226, 226, 226, 26, 192, 192, 192, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 2, 226, 226, 226, 43, 225, 225, 225, 51, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 51, 225, 225, 225, 51, 226, 226, 226, 43, 255, 255, 255, 1, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 2, 255, 255, 255, 0, 227, 227, 227, 9, 223, 223, 223, 47, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 51, 223, 223, 223, 47, 224, 224, 224, 8, 255, 255, 255, 0, 255, 255, 255, 2, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 4, 226, 226, 226, 43, 227, 227, 227, 9, 255, 255, 255, 0, 227, 227, 227, 9, 225, 225, 225, 17, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 17, 255, 255, 255, 8, 255, 255, 255, 0, 227, 227, 227, 9, 226, 226, 226, 43, 192, 192, 192, 4, 255, 255, 255, 0, 255, 255, 255, 0, 226, 226, 226, 26, 225, 225, 225, 51, 223, 223, 223, 47, 227, 227, 227, 9, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 9, 228, 228, 228, 47, 225, 225, 225, 51, 225, 225, 225, 25, 255, 255, 255, 0, 255, 255, 255, 0, 231, 231, 231, 41, 225, 225, 225, 51, 225, 225, 225, 51, 225, 225, 225, 17, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 18, 225, 225, 225, 51, 225, 225, 225, 51, 224, 224, 224, 40, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 41, 225, 225, 225, 51, 225, 225, 225, 51, 225, 225, 225, 17, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 89, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 200, 255, 255, 255, 0, 255, 255, 255, 0, 226, 226, 226, 26, 225, 225, 225, 51, 223, 223, 223, 47, 255, 255, 255, 8, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 42, 224, 224, 224, 233, 224, 224, 224, 255, 225, 225, 225, 124, 255, 255, 255, 0, 255, 255, 255, 0, 192, 192, 192, 4, 226, 226, 226, 43, 224, 224, 224, 8, 255, 255, 255, 0, 227, 227, 227, 9, 227, 227, 227, 18, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 18, 227, 227, 227, 9, 255, 255, 255, 0, 225, 225, 225, 42, 224, 224, 224, 211, 238, 238, 238, 15, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 1, 255, 255, 255, 0, 227, 227, 227, 9, 228, 228, 228, 47, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 1, 225, 225, 225, 51, 223, 223, 223, 47, 227, 227, 227, 9, 255, 255, 255, 0, 255, 255, 255, 6, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 2, 226, 226, 226, 43, 225, 225, 225, 51, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 1, 225, 225, 225, 51, 225, 225, 225, 51, 226, 226, 226, 43, 255, 255, 255, 2, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 192, 192, 192, 4, 226, 226, 226, 26, 224, 224, 224, 40, 255, 255, 255, 0, 255, 255, 255, 1, 229, 229, 229, 39, 225, 225, 225, 25, 255, 255, 255, 3, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_o41n3"] -image = SubResource("Image_miuuy") - -[sub_resource type="Image" id="Image_ern2r"] -data = { -"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 4, 226, 226, 226, 26, 224, 224, 224, 41, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 41, 226, 226, 226, 26, 192, 192, 192, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 2, 226, 226, 226, 43, 225, 225, 225, 51, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 51, 225, 225, 225, 51, 226, 226, 226, 43, 255, 255, 255, 1, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 2, 255, 255, 255, 0, 227, 227, 227, 9, 223, 223, 223, 47, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 51, 223, 223, 223, 47, 224, 224, 224, 8, 255, 255, 255, 0, 255, 255, 255, 2, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 4, 226, 226, 226, 43, 227, 227, 227, 9, 255, 255, 255, 0, 227, 227, 227, 9, 225, 225, 225, 17, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 17, 255, 255, 255, 8, 255, 255, 255, 0, 227, 227, 227, 9, 226, 226, 226, 43, 192, 192, 192, 4, 255, 255, 255, 0, 255, 255, 255, 0, 226, 226, 226, 26, 225, 225, 225, 51, 223, 223, 223, 47, 227, 227, 227, 9, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 9, 228, 228, 228, 47, 225, 225, 225, 51, 225, 225, 225, 25, 255, 255, 255, 0, 255, 255, 255, 0, 231, 231, 231, 41, 225, 225, 225, 51, 225, 225, 225, 51, 225, 225, 225, 17, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 18, 225, 225, 225, 51, 225, 225, 225, 51, 224, 224, 224, 40, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 41, 225, 225, 225, 51, 225, 225, 225, 51, 225, 225, 225, 17, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 18, 225, 225, 225, 51, 225, 225, 225, 51, 224, 224, 224, 40, 255, 255, 255, 0, 255, 255, 255, 0, 226, 226, 226, 26, 225, 225, 225, 51, 223, 223, 223, 47, 255, 255, 255, 8, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 9, 223, 223, 223, 47, 225, 225, 225, 51, 225, 225, 225, 25, 255, 255, 255, 0, 255, 255, 255, 0, 192, 192, 192, 4, 226, 226, 226, 43, 224, 224, 224, 8, 255, 255, 255, 0, 227, 227, 227, 9, 227, 227, 227, 18, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 101, 224, 224, 224, 49, 255, 255, 255, 0, 227, 227, 227, 9, 226, 226, 226, 43, 255, 255, 255, 3, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 1, 255, 255, 255, 0, 227, 227, 227, 9, 228, 228, 228, 47, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 238, 224, 224, 224, 49, 255, 255, 255, 0, 255, 255, 255, 2, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 2, 226, 226, 226, 43, 225, 225, 225, 51, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 209, 255, 255, 255, 6, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 192, 192, 192, 4, 226, 226, 226, 26, 224, 224, 224, 40, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 188, 224, 224, 224, 112, 230, 230, 230, 10, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_6oiqe"] -image = SubResource("Image_ern2r") - -[sub_resource type="Image" id="Image_qdci2"] -data = { -"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 4, 226, 226, 226, 26, 224, 224, 224, 41, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 41, 226, 226, 226, 26, 192, 192, 192, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 2, 226, 226, 226, 43, 225, 225, 225, 51, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 51, 225, 225, 225, 51, 226, 226, 226, 43, 255, 255, 255, 1, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 2, 255, 255, 255, 0, 227, 227, 227, 9, 223, 223, 223, 47, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 51, 223, 223, 223, 47, 224, 224, 224, 8, 255, 255, 255, 0, 255, 255, 255, 2, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 4, 226, 226, 226, 43, 227, 227, 227, 9, 255, 255, 255, 0, 227, 227, 227, 9, 225, 225, 225, 17, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 17, 255, 255, 255, 8, 255, 255, 255, 0, 227, 227, 227, 9, 226, 226, 226, 43, 192, 192, 192, 4, 255, 255, 255, 0, 255, 255, 255, 0, 226, 226, 226, 26, 225, 225, 225, 51, 223, 223, 223, 47, 227, 227, 227, 9, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 9, 228, 228, 228, 47, 225, 225, 225, 51, 225, 225, 225, 25, 255, 255, 255, 0, 255, 255, 255, 0, 231, 231, 231, 41, 225, 225, 225, 51, 225, 225, 225, 51, 225, 225, 225, 17, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 18, 225, 225, 225, 51, 225, 225, 225, 51, 224, 224, 224, 40, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 41, 225, 225, 225, 51, 225, 225, 225, 51, 225, 225, 225, 17, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 18, 225, 225, 225, 51, 225, 225, 225, 51, 224, 224, 224, 40, 255, 255, 255, 0, 255, 255, 255, 0, 226, 226, 226, 26, 225, 225, 225, 51, 223, 223, 223, 47, 255, 255, 255, 8, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 9, 223, 223, 223, 47, 225, 225, 225, 51, 225, 225, 225, 25, 255, 255, 255, 0, 255, 255, 255, 0, 192, 192, 192, 4, 226, 226, 226, 43, 224, 224, 224, 8, 255, 255, 255, 0, 226, 226, 226, 52, 225, 225, 225, 101, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 18, 227, 227, 227, 9, 255, 255, 255, 0, 227, 227, 227, 9, 226, 226, 226, 43, 255, 255, 255, 3, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 1, 255, 255, 255, 0, 227, 227, 227, 53, 224, 224, 224, 239, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 1, 225, 225, 225, 51, 223, 223, 223, 47, 227, 227, 227, 9, 255, 255, 255, 0, 255, 255, 255, 2, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 7, 224, 224, 224, 213, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 1, 225, 225, 225, 51, 225, 225, 225, 51, 226, 226, 226, 43, 255, 255, 255, 2, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 232, 232, 232, 11, 224, 224, 224, 113, 224, 224, 224, 188, 255, 255, 255, 0, 255, 255, 255, 1, 229, 229, 229, 39, 225, 225, 225, 25, 255, 255, 255, 3, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_l0amb"] -image = SubResource("Image_qdci2") - -[sub_resource type="Image" id="Image_hed0i"] -data = { -"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 4, 226, 226, 226, 26, 224, 224, 224, 41, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 41, 226, 226, 226, 26, 192, 192, 192, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 2, 226, 226, 226, 43, 225, 225, 225, 51, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 51, 225, 225, 225, 51, 226, 226, 226, 43, 255, 255, 255, 1, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 2, 255, 255, 255, 0, 227, 227, 227, 9, 223, 223, 223, 47, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 51, 223, 223, 223, 47, 224, 224, 224, 8, 255, 255, 255, 0, 255, 255, 255, 2, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 4, 226, 226, 226, 43, 227, 227, 227, 9, 255, 255, 255, 0, 227, 227, 227, 9, 225, 225, 225, 17, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 17, 255, 255, 255, 8, 255, 255, 255, 0, 227, 227, 227, 9, 226, 226, 226, 43, 192, 192, 192, 4, 255, 255, 255, 0, 255, 255, 255, 0, 226, 226, 226, 26, 225, 225, 225, 51, 223, 223, 223, 47, 227, 227, 227, 9, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 9, 228, 228, 228, 47, 225, 225, 225, 51, 225, 225, 225, 25, 255, 255, 255, 0, 255, 255, 255, 0, 231, 231, 231, 41, 225, 225, 225, 51, 225, 225, 225, 51, 225, 225, 225, 17, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 18, 225, 225, 225, 51, 225, 225, 225, 51, 224, 224, 224, 40, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 1, 255, 255, 255, 1, 255, 255, 255, 1, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 202, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 85, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 18, 225, 225, 225, 51, 225, 225, 225, 51, 224, 224, 224, 40, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 128, 224, 224, 224, 255, 224, 224, 224, 231, 224, 224, 224, 40, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 9, 223, 223, 223, 47, 225, 225, 225, 51, 225, 225, 225, 25, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 17, 224, 224, 224, 212, 229, 229, 229, 39, 255, 255, 255, 0, 227, 227, 227, 9, 227, 227, 227, 18, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 18, 227, 227, 227, 9, 255, 255, 255, 0, 227, 227, 227, 9, 226, 226, 226, 43, 255, 255, 255, 3, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 5, 255, 255, 255, 0, 227, 227, 227, 9, 228, 228, 228, 47, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 51, 223, 223, 223, 47, 227, 227, 227, 9, 255, 255, 255, 0, 255, 255, 255, 2, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 2, 226, 226, 226, 43, 225, 225, 225, 51, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 51, 225, 225, 225, 51, 226, 226, 226, 43, 255, 255, 255, 2, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 192, 192, 192, 4, 225, 225, 225, 25, 230, 230, 230, 40, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 40, 225, 225, 225, 25, 255, 255, 255, 3, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_nonnc"] -image = SubResource("Image_hed0i") - -[sub_resource type="Image" id="Image_8v04w"] -data = { -"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 4, 226, 226, 226, 26, 224, 224, 224, 41, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 41, 226, 226, 226, 26, 192, 192, 192, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 2, 226, 226, 226, 43, 225, 225, 225, 51, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 51, 225, 225, 225, 51, 226, 226, 226, 43, 255, 255, 255, 1, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 8, 255, 255, 255, 0, 227, 227, 227, 9, 223, 223, 223, 47, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 51, 223, 223, 223, 47, 224, 224, 224, 8, 255, 255, 255, 0, 255, 255, 255, 2, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 229, 229, 229, 19, 224, 224, 224, 218, 227, 227, 227, 45, 255, 255, 255, 0, 227, 227, 227, 9, 225, 225, 225, 17, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 17, 255, 255, 255, 8, 255, 255, 255, 0, 227, 227, 227, 9, 226, 226, 226, 43, 192, 192, 192, 4, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 131, 224, 224, 224, 255, 224, 224, 224, 234, 227, 227, 227, 45, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 9, 228, 228, 228, 47, 225, 225, 225, 51, 225, 225, 225, 25, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 202, 224, 224, 224, 252, 224, 224, 224, 252, 224, 224, 224, 82, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 18, 225, 225, 225, 51, 225, 225, 225, 51, 224, 224, 224, 40, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 41, 225, 225, 225, 51, 225, 225, 225, 51, 225, 225, 225, 17, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 18, 225, 225, 225, 51, 225, 225, 225, 51, 224, 224, 224, 40, 255, 255, 255, 0, 255, 255, 255, 0, 226, 226, 226, 26, 225, 225, 225, 51, 223, 223, 223, 47, 255, 255, 255, 8, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 9, 223, 223, 223, 47, 225, 225, 225, 51, 225, 225, 225, 25, 255, 255, 255, 0, 255, 255, 255, 0, 192, 192, 192, 4, 226, 226, 226, 43, 224, 224, 224, 8, 255, 255, 255, 0, 227, 227, 227, 9, 227, 227, 227, 18, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 18, 227, 227, 227, 9, 255, 255, 255, 0, 227, 227, 227, 9, 226, 226, 226, 43, 255, 255, 255, 3, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 1, 255, 255, 255, 0, 227, 227, 227, 9, 228, 228, 228, 47, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 51, 223, 223, 223, 47, 227, 227, 227, 9, 255, 255, 255, 0, 255, 255, 255, 2, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 2, 226, 226, 226, 43, 225, 225, 225, 51, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 51, 225, 225, 225, 51, 226, 226, 226, 43, 255, 255, 255, 2, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 192, 192, 192, 4, 226, 226, 226, 26, 224, 224, 224, 40, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 40, 225, 225, 225, 25, 255, 255, 255, 3, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_d2btj"] -image = SubResource("Image_8v04w") - -[sub_resource type="Image" id="Image_arwmg"] -data = { -"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 230, 230, 230, 30, 225, 225, 225, 149, 224, 224, 224, 221, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 41, 226, 226, 226, 26, 192, 192, 192, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 7, 224, 224, 224, 214, 224, 224, 224, 255, 224, 224, 224, 253, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 51, 225, 225, 225, 51, 226, 226, 226, 43, 255, 255, 255, 1, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 2, 255, 255, 255, 0, 231, 231, 231, 31, 224, 224, 224, 224, 224, 224, 224, 252, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 51, 223, 223, 223, 47, 224, 224, 224, 8, 255, 255, 255, 0, 255, 255, 255, 2, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 4, 226, 226, 226, 43, 227, 227, 227, 9, 255, 255, 255, 0, 224, 224, 224, 32, 227, 227, 227, 63, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 17, 255, 255, 255, 8, 255, 255, 255, 0, 227, 227, 227, 9, 226, 226, 226, 43, 192, 192, 192, 4, 255, 255, 255, 0, 255, 255, 255, 0, 226, 226, 226, 26, 225, 225, 225, 51, 223, 223, 223, 47, 227, 227, 227, 9, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 9, 228, 228, 228, 47, 225, 225, 225, 51, 225, 225, 225, 25, 255, 255, 255, 0, 255, 255, 255, 0, 231, 231, 231, 41, 225, 225, 225, 51, 225, 225, 225, 51, 225, 225, 225, 17, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 18, 225, 225, 225, 51, 225, 225, 225, 51, 224, 224, 224, 40, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 41, 225, 225, 225, 51, 225, 225, 225, 51, 225, 225, 225, 17, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 18, 225, 225, 225, 51, 225, 225, 225, 51, 224, 224, 224, 40, 255, 255, 255, 0, 255, 255, 255, 0, 226, 226, 226, 26, 225, 225, 225, 51, 223, 223, 223, 47, 255, 255, 255, 8, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 9, 223, 223, 223, 47, 225, 225, 225, 51, 225, 225, 225, 25, 255, 255, 255, 0, 255, 255, 255, 0, 192, 192, 192, 4, 226, 226, 226, 43, 224, 224, 224, 8, 255, 255, 255, 0, 227, 227, 227, 9, 227, 227, 227, 18, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 18, 227, 227, 227, 9, 255, 255, 255, 0, 227, 227, 227, 9, 226, 226, 226, 43, 255, 255, 255, 3, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 1, 255, 255, 255, 0, 227, 227, 227, 9, 228, 228, 228, 47, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 1, 225, 225, 225, 51, 223, 223, 223, 47, 227, 227, 227, 9, 255, 255, 255, 0, 255, 255, 255, 2, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 2, 226, 226, 226, 43, 225, 225, 225, 51, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 1, 225, 225, 225, 51, 225, 225, 225, 51, 226, 226, 226, 43, 255, 255, 255, 2, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 192, 192, 192, 4, 226, 226, 226, 26, 224, 224, 224, 40, 255, 255, 255, 0, 255, 255, 255, 1, 229, 229, 229, 39, 225, 225, 225, 25, 255, 255, 255, 3, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_1bxo7"] -image = SubResource("Image_arwmg") - -[sub_resource type="AnimatedTexture" id="AnimatedTexture_eylo1"] -frames = 8 -speed_scale = 2.5 -frame_0/texture = SubResource("ImageTexture_nwpuj") -frame_0/duration = 0.2 -frame_1/texture = SubResource("ImageTexture_pdcj5") -frame_1/duration = 0.2 -frame_2/texture = SubResource("ImageTexture_o41n3") -frame_2/duration = 0.2 -frame_3/texture = SubResource("ImageTexture_6oiqe") -frame_3/duration = 0.2 -frame_4/texture = SubResource("ImageTexture_l0amb") -frame_4/duration = 0.2 -frame_5/texture = SubResource("ImageTexture_nonnc") -frame_5/duration = 0.2 -frame_6/texture = SubResource("ImageTexture_d2btj") -frame_6/duration = 0.2 -frame_7/texture = SubResource("ImageTexture_1bxo7") -frame_7/duration = 0.2 - -[sub_resource type="Image" id="Image_rqglq"] -data = { -"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 195, 224, 224, 224, 210, 224, 224, 224, 56, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 253, 224, 224, 224, 139, 224, 224, 224, 8, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 215, 224, 224, 224, 56, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 253, 224, 224, 224, 139, 224, 224, 224, 8, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 183, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 182, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 252, 225, 225, 225, 134, 255, 255, 255, 6, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 212, 226, 226, 226, 52, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 252, 225, 225, 225, 134, 255, 255, 255, 6, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 191, 224, 224, 224, 206, 226, 226, 226, 52, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_dr7yj"] -image = SubResource("Image_rqglq") - -[sub_resource type="Image" id="Image_ltb1l"] -data = { -"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 184, 224, 224, 224, 255, 224, 224, 224, 181, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 184, 224, 224, 224, 202, 228, 228, 228, 37, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 239, 224, 224, 224, 74, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 253, 224, 224, 224, 123, 255, 255, 255, 1, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 173, 234, 234, 234, 12, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 188, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 185, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 168, 230, 230, 230, 10, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 252, 225, 225, 225, 118, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 237, 226, 226, 226, 70, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 181, 224, 224, 224, 255, 224, 224, 224, 180, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 188, 224, 224, 224, 201, 225, 225, 225, 34, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_oh8cr"] -image = SubResource("Image_ltb1l") - -[sub_resource type="Image" id="Image_2lq8w"] -data = { -"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 196, 224, 224, 224, 196, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 24, 226, 226, 226, 60, 226, 226, 226, 60, 224, 224, 224, 255, 224, 224, 224, 255, 226, 226, 226, 60, 226, 226, 226, 60, 233, 233, 233, 23, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 5, 225, 225, 225, 134, 224, 224, 224, 254, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 254, 225, 225, 225, 133, 255, 255, 255, 5, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 67, 224, 224, 224, 231, 224, 224, 224, 230, 224, 224, 224, 66, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 231, 231, 231, 21, 231, 231, 231, 21, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 71, 224, 224, 224, 236, 224, 224, 224, 236, 224, 224, 224, 236, 224, 224, 224, 236, 224, 224, 224, 236, 224, 224, 224, 236, 224, 224, 224, 236, 224, 224, 224, 236, 224, 224, 224, 236, 224, 224, 224, 236, 224, 224, 224, 236, 224, 224, 224, 236, 224, 224, 224, 236, 224, 224, 224, 236, 225, 225, 225, 67, 226, 226, 226, 69, 224, 224, 224, 232, 224, 224, 224, 232, 224, 224, 224, 232, 224, 224, 224, 232, 224, 224, 224, 232, 224, 224, 224, 232, 224, 224, 224, 232, 224, 224, 224, 232, 224, 224, 224, 232, 224, 224, 224, 232, 224, 224, 224, 232, 224, 224, 224, 232, 224, 224, 224, 232, 224, 224, 224, 232, 224, 224, 224, 66, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 231, 231, 231, 21, 230, 230, 230, 20, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 65, 224, 224, 224, 229, 224, 224, 224, 229, 224, 224, 224, 64, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 4, 224, 224, 224, 132, 224, 224, 224, 253, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 253, 224, 224, 224, 130, 255, 255, 255, 3, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 24, 224, 224, 224, 64, 224, 224, 224, 64, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 64, 224, 224, 224, 64, 233, 233, 233, 23, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 200, 224, 224, 224, 200, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_x1ivs"] -image = SubResource("Image_2lq8w") - -[sub_resource type="Image" id="Image_kwwmp"] -data = { -"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 237, 237, 237, 14, 224, 224, 224, 165, 224, 224, 224, 165, 237, 237, 237, 14, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 58, 225, 225, 225, 223, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 223, 225, 225, 225, 58, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 233, 233, 233, 23, 225, 225, 225, 124, 224, 224, 224, 128, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 128, 225, 225, 225, 124, 233, 233, 233, 23, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 233, 233, 233, 23, 225, 225, 225, 125, 224, 224, 224, 128, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 128, 225, 225, 225, 125, 233, 233, 233, 23, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 59, 224, 224, 224, 224, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 223, 225, 225, 225, 59, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 238, 238, 238, 15, 224, 224, 224, 165, 224, 224, 224, 165, 238, 238, 238, 15, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_i13wr"] -image = SubResource("Image_kwwmp") - -[node name="MainPanel" type="VSplitContainer"] -use_parent_material = true -clip_contents = true -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_right = -924.0 -grow_horizontal = 2 -grow_vertical = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 -split_offset = 200 -script = ExtResource("1") - -[node name="Panel" type="PanelContainer" parent="."] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="Tree" type="Tree" parent="Panel"] -use_parent_material = true -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 -theme_override_constants/icon_max_width = 16 -columns = 2 -allow_rmb_select = true -hide_root = true -select_mode = 1 - -[node name="discover_hint" type="HBoxContainer" parent="Panel"] -unique_name_in_owner = true -visible = false -use_parent_material = true -layout_mode = 2 -alignment = 1 - -[node name="spinner" type="Button" parent="Panel/discover_hint"] -unique_name_in_owner = true -clip_contents = true -custom_minimum_size = Vector2(64, 64) -layout_mode = 2 -size_flags_stretch_ratio = 1.94 -disabled = true -button_mask = 0 -text = "Discover Tests" -icon = SubResource("AnimatedTexture_eylo1") -flat = true -alignment = 2 - -[node name="report" type="PanelContainer" parent="."] -clip_contents = true -layout_mode = 2 -size_flags_horizontal = 11 -size_flags_vertical = 11 - -[node name="report_template" type="RichTextLabel" parent="report"] -use_parent_material = true -clip_contents = false -layout_mode = 2 -size_flags_horizontal = 3 -auto_translate = false -localize_numeral_system = false -focus_mode = 2 -bbcode_enabled = true -fit_content = true -selection_enabled = true - -[node name="ScrollContainer" type="ScrollContainer" parent="report"] -use_parent_material = true -custom_minimum_size = Vector2(0, 80) -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 11 - -[node name="list" type="VBoxContainer" parent="report/ScrollContainer"] -clip_contents = true -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="contextMenu" type="PopupMenu" parent="."] -size = Vector2i(133, 120) -auto_translate = false -item_count = 5 -item_0/text = "Run" -item_0/icon = SubResource("ImageTexture_dr7yj") -item_0/id = 0 -item_1/text = "Debug" -item_1/icon = SubResource("ImageTexture_oh8cr") -item_1/id = 1 -item_2/text = "" -item_2/id = 2 -item_2/separator = true -item_3/text = "Collapse All" -item_3/icon = SubResource("ImageTexture_x1ivs") -item_3/id = 3 -item_4/text = "Expand All" -item_4/icon = SubResource("ImageTexture_i13wr") -item_4/id = 4 - -[connection signal="item_activated" from="Panel/Tree" to="." method="_on_Tree_item_activated"] -[connection signal="item_mouse_selected" from="Panel/Tree" to="." method="_on_tree_item_mouse_selected"] -[connection signal="item_selected" from="Panel/Tree" to="." method="_on_Tree_item_selected"] -[connection signal="index_pressed" from="contextMenu" to="." method="_on_context_m_index_pressed"] diff --git a/addons/gdUnit4/src/ui/settings/GdUnitInputCapture.gd b/addons/gdUnit4/src/ui/settings/GdUnitInputCapture.gd deleted file mode 100644 index b5cc8370..00000000 --- a/addons/gdUnit4/src/ui/settings/GdUnitInputCapture.gd +++ /dev/null @@ -1,56 +0,0 @@ -@tool -class_name GdUnitInputCapture -extends Control - -signal input_completed(input_event: InputEventKey) - - -var _tween: Tween -var _input_event: InputEventKey - - -func _ready() -> void: - reset() - self_modulate = Color.WHITE - _tween = create_tween() - @warning_ignore("return_value_discarded") - _tween.set_loops() - @warning_ignore("return_value_discarded") - _tween.tween_property(%Label, "self_modulate", Color(1, 1, 1, .8), 1.0).from_current().set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_IN_OUT) - - -func reset() -> void: - _input_event = InputEventKey.new() - - -func _input(event: InputEvent) -> void: - if not is_visible_in_tree(): - return - if event is InputEventKey and event.is_pressed() and not event.is_echo(): - var _event := event as InputEventKey - match _event.keycode: - KEY_CTRL: - _input_event.ctrl_pressed = true - KEY_SHIFT: - _input_event.shift_pressed = true - KEY_ALT: - _input_event.alt_pressed = true - KEY_META: - _input_event.meta_pressed = true - _: - _input_event.keycode = _event.keycode - _apply_input_modifiers(_event) - accept_event() - - if event is InputEventKey and not event.is_pressed(): - input_completed.emit(_input_event) - hide() - - -func _apply_input_modifiers(event: InputEvent) -> void: - if event is InputEventWithModifiers: - var _event := event as InputEventWithModifiers - _input_event.meta_pressed = _event.meta_pressed or _input_event.meta_pressed - _input_event.alt_pressed = _event.alt_pressed or _input_event.alt_pressed - _input_event.shift_pressed = _event.shift_pressed or _input_event.shift_pressed - _input_event.ctrl_pressed = _event.ctrl_pressed or _input_event.ctrl_pressed diff --git a/addons/gdUnit4/src/ui/settings/GdUnitInputCapture.gd.uid b/addons/gdUnit4/src/ui/settings/GdUnitInputCapture.gd.uid deleted file mode 100644 index 397d20f6..00000000 --- a/addons/gdUnit4/src/ui/settings/GdUnitInputCapture.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://diwikaq2bawk diff --git a/addons/gdUnit4/src/ui/settings/GdUnitInputCapture.tscn b/addons/gdUnit4/src/ui/settings/GdUnitInputCapture.tscn deleted file mode 100644 index 7e62c438..00000000 --- a/addons/gdUnit4/src/ui/settings/GdUnitInputCapture.tscn +++ /dev/null @@ -1,36 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://pmnkxrhglak5"] - -[ext_resource type="Script" path="res://addons/gdUnit4/src/ui/settings/GdUnitInputCapture.gd" id="1_gki1u"] - -[node name="GdUnitInputMapper" type="Control"] -modulate = Color(0.929099, 0.929099, 0.929099, 0.936189) -top_level = true -layout_mode = 3 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 -script = ExtResource("1_gki1u") - -[node name="Label" type="Label" parent="."] -unique_name_in_owner = true -self_modulate = Color(0.401913, 0.401913, 0.401913, 0.461723) -top_level = true -layout_mode = 1 -anchors_preset = 8 -anchor_left = 0.5 -anchor_top = 0.5 -anchor_right = 0.5 -anchor_bottom = 0.5 -offset_left = -60.5 -offset_top = -19.5 -offset_right = 60.5 -offset_bottom = 19.5 -grow_horizontal = 2 -grow_vertical = 2 -theme_override_colors/font_color = Color(1, 1, 1, 1) -theme_override_font_sizes/font_size = 26 -text = "Press keys for shortcut" diff --git a/addons/gdUnit4/src/ui/settings/GdUnitSettingsDialog.gd b/addons/gdUnit4/src/ui/settings/GdUnitSettingsDialog.gd deleted file mode 100644 index 14a8bd5b..00000000 --- a/addons/gdUnit4/src/ui/settings/GdUnitSettingsDialog.gd +++ /dev/null @@ -1,327 +0,0 @@ -@tool -extends Window - -const EAXAMPLE_URL := "https://github.com/MikeSchulze/gdUnit4-examples/archive/refs/heads/master.zip" -const GdUnitTools := preload ("res://addons/gdUnit4/src/core/GdUnitTools.gd") -const GdUnitUpdateClient = preload ("res://addons/gdUnit4/src/update/GdUnitUpdateClient.gd") - -@onready var _update_client: GdUnitUpdateClient = $GdUnitUpdateClient -@onready var _version_label: RichTextLabel = %version -@onready var _btn_install: Button = %btn_install_examples -@onready var _progress_bar: ProgressBar = %ProgressBar -@onready var _progress_text: Label = %progress_lbl -@onready var _properties_template: Control = $property_template -@onready var _properties_common: Control = % "common-content" -@onready var _properties_ui: Control = % "ui-content" -@onready var _properties_shortcuts: Control = % "shortcut-content" -@onready var _properties_report: Control = % "report-content" -@onready var _input_capture: GdUnitInputCapture = %GdUnitInputCapture -@onready var _property_error: Window = % "propertyError" -@onready var _tab_container: TabContainer = %Properties -@onready var _update_tab: Control = %Update - -var _font_size: float - - -func _ready() -> void: - set_name("GdUnitSettingsDialog") - # initialize for testing - if not Engine.is_editor_hint(): - GdUnitSettings.setup() - GdUnit4Version.init_version_label(_version_label) - _font_size = GdUnitFonts.init_fonts(_version_label) - setup_properties(_properties_common, GdUnitSettings.COMMON_SETTINGS) - setup_properties(_properties_ui, GdUnitSettings.UI_SETTINGS) - setup_properties(_properties_report, GdUnitSettings.REPORT_SETTINGS) - setup_properties(_properties_shortcuts, GdUnitSettings.SHORTCUT_SETTINGS) - check_for_update() - - -func _sort_by_key(left: GdUnitProperty, right: GdUnitProperty) -> bool: - return left.name() < right.name() - - -func setup_properties(properties_parent: Control, property_category: String) -> void: - # Do remove first potential previous added properties (could be happened when the dlg is opened at twice) - for child in properties_parent.get_children(): - properties_parent.remove_child(child) - - var category_properties := GdUnitSettings.list_settings(property_category) - # sort by key - category_properties.sort_custom(_sort_by_key) - var theme_ := Theme.new() - theme_.set_constant("h_separation", "GridContainer", 12) - var last_category := "!" - var min_size_overall := 0.0 - var labels := [] - var inputs := [] - var info_labels := [] - var grid: GridContainer = null - for p in category_properties: - var min_size_ := 0.0 - var property: GdUnitProperty = p - var current_category := property.category() - if not grid or current_category != last_category: - grid = GridContainer.new() - grid.columns = 4 - grid.theme = theme_ - - var sub_category: Control = _properties_template.get_child(3).duplicate() - var category_label: Label = sub_category.get_child(0) - category_label.text = current_category.capitalize() - sub_category.custom_minimum_size.y = _font_size + 16 - properties_parent.add_child(sub_category) - properties_parent.add_child(grid) - last_category = current_category - # property name - var label: Label = _properties_template.get_child(0).duplicate() - label.text = _to_human_readable(property.name()) - labels.append(label) - grid.add_child(label) - - # property reset btn - var reset_btn: Button = _properties_template.get_child(1).duplicate() - reset_btn.icon = _get_btn_icon("Reload") - reset_btn.disabled = property.value() == property.default() - grid.add_child(reset_btn) - - # property type specific input element - var input: Node = _create_input_element(property, reset_btn) - inputs.append(input) - grid.add_child(input) - @warning_ignore("return_value_discarded") - reset_btn.pressed.connect(_on_btn_property_reset_pressed.bind(property, input, reset_btn)) - # property help text - var info: Label = _properties_template.get_child(2).duplicate() - info.text = property.help() - info_labels.append(info) - grid.add_child(info) - if min_size_overall < min_size_: - min_size_overall = min_size_ - - for controls: Array in [labels, inputs, info_labels]: - var _size: float = controls.map(func(c: Control) -> float: return c.size.x).max() - min_size_overall += _size - for control: Control in controls: - control.custom_minimum_size.x = _size - properties_parent.custom_minimum_size.x = min_size_overall - - -func _create_input_element(property: GdUnitProperty, reset_btn: Button) -> Node: - if property.is_selectable_value(): - var options := OptionButton.new() - options.alignment = HORIZONTAL_ALIGNMENT_CENTER - for value in property.value_set(): - options.add_item(value) - options.item_selected.connect(_on_option_selected.bind(property, reset_btn)) - options.select(property.int_value()) - return options - if property.type() == TYPE_BOOL: - var check_btn := CheckButton.new() - check_btn.toggled.connect(_on_property_text_changed.bind(property, reset_btn)) - check_btn.button_pressed = property.value() - return check_btn - if property.type() in [TYPE_INT, TYPE_STRING]: - var input := LineEdit.new() - input.text_changed.connect(_on_property_text_changed.bind(property, reset_btn)) - input.set_context_menu_enabled(false) - input.set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER) - input.set_expand_to_text_length_enabled(true) - input.text = str(property.value()) - return input - if property.type() == TYPE_PACKED_INT32_ARRAY: - var key_input_button := Button.new() - var value:PackedInt32Array = property.value() - key_input_button.text = to_shortcut(value) - key_input_button.pressed.connect(_on_shortcut_change.bind(key_input_button, property, reset_btn)) - return key_input_button - return Control.new() - - -func to_shortcut(keys: PackedInt32Array) -> String: - var input_event := InputEventKey.new() - for key in keys: - match key: - KEY_CTRL: input_event.ctrl_pressed = true - KEY_SHIFT: input_event.shift_pressed = true - KEY_ALT: input_event.alt_pressed = true - KEY_META: input_event.meta_pressed = true - _: - input_event.keycode = key as Key - return input_event.as_text() - - -func to_keys(input_event: InputEventKey) -> PackedInt32Array: - var keys := PackedInt32Array() - if input_event.ctrl_pressed: - keys.append(KEY_CTRL) - if input_event.shift_pressed: - keys.append(KEY_SHIFT) - if input_event.alt_pressed: - keys.append(KEY_ALT) - if input_event.meta_pressed: - keys.append(KEY_META) - keys.append(input_event.keycode) - return keys - - -func _to_human_readable(value: String) -> String: - return value.split("/")[-1].capitalize() - - -func _get_btn_icon(p_name: String) -> Texture2D: - if not Engine.is_editor_hint(): - var placeholder := PlaceholderTexture2D.new() - placeholder.size = Vector2(8, 8) - return placeholder - return GdUnitUiTools.get_icon(p_name) - - -func _install_examples() -> void: - _init_progress(5) - update_progress("Downloading examples") - await get_tree().process_frame - var tmp_path := GdUnitFileAccess.create_temp_dir("download") - var zip_file := tmp_path + "/examples.zip" - var response: GdUnitUpdateClient.HttpResponse = await _update_client.request_zip_package(EAXAMPLE_URL, zip_file) - if response.status() != 200: - push_warning("Examples cannot be retrieved from GitHub! \n Error code: %d : %s" % [response.status(), response.response()]) - update_progress("Install examples failed! Try it later again.") - await get_tree().create_timer(3).timeout - stop_progress() - return - # extract zip to tmp - update_progress("Install examples into project") - var result := GdUnitFileAccess.extract_zip(zip_file, "res://gdUnit4-examples/") - if result.is_error(): - update_progress("Install examples failed! %s" % result.error_message()) - await get_tree().create_timer(3).timeout - stop_progress() - return - update_progress("Refresh project") - await rescan() - await reimport("res://gdUnit4-examples/") - - update_progress("Examples successfully installed") - await get_tree().create_timer(3).timeout - stop_progress() - - -func rescan() -> void: - await get_tree().process_frame - var fs := EditorInterface.get_resource_filesystem() - fs.scan_sources() - while fs.is_scanning(): - await get_tree().create_timer(1).timeout - - -func reimport(path: String) -> void: - await get_tree().process_frame - var files := DirAccess.get_files_at(path) - EditorInterface.get_resource_filesystem().reimport_files(files) - for directory in DirAccess.get_directories_at(path): - reimport(directory) - - -func check_for_update() -> void: - if not GdUnitSettings.is_update_notification_enabled(): - return - var response :GdUnitUpdateClient.HttpResponse = await _update_client.request_latest_version() - if response.status() != 200: - printerr("Latest version information cannot be retrieved from GitHub!") - printerr("Error: %s" % response.response()) - return - var latest_version := _update_client.extract_latest_version(response) - if latest_version.is_greater(GdUnit4Version.current()): - var tab_index := _tab_container.get_tab_idx_from_control(_update_tab) - _tab_container.set_tab_button_icon(tab_index, GdUnitUiTools.get_icon("Notification", Color.YELLOW)) - _tab_container.set_tab_tooltip(tab_index, "An new update is available.") - - -func _on_btn_report_bug_pressed() -> void: - @warning_ignore("return_value_discarded") - OS.shell_open("https://github.com/MikeSchulze/gdUnit4/issues/new?assignees=MikeSchulze&labels=bug&projects=projects%2F5&template=bug_report.yml&title=GD-XXX%3A+Describe+the+issue+briefly") - - -func _on_btn_request_feature_pressed() -> void: - @warning_ignore("return_value_discarded") - OS.shell_open("https://github.com/MikeSchulze/gdUnit4/issues/new?assignees=MikeSchulze&labels=enhancement&projects=&template=feature_request.md&title=") - - -func _on_btn_install_examples_pressed() -> void: - _btn_install.disabled = true - await _install_examples() - _btn_install.disabled = false - - -func _on_btn_close_pressed() -> void: - hide() - - -func _on_btn_property_reset_pressed(property: GdUnitProperty, input: Node, reset_btn: Button) -> void: - if input is CheckButton: - var is_default_pressed: bool = property.default() - (input as CheckButton).button_pressed = is_default_pressed - elif input is LineEdit: - (input as LineEdit).text = str(property.default()) - # we have to update manually for text input fields because of no change event is emited - _on_property_text_changed(property.default(), property, reset_btn) - elif input is OptionButton: - (input as OptionButton).select(0) - _on_option_selected(0, property, reset_btn) - elif input is Button: - var value: PackedInt32Array = property.default() - (input as Button).text = to_shortcut(value) - _on_property_text_changed(value, property, reset_btn) - - -func _on_property_text_changed(new_value: Variant, property: GdUnitProperty, reset_btn: Button) -> void: - property.set_value(new_value) - reset_btn.disabled = property.value() == property.default() - var error: Variant = GdUnitSettings.update_property(property) - if error: - var label: Label = _property_error.get_child(0) as Label - label.set_text(str(error)) - var control := gui_get_focus_owner() - _property_error.show() - if control != null: - _property_error.position = control.global_position + Vector2(self.position) + Vector2(40, 40) - - -func _on_option_selected(index: int, property: GdUnitProperty, reset_btn: Button) -> void: - property.set_value(index) - reset_btn.disabled = property.value() == property.default() - GdUnitSettings.update_property(property) - - -func _on_shortcut_change(input_button: Button, property: GdUnitProperty, reset_btn: Button) -> void: - _input_capture.set_custom_minimum_size(_properties_shortcuts.get_size()) - _input_capture.visible = true - _input_capture.show() - _properties_shortcuts.visible = false - set_process_input(false) - _input_capture.reset() - var input_event: InputEventKey = await _input_capture.input_completed - input_button.text = input_event.as_text() - _on_property_text_changed(to_keys(input_event), property, reset_btn) - _properties_shortcuts.visible = true - set_process_input(true) - - -func _init_progress(max_value: int) -> void: - _progress_bar.visible = true - _progress_bar.max_value = max_value - _progress_bar.value = 0 - - -func _progress() -> void: - _progress_bar.value += 1 - - -func stop_progress() -> void: - _progress_bar.visible = false - - -func update_progress(message: String) -> void: - _progress_text.text = message - _progress_bar.value += 1 diff --git a/addons/gdUnit4/src/ui/settings/GdUnitSettingsDialog.gd.uid b/addons/gdUnit4/src/ui/settings/GdUnitSettingsDialog.gd.uid deleted file mode 100644 index 589dfad0..00000000 --- a/addons/gdUnit4/src/ui/settings/GdUnitSettingsDialog.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bk7c6m1wkjohm diff --git a/addons/gdUnit4/src/ui/settings/GdUnitSettingsDialog.tscn b/addons/gdUnit4/src/ui/settings/GdUnitSettingsDialog.tscn deleted file mode 100644 index 08afee43..00000000 --- a/addons/gdUnit4/src/ui/settings/GdUnitSettingsDialog.tscn +++ /dev/null @@ -1,349 +0,0 @@ -[gd_scene load_steps=9 format=3] - -[ext_resource type="Script" path="res://addons/gdUnit4/src/ui/settings/GdUnitSettingsDialog.gd" id="2"] -[ext_resource type="Texture2D" path="res://addons/gdUnit4/src/ui/settings/logo.png" id="3_isfyl"] -[ext_resource type="PackedScene" path="res://addons/gdUnit4/src/ui/templates/TestSuiteTemplate.tscn" id="4"] -[ext_resource type="PackedScene" path="res://addons/gdUnit4/src/ui/settings/GdUnitSettingsTabHooks.tscn" id="4_nf72w"] -[ext_resource type="PackedScene" path="res://addons/gdUnit4/src/update/GdUnitUpdateNotify.tscn" id="5_n1jtv"] -[ext_resource type="PackedScene" path="res://addons/gdUnit4/src/ui/settings/GdUnitInputCapture.tscn" id="5_xu3j8"] -[ext_resource type="Script" path="res://addons/gdUnit4/src/update/GdUnitUpdateClient.gd" id="8_2ggr0"] - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_hbbq5"] -content_margin_left = 10.0 -content_margin_right = 10.0 -bg_color = Color(0.172549, 0.113725, 0.141176, 1) -border_width_left = 4 -border_width_top = 4 -border_width_right = 4 -border_width_bottom = 4 -border_color = Color(0.87451, 0.0705882, 0.160784, 1) -border_blend = true -corner_radius_top_left = 8 -corner_radius_top_right = 8 -corner_radius_bottom_right = 8 -corner_radius_bottom_left = 8 -shadow_color = Color(0, 0, 0, 0.756863) -shadow_size = 10 -shadow_offset = Vector2(10, 10) - -[node name="GdUnitSettingsDialog" type="Window"] -disable_3d = true -gui_embed_subwindows = true -title = "GdUnit4 Settings" -initial_position = 1 -size = Vector2i(1400, 600) -visible = false -wrap_controls = true -exclusive = true -extend_to_title = true -script = ExtResource("2") - -[node name="property_template" type="Control" parent="."] -visible = false -layout_mode = 3 -anchors_preset = 0 -offset_left = 4.0 -offset_top = 4.0 -offset_right = 4.0 -offset_bottom = 4.0 -size_flags_horizontal = 0 - -[node name="Label" type="Label" parent="property_template"] -layout_mode = 1 -anchors_preset = 4 -anchor_top = 0.5 -anchor_bottom = 0.5 -offset_top = -11.5 -offset_right = 1.0 -offset_bottom = 11.5 -grow_vertical = 2 - -[node name="btn_reset" type="Button" parent="property_template"] -layout_mode = 0 -offset_right = 12.0 -offset_bottom = 40.0 -tooltip_text = "Reset to default value" -clip_text = true - -[node name="info" type="Label" parent="property_template"] -clip_contents = true -layout_mode = 1 -anchors_preset = 4 -anchor_top = 0.5 -anchor_bottom = 0.5 -offset_top = -11.5 -offset_right = 316.0 -offset_bottom = 11.5 -grow_vertical = 2 -size_flags_horizontal = 3 -max_lines_visible = 1 - -[node name="sub_category" type="Panel" parent="property_template"] -layout_mode = 1 -anchors_preset = 10 -anchor_right = 1.0 -offset_right = -220.0 -grow_horizontal = 2 -size_flags_horizontal = 3 - -[node name="Label" type="Label" parent="property_template/sub_category"] -layout_mode = 1 -anchors_preset = 4 -anchor_top = 0.5 -anchor_bottom = 0.5 -offset_left = 4.0 -offset_top = -11.5 -offset_right = 5.0 -offset_bottom = 11.5 -grow_vertical = 2 -theme_override_colors/font_color = Color(0.439216, 0.45098, 1, 1) - -[node name="GdUnitUpdateClient" type="Node" parent="."] -script = ExtResource("8_2ggr0") - -[node name="Panel" type="Panel" parent="."] -use_parent_material = true -clip_contents = true -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="PanelContainer" type="PanelContainer" parent="Panel"] -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="v" type="VBoxContainer" parent="Panel/PanelContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="MarginContainer" type="MarginContainer" parent="Panel/PanelContainer/v"] -use_parent_material = true -layout_mode = 2 -size_flags_vertical = 3 -theme_override_constants/margin_left = 4 -theme_override_constants/margin_top = 4 -theme_override_constants/margin_right = 4 - -[node name="GridContainer" type="HBoxContainer" parent="Panel/PanelContainer/v/MarginContainer"] -use_parent_material = true -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="PanelContainer" type="MarginContainer" parent="Panel/PanelContainer/v/MarginContainer/GridContainer"] -use_parent_material = true -layout_mode = 2 -size_flags_vertical = 3 - -[node name="Panel" type="VBoxContainer" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/PanelContainer"] -use_parent_material = true -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="CenterContainer" type="CenterContainer" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/PanelContainer/Panel"] -use_parent_material = true -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="logo" type="TextureRect" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/PanelContainer/Panel/CenterContainer"] -custom_minimum_size = Vector2(120, 120) -layout_mode = 2 -size_flags_horizontal = 0 -size_flags_vertical = 4 -texture = ExtResource("3_isfyl") -expand_mode = 1 -stretch_mode = 5 - -[node name="CenterContainer2" type="MarginContainer" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/PanelContainer/Panel"] -use_parent_material = true -custom_minimum_size = Vector2(0, 30) -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="version" type="RichTextLabel" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/PanelContainer/Panel/CenterContainer2"] -unique_name_in_owner = true -auto_translate_mode = 2 -use_parent_material = true -clip_contents = false -layout_mode = 2 -size_flags_horizontal = 3 -localize_numeral_system = false -bbcode_enabled = true -scroll_active = false -meta_underlined = false - -[node name="VBoxContainer" type="VBoxContainer" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/PanelContainer"] -custom_minimum_size = Vector2(200, 0) -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 -alignment = 2 - -[node name="btn_report_bug" type="Button" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/PanelContainer/VBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -tooltip_text = "Press to create a bug report" -text = "Report Bug" - -[node name="btn_request_feature" type="Button" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/PanelContainer/VBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -tooltip_text = "Press to create a feature request" -text = "Request Feature" - -[node name="btn_install_examples" type="Button" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/PanelContainer/VBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 3 -tooltip_text = "Press to install the advanced test examples" -disabled = true -text = "Install Examples" - -[node name="Properties" type="TabContainer" parent="Panel/PanelContainer/v/MarginContainer/GridContainer"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 3 -current_tab = 0 - -[node name="Common" type="ScrollContainer" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/Properties"] -layout_mode = 2 -metadata/_tab_index = 0 - -[node name="common-content" type="VBoxContainer" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/Properties/Common"] -unique_name_in_owner = true -clip_contents = true -custom_minimum_size = Vector2(1026, 0) -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="Hooks" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/Properties" instance=ExtResource("4_nf72w")] -visible = false -layout_mode = 2 - -[node name="UI" type="ScrollContainer" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/Properties"] -visible = false -layout_mode = 2 -metadata/_tab_index = 2 - -[node name="ui-content" type="VBoxContainer" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/Properties/UI"] -unique_name_in_owner = true -clip_contents = true -custom_minimum_size = Vector2(741, 0) -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="Shortcuts" type="ScrollContainer" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/Properties"] -visible = false -layout_mode = 2 -metadata/_tab_index = 3 - -[node name="shortcut-content" type="VBoxContainer" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/Properties/Shortcuts"] -unique_name_in_owner = true -clip_contents = true -custom_minimum_size = Vector2(683, 0) -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="Report" type="ScrollContainer" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/Properties"] -visible = false -layout_mode = 2 -metadata/_tab_index = 4 - -[node name="report-content" type="VBoxContainer" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/Properties/Report"] -unique_name_in_owner = true -clip_contents = true -custom_minimum_size = Vector2(667, 0) -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="Templates" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/Properties" instance=ExtResource("4")] -visible = false -layout_mode = 2 -metadata/_tab_index = 5 - -[node name="Update" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/Properties" instance=ExtResource("5_n1jtv")] -unique_name_in_owner = true -visible = false -layout_mode = 2 -metadata/_tab_index = 6 - -[node name="GdUnitInputCapture" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/Properties" instance=ExtResource("5_xu3j8")] -unique_name_in_owner = true -visible = false -modulate = Color(1.54884e-09, 1.54884e-09, 1.54884e-09, 0.1) -z_index = 1 -z_as_relative = false -layout_mode = 2 -size_flags_horizontal = 1 -size_flags_vertical = 1 - -[node name="propertyError" type="PopupPanel" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/Properties"] -unique_name_in_owner = true -initial_position = 1 -size = Vector2i(400, 100) -theme_override_styles/panel = SubResource("StyleBoxFlat_hbbq5") - -[node name="Label" type="Label" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/Properties/propertyError"] -offset_left = 10.0 -offset_top = 4.0 -offset_right = 390.0 -offset_bottom = 96.0 -theme_override_colors/font_color = Color(0.858824, 0, 0.109804, 1) -horizontal_alignment = 1 -vertical_alignment = 1 - -[node name="MarginContainer2" type="MarginContainer" parent="Panel/PanelContainer/v"] -layout_mode = 2 -size_flags_horizontal = 3 -theme_override_constants/margin_left = 4 -theme_override_constants/margin_right = 4 -theme_override_constants/margin_bottom = 4 - -[node name="HBoxContainer" type="HBoxContainer" parent="Panel/PanelContainer/v/MarginContainer2"] -layout_mode = 2 -size_flags_horizontal = 3 -alignment = 2 - -[node name="ProgressBar" type="ProgressBar" parent="Panel/PanelContainer/v/MarginContainer2/HBoxContainer"] -unique_name_in_owner = true -visible = false -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="progress_lbl" type="Label" parent="Panel/PanelContainer/v/MarginContainer2/HBoxContainer/ProgressBar"] -unique_name_in_owner = true -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 -clip_text = true - -[node name="btn_close" type="Button" parent="Panel/PanelContainer/v/MarginContainer2/HBoxContainer"] -custom_minimum_size = Vector2(200, 0) -layout_mode = 2 -text = "Close" - -[connection signal="close_requested" from="." to="." method="_on_btn_close_pressed"] -[connection signal="pressed" from="Panel/PanelContainer/v/MarginContainer/GridContainer/PanelContainer/VBoxContainer/btn_report_bug" to="." method="_on_btn_report_bug_pressed"] -[connection signal="pressed" from="Panel/PanelContainer/v/MarginContainer/GridContainer/PanelContainer/VBoxContainer/btn_request_feature" to="." method="_on_btn_request_feature_pressed"] -[connection signal="pressed" from="Panel/PanelContainer/v/MarginContainer/GridContainer/PanelContainer/VBoxContainer/btn_install_examples" to="." method="_on_btn_install_examples_pressed"] -[connection signal="pressed" from="Panel/PanelContainer/v/MarginContainer2/HBoxContainer/btn_close" to="." method="_on_btn_close_pressed"] diff --git a/addons/gdUnit4/src/ui/settings/GdUnitSettingsTabHooks.gd b/addons/gdUnit4/src/ui/settings/GdUnitSettingsTabHooks.gd deleted file mode 100644 index 3b01f340..00000000 --- a/addons/gdUnit4/src/ui/settings/GdUnitSettingsTabHooks.gd +++ /dev/null @@ -1,255 +0,0 @@ -@tool -extends ScrollContainer - - -@onready var _hooks_tree: Tree = %hooks_tree -@onready var _hook_description: RichTextLabel = %hook_description -@onready var _btn_move_up: Button = %hook_actions/btn_move_up -@onready var _btn_move_down: Button = %hook_actions/btn_move_down -@onready var _btn_delete: Button = %hook_actions/btn_delete_hook -@onready var _select_hook_dlg: FileDialog = %select_hook_dlg -@onready var _error_msg_popup :AcceptDialog = %error_msg_popup - -var _selected_hook_item: TreeItem = null -var _root: TreeItem -var _system_box_style: StyleBoxFlat -var _priority_box_style: StyleBoxFlat - -func _ready() -> void: - _setup_styles() - _setup_buttons() - _setup_tree() - _load_registered_hooks() - - -func _setup_styles() -> void: - _system_box_style = StyleBoxFlat.new() - _system_box_style.bg_color = Color(1.0, 0.76, 0.03, 1) - _system_box_style.corner_radius_top_left = 6 - _system_box_style.corner_radius_top_right = 6 - _system_box_style.corner_radius_bottom_left = 6 - _system_box_style.corner_radius_bottom_right = 6 - _priority_box_style = _system_box_style.duplicate() - _priority_box_style.bg_color = Color(0.26, 0.54, 0.89, 1) - - -func _setup_buttons() -> void: - #if Engine.is_editor_hint(): - # _btn_move_up.icon = GdUnitUiTools.get_icon("MoveUp") - # _btn_move_down.icon = GdUnitUiTools.get_icon("MoveDown") - # _btn_add.icon = GdUnitUiTools.get_icon("Add") - # _btn_delete.icon = GdUnitUiTools.get_icon("Remove") - pass - - -func _setup_tree() -> void: - _hooks_tree.clear() - _root = _hooks_tree.create_item() - _hooks_tree.set_columns(2) - _hooks_tree.set_column_custom_minimum_width(1, 32) - _hooks_tree.set_column_expand(1, false) - _hooks_tree.set_hide_root(true) - _hooks_tree.set_hide_folding(true) - _hooks_tree.set_select_mode(Tree.SELECT_SINGLE) - _hooks_tree.item_selected.connect(_on_hook_selected) - _hooks_tree.item_edited.connect(_on_item_edited) - - -func _load_registered_hooks() -> void: - var hook_service := GdUnitTestSessionHookService.instance() - for hook: GdUnitTestSessionHook in hook_service.enigne_hooks: - _create_hook_tree_item(hook) - - # Select first item if any - if _root.get_child_count() > 0: - var first_item: TreeItem = _root.get_first_child() - first_item.select(0) - _on_hook_selected() - - -func _create_hook_tree_item(hook: GdUnitTestSessionHook) -> TreeItem: - var item: TreeItem = _hooks_tree.create_item(_root) - item.set_custom_minimum_height(26) - # Column 0: Hook info with custom drawing - item.set_cell_mode(0, TreeItem.CELL_MODE_CUSTOM) - item.set_custom_draw_callback(0, _draw_hook_item) - item.set_editable(0, false) - item.set_metadata(0, hook) - # Column 1: Checkbox for enable/disable - item.set_cell_mode(1, TreeItem.CELL_MODE_CHECK) - item.set_checked(1, GdUnitTestSessionHookService.is_enabled(hook)) - item.set_editable(1, true) - item.set_custom_bg_color(1, _hook_bg_color(hook)) - item.set_tooltip_text(1, "Enable/Disable the Hook") - item.propagate_check(1) - - if _is_system_hook(hook): - item.set_tooltip_text(0, "System hook - (Read-only)") - else: - item.set_tooltip_text(0, "User hook") - return item - - -func _hook_bg_color(hook: GdUnitTestSessionHook) -> Color: - if _is_system_hook(hook): - return Color(0.133, 0.118, 0.090, 1) # Brownish background for system hooks - return Color(0.176, 0.196, 0.235, 1) # Dark background #2d3142 - - -func _draw_hook_item(item: TreeItem, rect: Rect2) -> void: - var hook := _get_hook(item) - var is_system := _is_system_hook(hook) - var is_selected := item == _selected_hook_item - - # Draw background - var bg_color := _hook_bg_color(hook) # Dark background #2d3142 - if is_selected: - bg_color = bg_color.lerp(Color(0.2, 0.4, 0.6, 0.3), 0.5) # Blue tint for selection - _hooks_tree.draw_rect(rect, bg_color) - - # Draw left border for system hooks - if is_system: - var border_rect := Rect2(rect.position.x, rect.position.y, 3, rect.size.y) - _hooks_tree.draw_rect(border_rect, Color(1.0, 0.76, 0.03, 1)) # Yellow border - - var font := _hooks_tree.get_theme_default_font() - - # Draw hook name - var hook_name := hook.name - var text_pos := Vector2(rect.position.x + ( 15 if is_system else 12), rect.position.y + 18) - var text_color := Color(0.95, 0.95, 0.95, 1) - _hooks_tree.draw_string(font, text_pos, hook_name, HORIZONTAL_ALIGNMENT_LEFT, -1, 14, text_color) - - # Draw system badge if needed - if is_system: - var badge_x := rect.position.x + rect.end.x - 100 - var badge_y := rect.position.y + 14 - var system_badge_rect := Rect2(badge_x, badge_y-8, 48, 16) - _hooks_tree.draw_style_box(_system_box_style, system_badge_rect) - - var system_text_pos := Vector2(badge_x + 4, badge_y + 4) - var system_font_size := 10 - _hooks_tree.draw_string(font, system_text_pos, "SYSTEM", HORIZONTAL_ALIGNMENT_CENTER, -1, system_font_size, Color(0.1, 0.1, 0.1, 1)) - - -func _create_hook_display_text(hook_name: String, priority: int, is_system: bool) -> String: - var text := hook_name + "\n" - text += "Priority: [color=#4299e1][bgcolor=#4299e1] " + str(priority) + " [/bgcolor][/color]" - - if is_system: - text += " [color=#1a202c][bgcolor=#ffc107] SYSTEM [/bgcolor][/color]" - - return text - - -func _update_hook_description() -> void: - if _selected_hook_item == null: - _hook_description.text = "[i]Select a hook to view its description[/i]" - return - _hook_description.text = _get_hook(_selected_hook_item).description - - -func _update_hook_buttons() -> void: - # Is nothing selected disable the move and delete buttons - if _selected_hook_item == null: - _btn_move_up.disabled = true - _btn_move_down.disabled = true - _btn_delete.disabled = true - return - - var hook := _get_hook(_selected_hook_item) - var is_system := _is_system_hook(hook) - - # Disable the move and delete buttons for system hooks by default - if is_system: - _btn_move_up.disabled = true - _btn_move_down.disabled = true - _btn_delete.disabled = true - return - - var prev_item: TreeItem = _selected_hook_item.get_prev() - var next_item: TreeItem = _selected_hook_item.get_next() - - if prev_item != null: - var prev_hook := _get_hook(prev_item) - _btn_move_up.disabled = _is_system_hook(prev_hook) - - _btn_move_down.disabled = next_item == null - _btn_delete.disabled = false - - -static func _get_hook(item: TreeItem) -> GdUnitTestSessionHook: - return item.get_metadata(0) - - -static func _is_system_hook(hook: GdUnitTestSessionHook) -> bool: - if hook == null: - return false - return hook.get_meta("SYSTEM_HOOK") - - -func _on_hook_selected() -> void: - _selected_hook_item = _hooks_tree.get_selected() - _update_hook_buttons() - _update_hook_description() - - -func _on_item_edited() -> void: - var selected_hook_item := _hooks_tree.get_selected() - if selected_hook_item != null: - var hook := _get_hook(selected_hook_item) - var is_enabled := selected_hook_item.is_checked(1) - GdUnitTestSessionHookService.instance().enable_hook(hook, is_enabled) - - -func _on_btn_add_hook_pressed() -> void: - _select_hook_dlg.show() - - -func _on_select_hook_dlg_file_selected(path: String) -> void: - _select_hook_dlg.set_current_path(path) - _on_select_hook_dlg_confirmed() - - -func _on_select_hook_dlg_confirmed() -> void: - _select_hook_dlg.hide() - var result := GdUnitTestSessionHookService.instance().load_hook(_select_hook_dlg.get_current_path()) - if result.is_error(): - _error_msg_popup.dialog_text = result.error_message() - _error_msg_popup.show() - return - - var hook: GdUnitTestSessionHook = result.value() - result = GdUnitTestSessionHookService.instance().register(hook) - if result.is_error(): - _error_msg_popup.dialog_text = result.error_message() - _error_msg_popup.show() - return - - var hook_added := _create_hook_tree_item(hook) - _hooks_tree.set_selected(hook_added, 0) - - -func _on_btn_delete_hook_pressed() -> void: - if _selected_hook_item != null: - _root.remove_child(_selected_hook_item) - GdUnitTestSessionHookService.instance()\ - .unregister(_get_hook(_selected_hook_item)) - _selected_hook_item = null - _update_hook_buttons() - - -func _on_btn_move_up_pressed() -> void: - var prev := _selected_hook_item.get_prev() - _selected_hook_item.move_before(prev) - GdUnitTestSessionHookService.instance()\ - .move_before(_get_hook(_selected_hook_item), _get_hook(prev)) - _update_hook_buttons() - - -func _on_btn_move_down_pressed() -> void: - var next := _selected_hook_item.get_next() - _selected_hook_item.move_after(next) - GdUnitTestSessionHookService.instance()\ - .move_after(_get_hook(_selected_hook_item), _get_hook(next)) - _update_hook_buttons() diff --git a/addons/gdUnit4/src/ui/settings/GdUnitSettingsTabHooks.gd.uid b/addons/gdUnit4/src/ui/settings/GdUnitSettingsTabHooks.gd.uid deleted file mode 100644 index 38508631..00000000 --- a/addons/gdUnit4/src/ui/settings/GdUnitSettingsTabHooks.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b10j5xjkq7vfc diff --git a/addons/gdUnit4/src/ui/settings/GdUnitSettingsTabHooks.tscn b/addons/gdUnit4/src/ui/settings/GdUnitSettingsTabHooks.tscn deleted file mode 100644 index a9a850c0..00000000 --- a/addons/gdUnit4/src/ui/settings/GdUnitSettingsTabHooks.tscn +++ /dev/null @@ -1,148 +0,0 @@ -[gd_scene load_steps=10 format=3 uid="uid://41l7a46fol5m"] - -[ext_resource type="Script" path="res://addons/gdUnit4/src/ui/settings/GdUnitSettingsTabHooks.gd" id="1_8yffn"] - -[sub_resource type="Image" id="Image_h5sr5"] -data = { -"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 234, 234, 234, 12, 224, 224, 224, 255, 224, 224, 224, 255, 234, 234, 234, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 1, 225, 225, 225, 174, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 173, 255, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 123, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 74, 224, 224, 224, 253, 224, 224, 224, 253, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 253, 224, 224, 224, 253, 224, 224, 224, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 228, 228, 228, 37, 224, 224, 224, 240, 224, 224, 224, 255, 224, 224, 224, 122, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 123, 224, 224, 224, 255, 224, 224, 224, 239, 228, 228, 228, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 200, 224, 224, 224, 255, 224, 224, 224, 172, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 1, 224, 224, 224, 173, 224, 224, 224, 255, 225, 225, 225, 199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 180, 224, 224, 224, 193, 234, 234, 234, 12, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 234, 234, 234, 12, 224, 224, 224, 193, 224, 224, 224, 179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 180, 224, 224, 224, 180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 181, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 180, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_77fm0"] -image = SubResource("Image_h5sr5") - -[sub_resource type="Image" id="Image_77fm0"] -data = { -"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 181, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 180, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 181, 224, 224, 224, 180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 181, 224, 224, 224, 193, 234, 234, 234, 12, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 234, 234, 234, 12, 224, 224, 224, 193, 224, 224, 224, 180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 200, 224, 224, 224, 255, 224, 224, 224, 173, 255, 255, 255, 1, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 1, 225, 225, 225, 174, 224, 224, 224, 255, 225, 225, 225, 199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 228, 228, 228, 37, 224, 224, 224, 239, 224, 224, 224, 255, 224, 224, 224, 122, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 123, 224, 224, 224, 255, 224, 224, 224, 239, 227, 227, 227, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 74, 224, 224, 224, 253, 224, 224, 224, 253, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 253, 224, 224, 224, 253, 224, 224, 224, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 123, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 1, 224, 224, 224, 173, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 234, 234, 234, 12, 224, 224, 224, 255, 224, 224, 224, 255, 234, 234, 234, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_rewru"] -image = SubResource("Image_77fm0") - -[sub_resource type="Image" id="Image_kppp6"] -data = { -"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_manhx"] -image = SubResource("Image_kppp6") - -[sub_resource type="Image" id="Image_rewru"] -data = { -"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 227, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 73, 224, 224, 224, 226, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 225, 226, 226, 226, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_4h4u1"] -image = SubResource("Image_rewru") - -[node name="Hooks" type="ScrollContainer"] -custom_minimum_size = Vector2(400, 300) -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 -script = ExtResource("1_8yffn") -metadata/_tab_index = 1 - -[node name="HBoxContainer" type="HBoxContainer" parent="."] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="hooks_content" type="VBoxContainer" parent="HBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="hooks_tree" type="Tree" parent="HBoxContainer/hooks_content"] -unique_name_in_owner = true -layout_direction = 2 -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 -hide_folding = true -hide_root = true - -[node name="hook_description" type="RichTextLabel" parent="HBoxContainer/hooks_content"] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 120) -layout_mode = 2 -size_flags_vertical = 2 -bbcode_enabled = true -text = "The test result Html reporting hook." -scroll_active = false - -[node name="hook_actions" type="VBoxContainer" parent="HBoxContainer"] -unique_name_in_owner = true -custom_minimum_size = Vector2(80, 0) -layout_mode = 2 -size_flags_horizontal = 0 -theme_override_constants/separation = 5 - -[node name="btn_move_up" type="Button" parent="HBoxContainer/hook_actions"] -layout_mode = 2 -tooltip_text = "Move hook up in priority" -disabled = true -icon = SubResource("ImageTexture_77fm0") -icon_alignment = 1 - -[node name="btn_move_down" type="Button" parent="HBoxContainer/hook_actions"] -layout_mode = 2 -tooltip_text = "Move hook down in priority" -disabled = true -icon = SubResource("ImageTexture_rewru") -icon_alignment = 1 - -[node name="btn_add_hook" type="Button" parent="HBoxContainer/hook_actions"] -layout_mode = 2 -tooltip_text = "Add new hook" -icon = SubResource("ImageTexture_manhx") -icon_alignment = 1 - -[node name="btn_delete_hook" type="Button" parent="HBoxContainer/hook_actions"] -layout_mode = 2 -tooltip_text = "Delete selected hook" -disabled = true -icon = SubResource("ImageTexture_4h4u1") -icon_alignment = 1 - -[node name="select_hook_dlg" type="FileDialog" parent="."] -unique_name_in_owner = true -disable_3d = true -title = "Open a File" -initial_position = 3 -current_screen = 0 -ok_button_text = "Open" -file_mode = 0 -filters = PackedStringArray("*.gd") - -[node name="error_msg_popup" type="AcceptDialog" parent="."] -unique_name_in_owner = true -initial_position = 3 -current_screen = 0 - -[connection signal="pressed" from="HBoxContainer/hook_actions/btn_move_up" to="." method="_on_btn_move_up_pressed"] -[connection signal="pressed" from="HBoxContainer/hook_actions/btn_move_down" to="." method="_on_btn_move_down_pressed"] -[connection signal="pressed" from="HBoxContainer/hook_actions/btn_add_hook" to="." method="_on_btn_add_hook_pressed"] -[connection signal="pressed" from="HBoxContainer/hook_actions/btn_delete_hook" to="." method="_on_btn_delete_hook_pressed"] -[connection signal="confirmed" from="select_hook_dlg" to="." method="_on_select_hook_dlg_confirmed"] -[connection signal="file_selected" from="select_hook_dlg" to="." method="_on_select_hook_dlg_file_selected"] diff --git a/addons/gdUnit4/src/ui/settings/logo.png b/addons/gdUnit4/src/ui/settings/logo.png deleted file mode 100644 index c1db2242..00000000 --- a/addons/gdUnit4/src/ui/settings/logo.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ed176306a061dff6c2a97c76e572bbbdee50cb7f5a496ba10d6898721f198351 -size 49775 diff --git a/addons/gdUnit4/src/ui/settings/logo.png.import b/addons/gdUnit4/src/ui/settings/logo.png.import deleted file mode 100644 index ebcd5b1c..00000000 --- a/addons/gdUnit4/src/ui/settings/logo.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cpsbyk6hskqhk" -path="res://.godot/imported/logo.png-deda0e4ba02a0b9e4e4a830029a5817f.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/gdUnit4/src/ui/settings/logo.png" -dest_files=["res://.godot/imported/logo.png-deda0e4ba02a0b9e4e4a830029a5817f.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/gdUnit4/src/ui/templates/TestSuiteTemplate.gd b/addons/gdUnit4/src/ui/templates/TestSuiteTemplate.gd deleted file mode 100644 index be5c3528..00000000 --- a/addons/gdUnit4/src/ui/templates/TestSuiteTemplate.gd +++ /dev/null @@ -1,129 +0,0 @@ -@tool -extends MarginContainer - -@onready var _template_editor :CodeEdit = $VBoxContainer/EdiorLayout/Editor -@onready var _tags_editor :CodeEdit = $Tags/MarginContainer/TextEdit -@onready var _title_bar :Panel = $VBoxContainer/sub_category -@onready var _save_button :Button = $VBoxContainer/Panel/HBoxContainer/Save -@onready var _selected_type :OptionButton = $VBoxContainer/EdiorLayout/Editor/MarginContainer/HBoxContainer/SelectType -@onready var _show_tags :PopupPanel = $Tags - - -var gd_key_words :PackedStringArray = ["extends", "class_name", "const", "var", "onready", "func", "void", "pass"] -var gdunit_key_words :PackedStringArray = ["GdUnitTestSuite", "before", "after", "before_test", "after_test"] -var _selected_template :int - - -func _ready() -> void: - setup_editor_colors() - setup_fonts() - setup_supported_types() - load_template(GdUnitTestSuiteTemplate.TEMPLATE_ID_GD) - setup_tags_help() - - -func _notification(what :int) -> void: - if what == EditorSettings.NOTIFICATION_EDITOR_SETTINGS_CHANGED: - setup_fonts() - - -func setup_editor_colors() -> void: - if not Engine.is_editor_hint(): - return - - var background_color := get_editor_color("text_editor/theme/highlighting/background_color", Color(0.1155, 0.132, 0.1595, 1)) - var text_color := get_editor_color("text_editor/theme/highlighting/text_color", Color(0.8025, 0.81, 0.8225, 1)) - var selection_color := get_editor_color("text_editor/theme/highlighting/selection_color", Color(0.44, 0.73, 0.98, 0.4)) - - for e :CodeEdit in [_template_editor, _tags_editor]: - var editor :CodeEdit = e - editor.add_theme_color_override("background_color", background_color) - editor.add_theme_color_override("font_color", text_color) - editor.add_theme_color_override("font_readonly_color", text_color) - editor.add_theme_color_override("font_selected_color", selection_color) - setup_highlighter(editor) - - -func setup_highlighter(editor :CodeEdit) -> void: - var highlighter := CodeHighlighter.new() - editor.set_syntax_highlighter(highlighter) - var number_color := get_editor_color("text_editor/theme/highlighting/number_color", Color(0.63, 1, 0.88, 1)) - var symbol_color := get_editor_color("text_editor/theme/highlighting/symbol_color", Color(0.67, 0.79, 1, 1)) - var function_color := get_editor_color("text_editor/theme/highlighting/function_color", Color(0.34, 0.7, 1, 1)) - var member_variable_color := get_editor_color("text_editor/theme/highlighting/member_variable_color", Color(0.736, 0.88, 1, 1)) - var comment_color := get_editor_color("text_editor/theme/highlighting/comment_color", Color(0.8025, 0.81, 0.8225, 0.5)) - var keyword_color := get_editor_color("text_editor/theme/highlighting/keyword_color", Color(1, 0.44, 0.52, 1)) - var base_type_color := get_editor_color("text_editor/theme/highlighting/base_type_color", Color(0.26, 1, 0.76, 1)) - var annotation_color := get_editor_color("text_editor/theme/highlighting/gdscript/annotation_color", Color(1, 0.7, 0.45, 1)) - - highlighter.clear_color_regions() - highlighter.clear_keyword_colors() - highlighter.add_color_region("#", "", comment_color, true) - highlighter.add_color_region("${", "}", Color.YELLOW) - highlighter.add_color_region("'", "'", Color.YELLOW) - highlighter.add_color_region("\"", "\"", Color.YELLOW) - highlighter.number_color = number_color - highlighter.symbol_color = symbol_color - highlighter.function_color = function_color - highlighter.member_variable_color = member_variable_color - highlighter.add_keyword_color("@", annotation_color) - highlighter.add_keyword_color("warning_ignore", annotation_color) - for word in gd_key_words: - highlighter.add_keyword_color(word, keyword_color) - for word in gdunit_key_words: - highlighter.add_keyword_color(word, base_type_color) - - -## Using this function to avoid null references to colors on inital Godot installations. -## For more details show https://github.com/MikeSchulze/gdUnit4/issues/533 -func get_editor_color(property_name: String, default: Color) -> Color: - var settings := EditorInterface.get_editor_settings() - return settings.get_setting(property_name) if settings.has_setting(property_name) else default - - -func setup_fonts() -> void: - if _template_editor: - @warning_ignore("return_value_discarded") - GdUnitFonts.init_fonts(_template_editor) - var font_size := GdUnitFonts.init_fonts(_tags_editor) - _title_bar.size.y = font_size + 16 - _title_bar.custom_minimum_size.y = font_size + 16 - - -func setup_supported_types() -> void: - _selected_type.clear() - _selected_type.add_item("GD - GDScript", GdUnitTestSuiteTemplate.TEMPLATE_ID_GD) - _selected_type.add_item("C# - CSharpScript", GdUnitTestSuiteTemplate.TEMPLATE_ID_CS) - - -func setup_tags_help() -> void: - _tags_editor.set_text(GdUnitTestSuiteTemplate.load_tags(_selected_template)) - - -func load_template(template_id :int) -> void: - _selected_template = template_id - _template_editor.set_text(GdUnitTestSuiteTemplate.load_template(template_id)) - - -func _on_Restore_pressed() -> void: - _template_editor.set_text(GdUnitTestSuiteTemplate.default_template(_selected_template)) - GdUnitTestSuiteTemplate.reset_to_default(_selected_template) - _save_button.disabled = true - - -func _on_Save_pressed() -> void: - GdUnitTestSuiteTemplate.save_template(_selected_template, _template_editor.get_text()) - _save_button.disabled = true - - -func _on_Tags_pressed() -> void: - _show_tags.popup_centered_ratio(.5) - - -func _on_Editor_text_changed() -> void: - _save_button.disabled = false - - -func _on_SelectType_item_selected(index :int) -> void: - load_template(_selected_type.get_item_id(index)) - setup_tags_help() diff --git a/addons/gdUnit4/src/ui/templates/TestSuiteTemplate.gd.uid b/addons/gdUnit4/src/ui/templates/TestSuiteTemplate.gd.uid deleted file mode 100644 index dfd742e8..00000000 --- a/addons/gdUnit4/src/ui/templates/TestSuiteTemplate.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cas22f80cg72g diff --git a/addons/gdUnit4/src/ui/templates/TestSuiteTemplate.tscn b/addons/gdUnit4/src/ui/templates/TestSuiteTemplate.tscn deleted file mode 100644 index 5ccc4430..00000000 --- a/addons/gdUnit4/src/ui/templates/TestSuiteTemplate.tscn +++ /dev/null @@ -1,127 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://dte0m2endcgtu"] - -[ext_resource type="Script" path="res://addons/gdUnit4/src/ui/templates/TestSuiteTemplate.gd" id="1"] - -[node name="TestSuiteTemplate" type="MarginContainer"] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 -script = ExtResource("1") - -[node name="VBoxContainer" type="VBoxContainer" parent="."] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="sub_category" type="Panel" parent="VBoxContainer"] -custom_minimum_size = Vector2(0, 30) -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="Label" type="Label" parent="VBoxContainer/sub_category"] -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 4.0 -offset_right = 4.0 -offset_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -text = "Test Suite Template -" - -[node name="EdiorLayout" type="VBoxContainer" parent="VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="Editor" type="CodeEdit" parent="VBoxContainer/EdiorLayout"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer/EdiorLayout/Editor"] -layout_mode = 1 -anchors_preset = 12 -anchor_top = 1.0 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_top = -31.0 -grow_horizontal = 2 -grow_vertical = 0 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/EdiorLayout/Editor/MarginContainer"] -layout_mode = 2 -size_flags_vertical = 8 -alignment = 2 - -[node name="Tags" type="Button" parent="VBoxContainer/EdiorLayout/Editor/MarginContainer/HBoxContainer"] -layout_mode = 2 -tooltip_text = "Shows supported tags." -text = "Supported Tags" - -[node name="SelectType" type="OptionButton" parent="VBoxContainer/EdiorLayout/Editor/MarginContainer/HBoxContainer"] -layout_mode = 2 -tooltip_text = "Select the script type specific template." -item_count = 2 -selected = 0 -popup/item_0/text = "GD - GDScript" -popup/item_0/id = 1000 -popup/item_1/text = "C# - CSharpScript" -popup/item_1/id = 2000 - -[node name="Panel" type="MarginContainer" parent="VBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/Panel"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 -alignment = 2 - -[node name="Restore" type="Button" parent="VBoxContainer/Panel/HBoxContainer"] -layout_mode = 2 -text = "Restore" - -[node name="Save" type="Button" parent="VBoxContainer/Panel/HBoxContainer"] -layout_mode = 2 -disabled = true -text = "Save" - -[node name="Tags" type="PopupPanel" parent="."] -size = Vector2i(300, 100) -unresizable = false -content_scale_aspect = 4 - -[node name="MarginContainer" type="MarginContainer" parent="Tags"] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 4.0 -offset_top = 4.0 -offset_right = -856.0 -offset_bottom = -552.0 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="TextEdit" type="CodeEdit" parent="Tags/MarginContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 -editable = false -context_menu_enabled = false -shortcut_keys_enabled = false -virtual_keyboard_enabled = false - -[connection signal="text_changed" from="VBoxContainer/EdiorLayout/Editor" to="." method="_on_Editor_text_changed"] -[connection signal="pressed" from="VBoxContainer/EdiorLayout/Editor/MarginContainer/HBoxContainer/Tags" to="." method="_on_Tags_pressed"] -[connection signal="item_selected" from="VBoxContainer/EdiorLayout/Editor/MarginContainer/HBoxContainer/SelectType" to="." method="_on_SelectType_item_selected"] -[connection signal="pressed" from="VBoxContainer/Panel/HBoxContainer/Restore" to="." method="_on_Restore_pressed"] -[connection signal="pressed" from="VBoxContainer/Panel/HBoxContainer/Save" to="." method="_on_Save_pressed"] diff --git a/addons/gdUnit4/src/update/GdMarkDownReader.gd b/addons/gdUnit4/src/update/GdMarkDownReader.gd deleted file mode 100644 index dab19e40..00000000 --- a/addons/gdUnit4/src/update/GdMarkDownReader.gd +++ /dev/null @@ -1,405 +0,0 @@ -@tool -extends RefCounted - -const GdUnitUpdateClient = preload("res://addons/gdUnit4/src/update/GdUnitUpdateClient.gd") - -const FONT_H1 := 22 -const FONT_H2 := 20 -const FONT_H3 := 18 -const FONT_H4 := 16 -const FONT_H5 := 14 -const FONT_H6 := 12 - -const HORIZONTAL_RULE := "[img=4000x2]res://addons/gdUnit4/src/update/assets/horizontal-line2.png[/img]" -const HEADER_RULE := "[font_size=%d]$1[/font_size]" -const HEADER_CENTERED_RULE := "[font_size=%d][center]$1[/center][/font_size]" - -const image_download_folder := "res://addons/gdUnit4/tmp-update/" - -const exclude_font_size := "\b(?!(?:(font_size))\b)" - -var md_replace_patterns := [ - # comments - [regex("(?m)^\\n?\\s*\\s*\\n?"), ""], - - # horizontal rules - [regex("(?m)^[ ]{0,3}---$"), HORIZONTAL_RULE], - [regex("(?m)^[ ]{0,3}___$"), HORIZONTAL_RULE], - [regex("(?m)^[ ]{0,3}\\*\\*\\*$"), HORIZONTAL_RULE], - - # headers - [regex("(?m)^###### (.*)"), HEADER_RULE % FONT_H6], - [regex("(?m)^##### (.*)"), HEADER_RULE % FONT_H5], - [regex("(?m)^#### (.*)"), HEADER_RULE % FONT_H4], - [regex("(?m)^### (.*)"), HEADER_RULE % FONT_H3], - [regex("(?m)^## (.*)"), (HEADER_RULE + HORIZONTAL_RULE) % FONT_H2], - [regex("(?m)^# (.*)"), (HEADER_RULE + HORIZONTAL_RULE) % FONT_H1], - [regex("(?m)^(.+)=={2,}$"), HEADER_RULE % FONT_H1], - [regex("(?m)^(.+)--{2,}$"), HEADER_RULE % FONT_H2], - # html headers - [regex("

((.*?\\R?)+)<\\/h1>"), (HEADER_RULE + HORIZONTAL_RULE) % FONT_H1], - [regex("((.*?\\R?)+)<\\/h1>"), (HEADER_CENTERED_RULE + HORIZONTAL_RULE) % FONT_H1], - [regex("

((.*?\\R?)+)<\\/h2>"), (HEADER_RULE + HORIZONTAL_RULE) % FONT_H2], - [regex("((.*?\\R?)+)<\\/h2>"), (HEADER_CENTERED_RULE + HORIZONTAL_RULE) % FONT_H1], - [regex("

((.*?\\R?)+)<\\/h3>"), HEADER_RULE % FONT_H3], - [regex("((.*?\\R?)+)<\\/h3>"), HEADER_CENTERED_RULE % FONT_H3], - [regex("

((.*?\\R?)+)<\\/h4>"), HEADER_RULE % FONT_H4], - [regex("((.*?\\R?)+)<\\/h4>"), HEADER_CENTERED_RULE % FONT_H4], - [regex("
((.*?\\R?)+)<\\/h5>"), HEADER_RULE % FONT_H5], - [regex("((.*?\\R?)+)<\\/h5>"), HEADER_CENTERED_RULE % FONT_H5], - [regex("
((.*?\\R?)+)<\\/h6>"), HEADER_RULE % FONT_H6], - [regex("((.*?\\R?)+)<\\/h6>"), HEADER_CENTERED_RULE % FONT_H6], - - # asterics - #[regex("(\\*)"), "xxx$1xxx"], - - # extract/compile image references - [regex("!\\[(.*?)\\]\\[(.*?)\\]"), process_image_references], - # extract images with path and optional tool tip - [regex("!\\[(.*?)\\]\\((.*?)(( )+(.*?))?\\)"), process_image], - - # links - [regex("([!]|)\\[(.+)\\]\\(([^ ]+?)\\)"), "[url={\"url\":\"$3\"}]$2[/url]"], - # links with tool tip - [regex("([!]|)\\[(.+)\\]\\(([^ ]+?)( \"(.+)\")?\\)"), "[url={\"url\":\"$3\", \"tool_tip\":\"$5\"}]$2[/url]"], - # links to github, as shorted link - [regex("(https://github.*/?/(\\S+))"), '[url={"url":"$1", "tool_tip":"$1"}]#$2[/url]'], - - # embeded text - [regex("(?m)^[ ]{0,3}>(.*?)$"), "[img=50x14]res://addons/gdUnit4/src/update/assets/embedded.png[/img][i]$1[/i]"], - - # italic + bold font - [regex("[_]{3}(.*?)[_]{3}"), "[i][b]$1[/b][/i]"], - [regex("[\\*]{3}(.*?)[\\*]{3}"), "[i][b]$1[/b][/i]"], - # bold font - [regex("(.*?)<\\/b>"), "[b]$1[/b]"], - [regex("[_]{2}(.*?)[_]{2}"), "[b]$1[/b]"], - [regex("[\\*]{2}(.*?)[\\*]{2}"), "[b]$1[/b]"], - # italic font - [regex("(.*?)<\\/i>"), "[i]$1[/i]"], - [regex(exclude_font_size+"_(.*?)_"), "[i]$1[/i]"], - [regex("\\*(.*?)\\*"), "[i]$1[/i]"], - - # strikethrough font - [regex("(.*?)"), "[s]$1[/s]"], - [regex("~~(.*?)~~"), "[s]$1[/s]"], - [regex("~(.*?)~"), "[s]$1[/s]"], - - # handling lists - # using an image for dots - [regex("(?m)^[ ]{0,1}[*\\-+] (.*)$"), list_replace(0)], - [regex("(?m)^[ ]{2,3}[*\\-+] (.*)$"), list_replace(1)], - [regex("(?m)^[ ]{4,5}[*\\-+] (.*)$"), list_replace(2)], - [regex("(?m)^[ ]{6,7}[*\\-+] (.*)$"), list_replace(3)], - [regex("(?m)^[ ]{8,9}[*\\-+] (.*)$"), list_replace(4)], - - # code - [regex("``([\\s\\S]*?)``"), code_block("$1")], - [regex("`([\\s\\S]*?)`{1,2}"), code_block("$1")], -] - -var code_block_patterns := [ - # code blocks, code blocks looks not like code blocks in richtext - [regex("```(javascript|python|shell|gdscript|gd)([\\s\\S]*?\n)```"), code_block("$2", true)], -] - -var _img_replace_regex := RegEx.new() -var _image_urls := PackedStringArray() -var _on_table_tag := false -var _client: GdUnitUpdateClient - - -static func regex(pattern: String) -> RegEx: - var regex_ := RegEx.new() - var err := regex_.compile(pattern) - if err != OK: - push_error("error '%s' checked pattern '%s'" % [err, pattern]) - return null - return regex_ - - -func _init() -> void: - @warning_ignore("return_value_discarded") - _img_replace_regex.compile("\\[img\\]((.*?))\\[/img\\]") - - -func set_http_client(client: GdUnitUpdateClient) -> void: - _client = client - - -@warning_ignore("return_value_discarded") -func _notification(what: int) -> void: - if what == NOTIFICATION_PREDELETE: - # finally remove_at the downloaded images - for image in _image_urls: - DirAccess.remove_absolute(image) - DirAccess.remove_absolute(image + ".import") - - -func list_replace(indent: int) -> String: - var replace_pattern := "[img=12x12]res://addons/gdUnit4/src/update/assets/dot2.png[/img]" if indent %2 else "[img=12x12]res://addons/gdUnit4/src/update/assets/dot1.png[/img]" - replace_pattern += " $1" - - for index in indent: - replace_pattern = replace_pattern.insert(0, " ") - return replace_pattern - - -func code_block(replace: String, border: bool = false) -> String: - if border: - return """ - [img=1400x14]res://addons/gdUnit4/src/update/assets/border_top.png[/img] - [indent][color=GRAY][font_size=16]%s[/font_size][/color][/indent] - [img=1400x14]res://addons/gdUnit4/src/update/assets/border_bottom.png[/img] - """.dedent() % replace - return "[code][bgcolor=DARK_SLATE_GRAY][color=GRAY][font_size=16]%s[/font_size][/color][/bgcolor][/code]" % replace - - -func convert_text(input: String) -> String: - input = process_tables(input) - - for pattern: Array in md_replace_patterns: - var regex_: RegEx = pattern[0] - var bb_replace: Variant = pattern[1] - if bb_replace is Callable: - @warning_ignore("unsafe_method_access") - input = await bb_replace.call(regex_, input) - else: - @warning_ignore("unsafe_cast") - input = regex_.sub(input, bb_replace as String, true) - return input - - -func convert_code_block(input: String) -> String: - for pattern: Array in code_block_patterns: - var regex_: RegEx = pattern[0] - var bb_replace: Variant = pattern[1] - if bb_replace is Callable: - @warning_ignore("unsafe_method_access") - input = await bb_replace.call(regex_, input) - else: - @warning_ignore("unsafe_cast") - input = regex_.sub(input, bb_replace as String, true) - return input - - -func to_bbcode(input: String) -> String: - var re := regex("(?m)```[\\s\\S]*?```") - var current_pos := 0 - var as_bbcode := "" - - # we split by code blocks to handle this blocks customized - for result in re.search_all(input): - # Add text before code block - if result.get_start() > current_pos: - as_bbcode += await convert_text(input.substr(current_pos, result.get_start() - current_pos)) - # Add code block - as_bbcode += await convert_code_block(result.get_string()) - current_pos = result.get_end() - - # Add remaining text after last code block - if current_pos < input.length(): - as_bbcode += await convert_text(input.substr(current_pos)) - return as_bbcode - - -func process_tables(input: String) -> String: - var bbcode := PackedStringArray() - var lines: Array[String] = Array(input.split("\n") as Array, TYPE_STRING, "", null) - while not lines.is_empty(): - if is_table(lines[0]): - bbcode.append_array(parse_table(lines)) - continue - @warning_ignore("return_value_discarded", "unsafe_cast") - bbcode.append(lines.pop_front() as String) - return "\n".join(bbcode) - - -class GdUnitMDReaderTable: - var _columns: int - var _rows: Array[Row] = [] - - class Row: - var _cells := PackedStringArray() - - - func _init(cells: PackedStringArray, columns: int) -> void: - _cells = cells - for i in range(_cells.size(), columns): - @warning_ignore("return_value_discarded") - _cells.append("") - - - func to_bbcode(cell_sizes: PackedInt32Array, bold: bool) -> String: - var cells := PackedStringArray() - for cell_index in _cells.size(): - var cell: String = _cells[cell_index] - if cell.strip_edges() == "--": - cell = create_line(cell_sizes[cell_index]) - if bold: - cell = "[b]%s[/b]" % cell - @warning_ignore("return_value_discarded") - cells.append("[cell]%s[/cell]" % cell) - return "|".join(cells) - - - func create_line(length: int) -> String: - var line := "" - for i in length: - line += "-" - return line - - - func _init(columns: int) -> void: - _columns = columns - - - func parse_row(line :String) -> bool: - # is line containing cells? - if line.find("|") == -1: - return false - _rows.append(Row.new(line.split("|"), _columns)) - return true - - - func calculate_max_cell_sizes() -> PackedInt32Array: - var cells_size := PackedInt32Array() - for column in _columns: - @warning_ignore("return_value_discarded") - cells_size.append(0) - - for row_index in _rows.size(): - var row: Row = _rows[row_index] - for cell_index in row._cells.size(): - var cell_size: int = cells_size[cell_index] - var size := row._cells[cell_index].length() - if size > cell_size: - cells_size[cell_index] = size - return cells_size - - - @warning_ignore("return_value_discarded") - func to_bbcode() -> PackedStringArray: - var cell_sizes := calculate_max_cell_sizes() - var bb_code := PackedStringArray() - - bb_code.append("[table=%d]" % _columns) - for row_index in _rows.size(): - bb_code.append(_rows[row_index].to_bbcode(cell_sizes, row_index==0)) - bb_code.append("[/table]\n") - return bb_code - - -func parse_table(lines: Array) -> PackedStringArray: - var line: String = lines[0] - var table := GdUnitMDReaderTable.new(line.count("|") + 1) - while not lines.is_empty(): - line = lines.pop_front() - if not table.parse_row(line): - break - return table.to_bbcode() - - -func is_table(line: String) -> bool: - return line.find("|") != -1 - - -func open_table(line: String) -> String: - _on_table_tag = true - return "[table=%d]" % (line.count("|") + 1) - - -func close_table() -> String: - _on_table_tag = false - return "[/table]" - - -func extract_cells(line: String, bold := false) -> String: - var cells := "" - for cell in line.split("|"): - if bold: - cell = "[b]%s[/b]" % cell - cells += "[cell]%s[/cell]" % cell - return cells - - -func process_image_references(p_regex: RegEx, p_input: String) -> String: - #return p_input - - # exists references? - var matches := p_regex.search_all(p_input) - if matches.is_empty(): - return p_input - # collect image references and remove_at it - var references := Dictionary() - var link_regex := regex("\\[(\\S+)\\]:(\\S+)([ ]\"(.*)\")?") - # create copy of original source to replace checked it - var input := p_input.replace("\r", "") - var extracted_references := p_input.replace("\r", "") - for reg_match in link_regex.search_all(input): - var line := reg_match.get_string(0) + "\n" - var ref := reg_match.get_string(1) - #var topl_tip = reg_match.get_string(4) - # collect reference and url - references[ref] = reg_match.get_string(2) - extracted_references = extracted_references.replace(line, "") - - # replace image references by collected url's - for reference_key: String in references.keys(): - var regex_key := regex("\\](\\[%s\\])" % reference_key) - for reg_match in regex_key.search_all(extracted_references): - var ref: String = reg_match.get_string(0) - var image_url: String = "](%s)" % references.get(reference_key) - extracted_references = extracted_references.replace(ref, image_url) - return extracted_references - - -@warning_ignore("return_value_discarded") -func process_image(p_regex: RegEx, p_input: String) -> String: - #return p_input - var to_replace := PackedStringArray() - var tool_tips := PackedStringArray() - # find all matches - var matches := p_regex.search_all(p_input) - if matches.is_empty(): - return p_input - for reg_match in matches: - # grap the parts to replace and store temporay because a direct replace will distort the offsets - to_replace.append(p_input.substr(reg_match.get_start(0), reg_match.get_end(0))) - # grap optional tool tips - tool_tips.append(reg_match.get_string(5)) - # finally replace all findings - for replace in to_replace: - var re := p_regex.sub(replace, "[img]$2[/img]") - p_input = p_input.replace(replace, re) - return await _process_external_image_resources(p_input) - - -func _process_external_image_resources(input: String) -> String: - @warning_ignore("return_value_discarded") - DirAccess.make_dir_recursive_absolute(image_download_folder) - # scan all img for external resources and download it - for value in _img_replace_regex.search_all(input): - if value.get_group_count() >= 1: - var image_url: String = value.get_string(1) - # if not a local resource we need to download it - if image_url.begins_with("http"): - if OS.is_stdout_verbose(): - prints("download image:", image_url) - var response := await _client.request_image(image_url) - if response.status() == 200: - var image := Image.new() - var error := image.load_png_from_buffer(response.get_body()) - if error != OK: - prints("Error creating image from response", error) - # replace characters where format characters - var new_url := image_download_folder + image_url.get_file().replace("_", "-") - if new_url.get_extension() != 'png': - new_url = new_url + '.png' - var err := image.save_png(new_url) - if err: - push_error("Can't save image to '%s'. Error: %s" % [new_url, error_string(err)]) - @warning_ignore("return_value_discarded") - _image_urls.append(new_url) - input = input.replace(image_url, new_url) - return input diff --git a/addons/gdUnit4/src/update/GdMarkDownReader.gd.uid b/addons/gdUnit4/src/update/GdMarkDownReader.gd.uid deleted file mode 100644 index 5f7b4164..00000000 --- a/addons/gdUnit4/src/update/GdMarkDownReader.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c2ii27n08li2k diff --git a/addons/gdUnit4/src/update/GdUnitPatch.gd b/addons/gdUnit4/src/update/GdUnitPatch.gd deleted file mode 100644 index daa20f7b..00000000 --- a/addons/gdUnit4/src/update/GdUnitPatch.gd +++ /dev/null @@ -1,20 +0,0 @@ -class_name GdUnitPatch -extends RefCounted - -const PATCH_VERSION = "patch_version" - -var _version :GdUnit4Version - - -func _init(version_ :GdUnit4Version) -> void: - _version = version_ - - -func version() -> GdUnit4Version: - return _version - - -# this function needs to be implement -func execute() -> bool: - push_error("The function 'execute()' is not implemented at %s" % self) - return false diff --git a/addons/gdUnit4/src/update/GdUnitPatch.gd.uid b/addons/gdUnit4/src/update/GdUnitPatch.gd.uid deleted file mode 100644 index d75401b1..00000000 --- a/addons/gdUnit4/src/update/GdUnitPatch.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://drpr6gj1mlhxl diff --git a/addons/gdUnit4/src/update/GdUnitPatcher.gd b/addons/gdUnit4/src/update/GdUnitPatcher.gd deleted file mode 100644 index 73d25c92..00000000 --- a/addons/gdUnit4/src/update/GdUnitPatcher.gd +++ /dev/null @@ -1,75 +0,0 @@ -class_name GdUnitPatcher -extends RefCounted - - -const _base_dir := "res://addons/gdUnit4/src/update/patches/" - -var _patches := Dictionary() - - -func scan(current :GdUnit4Version) -> void: - _scan(_base_dir, current) - - -func _scan(scan_path :String, current :GdUnit4Version) -> void: - _patches = Dictionary() - var patch_paths := _collect_patch_versions(scan_path, current) - for path in patch_paths: - prints("scan for patches checked '%s'" % path) - _patches[path] = _scan_patches(path) - - -func patch_count() -> int: - var count := 0 - for key :String in _patches.keys(): - @warning_ignore("unsafe_method_access") - count += _patches[key].size() - return count - - -func execute() -> void: - for key :String in _patches.keys(): - for path :String in _patches[key]: - var patch :GdUnitPatch = (load(key + "/" + path) as GDScript).new() - if patch: - prints("execute patch", patch.version(), patch.get_script().resource_path) - if not patch.execute(): - prints("error checked execution patch %s" % key + "/" + path) - - -func _collect_patch_versions(scan_path :String, current :GdUnit4Version) -> PackedStringArray: - if not DirAccess.dir_exists_absolute(scan_path): - return PackedStringArray() - var patches := Array() - var dir := DirAccess.open(scan_path) - if dir != null: - @warning_ignore("return_value_discarded") - dir.list_dir_begin() # TODO GODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547 - var next := "." - while next != "": - next = dir.get_next() - if next.is_empty() or next == "." or next == "..": - continue - var version := GdUnit4Version.parse(next) - if version.is_greater(current): - patches.append(scan_path + next) - patches.sort() - return PackedStringArray(patches) - - -func _scan_patches(path :String) -> PackedStringArray: - var patches := Array() - var dir := DirAccess.open(path) - if dir != null: - @warning_ignore("return_value_discarded") - dir.list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547 - var next := "." - while next != "": - next = dir.get_next() - # step over directory links and .uid files - if next.is_empty() or next == "." or next == ".." or next.ends_with(".uid"): - continue - patches.append(next) - # make sorted from lowest to high version - patches.sort() - return PackedStringArray(patches) diff --git a/addons/gdUnit4/src/update/GdUnitPatcher.gd.uid b/addons/gdUnit4/src/update/GdUnitPatcher.gd.uid deleted file mode 100644 index 80127b6b..00000000 --- a/addons/gdUnit4/src/update/GdUnitPatcher.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cxv57lcra5lsd diff --git a/addons/gdUnit4/src/update/GdUnitUpdate.gd b/addons/gdUnit4/src/update/GdUnitUpdate.gd deleted file mode 100644 index 97b7fdd1..00000000 --- a/addons/gdUnit4/src/update/GdUnitUpdate.gd +++ /dev/null @@ -1,305 +0,0 @@ -@tool -extends Container - -const GdUnitTools := preload("res://addons/gdUnit4/src/core/GdUnitTools.gd") -const GdUnitUpdateClient := preload("res://addons/gdUnit4/src/update/GdUnitUpdateClient.gd") -const GDUNIT_TEMP := "user://tmp" - -@onready var _progress_content: RichTextLabel = %message -@onready var _progress_bar: TextureProgressBar = %progress -@onready var _cancel_btn: Button = %cancel -@onready var _update_btn: Button = %update -@onready var _spinner_img := GdUnitUiTools.get_spinner() - - -var _debug_mode := false -var _update_client :GdUnitUpdateClient -var _download_url :String - - -func _ready() -> void: - init_progress(6) - - -func _process(_delta :float) -> void: - if _progress_content != null and _progress_content.is_visible_in_tree(): - _progress_content.queue_redraw() - - -func init_progress(max_value: int) -> void: - _cancel_btn.disabled = false - _update_btn.disabled = false - _progress_bar.max_value = max_value - _progress_bar.value = 1 - message_h4("Press [Update] to start.", Color.GREEN, false) - - -func setup(update_client: GdUnitUpdateClient, download_url: String) -> void: - _update_client = update_client - _download_url = download_url - - -func update_progress(message: String, color := Color.GREEN) -> void: - message_h4(message, color) - _progress_bar.value += 1 - if _debug_mode: - await get_tree().create_timer(3).timeout - await get_tree().create_timer(.2).timeout - - -func _colored(message: String, color: Color) -> String: - return "[color=#%s]%s[/color]" % [color.to_html(), message] - - -func message_h4(message: String, color: Color, show_spinner := true) -> void: - _progress_content.clear() - if show_spinner: - _progress_content.add_image(_spinner_img) - _progress_content.append_text(" [font_size=16]%s[/font_size]" % _colored(message, color)) - if _debug_mode: - prints(message) - - -@warning_ignore("return_value_discarded") -func run_update() -> void: - _cancel_btn.disabled = true - _update_btn.disabled = true - - await update_progress("Downloading the update.") - await download_release() - await update_progress("Extracting") - var zip_file := temp_dir() + "/update.zip" - var tmp_path := create_temp_dir("update") - var result :Variant = extract_zip(zip_file, tmp_path) - if result == null: - await update_progress("Update failed! .. Rollback.", Color.INDIAN_RED) - await get_tree().create_timer(3).timeout - _cancel_btn.disabled = false - _update_btn.disabled = false - init_progress(5) - hide() - return - - await update_progress("Uninstall GdUnit4.") - disable_gdUnit() - if not _debug_mode: - GdUnitFileAccess.delete_directory("res://addons/gdUnit4/") - # give editor time to react on deleted files - await get_tree().create_timer(1).timeout - - await update_progress("Install new GdUnit4 version.") - if _debug_mode: - copy_directory(tmp_path, "res://debug") - else: - copy_directory(tmp_path, "res://") - - await update_progress("Patch invalid UID's") - await patch_uids() - - await rebuild_project() - - await update_progress("New GdUnit version successfully installed, Restarting Godot please wait.") - await get_tree().create_timer(3).timeout - enable_gdUnit() - hide() - GdUnitFileAccess.delete_directory("res://addons/.gdunit_update") - restart_godot() - - -func patch_uids(path := "res://addons/gdUnit4/src/") -> void: - var to_reimport: PackedStringArray - for file in DirAccess.get_files_at(path): - var file_path := path.path_join(file) - var ext := file.get_extension() - - if ext == "tscn" or ext == "scn" or ext == "tres" or ext == "res": - message_h4("Patch GdUnit4 scene: '%s'" % file, Color.WEB_GREEN) - remove_uids_from_file(file_path) - elif FileAccess.file_exists(file_path + ".import"): - to_reimport.append(file_path) - - if not to_reimport.is_empty(): - message_h4("Reimport resources '%s'" % ", ".join(to_reimport), Color.WEB_GREEN) - if Engine.is_editor_hint(): - EditorInterface.get_resource_filesystem().reimport_files(to_reimport) - - for dir in DirAccess.get_directories_at(path): - if not dir.begins_with("."): - patch_uids(path.path_join(dir)) - await get_tree().process_frame - - -func remove_uids_from_file(file_path: String) -> bool: - var file := FileAccess.open(file_path, FileAccess.READ) - if file == null: - print("Failed to open file: ", file_path) - return false - - var original_content := file.get_as_text() - file.close() - - # Remove UIDs using regex - var regex := RegEx.new() - regex.compile("(\\[ext_resource[^\\]]*?)\\s+uid=\"uid://[^\"]*\"") - - var modified_content := regex.sub(original_content, "$1", true) - - # Check if any changes were made - if original_content != modified_content: - prints("Patched invalid uid's out in '%s'" % file_path) - # Write the modified content back - file = FileAccess.open(file_path, FileAccess.WRITE) - if file == null: - print("Failed to write to file: ", file_path) - return false - - file.store_string(modified_content) - file.close() - return true - - return false - - -func restart_godot() -> void: - prints("Force restart Godot") - EditorInterface.restart_editor(true) - - -@warning_ignore("return_value_discarded") -func enable_gdUnit() -> void: - var enabled_plugins := PackedStringArray() - if ProjectSettings.has_setting("editor_plugins/enabled"): - enabled_plugins = ProjectSettings.get_setting("editor_plugins/enabled") - if not enabled_plugins.has("res://addons/gdUnit4/plugin.cfg"): - enabled_plugins.append("res://addons/gdUnit4/plugin.cfg") - ProjectSettings.set_setting("editor_plugins/enabled", enabled_plugins) - ProjectSettings.save() - - -func disable_gdUnit() -> void: - EditorInterface.set_plugin_enabled("gdUnit4", false) - - -func temp_dir() -> String: - if not DirAccess.dir_exists_absolute(GDUNIT_TEMP): - @warning_ignore("return_value_discarded") - DirAccess.make_dir_recursive_absolute(GDUNIT_TEMP) - return GDUNIT_TEMP - - -func create_temp_dir(folder_name :String) -> String: - var new_folder := temp_dir() + "/" + folder_name - GdUnitFileAccess.delete_directory(new_folder) - if not DirAccess.dir_exists_absolute(new_folder): - @warning_ignore("return_value_discarded") - DirAccess.make_dir_recursive_absolute(new_folder) - return new_folder - - -func copy_directory(from_dir: String, to_dir: String) -> bool: - if not DirAccess.dir_exists_absolute(from_dir): - printerr("Source directory not found '%s'" % from_dir) - return false - # check if destination exists - if not DirAccess.dir_exists_absolute(to_dir): - # create it - var err := DirAccess.make_dir_recursive_absolute(to_dir) - if err != OK: - printerr("Can't create directory '%s'. Error: %s" % [to_dir, error_string(err)]) - return false - var source_dir := DirAccess.open(from_dir) - var dest_dir := DirAccess.open(to_dir) - if source_dir != null: - @warning_ignore("return_value_discarded") - source_dir.list_dir_begin() - var next := "." - - while next != "": - next = source_dir.get_next() - if next == "" or next == "." or next == "..": - continue - var source := source_dir.get_current_dir() + "/" + next - var dest := dest_dir.get_current_dir() + "/" + next - if source_dir.current_is_dir(): - @warning_ignore("return_value_discarded") - copy_directory(source + "/", dest) - continue - var err := source_dir.copy(source, dest) - if err != OK: - printerr("Error checked copy file '%s' to '%s'" % [source, dest]) - return false - return true - else: - printerr("Directory not found: " + from_dir) - return false - - -func extract_zip(zip_package: String, dest_path: String) -> Variant: - var zip: ZIPReader = ZIPReader.new() - var err := zip.open(zip_package) - if err != OK: - printerr("Extracting `%s` failed! Please collect the error log and report this. Error Code: %s" % [zip_package, err]) - return null - var zip_entries: PackedStringArray = zip.get_files() - # Get base path and step over archive folder - var archive_path := zip_entries[0] - zip_entries.remove_at(0) - - for zip_entry in zip_entries: - var new_file_path: String = dest_path + "/" + zip_entry.replace(archive_path, "") - if zip_entry.ends_with("/"): - @warning_ignore("return_value_discarded") - DirAccess.make_dir_recursive_absolute(new_file_path) - continue - var file: FileAccess = FileAccess.open(new_file_path, FileAccess.WRITE) - file.store_buffer(zip.read_file(zip_entry)) - @warning_ignore("return_value_discarded") - zip.close() - return dest_path - - -func download_release() -> void: - var zip_file := GdUnitFileAccess.temp_dir() + "/update.zip" - var response :GdUnitUpdateClient.HttpResponse - if _debug_mode: - response = GdUnitUpdateClient.HttpResponse.new(200, PackedByteArray()) - zip_file = "res://update.zip" - return - - response = await _update_client.request_zip_package(_download_url, zip_file) - if response.status() != 200: - push_warning("Update information cannot be retrieved from GitHub! \n Error code: %d : %s" % [response.status(), response.response()]) - message_h4("Download the update failed! Try it later again.", Color.INDIAN_RED) - await get_tree().create_timer(3).timeout - - -func rebuild_project() -> void: - # Check if this is a Godot .NET runtime instance - if not ClassDB.class_exists("CSharpScript"): - return - - update_progress("Rebuild the project ...") - await get_tree().process_frame - - var output := [] - var exit_code := OS.execute("dotnet", ["build"], output) - if exit_code == -1: - message_h4("Rebuild the project failed, check your project dependencies.", Color.INDIAN_RED) - await get_tree().create_timer(3).timeout - return - - for out: String in output: - print_rich("[color=DEEP_SKY_BLUE] %s" % out.strip_edges()) - await get_tree().process_frame - - -func _on_confirmed() -> void: - await run_update() - - -func _on_cancel_pressed() -> void: - hide() - - -func _on_update_pressed() -> void: - await run_update() diff --git a/addons/gdUnit4/src/update/GdUnitUpdate.gd.uid b/addons/gdUnit4/src/update/GdUnitUpdate.gd.uid deleted file mode 100644 index 99bd956a..00000000 --- a/addons/gdUnit4/src/update/GdUnitUpdate.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://2cvldn16wv2b diff --git a/addons/gdUnit4/src/update/GdUnitUpdate.tscn b/addons/gdUnit4/src/update/GdUnitUpdate.tscn deleted file mode 100644 index 20d60b76..00000000 --- a/addons/gdUnit4/src/update/GdUnitUpdate.tscn +++ /dev/null @@ -1,100 +0,0 @@ -[gd_scene load_steps=6 format=3 uid="uid://2eahgaw88y6q"] - -[ext_resource type="Script" path="res://addons/gdUnit4/src/update/GdUnitUpdate.gd" id="1"] - -[sub_resource type="Gradient" id="Gradient_wilsr"] -colors = PackedColorArray(0.151276, 0.151276, 0.151276, 1, 1, 1, 1, 1) - -[sub_resource type="GradientTexture2D" id="GradientTexture2D_45cww"] -gradient = SubResource("Gradient_wilsr") -fill_to = Vector2(0.75641, 0) - -[sub_resource type="Gradient" id="Gradient_i0qp8"] -colors = PackedColorArray(1, 1, 1, 1, 0.20871, 0.20871, 0.20871, 1) - -[sub_resource type="GradientTexture2D" id="GradientTexture2D_wilsr"] -gradient = SubResource("Gradient_i0qp8") -fill_from = Vector2(0.794872, 0) -fill_to = Vector2(0, 0) - -[node name="GdUnitUpdate" type="MarginContainer"] -clip_contents = true -custom_minimum_size = Vector2(0, 80) -anchors_preset = 10 -anchor_right = 1.0 -offset_bottom = 80.0 -grow_horizontal = 2 -size_flags_horizontal = 3 -theme_override_constants/margin_left = 10 -theme_override_constants/margin_right = 10 -script = ExtResource("1") - -[node name="VBoxContainer" type="VBoxContainer" parent="."] -layout_mode = 2 - -[node name="Panel" type="Panel" parent="VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="message" type="RichTextLabel" parent="VBoxContainer/Panel"] -unique_name_in_owner = true -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -bbcode_enabled = true -text = "aaaaa" -fit_content = true -scroll_active = false -shortcut_keys_enabled = false - -[node name="Panel2" type="Panel" parent="VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="progress" type="TextureProgressBar" parent="VBoxContainer/Panel2"] -unique_name_in_owner = true -auto_translate_mode = 2 -clip_contents = true -custom_minimum_size = Vector2(0, 20) -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -localize_numeral_system = false -min_value = 1.0 -max_value = 5.0 -value = 1.0 -rounded = true -allow_greater = true -nine_patch_stretch = true -texture_under = SubResource("GradientTexture2D_45cww") -texture_progress = SubResource("GradientTexture2D_wilsr") -tint_under = Color(0.0235294, 0.145098, 0.168627, 1) -tint_progress = Color(0.288912, 0.233442, 0.533772, 1) - -[node name="PanelContainer" type="MarginContainer" parent="VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/PanelContainer"] -layout_mode = 2 -theme_override_constants/separation = 10 -alignment = 2 - -[node name="update" type="Button" parent="VBoxContainer/PanelContainer/HBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -text = "Update" - -[node name="cancel" type="Button" parent="VBoxContainer/PanelContainer/HBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -text = "Cancel" - -[connection signal="pressed" from="VBoxContainer/PanelContainer/HBoxContainer/update" to="." method="_on_update_pressed"] -[connection signal="pressed" from="VBoxContainer/PanelContainer/HBoxContainer/cancel" to="." method="_on_cancel_pressed"] diff --git a/addons/gdUnit4/src/update/GdUnitUpdateClient.gd b/addons/gdUnit4/src/update/GdUnitUpdateClient.gd deleted file mode 100644 index b4f54b74..00000000 --- a/addons/gdUnit4/src/update/GdUnitUpdateClient.gd +++ /dev/null @@ -1,98 +0,0 @@ -@tool -extends Node - -signal request_completed(response: HttpResponse) - -class HttpResponse: - var _http_status: int - var _body: PackedByteArray - - - func _init(http_status: int, body: PackedByteArray) -> void: - _http_status = http_status - _body = body - - - func status() -> int: - return _http_status - - - func response() -> Variant: - if _http_status != 200: - return _body.get_string_from_utf8() - - var test_json_conv := JSON.new() - @warning_ignore("return_value_discarded") - var error := test_json_conv.parse(_body.get_string_from_utf8()) - if error != OK: - return "HttpResponse: %s Error: %s" % [error_string(error), _body.get_string_from_utf8()] - return test_json_conv.get_data() - - func get_body() -> PackedByteArray: - return _body - - -var _http_request := HTTPRequest.new() - - -func _ready() -> void: - add_child(_http_request) - @warning_ignore("return_value_discarded") - _http_request.request_completed.connect(_on_request_completed) - - -func _notification(what: int) -> void: - if what == NOTIFICATION_PREDELETE: - if is_instance_valid(_http_request): - _http_request.queue_free() - - -#func list_tags() -> void: -# _http_request.connect("request_completed",Callable(self,"_response_request_tags")) -# var error = _http_request.request("https://api.github.com/repos/MikeSchulze/gdUnit4/tags") -# if error != OK: -# push_error("An error occurred in the HTTP request.") - - -func request_latest_version() -> HttpResponse: - var error := _http_request.request("https://api.github.com/repos/MikeSchulze/gdUnit4/tags") - if error != OK: - var message := "Request latest version failed, %s" % error_string(error) - return HttpResponse.new(error, message.to_utf8_buffer()) - return await self.request_completed - - -func request_releases() -> HttpResponse: - var error := _http_request.request("https://api.github.com/repos/MikeSchulze/gdUnit4/releases") - if error != OK: - var message := "request_releases failed: %d" % error - return HttpResponse.new(error, message.to_utf8_buffer()) - return await self.request_completed - - -func request_image(url: String) -> HttpResponse: - var error := _http_request.request(url) - if error != OK: - var message := "request_image failed: %d" % error - return HttpResponse.new(error, message.to_utf8_buffer()) - return await self.request_completed - - -func request_zip_package(url: String, file: String) -> HttpResponse: - _http_request.set_download_file(file) - var error := _http_request.request(url) - if error != OK: - var message := "request_zip_package failed: %d" % error - return HttpResponse.new(error, message.to_utf8_buffer()) - return await self.request_completed - - -func extract_latest_version(response: HttpResponse) -> GdUnit4Version: - var body: Array = response.response() - return GdUnit4Version.parse(str(body[0]["name"])) - - -func _on_request_completed(_result: int, response_http_status: int, _headers: PackedStringArray, body: PackedByteArray) -> void: - if _http_request.get_http_client_status() != HTTPClient.STATUS_DISCONNECTED: - _http_request.set_download_file("") - request_completed.emit(HttpResponse.new(response_http_status, body)) diff --git a/addons/gdUnit4/src/update/GdUnitUpdateClient.gd.uid b/addons/gdUnit4/src/update/GdUnitUpdateClient.gd.uid deleted file mode 100644 index bdad4a9d..00000000 --- a/addons/gdUnit4/src/update/GdUnitUpdateClient.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cybga3asuikuv diff --git a/addons/gdUnit4/src/update/GdUnitUpdateNotify.gd b/addons/gdUnit4/src/update/GdUnitUpdateNotify.gd deleted file mode 100644 index f4ae9aca..00000000 --- a/addons/gdUnit4/src/update/GdUnitUpdateNotify.gd +++ /dev/null @@ -1,206 +0,0 @@ -@tool -extends MarginContainer - -#signal request_completed(response) - -const GdMarkDownReader = preload("res://addons/gdUnit4/src/update/GdMarkDownReader.gd") -const GdUnitUpdateClient = preload("res://addons/gdUnit4/src/update/GdUnitUpdateClient.gd") -const GdUnitUpdateProgress = preload("res://addons/gdUnit4/src/update/GdUnitUpdate.gd") - -@onready var _md_reader: GdMarkDownReader = GdMarkDownReader.new() -@onready var _update_client: GdUnitUpdateClient = $GdUnitUpdateClient -@onready var _header: Label = $Panel/GridContainer/PanelContainer/header -@onready var _update_button: Button = $Panel/GridContainer/Panel/HBoxContainer/update -@onready var _content: RichTextLabel = $Panel/GridContainer/PanelContainer2/ScrollContainer/MarginContainer/content -@onready var _update_progress :GdUnitUpdateProgress = %update_banner - -var _debug_mode := false -var _patcher := GdUnitPatcher.new() -var _current_version := GdUnit4Version.current() - - -func _ready() -> void: - _update_button.set_disabled(false) - _md_reader.set_http_client(_update_client) - @warning_ignore("return_value_discarded") - #GdUnitFonts.init_fonts(_content) - _update_progress.set_visible(false) - _update_progress.hidden.connect(func() -> void: - _update_button.set_disabled(false) - ) - - -func request_releases() -> bool: - if _debug_mode: - _update_progress._debug_mode = _debug_mode - _header.text = "A new version 'v4.4.4' is available" - _update_button.set_disabled(false) - return true - - var response :GdUnitUpdateClient.HttpResponse = await _update_client.request_latest_version() - if response.status() != 200: - _header.text = "Update information cannot be retrieved from GitHub!" - message_h4("\n\nError: %s" % response.response(), Color.INDIAN_RED) - return false - var latest_version := _update_client.extract_latest_version(response) - # if same version exit here no update need - if latest_version.is_greater(_current_version): - _patcher.scan(_current_version) - _header.text = "A new version '%s' is available" % latest_version - var download_zip_url := extract_zip_url(response) - _update_progress.setup(_update_client, download_zip_url) - _update_button.set_disabled(false) - return true - else: - _header.text = "No update is available." - _update_button.set_disabled(true) - return false - - -func _colored(message_: String, color: Color) -> String: - return "[color=#%s]%s[/color]" % [color.to_html(), message_] - - -func message_h4(message_: String, color: Color, clear := true) -> void: - if clear: - _content.clear() - _content.append_text("[font_size=16]%s[/font_size]" % _colored(message_, color)) - - -func message(message_: String, color: Color) -> void: - _content.clear() - _content.append_text(_colored(message_, color)) - - -func _process(_delta: float) -> void: - if _content != null and _content.is_visible_in_tree(): - _content.queue_redraw() - - -func show_update() -> void: - if not GdUnitSettings.is_update_notification_enabled(): - _header.text = "No update is available." - message_h4("The search for updates is deactivated.", Color.CORNFLOWER_BLUE) - _update_button.set_disabled(true) - return - - if not await request_releases(): - return - _update_button.set_disabled(true) - - prints("Scan for GdUnit4 Update ...") - message_h4("\n\n\nRequest release infos ... ", Color.SNOW) - _content.add_image(GdUnitUiTools.get_spinner(), 32, 32) - - var content: String - if _debug_mode: - await get_tree().create_timer(.2).timeout - var template := FileAccess.open("res://addons/gdUnit4/test/update/resources/http_response_releases.txt", FileAccess.READ).get_as_text() - content = await _md_reader.to_bbcode(template) - else: - var response :GdUnitUpdateClient.HttpResponse = await _update_client.request_releases() - if response.status() == 200: - content = await extract_releases(response, _current_version) - else: - message_h4("\n\n\nError checked request available releases!", Color.INDIAN_RED) - return - - # finally force rescan to import images as textures - if Engine.is_editor_hint(): - await rescan() - message(content, Color.CADET_BLUE) - _update_button.set_disabled(false) - - - -func extract_zip_url(response: GdUnitUpdateClient.HttpResponse) -> String: - var body :Array = response.response() - return body[0]["zipball_url"] - - -func extract_releases(response: GdUnitUpdateClient.HttpResponse, current_version: GdUnit4Version) -> String: - await get_tree().process_frame - var result := "" - for release :Dictionary in response.response(): - var release_version := str(release["tag_name"]) - if GdUnit4Version.parse(release_version).equals(current_version): - break - var release_description := _colored("

GdUnit Release %s

" % release_version, Color.CORNFLOWER_BLUE) - release_description += "\n" - release_description += release["body"] - release_description += "\n\n" - result += await _md_reader.to_bbcode(release_description) - return result - - -func rescan() -> void: - if Engine.is_editor_hint(): - if OS.is_stdout_verbose(): - prints(".. reimport release resources") - var fs := EditorInterface.get_resource_filesystem() - fs.scan() - while fs.is_scanning(): - if OS.is_stdout_verbose(): - progressBar(fs.get_scanning_progress() * 100 as int) - await get_tree().process_frame - await get_tree().process_frame - await get_tree().create_timer(1).timeout - - -func progressBar(p_progress: int) -> void: - if p_progress < 0: - p_progress = 0 - if p_progress > 100: - p_progress = 100 - printraw("scan [%-50s] %-3d%%\r" % ["".lpad(int(p_progress/2.0), "#").rpad(50, "-"), p_progress]) - - -@warning_ignore("return_value_discarded") -func _on_update_pressed() -> void: - _update_button.set_disabled(true) - # close all opend scripts before start the update - if not _debug_mode: - ScriptEditorControls.close_open_editor_scripts() - # copy update source to a temp because the update is deleting the whole gdUnit folder - DirAccess.make_dir_absolute("res://addons/.gdunit_update") - DirAccess.copy_absolute("res://addons/gdUnit4/src/update/GdUnitUpdate.tscn", "res://addons/.gdunit_update/GdUnitUpdate.tscn") - DirAccess.copy_absolute("res://addons/gdUnit4/src/update/GdUnitUpdate.gd", "res://addons/.gdunit_update/GdUnitUpdate.gd") - var source := FileAccess.open("res://addons/gdUnit4/src/update/GdUnitUpdate.tscn", FileAccess.READ) - var content := source.get_as_text().replace("res://addons/gdUnit4/src/update/GdUnitUpdate.gd", "res://addons/.gdunit_update/GdUnitUpdate.gd") - var dest := FileAccess.open("res://addons/.gdunit_update/GdUnitUpdate.tscn", FileAccess.WRITE) - dest.store_string(content) - _update_progress.set_visible(true) - - -func _on_show_next_toggled(enabled: bool) -> void: - GdUnitSettings.set_update_notification(enabled) - - -func _on_cancel_pressed() -> void: - hide() - - -func _on_content_meta_clicked(meta: String) -> void: - var properties: Dictionary = str_to_var(meta) - if properties.has("url"): - @warning_ignore("return_value_discarded") - OS.shell_open(str(properties.get("url"))) - - -func _on_content_meta_hover_started(meta: String) -> void: - var properties: Dictionary = str_to_var(meta) - if properties.has("tool_tip"): - _content.set_tooltip_text(str(properties.get("tool_tip"))) - - -@warning_ignore("unused_parameter") -func _on_content_meta_hover_ended(meta: String) -> void: - _content.set_tooltip_text("") - - -func _on_visibility_changed() -> void: - if not is_visible_in_tree(): - return - if _update_progress != null: - _update_progress.set_visible(false) - await show_update() diff --git a/addons/gdUnit4/src/update/GdUnitUpdateNotify.gd.uid b/addons/gdUnit4/src/update/GdUnitUpdateNotify.gd.uid deleted file mode 100644 index 64610aef..00000000 --- a/addons/gdUnit4/src/update/GdUnitUpdateNotify.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://crycbwg5hjrkl diff --git a/addons/gdUnit4/src/update/GdUnitUpdateNotify.tscn b/addons/gdUnit4/src/update/GdUnitUpdateNotify.tscn deleted file mode 100644 index 46119f14..00000000 --- a/addons/gdUnit4/src/update/GdUnitUpdateNotify.tscn +++ /dev/null @@ -1,97 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://0xyeci1tqebj"] - -[ext_resource type="Script" path="res://addons/gdUnit4/src/update/GdUnitUpdateNotify.gd" id="1_112wo"] -[ext_resource type="Script" path="res://addons/gdUnit4/src/update/GdUnitUpdateClient.gd" id="2_18asx"] -[ext_resource type="PackedScene" path="res://addons/gdUnit4/src/update/GdUnitUpdate.tscn" id="3_x87h6"] - -[node name="Control" type="MarginContainer"] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 -script = ExtResource("1_112wo") - -[node name="GdUnitUpdateClient" type="Node" parent="."] -script = ExtResource("2_18asx") - -[node name="Panel" type="Panel" parent="."] -layout_mode = 2 - -[node name="GridContainer" type="VBoxContainer" parent="Panel"] -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 -alignment = 1 - -[node name="PanelContainer" type="MarginContainer" parent="Panel/GridContainer"] -layout_mode = 2 -theme_override_constants/margin_left = 4 -theme_override_constants/margin_top = 4 -theme_override_constants/margin_right = 4 -theme_override_constants/margin_bottom = 4 - -[node name="header" type="Label" parent="Panel/GridContainer/PanelContainer"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 9 - -[node name="PanelContainer2" type="PanelContainer" parent="Panel/GridContainer"] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="ScrollContainer" type="ScrollContainer" parent="Panel/GridContainer/PanelContainer2"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="MarginContainer" type="MarginContainer" parent="Panel/GridContainer/PanelContainer2/ScrollContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="content" type="RichTextLabel" parent="Panel/GridContainer/PanelContainer2/ScrollContainer/MarginContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 -bbcode_enabled = true - -[node name="update_banner" parent="Panel/GridContainer" instance=ExtResource("3_x87h6")] -unique_name_in_owner = true -visible = false -layout_mode = 2 -size_flags_horizontal = 1 -size_flags_vertical = 8 - -[node name="Panel" type="MarginContainer" parent="Panel/GridContainer"] -layout_mode = 2 -size_flags_vertical = 8 -theme_override_constants/margin_left = 4 -theme_override_constants/margin_top = 4 -theme_override_constants/margin_right = 4 -theme_override_constants/margin_bottom = 4 - -[node name="HBoxContainer" type="HBoxContainer" parent="Panel/GridContainer/Panel"] -use_parent_material = true -layout_mode = 2 -theme_override_constants/separation = 4 - -[node name="update" type="Button" parent="Panel/GridContainer/Panel/HBoxContainer"] -custom_minimum_size = Vector2(100, 40) -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 4 -text = "Update" - -[connection signal="visibility_changed" from="." to="." method="_on_visibility_changed"] -[connection signal="meta_clicked" from="Panel/GridContainer/PanelContainer2/ScrollContainer/MarginContainer/content" to="." method="_on_content_meta_clicked"] -[connection signal="meta_hover_ended" from="Panel/GridContainer/PanelContainer2/ScrollContainer/MarginContainer/content" to="." method="_on_content_meta_hover_ended"] -[connection signal="meta_hover_started" from="Panel/GridContainer/PanelContainer2/ScrollContainer/MarginContainer/content" to="." method="_on_content_meta_hover_started"] -[connection signal="pressed" from="Panel/GridContainer/Panel/HBoxContainer/update" to="." method="_on_update_pressed"] diff --git a/addons/gdUnit4/src/update/assets/border_bottom.png b/addons/gdUnit4/src/update/assets/border_bottom.png deleted file mode 100644 index 2eb4a6f9..00000000 --- a/addons/gdUnit4/src/update/assets/border_bottom.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:37a40709349e82f04b542de8d17c4118d68531f6515964b0e03f28f6ee529772 -size 1757 diff --git a/addons/gdUnit4/src/update/assets/border_bottom.png.import b/addons/gdUnit4/src/update/assets/border_bottom.png.import deleted file mode 100644 index 8b5da955..00000000 --- a/addons/gdUnit4/src/update/assets/border_bottom.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cse3iwnghcmkn" -path="res://.godot/imported/border_bottom.png-30d66a4c67e3a03ad191e37cdf16549d.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/gdUnit4/src/update/assets/border_bottom.png" -dest_files=["res://.godot/imported/border_bottom.png-30d66a4c67e3a03ad191e37cdf16549d.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/gdUnit4/src/update/assets/border_top.png b/addons/gdUnit4/src/update/assets/border_top.png deleted file mode 100644 index fcfe17dc..00000000 --- a/addons/gdUnit4/src/update/assets/border_top.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ca6f5d7f59cf272dc87fc4762bd7ec82502bb1987c7803ebaea594408401ac47 -size 1749 diff --git a/addons/gdUnit4/src/update/assets/border_top.png.import b/addons/gdUnit4/src/update/assets/border_top.png.import deleted file mode 100644 index 23bce284..00000000 --- a/addons/gdUnit4/src/update/assets/border_top.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://peoblq5q6qhm" -path="res://.godot/imported/border_top.png-c47cbebdb755144731c6ae309e18bbaa.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/gdUnit4/src/update/assets/border_top.png" -dest_files=["res://.godot/imported/border_top.png-c47cbebdb755144731c6ae309e18bbaa.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/gdUnit4/src/update/assets/dot1.png b/addons/gdUnit4/src/update/assets/dot1.png deleted file mode 100644 index 0ae482f2..00000000 --- a/addons/gdUnit4/src/update/assets/dot1.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f37474a8d5dc0c9574cef6fad5308922841e60deb31213e2723e3dd2755bd7e5 -size 730 diff --git a/addons/gdUnit4/src/update/assets/dot1.png.import b/addons/gdUnit4/src/update/assets/dot1.png.import deleted file mode 100644 index a8bc5b04..00000000 --- a/addons/gdUnit4/src/update/assets/dot1.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bhfi0qh1a2hwx" -path="res://.godot/imported/dot1.png-380baf1b5247addda93bce3c799aa4e7.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/gdUnit4/src/update/assets/dot1.png" -dest_files=["res://.godot/imported/dot1.png-380baf1b5247addda93bce3c799aa4e7.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/gdUnit4/src/update/assets/dot2.png b/addons/gdUnit4/src/update/assets/dot2.png deleted file mode 100644 index 02b0af76..00000000 --- a/addons/gdUnit4/src/update/assets/dot2.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c12758bd1b0b0ef88811b50affd3957bbf9c9e6c0922c0de199a4a3649643103 -size 883 diff --git a/addons/gdUnit4/src/update/assets/dot2.png.import b/addons/gdUnit4/src/update/assets/dot2.png.import deleted file mode 100644 index 23930c7c..00000000 --- a/addons/gdUnit4/src/update/assets/dot2.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dg86wkmvp1qyn" -path="res://.godot/imported/dot2.png-86a9db80ef4413e353c4339ad8f68a5f.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/gdUnit4/src/update/assets/dot2.png" -dest_files=["res://.godot/imported/dot2.png-86a9db80ef4413e353c4339ad8f68a5f.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/gdUnit4/src/update/assets/embedded.png b/addons/gdUnit4/src/update/assets/embedded.png deleted file mode 100644 index b09c232f..00000000 --- a/addons/gdUnit4/src/update/assets/embedded.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:08cead78bbc3d7aefda91f376b1280195333d94a32222b1490876fabf0823f6b -size 287 diff --git a/addons/gdUnit4/src/update/assets/embedded.png.import b/addons/gdUnit4/src/update/assets/embedded.png.import deleted file mode 100644 index 56cb94f4..00000000 --- a/addons/gdUnit4/src/update/assets/embedded.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://d160etflupwba" -path="res://.godot/imported/embedded.png-29390948772209a603567d24f8766495.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/gdUnit4/src/update/assets/embedded.png" -dest_files=["res://.godot/imported/embedded.png-29390948772209a603567d24f8766495.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/gdUnit4/src/update/assets/horizontal-line2.png b/addons/gdUnit4/src/update/assets/horizontal-line2.png deleted file mode 100644 index 91ccc243..00000000 --- a/addons/gdUnit4/src/update/assets/horizontal-line2.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fb01fb89e6b3ff826f05e772336f0cd855e1e838ef920cac9fd6a3e3504dacd9 -size 332 diff --git a/addons/gdUnit4/src/update/assets/horizontal-line2.png.import b/addons/gdUnit4/src/update/assets/horizontal-line2.png.import deleted file mode 100644 index 3931900d..00000000 --- a/addons/gdUnit4/src/update/assets/horizontal-line2.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bloqm443lywyi" -path="res://.godot/imported/horizontal-line2.png-92618e6ee5cc9002847547a8c9deadbc.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/gdUnit4/src/update/assets/horizontal-line2.png" -dest_files=["res://.godot/imported/horizontal-line2.png-92618e6ee5cc9002847547a8c9deadbc.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/tests/ExampleTest.cs b/tests/ExampleTest.cs index 3f7b419f..527ea6e7 100644 --- a/tests/ExampleTest.cs +++ b/tests/ExampleTest.cs @@ -1,28 +1,28 @@ -// namespace Movementtests.tests; -// -// using GdUnit4; -// using static GdUnit4.Assertions; -// -// [TestSuite] -// public class ExampleTest -// { -// [Before] -// public void Setup() { -// // Setup suite-level shared resources, expensive setup -// } -// -// [After] -// public void Cleanup() { -// // Cleanup suite-level shared resources, expensive setup -// } -// -// [TestCase] -// public void StringToLower() { -// AssertString("AbcD".ToLower()).IsEqual("abcd"); -// } -// -// [TestCase] -// public void StringToUpper() { -// AssertString("AbcD".ToUpper()).IsEqual("ABCD"); -// } -// } \ No newline at end of file +namespace Movementtests.tests; + +using GdUnit4; +using static GdUnit4.Assertions; + +[TestSuite] +public class ExampleTest +{ + [Before] + public void Setup() { + // Setup suite-level shared resources, expensive setup + } + + [After] + public void Cleanup() { + // Cleanup suite-level shared resources, expensive setup + } + + [TestCase] + public void StringToLower() { + AssertString("AbcD".ToLower()).IsEqual("abcd"); + } + + [TestCase] + public void StringToUpper() { + AssertString("AbcD".ToUpper()).IsEqual("ABCD"); + } +} \ No newline at end of file