diff --git a/.github/workflows/README.md b/.github/workflows/README.md
index 0fe1570677..86483386e5 100644
--- a/.github/workflows/README.md
+++ b/.github/workflows/README.md
@@ -29,8 +29,9 @@ The repository uses multiple GitHub Actions workflows. What runs and when:
1. Each OS checks out code, restores, and builds locally
2. **Performance optimizations**:
- Disables Windows Defender on Windows runners (significant speedup)
-3. Runs two test jobs:
- - **Non-parallel UnitTests**: `Tests/UnitTests` with diagnostic output
+3. Runs three test jobs:
+ - **Non-parallel UnitTests.Legacy**: `Tests/UnitTests.Legacy` with diagnostic output
+ - **Non-parallel UnitTests.NonParallelizable**: `Tests/UnitTests.NonParallelizable` with diagnostic output
- **Parallel UnitTestsParallelizable**: `Tests/UnitTestsParallelizable` with diagnostic output
4. Uploads test logs and diagnostic data from all runners
@@ -87,7 +88,8 @@ The repository uses multiple GitHub Actions workflows. What runs and when:
# Full CI sequence:
dotnet restore
dotnet build --configuration Debug --no-restore
-dotnet test --project Tests/UnitTests --no-build --verbosity normal
+dotnet test --project Tests/UnitTests.Legacy --no-build --verbosity normal
+dotnet test --project Tests/UnitTests.NonParallelizable --no-build --verbosity normal
dotnet test --project Tests/UnitTestsParallelizable --no-build --verbosity normal
dotnet build --configuration Release --no-restore
```
diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml
index 9cd63dfb0c..ee36a3263c 100644
--- a/.github/workflows/unit-tests.yml
+++ b/.github/workflows/unit-tests.yml
@@ -47,14 +47,14 @@ jobs:
Add-MpPreference -ExclusionPath "${{ github.workspace }}"
Add-MpPreference -ExclusionProcess "dotnet.exe"
- - name: Run UnitTests
+ - name: Run UnitTests.NonParallelizable
shell: bash
run: |
dotnet test \
- --project Tests/UnitTests \
+ --project Tests/UnitTests.NonParallelizable \
--no-build \
--verbosity normal \
- --diagnostic --diagnostic-output-directory logs/UnitTests/${{ runner.os }}
+ --diagnostic --diagnostic-output-directory logs/UnitTests.NonParallelizable/${{ runner.os }}
- name: Upload Test Logs
if: always()
@@ -62,8 +62,8 @@ jobs:
with:
name: non_parallel_unittests-logs-${{ runner.os }}
path: |
- logs/UnitTests/
- Tests/UnitTests/logs/
+ logs/UnitTests.NonParallelizable/
+ Tests/UnitTests.NonParallelizable/logs/
TestResults/
**/*.dmp
if-no-files-found: ignore
diff --git a/Terminal.Gui/Terminal.Gui.csproj b/Terminal.Gui/Terminal.Gui.csproj
index 544579f229..1ae0543353 100644
--- a/Terminal.Gui/Terminal.Gui.csproj
+++ b/Terminal.Gui/Terminal.Gui.csproj
@@ -83,6 +83,8 @@
+
+
diff --git a/Terminal.sln b/Terminal.sln
index e2663bcd20..30911810be 100644
--- a/Terminal.sln
+++ b/Terminal.sln
@@ -105,7 +105,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NativeAot", "Examples\Nativ
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmarks", "Tests\Benchmarks\Benchmarks.csproj", "{242FBD3E-2EC6-4274-BD40-8E62AF9327B2}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "Tests\UnitTests\UnitTests.csproj", "{038B09F5-EF3A-F21E-7C10-A6551866ECE2}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests.Legacy", "Tests\UnitTests.Legacy\UnitTests.Legacy.csproj", "{038B09F5-EF3A-F21E-7C10-A6551866ECE2}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests.NonParallelizable", "Tests\UnitTests.NonParallelizable\UnitTests.NonParallelizable.csproj", "{B7C94F2A-3E8D-4A1B-9F5C-2D1E6A3B7C90}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IntegrationTests", "Tests\IntegrationTests\IntegrationTests.csproj", "{F74EC349-B988-FCFA-A1E5-967F70FB75B5}"
EndProject
@@ -123,7 +125,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Testing", "Testing", "{1A3C
ProjectSection(SolutionItems) = preProject
codecov.yml = codecov.yml
Scripts\Run-LocalCoverage.ps1 = Scripts\Run-LocalCoverage.ps1
- Tests\UnitTests\runsettings.xml = Tests\UnitTests\runsettings.xml
+ Tests\UnitTests.Legacy\runsettings.xml = Tests\UnitTests.Legacy\runsettings.xml
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluentExample", "Examples\FluentExample\FluentExample.csproj", "{8C05292F-86C9-C29A-635B-A4DFC5955D1C}"
@@ -189,6 +191,10 @@ Global
{038B09F5-EF3A-F21E-7C10-A6551866ECE2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{038B09F5-EF3A-F21E-7C10-A6551866ECE2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{038B09F5-EF3A-F21E-7C10-A6551866ECE2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B7C94F2A-3E8D-4A1B-9F5C-2D1E6A3B7C90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B7C94F2A-3E8D-4A1B-9F5C-2D1E6A3B7C90}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B7C94F2A-3E8D-4A1B-9F5C-2D1E6A3B7C90}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B7C94F2A-3E8D-4A1B-9F5C-2D1E6A3B7C90}.Release|Any CPU.Build.0 = Release|Any CPU
{F74EC349-B988-FCFA-A1E5-967F70FB75B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F74EC349-B988-FCFA-A1E5-967F70FB75B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F74EC349-B988-FCFA-A1E5-967F70FB75B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -248,6 +254,7 @@ Global
{E6D716C6-AC94-4150-B10A-44AE13F79344} = {3DD033C0-E023-47BF-A808-9CCE30873C3E}
{242FBD3E-2EC6-4274-BD40-8E62AF9327B2} = {A589126F-C71A-4FEE-B7EA-2DCA1ADF6A46}
{038B09F5-EF3A-F21E-7C10-A6551866ECE2} = {A589126F-C71A-4FEE-B7EA-2DCA1ADF6A46}
+ {B7C94F2A-3E8D-4A1B-9F5C-2D1E6A3B7C90} = {A589126F-C71A-4FEE-B7EA-2DCA1ADF6A46}
{F74EC349-B988-FCFA-A1E5-967F70FB75B5} = {A589126F-C71A-4FEE-B7EA-2DCA1ADF6A46}
{96ACE8BA-2E07-7537-FBF2-E8176CCB8080} = {A589126F-C71A-4FEE-B7EA-2DCA1ADF6A46}
{DE780834-190A-8277-51FD-750CC666E82D} = {A589126F-C71A-4FEE-B7EA-2DCA1ADF6A46}
diff --git a/Tests/IntegrationTests/IntegrationTests.csproj b/Tests/IntegrationTests/IntegrationTests.csproj
index 8b1545686a..1faeffd3ec 100644
--- a/Tests/IntegrationTests/IntegrationTests.csproj
+++ b/Tests/IntegrationTests/IntegrationTests.csproj
@@ -34,7 +34,7 @@
-
+
diff --git a/Tests/README.md b/Tests/README.md
index 805a8b54a9..78efbc3b35 100644
--- a/Tests/README.md
+++ b/Tests/README.md
@@ -2,28 +2,90 @@
This folder contains the tests for Terminal.Gui.
-## ./UnitTests
+## Test Projects
-This folder contains the unit tests for Terminal.Gui that can not be run in parallel. This is because they
-depend on `Application` or other class that use static state or `ConfigurationManager`.
+### ./UnitTestsParallelizable
-We should be striving to move as many tests as possible to the `./UnitTestsParallelizable` folder.
+The primary home for new tests. Tests here run in parallel (`parallelizeAssembly: true`, `maxParallelThreads: 12`)
+and **must not** touch any process-wide static state.
-## ./UnitTestsParallelizable
+### ./UnitTests.NonParallelizable
-This folder contains the unit tests for Terminal.Gui that can be run in parallel.
+Tests that either explicitly test process-wide static state, or must set process-wide statics, or otherwise
+cannot be run concurrently with other tests. These tests run with `parallelizeAssembly: false`.
-## ./IntegrationTests
+### ./UnitTests.Legacy
-This folder contains the integration tests for Terminal.Gui.
+Tests that have not yet been ported to `UnitTestsParallelizable` or `UnitTests.NonParallelizable`.
+These tests are candidates for rewrite (if the case is not covered elsewhere) or deletion (if already covered).
+Do not add new tests here.
-## ./StressTests
+### ./IntegrationTests
-This folder contains the stress tests for Terminal.Gui.
+Integration tests for Terminal.Gui.
-## ./PerformanceTests
+### ./StressTests
-This folder WILL contain the performance tests for Terminal.Gui.
+Stress tests for Terminal.Gui.
+---
+
+## Static State in Terminal.Gui
+
+The following classes and properties use process-wide static state. Tests that read or write these **must not**
+go in `UnitTestsParallelizable` — they belong in `UnitTests.NonParallelizable`.
+
+### `Application` (legacy static façade — `Terminal.Gui.App/Legacy/`)
+
+| Member | Notes |
+|--------|-------|
+| `Application.Instance` | Returns `ApplicationImpl.Instance` (singleton) |
+| `Application.Init(driverName)` | Initializes the singleton; sets `Initialized`, `Driver`, `MainThreadId`, `SynchronizationContext` |
+| `Application.Shutdown()` | Disposes the singleton; resets all static fields |
+| `Application.Initialized` | Global bool; true between `Init` and `Shutdown` |
+| `Application.MainThreadId` | Process-wide main thread ID set by `Init` |
+| `Application.Driver` | The active `IDriver` singleton |
+| `Application.DefaultKeyBindings` | Process-wide default key-binding dictionary (mutable `IDictionary`) |
+| `Application.ForceDriver` | Persists across tests unless reset |
+| `Application.Keyboard` | Delegates to `ApplicationImpl.Instance.Keyboard` |
+| `Application.Navigation` | Delegates to `ApplicationImpl.Instance.Navigation` |
+| `Application.Popovers` | Delegates to `ApplicationImpl.Instance.Popovers` |
+| `Application.Screen` | Delegates to `ApplicationImpl.Instance.Screen` |
+| `Application.ResetState()` | Resets all static backing fields to defaults |
+| `SynchronizationContext.Current` | Set by `Application.Init`; process-wide |
+
+### `ApplicationImpl` (singleton — `Terminal.Gui.App/ApplicationImpl.cs`)
+
+| Member | Notes |
+|--------|-------|
+| `ApplicationImpl.Instance` | Process-wide singleton; set by `SetInstance()` |
+| `ApplicationImpl.SetInstance(impl)` | Replaces the singleton (used in tests) |
+| `ApplicationImpl.ResetModelUsageTracking()` | Resets the static "which model was used" flag |
+
+### `ConfigurationManager` (singleton — `Terminal.Gui.Configuration/`)
+
+| Member | Notes |
+|--------|-------|
+| `CM.IsEnabled` | Global flag; affects all code reading configuration |
+| `CM.Disable(reset)` | Disables and optionally resets to hard-coded defaults |
+
+### `View.Diagnostics` (static field — `Terminal.Gui.ViewBase/View.cs`)
+
+| Member | Notes |
+|--------|-------|
+| `View.Diagnostics` | `ViewDiagnosticFlags`; process-wide debug flags |
+
+---
+
+## Which Project Does My Test Belong In?
+
+| Test characteristic | Project |
+|---------------------|---------|
+| No static state; no `Application.Init`/`Shutdown`; no `ConfigurationManager` mutations | `UnitTestsParallelizable` |
+| Calls `Application.Init`/`Shutdown` directly, or mutates `Application.DefaultKeyBindings`, `Application.ForceDriver`, or `ApplicationImpl.ResetModelUsageTracking()` | `UnitTests.NonParallelizable` |
+| Uses `[AutoInitShutdown]` or `[SetupFakeApplication]` (fake driver, does not call real `Application.Init`) | Currently in `UnitTests.Legacy`; migrate to `UnitTestsParallelizable` or `UnitTests.NonParallelizable` after review |
+| Not yet reviewed / ported | `UnitTests.Legacy` |
+
+---
See the [Testing wiki](https://github.com/gui-cs/Terminal.Gui/wiki/Testing) for details on how to add more tests.
diff --git a/Tests/UnitTests/AssemblyInfo.cs b/Tests/UnitTests.Legacy/AssemblyInfo.cs
similarity index 100%
rename from Tests/UnitTests/AssemblyInfo.cs
rename to Tests/UnitTests.Legacy/AssemblyInfo.cs
diff --git a/Tests/UnitTests/AutoInitShutdownAttribute.cs b/Tests/UnitTests.Legacy/AutoInitShutdownAttribute.cs
similarity index 100%
rename from Tests/UnitTests/AutoInitShutdownAttribute.cs
rename to Tests/UnitTests.Legacy/AutoInitShutdownAttribute.cs
diff --git a/Tests/UnitTests/DriverAssert.cs b/Tests/UnitTests.Legacy/DriverAssert.cs
similarity index 100%
rename from Tests/UnitTests/DriverAssert.cs
rename to Tests/UnitTests.Legacy/DriverAssert.cs
diff --git a/Tests/UnitTests/FakeDriver/FakeApplicationFactory.cs b/Tests/UnitTests.Legacy/FakeDriver/FakeApplicationFactory.cs
similarity index 100%
rename from Tests/UnitTests/FakeDriver/FakeApplicationFactory.cs
rename to Tests/UnitTests.Legacy/FakeDriver/FakeApplicationFactory.cs
diff --git a/Tests/UnitTests/FakeDriver/FakeApplicationLifecycle.cs b/Tests/UnitTests.Legacy/FakeDriver/FakeApplicationLifecycle.cs
similarity index 100%
rename from Tests/UnitTests/FakeDriver/FakeApplicationLifecycle.cs
rename to Tests/UnitTests.Legacy/FakeDriver/FakeApplicationLifecycle.cs
diff --git a/Tests/UnitTests/OutputAssert.cs b/Tests/UnitTests.Legacy/OutputAssert.cs
similarity index 100%
rename from Tests/UnitTests/OutputAssert.cs
rename to Tests/UnitTests.Legacy/OutputAssert.cs
diff --git a/Tests/UnitTests.Legacy/README.md b/Tests/UnitTests.Legacy/README.md
new file mode 100644
index 0000000000..ad8be9df31
--- /dev/null
+++ b/Tests/UnitTests.Legacy/README.md
@@ -0,0 +1,13 @@
+# UnitTests.Legacy
+
+This project contains tests that have not yet been ported to `UnitTestsParallelizable` or `UnitTests.NonParallelizable`.
+
+**Do not add new tests here.** New tests should go in:
+- [`../UnitTestsParallelizable`](../UnitTestsParallelizable/README.md) for tests with no static state dependency.
+- [`../UnitTests.NonParallelizable`](../UnitTests.NonParallelizable/README.md) for tests that explicitly depend on process-wide static state.
+
+Each test class in this project is a candidate for one of:
+1. **Rewrite** in the appropriate project if the case is not already covered.
+2. **Deletion** if the case is already covered in `UnitTestsParallelizable`.
+
+See the [Testing wiki](https://github.com/gui-cs/Terminal.Gui/wiki/Testing) for details.
diff --git a/Tests/UnitTests/SetupFakeApplicationAttribute.cs b/Tests/UnitTests.Legacy/SetupFakeApplicationAttribute.cs
similarity index 100%
rename from Tests/UnitTests/SetupFakeApplicationAttribute.cs
rename to Tests/UnitTests.Legacy/SetupFakeApplicationAttribute.cs
diff --git a/Tests/UnitTests/TestDriverBase.cs b/Tests/UnitTests.Legacy/TestDriverBase.cs
similarity index 100%
rename from Tests/UnitTests/TestDriverBase.cs
rename to Tests/UnitTests.Legacy/TestDriverBase.cs
diff --git a/Tests/UnitTests/TestLogging.cs b/Tests/UnitTests.Legacy/TestLogging.cs
similarity index 100%
rename from Tests/UnitTests/TestLogging.cs
rename to Tests/UnitTests.Legacy/TestLogging.cs
diff --git a/Tests/UnitTests/TestRespondersDisposedAttribute.cs b/Tests/UnitTests.Legacy/TestRespondersDisposedAttribute.cs
similarity index 100%
rename from Tests/UnitTests/TestRespondersDisposedAttribute.cs
rename to Tests/UnitTests.Legacy/TestRespondersDisposedAttribute.cs
diff --git a/Tests/UnitTests/TestsAllViews.cs b/Tests/UnitTests.Legacy/TestsAllViews.cs
similarity index 100%
rename from Tests/UnitTests/TestsAllViews.cs
rename to Tests/UnitTests.Legacy/TestsAllViews.cs
diff --git a/Tests/UnitTests/UnitTests.csproj b/Tests/UnitTests.Legacy/UnitTests.Legacy.csproj
similarity index 98%
rename from Tests/UnitTests/UnitTests.csproj
rename to Tests/UnitTests.Legacy/UnitTests.Legacy.csproj
index 1771097314..98cce1be6b 100644
--- a/Tests/UnitTests/UnitTests.csproj
+++ b/Tests/UnitTests.Legacy/UnitTests.Legacy.csproj
@@ -9,6 +9,7 @@
2.0
+ UnitTests.Legacy
Exe
true
true
diff --git a/Tests/UnitTests/UnitTests.csproj.DotSettings b/Tests/UnitTests.Legacy/UnitTests.Legacy.csproj.DotSettings
similarity index 100%
rename from Tests/UnitTests/UnitTests.csproj.DotSettings
rename to Tests/UnitTests.Legacy/UnitTests.Legacy.csproj.DotSettings
diff --git a/Tests/UnitTests/UnitTests.sln b/Tests/UnitTests.Legacy/UnitTests.Legacy.sln
similarity index 87%
rename from Tests/UnitTests/UnitTests.sln
rename to Tests/UnitTests.Legacy/UnitTests.Legacy.sln
index 0d950924ca..b7af8b233c 100644
--- a/Tests/UnitTests/UnitTests.sln
+++ b/Tests/UnitTests.Legacy/UnitTests.Legacy.sln
@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.002.0
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests", "UnitTests.csproj", "{A29633F2-B26E-48B2-997A-1733286E3C13}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests.Legacy", "UnitTests.Legacy.csproj", "{A29633F2-B26E-48B2-997A-1733286E3C13}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
diff --git a/Tests/UnitTests/runsettings.coverage.xml b/Tests/UnitTests.Legacy/runsettings.coverage.xml
similarity index 100%
rename from Tests/UnitTests/runsettings.coverage.xml
rename to Tests/UnitTests.Legacy/runsettings.coverage.xml
diff --git a/Tests/UnitTests/runsettings.xml b/Tests/UnitTests.Legacy/runsettings.xml
similarity index 100%
rename from Tests/UnitTests/runsettings.xml
rename to Tests/UnitTests.Legacy/runsettings.xml
diff --git a/Tests/UnitTests/xunit.runner.json b/Tests/UnitTests.Legacy/xunit.runner.json
similarity index 100%
rename from Tests/UnitTests/xunit.runner.json
rename to Tests/UnitTests.Legacy/xunit.runner.json
diff --git a/Tests/UnitTests/Application/ApplicationModelFencingTests.cs b/Tests/UnitTests.NonParallelizable/Application/ApplicationModelFencingTests.cs
similarity index 99%
rename from Tests/UnitTests/Application/ApplicationModelFencingTests.cs
rename to Tests/UnitTests.NonParallelizable/Application/ApplicationModelFencingTests.cs
index eaaf6d3728..a0b6cb1a9f 100644
--- a/Tests/UnitTests/Application/ApplicationModelFencingTests.cs
+++ b/Tests/UnitTests.NonParallelizable/Application/ApplicationModelFencingTests.cs
@@ -1,4 +1,4 @@
-namespace UnitTests.ApplicationTests;
+namespace UnitTests.NonParallelizable.ApplicationTests;
///
/// Tests to ensure that mixing legacy static Application and modern instance-based models
diff --git a/Tests/UnitTests/Application/Keyboard/ApplicationKeyboardThreadSafetyTests.cs b/Tests/UnitTests.NonParallelizable/Application/Keyboard/ApplicationKeyboardThreadSafetyTests.cs
similarity index 99%
rename from Tests/UnitTests/Application/Keyboard/ApplicationKeyboardThreadSafetyTests.cs
rename to Tests/UnitTests.NonParallelizable/Application/Keyboard/ApplicationKeyboardThreadSafetyTests.cs
index 8e170bc6fd..d29437dd76 100644
--- a/Tests/UnitTests/Application/Keyboard/ApplicationKeyboardThreadSafetyTests.cs
+++ b/Tests/UnitTests.NonParallelizable/Application/Keyboard/ApplicationKeyboardThreadSafetyTests.cs
@@ -1,7 +1,7 @@
#nullable enable
// ReSharper disable AccessToDisposedClosure
-namespace UnitTests.ApplicationTests.Keyboard;
+namespace UnitTests.NonParallelizable.ApplicationTests.Keyboard;
///
/// Tests to verify that ApplicationKeyboard is thread-safe for concurrent access scenarios.
diff --git a/Tests/UnitTests/Application/Keyboard/KeyboardSetterTests.cs b/Tests/UnitTests.NonParallelizable/Application/Keyboard/KeyboardSetterTests.cs
similarity index 98%
rename from Tests/UnitTests/Application/Keyboard/KeyboardSetterTests.cs
rename to Tests/UnitTests.NonParallelizable/Application/Keyboard/KeyboardSetterTests.cs
index 6388369021..ca3f4fa1d7 100644
--- a/Tests/UnitTests/Application/Keyboard/KeyboardSetterTests.cs
+++ b/Tests/UnitTests.NonParallelizable/Application/Keyboard/KeyboardSetterTests.cs
@@ -1,7 +1,7 @@
// Tests that mutate Application.DefaultKeyBindings (static state).
// These MUST NOT be in UnitTestsParallelizable.
-namespace UnitTests.ApplicationTests.Keyboard;
+namespace UnitTests.NonParallelizable.ApplicationTests.Keyboard;
public class KeyboardSetterTests
{
diff --git a/Tests/UnitTests.NonParallelizable/Application/SynchronizationContextTests.cs b/Tests/UnitTests.NonParallelizable/Application/SynchronizationContextTests.cs
new file mode 100644
index 0000000000..ab3641dee8
--- /dev/null
+++ b/Tests/UnitTests.NonParallelizable/Application/SynchronizationContextTests.cs
@@ -0,0 +1,52 @@
+// Copilot
+#nullable enable
+
+namespace UnitTests.NonParallelizable.ApplicationTests;
+
+///
+/// Tests for the that is set during the Terminal.Gui application lifecycle.
+/// Must run non-concurrently because and mutate
+/// the process-wide .
+///
+public class SynchronizationContextTests
+{
+ [Fact]
+ public void Init_SetsSynchronizationContext_Dispose_ClearsIt ()
+ {
+ IApplication app = Application.Create ();
+
+ try
+ {
+ app.Init (DriverRegistry.Names.ANSI);
+
+ Assert.NotNull (SynchronizationContext.Current);
+ }
+ finally
+ {
+ app.Dispose ();
+ }
+
+ Assert.Null (SynchronizationContext.Current);
+ }
+
+ [Fact]
+ public void Init_SynchronizationContext_CreateCopy_ReturnsDifferentInstance ()
+ {
+ IApplication app = Application.Create ();
+
+ try
+ {
+ app.Init (DriverRegistry.Names.ANSI);
+
+ SynchronizationContext context = SynchronizationContext.Current!;
+ SynchronizationContext copy = context.CreateCopy ();
+
+ Assert.NotNull (copy);
+ Assert.NotSame (context, copy);
+ }
+ finally
+ {
+ app.Dispose ();
+ }
+ }
+}
diff --git a/Tests/UnitTests.NonParallelizable/AssemblyInfo.cs b/Tests/UnitTests.NonParallelizable/AssemblyInfo.cs
new file mode 100644
index 0000000000..e6cc8f6e5c
--- /dev/null
+++ b/Tests/UnitTests.NonParallelizable/AssemblyInfo.cs
@@ -0,0 +1,15 @@
+global using Attribute = Terminal.Gui.Drawing.Attribute;
+global using Color = Terminal.Gui.Drawing.Color;
+global using CM = Terminal.Gui.Configuration.ConfigurationManager;
+global using Terminal.Gui.App;
+global using Terminal.Gui.Time;
+global using Terminal.Gui.Testing;
+global using Terminal.Gui.Drivers;
+global using Terminal.Gui.Input;
+global using Terminal.Gui.Configuration;
+global using Terminal.Gui.ViewBase;
+global using Terminal.Gui.Views;
+global using Terminal.Gui.Drawing;
+global using Terminal.Gui.Text;
+global using Terminal.Gui.Resources;
+global using Terminal.Gui.FileServices;
diff --git a/Tests/UnitTests/Configuration/ConfigurationMangerTests.cs b/Tests/UnitTests.NonParallelizable/Configuration/ConfigurationMangerTests.cs
similarity index 99%
rename from Tests/UnitTests/Configuration/ConfigurationMangerTests.cs
rename to Tests/UnitTests.NonParallelizable/Configuration/ConfigurationMangerTests.cs
index 7bfeaf2f84..81b77f8f80 100644
--- a/Tests/UnitTests/Configuration/ConfigurationMangerTests.cs
+++ b/Tests/UnitTests.NonParallelizable/Configuration/ConfigurationMangerTests.cs
@@ -10,9 +10,9 @@
#pragma warning disable IDE1006
-namespace UnitTests.ConfigurationTests;
+namespace UnitTests.NonParallelizable.ConfigurationTests;
-public class ConfigurationManagerTests (ITestOutputHelper output)
+public class ConfigurationMangerTests (ITestOutputHelper output)
{
[Fact]
public void ModuleInitializer_Was_Called ()
@@ -684,7 +684,7 @@ public void ResetToHardCodedDefaults_Resets ()
}
}
]
-}
+}
";
// ResetToCurrentValues ();
@@ -1073,7 +1073,7 @@ public void InvalidJsonLogs ()
// "brown" is not a color
var json = @"
{
- ""Themes"" : [
+ ""Themes"" : [
{
""Default"" : {
""Schemes"": [
@@ -1096,7 +1096,7 @@ public void InvalidJsonLogs ()
// AbNormal is not a Scheme attribute
json = @"
{
- ""Themes"" : [
+ ""Themes"" : [
{
""Default"" : {
""Schemes"": [
@@ -1119,7 +1119,7 @@ public void InvalidJsonLogs ()
// Modify hotNormal background only
json = @"
{
- ""Themes"" : [
+ ""Themes"" : [
{
""Default"" : {
""Schemes"": [
@@ -1182,7 +1182,7 @@ public void InvalidJsonThrows ()
// AbNormal is not a Scheme attribute
json = @"
{
- ""Themes"" : [
+ ""Themes"" : [
{
""Default"" : {
""Schemes"": [
@@ -1206,7 +1206,7 @@ public void InvalidJsonThrows ()
// Modify hotNormal background only
json = @"
{
- ""Themes"" : [
+ ""Themes"" : [
{
""Default"" : {
""Schemes"": [
@@ -1386,7 +1386,7 @@ public void SourcesManager_Load_FromJson_Loads ()
}
}
]
-}
+}
";
//ResetToCurrentValues ();
diff --git a/Tests/UnitTests/Configuration/GlyphTests.cs b/Tests/UnitTests.NonParallelizable/Configuration/GlyphTests.cs
similarity index 96%
rename from Tests/UnitTests/Configuration/GlyphTests.cs
rename to Tests/UnitTests.NonParallelizable/Configuration/GlyphTests.cs
index 6112093796..2cc49b3f5d 100644
--- a/Tests/UnitTests/Configuration/GlyphTests.cs
+++ b/Tests/UnitTests.NonParallelizable/Configuration/GlyphTests.cs
@@ -3,7 +3,7 @@
using System.Text.Json;
using static Terminal.Gui.Configuration.ConfigurationManager;
-namespace UnitTests.ConfigurationTests;
+namespace UnitTests.NonParallelizable.ConfigurationTests;
public class GlyphTests
{
diff --git a/Tests/UnitTests.NonParallelizable/README.md b/Tests/UnitTests.NonParallelizable/README.md
new file mode 100644
index 0000000000..034e109360
--- /dev/null
+++ b/Tests/UnitTests.NonParallelizable/README.md
@@ -0,0 +1,24 @@
+# UnitTests.NonParallelizable
+
+This project contains tests that must not run concurrently with other tests because they read or write
+process-wide static state.
+
+## When to add tests here
+
+Add a test here if it does **any** of the following:
+
+- Calls `Application.Init()` or `Application.Shutdown()` directly (not through `SetupFakeApplication`).
+- Mutates `Application.DefaultKeyBindings` (a process-wide static dictionary).
+- Calls `ApplicationImpl.ResetModelUsageTracking()`.
+- Calls `Application.Create()` and tests the static-vs-instance model fencing.
+- Sets `SynchronizationContext.Current` or depends on it being in a particular state.
+- Otherwise cannot be run concurrently with other tests due to shared mutable static state.
+
+## What does NOT belong here
+
+- Tests that use `[SetupFakeApplication]` or `ApplicationImpl.SetInstance()` — those use a fake driver
+ instance and do not touch global static state in a way that prevents parallelism. They may belong in
+ `UnitTestsParallelizable` after review.
+- New feature tests — those belong in `UnitTestsParallelizable`.
+
+See the [Testing wiki](https://github.com/gui-cs/Terminal.Gui/wiki/Testing) for details.
diff --git a/Tests/UnitTests.NonParallelizable/UnitTests.NonParallelizable.csproj b/Tests/UnitTests.NonParallelizable/UnitTests.NonParallelizable.csproj
new file mode 100644
index 0000000000..76f1c2b6bf
--- /dev/null
+++ b/Tests/UnitTests.NonParallelizable/UnitTests.NonParallelizable.csproj
@@ -0,0 +1,61 @@
+
+
+
+
+
+ 2.0
+ 2.0
+ 2.0
+ 2.0
+
+
+ UnitTests.NonParallelizable
+ Exe
+ true
+ true
+ false
+ true
+ true
+ true
+ portable
+ $(DefineConstants);JETBRAINS_ANNOTATIONS;CONTRACTS_FULL
+ enable
+ true
+ $(NoWarn);AD0001
+ true
+
+
+ true
+ $(DefineConstants);DEBUG_IDISPOSABLE
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
+
+
+
+
diff --git a/Tests/UnitTests.NonParallelizable/xunit.runner.json b/Tests/UnitTests.NonParallelizable/xunit.runner.json
new file mode 100644
index 0000000000..d47a70ea08
--- /dev/null
+++ b/Tests/UnitTests.NonParallelizable/xunit.runner.json
@@ -0,0 +1,6 @@
+{
+ "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json",
+ "parallelizeTestCollections": false,
+ "parallelizeAssembly": false,
+ "stopOnFail": false
+}
diff --git a/Tests/UnitTests/Application/ApplicationForceDriverTests.cs b/Tests/UnitTests/Application/ApplicationForceDriverTests.cs
deleted file mode 100644
index 7d3ab3e118..0000000000
--- a/Tests/UnitTests/Application/ApplicationForceDriverTests.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using UnitTests;
-
-namespace UnitTests.ApplicationTests;
-
-public class ApplicationForceDriverTests : TestDriverBase
-{
- [Fact (Skip = "Bogus test now that config properties are handled correctly")]
- public void ForceDriver_Does_Not_Changes_If_It_Has_Valid_Value ()
- {
- Assert.False (Application.Initialized);
- Assert.Null (Application.Driver);
- Assert.Equal (string.Empty, Application.ForceDriver);
-
- Application.ForceDriver = DriverRegistry.Names.ANSI;
- Assert.Equal (DriverRegistry.Names.ANSI, Application.ForceDriver);
-
- Application.ForceDriver = DriverRegistry.Names.DOTNET;
- Assert.Equal (DriverRegistry.Names.ANSI, Application.ForceDriver);
- }
-
- [Fact (Skip = "Bogus test now that config properties are handled correctly")]
- public void ForceDriver_Throws_If_Initialized_Changed_To_Another_Value ()
- {
- IDriver driver = CreateTestDriver ();
-
- Assert.False (Application.Initialized);
- Assert.Null (Application.Driver);
- Assert.Equal (string.Empty, Application.ForceDriver);
-
- Application.Init (driverName: DriverRegistry.Names.ANSI);
- Assert.True (Application.Initialized);
- Assert.NotNull (Application.Driver);
- Assert.Equal (DriverRegistry.Names.ANSI, Application.Driver.GetName ());
- Assert.Equal (string.Empty, Application.ForceDriver);
-
- Assert.Throws (() => Application.ForceDriver = "dotnet");
-
- Application.ForceDriver = DriverRegistry.Names.ANSI;
- Assert.Equal (DriverRegistry.Names.ANSI, Application.ForceDriver);
- }
-}
diff --git a/Tests/UnitTests/Application/ApplicationPopoverTests.cs b/Tests/UnitTests/Application/ApplicationPopoverTests.cs
deleted file mode 100644
index 6d6ba01877..0000000000
--- a/Tests/UnitTests/Application/ApplicationPopoverTests.cs
+++ /dev/null
@@ -1,370 +0,0 @@
-#nullable enable
-namespace UnitTests.ApplicationTests;
-
-public class ApplicationPopoverTests
-{
- [Fact]
- public void Application_Init_Initializes_PopoverManager ()
- {
- try
- {
- // Arrange
- Application.Init (DriverRegistry.Names.ANSI);
-
- // Act
- Assert.NotNull (Application.Popovers);
- }
- finally
- {
- Application.Shutdown ();
- }
- }
-
- [Fact]
- public void Application_Shutdown_Resets_PopoverManager ()
- {
- try
- {
- // Arrange
-
- Application.Init (DriverRegistry.Names.ANSI);
-
- // Act
- Assert.NotNull (Application.Popovers);
-
- Application.Shutdown ();
-
- // Test
- }
- finally
- {
- Application.Shutdown ();
- }
- }
-
- [Fact]
- public void Application_End_Does_Not_Reset_PopoverManager ()
- {
- Runnable? top = null;
-
- try
- {
- // Arrange
- Application.Init (DriverRegistry.Names.ANSI);
- Assert.NotNull (Application.Popovers);
- Application.StopAfterFirstIteration = true;
-
- top = new ();
- SessionToken rs = Application.Begin (top);
-
- // Act
- Application.End (rs);
-
- // Test
- Assert.NotNull (Application.Popovers);
- }
- finally
- {
- top?.Dispose ();
- Application.Shutdown ();
- }
- }
-
- [Fact]
- public void Application_End_Hides_Active ()
- {
- Runnable? top = null;
-
- try
- {
- // Arrange
- Application.Init (DriverRegistry.Names.ANSI);
- Application.StopAfterFirstIteration = true;
-
- top = new ();
- SessionToken rs = Application.Begin (top);
-
- PopoverTestClass? popover = new ();
-
- Application.Popovers?.Register (popover);
- Application.Popovers?.Show (popover);
- Assert.True (popover.Visible);
-
- // Act
- Application.End (rs);
-
- // Test
- Assert.False (popover.Visible);
- Assert.NotNull (Application.Popovers);
-
- popover.Dispose ();
- Assert.Equal (1, popover.DisposedCount);
- }
- finally
- {
- top?.Dispose ();
- Application.Shutdown ();
- }
- }
-
- [Fact]
- public void Application_Shutdown_Disposes_Registered_Popovers ()
- {
- try
- {
- // Arrange
-
- Application.Init (DriverRegistry.Names.ANSI);
-
- PopoverTestClass? popover = new ();
-
- // Act
- Application.Popovers?.Register (popover);
- Application.Shutdown ();
-
- // Test
- Assert.Equal (1, popover.DisposedCount);
- }
- finally
- {
- Application.Shutdown ();
- }
- }
-
- [Fact]
- public void Application_Shutdown_Does_Not_Dispose_DeRegistered_Popovers ()
- {
- try
- {
- // Arrange
-
- Application.Init (DriverRegistry.Names.ANSI);
-
- PopoverTestClass? popover = new ();
-
- Application.Popovers?.Register (popover);
-
- // Act
- Application.Popovers?.DeRegister (popover);
- Application.Shutdown ();
-
- // Test
- Assert.Equal (0, popover.DisposedCount);
-
- popover.Dispose ();
- Assert.Equal (1, popover.DisposedCount);
- }
- finally
- {
- Application.Shutdown ();
- }
- }
-
- [Fact]
- public void Application_Shutdown_Does_Not_Dispose_ActiveNotRegistered_Popover ()
- {
- try
- {
- // Arrange
-
- Application.Init (DriverRegistry.Names.ANSI);
-
- PopoverTestClass? popover = new ();
- Application.Popovers?.Register (popover);
- Application.Popovers?.Show (popover);
- Application.Popovers?.DeRegister (popover);
-
- // Act
- Application.Shutdown ();
-
- // Test
- Assert.Equal (0, popover.DisposedCount);
-
- popover.Dispose ();
- Assert.Equal (1, popover.DisposedCount);
- }
- finally
- {
- Application.Shutdown ();
- }
- }
-
- [Fact]
- public void Register_SetsRunnable ()
- {
- try
- {
- // Arrange
-
- Application.Init (DriverRegistry.Names.ANSI);
- Application.Begin (new Runnable ());
- PopoverTestClass? popover = new ();
-
- // Act
- Application.Popovers?.Register (popover);
-
- // Assert
- Assert.Equal (Application.TopRunnableView as IRunnable, popover.Owner);
- }
- finally
- {
- Application.TopRunnableView?.Dispose ();
- Application.Shutdown ();
- }
- }
-
- [Fact]
- public void Keyboard_Events_Go_Only_To_Popover_Associated_With_Runnable ()
- {
- try
- {
- // Arrange
- Application.Init (DriverRegistry.Names.ANSI);
-
- Runnable? initialRunnable = new () { Id = "initialRunnable" };
- Application.Begin (initialRunnable);
- PopoverTestClass? popover = new ();
- var keyDownEvents = 0;
-
- popover.KeyDown += (s, e) =>
- {
- keyDownEvents++;
- e.Handled = true;
- }; // Ensure it handles the key
-
- Application.Popovers?.Register (popover);
-
- // Act
- Application.RaiseKeyDownEvent (Key.A); // Goes to initialRunnable
-
- Runnable? secondaryRunnable = new () { Id = "secondaryRunnable" };
- Application.Begin (secondaryRunnable);
-
- Application.RaiseKeyDownEvent (Key.A); // Goes to secondaryRunnable
-
- // Test
- Assert.Equal (1, keyDownEvents);
-
- popover.Dispose ();
- Assert.Equal (1, popover.DisposedCount);
- }
- finally
- {
- Application.Shutdown ();
- }
- }
-
- // See: https://github.com/gui-cs/Terminal.Gui/issues/4122
- [Theory]
- [InlineData (0, 0, new [] { "runnable" })]
- [InlineData (10, 10, new string [] { })]
- [InlineData (1, 1, new [] { "runnable", "view" })]
- [InlineData (5, 5, new [] { "runnable" })]
- [InlineData (6, 6, new [] { "popoverSubView" })]
- [InlineData (7, 7, new [] { "runnable" })]
- [InlineData (3, 3, new [] { "runnable" })]
- public void GetViewsUnderMouse_Supports_ActivePopover (int mouseX, int mouseY, string [] viewIdStrings)
- {
- PopoverTestClass? popover = null;
-
- try
- {
- // Arrange
- Application.Init (DriverRegistry.Names.ANSI);
-
- Runnable? runnable = new ()
- {
- Frame = new (0, 0, 10, 10),
- Id = "runnable"
- };
- Application.Begin (runnable);
-
- View? view = new ()
- {
- Id = "view",
- X = 1,
- Y = 1,
- Width = 2,
- Height = 2
- };
-
- runnable.Add (view);
-
- popover = new ()
- {
- Id = "popover",
- X = 5,
- Y = 5,
- Width = 3,
- Height = 3
- }; // at 5,5 to 8,8 (screen)
-
- View? popoverSubView = new ()
- {
- Id = "popoverSubView",
- X = 1,
- Y = 1,
- Width = 1,
- Height = 1
- };
-
- popover.Add (popoverSubView);
- Application.Popovers?.Register (popover);
-
- Application.Popovers?.Show (popover);
-
- List found = view.GetViewsUnderLocation (new (mouseX, mouseY), ViewportSettingsFlags.TransparentMouse);
-
- string [] foundIds = found.Select (v => v!.Id).ToArray ();
-
- Assert.Equal (viewIdStrings, foundIds);
- }
- finally
- {
- popover?.Dispose ();
- Application.Shutdown ();
- }
- }
-
- public class PopoverTestClass : PopoverImpl
- {
- public List HandledKeys { get; } = [];
- public int NewCommandInvokeCount { get; private set; }
-
-#if DEBUG_IDISPOSABLE
- // NOTE: Hides the base DisposedCount property
- public new int DisposedCount { get; private set; }
-#else
- public int DisposedCount { get; private set; }
-#endif
- public PopoverTestClass ()
- {
- CanFocus = true;
- AddCommand (Command.New, NewCommandHandler!);
- HotKeyBindings.Add (Key.N.WithCtrl, Command.New);
-
- return;
-
- bool? NewCommandHandler (ICommandContext ctx)
- {
- NewCommandInvokeCount++;
-
- return false;
- }
- }
-
- protected override bool OnKeyDown (Key key)
- {
- HandledKeys.Add (key);
-
- return false;
- }
-
- ///
- protected override void Dispose (bool disposing)
- {
- base.Dispose (disposing);
- DisposedCount++;
- }
- }
-}
diff --git a/Tests/UnitTests/Application/ApplicationScreenTests.cs b/Tests/UnitTests/Application/ApplicationScreenTests.cs
deleted file mode 100644
index 0bc65ea801..0000000000
--- a/Tests/UnitTests/Application/ApplicationScreenTests.cs
+++ /dev/null
@@ -1,99 +0,0 @@
-namespace UnitTests.ApplicationTests;
-
-public class ApplicationScreenTests
-{
- public ApplicationScreenTests (ITestOutputHelper output) { }
-
- [Fact]
- [AutoInitShutdown]
- public void ClearContents_Called_When_Top_Frame_Changes ()
- {
- var top = new Runnable ();
- SessionToken rs = Application.Begin (top);
-
- // Arrange
- var clearedContentsRaised = 0;
-
- Application.Driver!.ClearedContents += OnClearedContents;
-
- // Act
- Application.LayoutAndDraw ();
-
- // Assert
- Assert.Equal (0, clearedContentsRaised);
-
- // Act
- Application.TopRunnableView!.SetNeedsLayout ();
- Application.LayoutAndDraw ();
-
- // Assert
- Assert.Equal (0, clearedContentsRaised);
-
- // Act
- Application.TopRunnableView.X = 1;
- Application.LayoutAndDraw ();
-
- // Assert
- Assert.Equal (1, clearedContentsRaised);
-
- // Act
- Application.TopRunnableView.Width = 10;
- Application.LayoutAndDraw ();
-
- // Assert
- Assert.Equal (2, clearedContentsRaised);
-
- // Act
- Application.TopRunnableView.Y = 1;
- Application.LayoutAndDraw ();
-
- // Assert
- Assert.Equal (3, clearedContentsRaised);
-
- // Act
- Application.TopRunnableView.Height = 10;
- Application.LayoutAndDraw ();
-
- // Assert
- Assert.Equal (4, clearedContentsRaised);
-
- Application.Driver!.ClearedContents -= OnClearedContents;
-
- Application.End (rs);
-
- return;
-
- void OnClearedContents (object e, EventArgs a) { clearedContentsRaised++; }
- }
-
- [Fact]
- public void ClearScreenNextIteration_Resets_To_False_After_LayoutAndDraw ()
- {
- // Arrange
- Application.ResetState (true);
- Application.Init (DriverRegistry.Names.ANSI);
-
- // Act
- Application.ClearScreenNextIteration = true;
- Application.LayoutAndDraw ();
-
- // Assert
- Assert.False (Application.ClearScreenNextIteration);
-
- // Cleanup
- Application.ResetState (true);
- }
-
- [Fact]
- [SetupFakeApplication]
- public void Screen_Changes_OnScreenChanged_Without_Call_Application_Init ()
- {
- Assert.Equal (new (0, 0, 80, 25), Application.Screen);
-
- // Act
- Application.Driver!.SetScreenSize (120, 30);
-
- // Assert
- Assert.Equal (new (0, 0, 120, 30), Application.Screen);
- }
-}
diff --git a/Tests/UnitTests/Application/MainLoopTTests.cs b/Tests/UnitTests/Application/MainLoopTTests.cs
deleted file mode 100644
index 5829179c66..0000000000
--- a/Tests/UnitTests/Application/MainLoopTTests.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using Moq;
-
-namespace UnitTests.ApplicationTests;
-public class MainLoopTTests
-{
- //[Fact]
- //public void MainLoopT_NotInitialized_Throws()
- //{
- // var m = new MainLoop ();
-
- // Assert.Throws (() => m.TimedEvents);
- // Assert.Throws (() => m.InputBuffer);
- // Assert.Throws (() => m.InputProcessor);
- // Assert.Throws (() => m.Out);
- // Assert.Throws (() => m.AnsiRequestScheduler);
- // Assert.Throws (() => m.WindowSizeMonitor);
-
- // var componentFactory = new Mock> ();
-
- // componentFactory.Setup (
- // c => c.CreateWindowSizeMonitor (
- // It.IsAny (),
- // It.IsAny ()))
- // .Returns (Mock.Of ());
-
- // m.Initialize (new TimedEvents (),
- // new ConcurrentQueue (),
- // Mock.Of (),
- // Mock.Of(),
- // componentFactory.Object
- // );
-
- // Assert.NotNull (m.TimedEvents);
- // Assert.NotNull (m.InputBuffer);
- // Assert.NotNull (m.InputProcessor);
- // Assert.NotNull (m.Out);
- // Assert.NotNull (m.AnsiRequestScheduler);
- // Assert.NotNull (m.WindowSizeMonitor);
- //}
-}
diff --git a/Tests/UnitTests/Application/Mouse/ApplicationMouseTests.cs b/Tests/UnitTests/Application/Mouse/ApplicationMouseTests.cs
deleted file mode 100644
index 6f1c7855aa..0000000000
--- a/Tests/UnitTests/Application/Mouse/ApplicationMouseTests.cs
+++ /dev/null
@@ -1,397 +0,0 @@
-#nullable enable
-
-// Alias Console to MockConsole so we don't accidentally use Console
-
-namespace UnitTests.ApplicationTests;
-
-[Trait ("Category", "Input")]
-public class ApplicationMouseTests
-{
- private readonly ITestOutputHelper _output;
-
- public ApplicationMouseTests (ITestOutputHelper output)
- {
- _output = output;
-#if DEBUG_IDISPOSABLE
- View.Instances.Clear ();
-#endif
- }
-
- #region mouse coordinate tests
-
- // test Application.MouseEvent - ensure coordinates are screen relative
- [Theory]
-
- // inside tests
- [InlineData (0, 0, 0, 0, true)]
- [InlineData (1, 0, 1, 0, true)]
- [InlineData (0, 1, 0, 1, true)]
- [InlineData (9, 0, 9, 0, true)]
- [InlineData (0, 9, 0, 9, true)]
-
- // outside tests
- [InlineData (-1, -1, -1, -1, true)]
- [InlineData (0, -1, 0, -1, true)]
- [InlineData (-1, 0, -1, 0, true)]
- public void MouseEventCoordinatesAreScreenRelative (int clickX, int clickY, int expectedX, int expectedY, bool expectedClicked)
- {
- var mouse = new Mouse { ScreenPosition = new Point (clickX, clickY), Flags = MouseFlags.LeftButtonPressed };
- var clicked = false;
-
- void OnApplicationOnMouseEvent (object? s, Mouse e)
- {
- Assert.Equal (expectedX, e.ScreenPosition.X);
- Assert.Equal (expectedY, e.ScreenPosition.Y);
- clicked = true;
- }
-
- Application.MouseEvent += OnApplicationOnMouseEvent;
-
- Application.RaiseMouseEvent (mouse);
- Assert.Equal (expectedClicked, clicked);
- Application.MouseEvent -= OnApplicationOnMouseEvent;
- }
-
- ///
- /// Tests that the mouse coordinates passed to the focused view are correct when the mouse is clicked. No adornments;
- /// Frame == Viewport
- ///
- [Theory]
- [AutoInitShutdown]
-
- // click inside view tests
- [InlineData (0, 0, 0, 0, 0, true)]
- [InlineData (0, 1, 0, 1, 0, true)]
- [InlineData (0, 0, 1, 0, 1, true)]
- [InlineData (0, 9, 0, 9, 0, true)]
- [InlineData (0, 0, 9, 0, 9, true)]
-
- // view is offset from origin ; click is inside view
- [InlineData (1, 1, 1, 0, 0, true)]
- [InlineData (1, 2, 1, 1, 0, true)]
- [InlineData (1, 1, 2, 0, 1, true)]
- [InlineData (1, 9, 1, 8, 0, true)]
- [InlineData (1, 1, 9, 0, 8, true)]
-
- // click outside view tests
- [InlineData (0, -1, -1, 0, 0, false)]
- [InlineData (0, 0, -1, 0, 0, false)]
- [InlineData (0, -1, 0, 0, 0, false)]
- [InlineData (0, 0, 10, 0, 0, false)]
- [InlineData (0, 10, 0, 0, 0, false)]
- [InlineData (0, 10, 10, 0, 0, false)]
-
- // view is offset from origin ; click is outside view
- [InlineData (1, 0, 0, 0, 0, false)]
- [InlineData (1, 1, 0, 0, 0, false)]
- [InlineData (1, 0, 1, 0, 0, false)]
- [InlineData (1, 9, 0, 0, 0, false)]
- [InlineData (1, 0, 9, 0, 0, false)]
- public void MouseCoordinatesTest_NoAdornments (int offset, int clickX, int clickY, int expectedX, int expectedY, bool expectedClicked)
- {
- Size size = new (10, 10);
- Point pos = new (offset, offset);
-
- var clicked = false;
-
- var view = new View { X = pos.X, Y = pos.Y, Width = size.Width, Height = size.Height };
-
- var mouseEventToRaise = new Mouse { ScreenPosition = new Point (clickX, clickY), Flags = MouseFlags.LeftButtonClicked };
-
- view.MouseEvent += (s, mouse) =>
- {
- Assert.Equal (expectedX, mouse.Position!.Value.X);
- Assert.Equal (expectedY, mouse.Position!.Value.Y);
- clicked = true;
- };
-
- var top = new Runnable ();
- top.Add (view);
- Application.Begin (top);
-
- Application.RaiseMouseEvent (mouseEventToRaise);
- Assert.Equal (expectedClicked, clicked);
- top.Dispose ();
- }
-
- #endregion mouse coordinate tests
-
- #region mouse grab tests
-
- [Fact (Skip = "Rebuild to use ScrollBar")]
- [AutoInitShutdown]
- public void IsGrabbed_WithNullMouseEventView ()
- {
- //var tf = new TextField { Width = 10 };
- //var sv = new ScrollView { Width = Dim.Fill (), Height = Dim.Fill () };
- //sv.SetContentSize (new (100, 100));
-
- //sv.Add (tf);
- //var top = new Runnable ();
- //top.Add (sv);
-
- //int iterations = -1;
-
- //ApplicationImpl.Instance.Iteration += (s, a) =>
- // {
- // iterations++;
-
- // if (iterations == 0)
- // {
- // Assert.True (tf.HasFocus);
- // Assert.False (Application.Mouse.IsGrabbed (anyView));
-
- // Application.RaiseMouseEvent (new () { ScreenPosition = new (5, 5), Flags = MouseFlags.PositionReport });
-
- // Assert.True (Application.Mouse.IsGrabbed (sv));
-
- // MessageBox.Query (App, "Title", "Test", "Ok");
-
- // Assert.False (Application.Mouse.IsGrabbed (anyView));
- // }
- // else if (iterations == 1)
- // {
- // // Application.Mouse.IsGrabbed is false because
- // // another runnable (Dialog) was opened
- // Assert.False (Application.Mouse.IsGrabbed (anyView));
-
- // Application.RaiseMouseEvent (new () { ScreenPosition = new (5, 5), Flags = MouseFlags.PositionReport });
-
- // Assert.False (Application.Mouse.IsGrabbed (anyView));
-
- // Application.RaiseMouseEvent (new () { ScreenPosition = new (40, 12), Flags = MouseFlags.PositionReport });
-
- // Assert.False (Application.Mouse.IsGrabbed (anyView));
-
- // Application.RaiseMouseEvent (new () { ScreenPosition = new (0, 0), Flags = MouseFlags.LeftButtonPressed });
-
- // Assert.False (Application.Mouse.IsGrabbed (anyView));
-
- // Application.RequestStop ();
- // }
- // else if (iterations == 2)
- // {
- // Assert.False (Application.Mouse.IsGrabbed (anyView));
-
- // Application.RequestStop ();
- // }
- // };
-
- //Application.Run (top);
- //top.Dispose ();
- }
-
- [Fact]
- [AutoInitShutdown]
- public void IsGrabbed_GrabbedMouse_UnGrabbedMouse ()
- {
- View? grabView = null;
- var count = 0;
-
- var view1 = new View { Id = "view1" };
- var view2 = new View { Id = "view2" };
- var view3 = new View { Id = "view3" };
-
- Application.Mouse.GrabbedMouse += Application_GrabbedMouse;
- Application.Mouse.UnGrabbedMouse += Application_UnGrabbedMouse;
-
- Application.Mouse.GrabMouse (view1);
- Assert.Equal (0, count);
- Assert.Equal (grabView, view1);
- Assert.True (Application.Mouse.IsGrabbed (view1));
-
- Application.Mouse.UngrabMouse ();
- Assert.Equal (1, count);
- Assert.Equal (grabView, view1);
- Assert.False (Application.Mouse.IsGrabbed (view1));
-
- Application.Mouse.GrabbedMouse += Application_GrabbedMouse;
- Application.Mouse.UnGrabbedMouse += Application_UnGrabbedMouse;
-
- Application.Mouse.GrabMouse (view2);
- Assert.Equal (1, count);
- Assert.Equal (grabView, view2);
- Assert.True (Application.Mouse.IsGrabbed (view2));
-
- Application.Mouse.UngrabMouse ();
- Assert.Equal (2, count);
- Assert.Equal (grabView, view2);
- Assert.True (Application.Mouse.IsGrabbed (view3));
- Application.Mouse.UngrabMouse ();
- Assert.False (Application.Mouse.IsGrabbed (view3));
-
- void Application_GrabbedMouse (object? sender, ViewEventArgs e)
- {
- if (count == 0)
- {
- Assert.Equal (view1, e.View);
- grabView = view1;
- }
- else
- {
- Assert.Equal (view2, e.View);
- grabView = view2;
- }
-
- Application.Mouse.GrabbedMouse -= Application_GrabbedMouse;
- }
-
- void Application_UnGrabbedMouse (object? sender, ViewEventArgs e)
- {
- if (count == 0)
- {
- Assert.Equal (view1, e.View);
- Assert.Equal (grabView, e.View);
- }
- else
- {
- Assert.Equal (view2, e.View);
- Assert.Equal (grabView, e.View);
- }
-
- count++;
-
- if (count > 1)
- {
- // It's possible to grab another view after the previous was ungrabbed
- Application.Mouse.GrabMouse (view3);
- }
-
- Application.Mouse.UnGrabbedMouse -= Application_UnGrabbedMouse;
- }
- }
-
- [Fact]
- [AutoInitShutdown]
- public void IsGrabbed_Parameterless_ReturnsTrueWhenAnyViewGrabbed ()
- {
- var view1 = new View { Id = "view1" };
- var view2 = new View { Id = "view2" };
-
- // Initially no view has the grab
- Assert.False (Application.Mouse.IsGrabbed ());
-
- // Grab view1
- Application.Mouse.GrabMouse (view1);
- Assert.True (Application.Mouse.IsGrabbed ());
- Assert.True (Application.Mouse.IsGrabbed (view1));
- Assert.False (Application.Mouse.IsGrabbed (view2));
-
- // Ungrab
- Application.Mouse.UngrabMouse ();
- Assert.False (Application.Mouse.IsGrabbed ());
- Assert.False (Application.Mouse.IsGrabbed (view1));
-
- // Grab view2
- Application.Mouse.GrabMouse (view2);
- Assert.True (Application.Mouse.IsGrabbed ());
- Assert.False (Application.Mouse.IsGrabbed (view1));
- Assert.True (Application.Mouse.IsGrabbed (view2));
-
- // Ungrab
- Application.Mouse.UngrabMouse ();
- Assert.False (Application.Mouse.IsGrabbed ());
-
- view1.Dispose ();
- view2.Dispose ();
- }
-
- [Fact]
- [AutoInitShutdown]
- public void IsGrabbed_Parameterless_ReturnsFalseAfterViewDisposed ()
- {
- var view = new View { Id = "view" };
-
- Application.Mouse.GrabMouse (view);
- Assert.True (Application.Mouse.IsGrabbed ());
- Assert.True (Application.Mouse.IsGrabbed (view));
-
- // Dispose without ungrabbing - WeakReference should handle this
- view.Dispose ();
-
- // After disposal, the WeakReference may still hold the reference until GC
- // But once GC runs, IsGrabbed() should return false
- // For deterministic testing, we ungrab first
- Application.Mouse.UngrabMouse ();
- Assert.False (Application.Mouse.IsGrabbed ());
- }
-
- [Fact]
- [AutoInitShutdown]
- public void View_Is_Responsible_For_Calling_UnGrabMouse_Before_Being_Disposed ()
- {
- var count = 0;
- var view = new View { Width = 1, Height = 1 };
- view.MouseEvent += (s, e) => count++;
- var top = new Runnable ();
- top.Add (view);
- Application.Begin (top);
-
- Assert.False (Application.Mouse.IsGrabbed (view));
- Application.Mouse.GrabMouse (view);
- Assert.True (Application.Mouse.IsGrabbed (view));
- top.Remove (view);
- Application.Mouse.UngrabMouse ();
- view.Dispose ();
-#if DEBUG_IDISPOSABLE
- Assert.True (view.WasDisposed);
-#endif
-
- Application.RaiseMouseEvent (new Mouse { ScreenPosition = new Point (0, 0), Flags = MouseFlags.LeftButtonPressed });
- Assert.False (Application.Mouse.IsGrabbed (view));
- Assert.Equal (0, count);
- top.Dispose ();
- }
-
- [Fact]
- [AutoInitShutdown]
- public void MouseGrab_EventSentToGrabView_HasCorrectView ()
- {
- // BEFORE FIX: viewRelativeMouseEvent.View = deepestViewUnderMouse ?? IsGrabbed (potentially targetView).
- // AFTER FIX: viewRelativeMouseEvent.View = IsGrabbed (always the grab view).
- // Test fails before fix (receivedView == targetView), passes after fix (receivedView == grabView).
-
- var grabView = new View
- {
- Id = "grab",
- X = 0,
- Y = 0,
- Width = 5,
- Height = 5
- };
-
- var targetView = new View
- {
- Id = "target",
- X = 0,
- Y = 0,
- Width = 5,
- Height = 5
- };
-
- View? receivedView = null;
- grabView.MouseEvent += (_, e) => receivedView = e.View;
-
- var top = new Runnable { Width = 20, Height = 10 };
- top.Add (grabView);
- top.Add (targetView); // deepestViewUnderMouse = targetView
- Application.Begin (top);
-
- Application.Mouse.GrabMouse (grabView);
- Assert.True (Application.Mouse.IsGrabbed (grabView));
-
- Application.RaiseMouseEvent (new Mouse
- {
- ScreenPosition = new Point (2, 2), // Inside both views
- Flags = MouseFlags.LeftButtonClicked
- });
-
- // EXPECTED: Event sent to grab view has View == grabView.
- Assert.Equal (grabView, receivedView);
-
- Application.Mouse.UngrabMouse ();
- top.Dispose ();
- }
-
- #endregion
-}
diff --git a/Tests/UnitTests/Application/SynchronizatonContextTests.cs b/Tests/UnitTests/Application/SynchronizatonContextTests.cs
deleted file mode 100644
index e124b810bc..0000000000
--- a/Tests/UnitTests/Application/SynchronizatonContextTests.cs
+++ /dev/null
@@ -1,101 +0,0 @@
-// Alias Console to MockConsole so we don't accidentally use Console
-
-using UnitTests;
-
-namespace UnitTests.ApplicationTests;
-
-public class SyncrhonizationContextTests
-{
- [Fact]
- public void SynchronizationContext_CreateCopy ()
- {
- Application.Init (DriverRegistry.Names.ANSI);
- SynchronizationContext context = SynchronizationContext.Current;
- Assert.NotNull (context);
-
- SynchronizationContext contextCopy = context.CreateCopy ();
- Assert.NotNull (contextCopy);
-
- Assert.NotEqual (context, contextCopy);
- Application.Shutdown ();
- }
-
- private readonly object _lockPost = new ();
-
- [Theory]
- [InlineData (DriverRegistry.Names.ANSI)]
- [InlineData (DriverRegistry.Names.WINDOWS)]
- [InlineData (DriverRegistry.Names.DOTNET)]
- public void SynchronizationContext_Post (string driverName = null)
- {
- lock (_lockPost)
- {
- Application.Init (driverName);
-
- SynchronizationContext context = SynchronizationContext.Current;
-
- var success = false;
-
- Task.Run (() =>
- {
- while (Application.TopRunnable is { IsRunning: false })
- {
- Thread.Sleep (500);
- }
-
- // non blocking
- context.Post (delegate
- {
- success = true;
-
- // then tell the application to quit
- Application.Invoke (() => Application.RequestStop ());
- },
- null);
-
- if (Application.TopRunnable is { IsRunning: true })
- {
- Assert.False (success);
- }
- },
- TestContext.Current.CancellationToken);
-
- // blocks here until the RequestStop is processed at the end of the test
- Application.Run ();
- Assert.True (success);
-
- Application.Shutdown ();
- }
- }
-
- [Fact]
- [AutoInitShutdown]
- public void SynchronizationContext_Send ()
- {
- SynchronizationContext context = SynchronizationContext.Current;
-
- var success = false;
-
- Task.Run (() =>
- {
- Thread.Sleep (500);
-
- // blocking
- context.Send (delegate
- {
- success = true;
-
- // then tell the application to quit
- Application.Invoke (() => Application.RequestStop ());
- },
- null);
- Assert.True (success);
- },
- TestContext.Current.CancellationToken);
-
- // blocks here until the RequestStop is processed at the end of the test
- Application.Run ();
- Assert.True (success);
- Application.Shutdown ();
- }
-}
diff --git a/Tests/UnitTests/Application/TimedEventsTests.cs b/Tests/UnitTests/Application/TimedEventsTests.cs
deleted file mode 100644
index ffce360276..0000000000
--- a/Tests/UnitTests/Application/TimedEventsTests.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-#nullable enable
-namespace UnitTests.ApplicationTests;
-
-///
-/// Tests for TimedEvents class, focusing on high-resolution timing with Stopwatch.
-///
-public class TimedEventsTests
-{
-
-}
diff --git a/Tests/UnitTests/Clipboard/ClipboardTests.cs b/Tests/UnitTests/Clipboard/ClipboardTests.cs
deleted file mode 100644
index 13b690ad10..0000000000
--- a/Tests/UnitTests/Clipboard/ClipboardTests.cs
+++ /dev/null
@@ -1,340 +0,0 @@
-namespace UnitTests.ClipboardTests;
-
-#if RUN_CLIPBOARD_UNIT_TESTS
-public class ClipboardTests
-{
- readonly ITestOutputHelper output;
- public ClipboardTests (ITestOutputHelper output) { this.output = output; }
-
- [Fact, AutoInitShutdown (useFakeClipboard: true, fakeClipboardAlwaysThrowsNotSupportedException: true)]
- public void IClipboard_GetClipBoardData_Throws_NotSupportedException ()
- {
- var iclip = Application.Driver?.Clipboard;
- Assert.Throws (() => iclip.GetClipboardData ());
- }
-
- [Fact, AutoInitShutdown (useFakeClipboard: true, fakeClipboardAlwaysThrowsNotSupportedException: true)]
- public void IClipboard_SetClipBoardData_Throws_NotSupportedException ()
- {
- var iclip = Application.Driver?.Clipboard;
- Assert.Throws (() => iclip.SetClipboardData ("foo"));
- }
-
- [Fact, AutoInitShutdown (useFakeClipboard: true)]
- public void IApplication_Clipboard_Property_Works ()
- {
- if (Application.Clipboard?.IsSupported != true)
- {
- output.WriteLine ($"The Clipboard not supported on this platform.");
- return;
- }
-
- string clipText = "The IApplication_Clipboard_Property_Works unit test pasted this to the OS clipboard.";
-
- // Use the new IApplication.Clipboard property
- Application.Clipboard.SetClipboardData (clipText);
-
- ApplicationImpl.Instance.Iteration += (s, a) => ApplicationImpl.Instance.RequestStop ();
- ApplicationImpl.Instance.Run>().Dispose();
-
- Assert.True(Application.Clipboard.TryGetClipboardData(out string result));
- Assert.Equal (clipText, result);
- }
-
- [Fact, AutoInitShutdown (useFakeClipboard: true)]
- public void Contents_Fake_Gets_Sets ()
- {
- if (!Clipboard.IsSupported)
- {
- output.WriteLine ($"The Clipboard not supported on this platform.");
-
- return;
- }
-
- string clipText = "The Contents_Gets_Sets unit test pasted this to the OS clipboard.";
- Clipboard.Contents = clipText;
-
- ApplicationImpl.Instance.Iteration += (s, a) => Application.RequestStop ();
- Application.Run ();
-
- Assert.Equal (clipText, Clipboard.Contents);
- }
-
- [Fact, AutoInitShutdown (useFakeClipboard: false)]
- public void Contents_Gets_Sets ()
- {
- if (!Clipboard.IsSupported)
- {
- output.WriteLine ($"The Clipboard not supported on this platform.");
-
- return;
- }
-
- string clipText = "The Contents_Gets_Sets unit test pasted this to the OS clipboard.";
- Clipboard.Contents = clipText;
-
- ApplicationImpl.Instance.Iteration += (s, a) => Application.RequestStop ();
- Application.Run ();
-
- Assert.Equal (clipText, Clipboard.Contents);
- }
-
- [Fact, AutoInitShutdown (useFakeClipboard: false)]
- public void Contents_Gets_Sets_When_IsSupportedFalse ()
- {
- if (!Clipboard.IsSupported)
- {
- output.WriteLine ($"The Clipboard not supported on this platform.");
-
- return;
- }
-
- string clipText = "The Contents_Gets_Sets unit test pasted this to the OS clipboard.";
- Clipboard.Contents = clipText;
-
- ApplicationImpl.Instance.Iteration += (s, a) => Application.RequestStop ();
- Application.Run ();
-
- Assert.Equal (clipText, Clipboard.Contents);
- }
-
- [Fact, AutoInitShutdown (useFakeClipboard: true)]
- public void Contents_Fake_Gets_Sets_When_IsSupportedFalse ()
- {
- if (!Clipboard.IsSupported)
- {
- output.WriteLine ($"The Clipboard not supported on this platform.");
-
- return;
- }
-
- string clipText = "The Contents_Gets_Sets unit test pasted this to the OS clipboard.";
- Clipboard.Contents = clipText;
-
- ApplicationImpl.Instance.Iteration += (s, a) => Application.RequestStop ();
- Application.Run ();
-
- Assert.Equal (clipText, Clipboard.Contents);
- }
-
- [Fact, AutoInitShutdown (useFakeClipboard: false)]
- public void IsSupported_Get ()
- {
- if (Clipboard.IsSupported)
- {
- Assert.True (Clipboard.IsSupported);
- }
- else
- {
- Assert.False (Clipboard.IsSupported);
- }
- }
-
- [Fact, AutoInitShutdown (useFakeClipboard: false)]
- public void TryGetClipboardData_Gets_From_OS_Clipboard ()
- {
- string clipText = "The TryGetClipboardData_Gets_From_OS_Clipboard unit test pasted this to the OS clipboard.";
- Clipboard.Contents = clipText;
-
- ApplicationImpl.Instance.Iteration += (s, a) => Application.RequestStop ();
-
- Application.Run ();
-
- if (Clipboard.IsSupported)
- {
- Assert.True (Clipboard.TryGetClipboardData (out string result));
- Assert.Equal (clipText, result);
- }
- else
- {
- Assert.False (Clipboard.TryGetClipboardData (out string result));
- Assert.NotEqual (clipText, result);
- }
- }
-
- [Fact, AutoInitShutdown (useFakeClipboard: false)]
- public void TrySetClipboardData_Sets_The_OS_Clipboard ()
- {
- string clipText = "The TrySetClipboardData_Sets_The_OS_Clipboard unit test pasted this to the OS clipboard.";
-
- if (Clipboard.IsSupported)
- {
- Assert.True (Clipboard.TrySetClipboardData (clipText));
- }
- else
- {
- Assert.False (Clipboard.TrySetClipboardData (clipText));
- }
-
- ApplicationImpl.Instance.Iteration += (s, a) => Application.RequestStop ();
-
- Application.Run ();
-
- if (Clipboard.IsSupported)
- {
- Assert.Equal (clipText, Clipboard.Contents);
- }
- else
- {
- Assert.NotEqual (clipText, Clipboard.Contents);
- }
- }
-
- // Disabling this test for now because it is not reliable
-#if false
- [Fact, AutoInitShutdown (useFakeClipboard: false)]
- public void Contents_Copies_From_OS_Clipboard ()
- {
- if (!Clipboard.IsSupported) {
- output.WriteLine ($"The Clipboard not supported on this platform.");
- return;
- }
-
- var clipText = "The Contents_Copies_From_OS_Clipboard unit test pasted this to the OS clipboard.";
- var failed = false;
- var getClipText = "";
-
- ApplicationImpl.Instance.Iteration += (s, a) => {
- int exitCode = 0;
- string result = "";
- output.WriteLine ($"Pasting to OS clipboard: {clipText}...");
-
- if (RuntimeInformation.IsOSPlatform (OSPlatform.Windows)) {
- (exitCode, result) =
- ClipboardProcessRunner.Process ("powershell.exe", $"-command \"Set-Clipboard -Value \\\"{clipText}\\\"\"");
- output.WriteLine ($" Windows: powershell.exe Set-Clipboard: exitCode = {exitCode}, result = {result}");
- getClipText = Clipboard.Contents;
-
- } else if (RuntimeInformation.IsOSPlatform (OSPlatform.OSX)) {
- (exitCode, result) = ClipboardProcessRunner.Process ("pbcopy", string.Empty, clipText);
- output.WriteLine ($" OSX: pbcopy: exitCode = {exitCode}, result = {result}");
- getClipText = Clipboard.Contents;
-
- } else if (RuntimeInformation.IsOSPlatform (OSPlatform.Linux)) {
- if (Is_WSL_Platform ()) {
- try {
- // This runs the WINDOWS version of powershell.exe via WSL.
- (exitCode, result) =
- ClipboardProcessRunner.Process ("powershell.exe", $"-noprofile -command \"Set-Clipboard -Value \\\"{clipText}\\\"\"");
- output.WriteLine ($" WSL: powershell.exe Set-Clipboard: exitCode = {exitCode}, result = {result}");
- } catch {
- failed = true;
- }
-
- if (!failed) {
- // If we set the OS clipboard via Powershell, then getting Contents should return the same text.
- getClipText = Clipboard.Contents;
- output.WriteLine ($" WSL: Clipboard.Contents: {getClipText}");
- }
- Application.RequestStop ();
- return;
- }
-
- if (failed = xclipExists () == false) {
- // if xclip doesn't exist then exit.
- output.WriteLine ($" WSL: no xclip found.");
- Application.RequestStop ();
- return;
- }
-
- // If we get here, powershell didn't work and xclip exists...
- (exitCode, result) =
- ClipboardProcessRunner.Process ("bash", $"-c \"xclip -sel clip -i\"", clipText);
- output.WriteLine ($" Linux: bash xclip -sel clip -i: exitCode = {exitCode}, result = {result}");
-
- if (!failed) {
- getClipText = Clipboard.Contents;
- output.WriteLine ($" Linux via xclip: Clipboard.Contents: {getClipText}");
- }
- }
-
- Application.RequestStop ();
- };
-
- Application.Run ();
-
- if (!failed) Assert.Equal (clipText, getClipText);
- }
-
- [Fact, AutoInitShutdown (useFakeClipboard: false)]
- public void Contents_Pastes_To_OS_Clipboard ()
- {
- if (!Clipboard.IsSupported) {
- output.WriteLine ($"The Clipboard not supported on this platform.");
- return;
- }
-
- var clipText = "The Contents_Pastes_To_OS_Clipboard unit test pasted this via Clipboard.Contents.";
- var clipReadText = "";
- var failed = false;
-
- ApplicationImpl.Instance.Iteration += (s, a) => {
- Clipboard.Contents = clipText;
-
- int exitCode = 0;
- output.WriteLine ($"Getting OS clipboard...");
-
- if (RuntimeInformation.IsOSPlatform (OSPlatform.Windows)) {
- (exitCode, clipReadText) =
- ClipboardProcessRunner.Process ("powershell.exe", "-noprofile -command \"Get-Clipboard\"");
- output.WriteLine ($" Windows: powershell.exe Get-Clipboard: exitCode = {exitCode}, result = {clipReadText}");
-
- } else if (RuntimeInformation.IsOSPlatform (OSPlatform.OSX)) {
- (exitCode, clipReadText) = ClipboardProcessRunner.Process ("pbpaste", "");
- output.WriteLine ($" OSX: pbpaste: exitCode = {exitCode}, result = {clipReadText}");
-
- } else if (RuntimeInformation.IsOSPlatform (OSPlatform.Linux)) {
- if (Is_WSL_Platform ()) {
- (exitCode, clipReadText) =
- ClipboardProcessRunner.Process ("powershell.exe", "-noprofile -command \"Get-Clipboard\"");
- output.WriteLine ($" WSL: powershell.exe Get-Clipboard: exitCode = {exitCode}, result = {clipReadText}");
- if (exitCode == 0) {
- Application.RequestStop ();
- return;
- }
- failed = true;
- }
-
- if (failed = xclipExists () == false) {
- // xclip doesn't exist then exit.
- Application.RequestStop ();
- return;
- }
-
- (exitCode, clipReadText) = ClipboardProcessRunner.Process ("bash", $"-c \"xclip -sel clip -o\"");
- output.WriteLine ($" Linux: bash xclip -sel clip -o: exitCode = {exitCode}, result = {clipReadText}");
- Assert.Equal (0, exitCode);
- }
-
- Application.RequestStop ();
- };
-
- Application.Run ();
-
- if (!failed) Assert.Equal (clipText, clipReadText.TrimEnd ());
-
- }
-#endif
-
- bool Is_WSL_Platform ()
- {
- (int _, string result) = ClipboardProcessRunner.Process ("bash", $"-c \"uname -a\"");
-
- return result.Contains ("microsoft") && result.Contains ("WSL");
- }
-
- bool xclipExists ()
- {
- try
- {
- (int _, string result) = ClipboardProcessRunner.Process ("bash", $"-c \"which xclip\"");
-
- return result.TrimEnd () != "";
- }
- catch (Exception)
- {
- return false;
- }
- }
-}
-#endif
diff --git a/Tests/UnitTests/Configuration/AppScopeTests.cs b/Tests/UnitTests/Configuration/AppScopeTests.cs
deleted file mode 100644
index df40886603..0000000000
--- a/Tests/UnitTests/Configuration/AppScopeTests.cs
+++ /dev/null
@@ -1,126 +0,0 @@
-#nullable enable
-using System.Text.Json;
-using UnitTests;
-using static Terminal.Gui.Configuration.ConfigurationManager;
-
-namespace UnitTests.ConfigurationTests;
-
-public class AppSettingsScopeTests
-{
- [Fact]
- public void Empty_By_Default_Disabled ()
- {
- Assert.False (IsEnabled);
-
- Assert.NotNull (Settings! ["AppSettings"].PropertyValue);
-
- AppSettingsScope? appSettings = (Settings! ["AppSettings"].PropertyValue as AppSettingsScope);
- Assert.Equal (10, appSettings!.Count); // 10 test properties
-
- Assert.Equal ("test", (((AppSettingsScope)Settings! ["AppSettings"].PropertyValue!)!) ["AppSettingsTestClass.ReferenceProperty"].PropertyValue);
- }
-
- [Fact]
- public void Empty_By_Default_Enabled ()
- {
- Enable (ConfigLocations.HardCoded);
-
- Assert.NotNull (Settings! ["AppSettings"].PropertyValue);
-
- AppSettingsScope? appSettings = (Settings! ["AppSettings"].PropertyValue as AppSettingsScope);
- Assert.Equal (10, appSettings!.Count); // 10 test properties
- Assert.Equal ("test", (((AppSettingsScope)Settings! ["AppSettings"].PropertyValue!)!) ["AppSettingsTestClass.ReferenceProperty"].PropertyValue);
-
- Disable (resetToHardCodedDefaults: true);
- }
-
- [Fact]
- public void Apply_ShouldApplyUpdatedProperties ()
- {
- Enable (ConfigLocations.HardCoded);
-
- Assert.Null (AppSettingsTestClass.NullableValueProperty);
- Assert.NotEmpty (AppSettings!);
- Assert.Null (AppSettings! ["AppSettingsTestClass.NullableValueProperty"].PropertyValue);
-
- AppSettingsTestClass.NullableValueProperty = true;
- UpdateToCurrentValues ();
- Assert.True (AppSettingsTestClass.NullableValueProperty);
- Assert.NotEmpty (AppSettings);
- Assert.True (AppSettings ["AppSettingsTestClass.NullableValueProperty"].PropertyValue as bool?);
-
- AppSettings ["AppSettingsTestClass.NullableValueProperty"].PropertyValue = false;
- Assert.False (AppSettings ["AppSettingsTestClass.NullableValueProperty"].PropertyValue as bool?);
-
- // ConfigurationManager.Settings should NOT apply theme settings
- Settings!.Apply ();
- Assert.True (AppSettingsTestClass.NullableValueProperty);
-
- // ConfigurationManager.Themes should NOT apply theme settings
- ThemeManager.Themes! [ThemeManager.Theme]!.Apply ();
- Assert.True (AppSettingsTestClass.NullableValueProperty);
-
- // ConfigurationManager.AppSettings should NOT apply theme settings
- AppSettings.Apply ();
- Assert.False (AppSettingsTestClass.NullableValueProperty);
- Disable (resetToHardCodedDefaults: true);
- }
-
- [Fact]
- public void TestNullable ()
- {
- Enable (ConfigLocations.HardCoded);
-
- AppSettingsTestClass.NullableValueProperty = null;
- Assert.Null (AppSettingsTestClass.NullableValueProperty);
-
- ResetToHardCodedDefaults ();
- Assert.Null (AppSettings! ["AppSettingsTestClass.NullableValueProperty"].PropertyValue);
-
- Apply ();
- Assert.Null (AppSettings! ["AppSettingsTestClass.NullableValueProperty"].PropertyValue);
- Assert.Null (AppSettingsTestClass.NullableValueProperty);
-
- AppSettingsTestClass.NullableValueProperty = true;
- UpdateToCurrentValues ();
- Assert.True ((bool)AppSettings! ["AppSettingsTestClass.NullableValueProperty"].PropertyValue!);
- Assert.True (AppSettingsTestClass.NullableValueProperty);
- Assert.NotNull (AppSettingsTestClass.NullableValueProperty);
- Apply ();
- Assert.True (AppSettingsTestClass.NullableValueProperty);
- Assert.NotNull (AppSettingsTestClass.NullableValueProperty);
-
- Disable (resetToHardCodedDefaults: true);
- }
-
- [Fact]
- public void TestSerialize_RoundTrip ()
- {
- Enable (ConfigLocations.HardCoded);
-
- AppSettingsScope initial = AppSettings!;
-
- string serialized = JsonSerializer.Serialize (AppSettings, SerializerContext.Options);
- var deserialized = JsonSerializer.Deserialize (serialized, SerializerContext.Options);
-
- Assert.NotEqual (initial, deserialized);
- Assert.Equal (deserialized!.Count, initial.Count);
-
- Disable (resetToHardCodedDefaults: true);
- }
-
- public class AppSettingsTestClass
- {
- [ConfigurationProperty (Scope = typeof (AppSettingsScope))]
- public static bool ValueProperty { get; set; }
-
- [ConfigurationProperty (Scope = typeof (AppSettingsScope))]
- public static bool? NullableValueProperty { get; set; }
-
- [ConfigurationProperty (Scope = typeof (AppSettingsScope))]
- public static string ReferenceProperty { get; set; } = "test";
-
- [ConfigurationProperty (Scope = typeof (AppSettingsScope))]
- public static string? NullableReferenceProperty { get; set; }
- }
-}
diff --git a/Tests/UnitTests/Configuration/ConfigPropertyTests.cs b/Tests/UnitTests/Configuration/ConfigPropertyTests.cs
deleted file mode 100644
index b516291da9..0000000000
--- a/Tests/UnitTests/Configuration/ConfigPropertyTests.cs
+++ /dev/null
@@ -1,468 +0,0 @@
-#nullable enable
-using System.Collections.Concurrent;
-using System.Reflection;
-using System.Text.Json;
-
-namespace UnitTests.ConfigurationTests;
-
-public class ConfigPropertyTests
-{
- [Fact]
- public void Apply_PropertyValueIsAppliedToStatic_String_Property ()
- {
- // Arrange
- TestConfiguration.Reset ();
- var propertyInfo = typeof (TestConfiguration).GetProperty (nameof (TestConfiguration.TestStringProperty));
- var configProperty = new ConfigProperty
- {
- PropertyInfo = propertyInfo,
- PropertyValue = "UpdatedValue"
- };
-
- // Act
- var result = configProperty.Apply ();
-
- // Assert
- Assert.Equal (1, TestConfiguration.TestStringPropertySetCount);
- Assert.True (result);
- Assert.Equal ("UpdatedValue", TestConfiguration.TestStringProperty);
- TestConfiguration.Reset ();
- }
-
- [Fact]
- public void Apply_PropertyValueIsAppliedToStatic_Key_Property ()
- {
- // Arrange
- TestConfiguration.Reset ();
- var propertyInfo = typeof (TestConfiguration).GetProperty (nameof (TestConfiguration.TestKeyProperty));
- var configProperty = new ConfigProperty
- {
- PropertyInfo = propertyInfo,
- PropertyValue = Key.Q.WithCtrl
- };
-
- // Act
- var result = configProperty.Apply ();
-
- // Assert
- Assert.Equal (1, TestConfiguration.TestKeyPropertySetCount);
- Assert.True (result);
- Assert.Equal (Key.Q.WithCtrl, TestConfiguration.TestKeyProperty);
- TestConfiguration.Reset ();
- }
-
- [Fact]
- public void RetrieveValue_GetsCurrentValueOfStaticProperty ()
- {
- // Arrange
- TestConfiguration.TestStringProperty = "CurrentValue";
- var propertyInfo = typeof (TestConfiguration).GetProperty (nameof (TestConfiguration.TestStringProperty));
- var configProperty = new ConfigProperty
- {
- PropertyInfo = propertyInfo
- };
-
- // Act
- var value = configProperty.UpdateToCurrentValue ();
-
- // Assert
- Assert.Equal ("CurrentValue", value);
- Assert.Equal ("CurrentValue", configProperty.PropertyValue);
- }
-
- [Fact]
- public void DeepCloneFrom_Updates_String_Property_Value ()
- {
- // Arrange
- TestConfiguration.Reset ();
- var propertyInfo = typeof (TestConfiguration).GetProperty (nameof (TestConfiguration.TestStringProperty));
- var configProperty = new ConfigProperty
- {
- PropertyInfo = propertyInfo,
- PropertyValue = "InitialValue"
- };
-
- // Act
- var updatedValue = configProperty.UpdateFrom ("NewValue");
-
- // Assert
- Assert.Equal (0, TestConfiguration.TestStringPropertySetCount);
- Assert.Equal ("NewValue", updatedValue);
- Assert.Equal ("NewValue", configProperty.PropertyValue);
- TestConfiguration.Reset ();
- }
-
- //[Fact]
- //public void UpdateValueFrom_InvalidType_ThrowsArgumentException()
- //{
- // // Arrange
- // var propertyInfo = typeof(TestConfiguration).GetProperty(nameof(TestConfiguration.TestStringProperty));
- // var configProperty = new ConfigProperty
- // {
- // PropertyInfo = propertyInfo
- // };
-
- // // Act & Assert
- // Assert.Throws(() => configProperty.UpdateValueFrom(123));
- //}
-
- [Fact]
- public void Apply_TargetInvocationException_ThrowsJsonException ()
- {
- // Arrange
- var propertyInfo = typeof (TestConfiguration).GetProperty (nameof (TestConfiguration.TestStringProperty));
- var configProperty = new ConfigProperty
- {
- PropertyInfo = propertyInfo,
- PropertyValue = null // This will cause ArgumentNullException in the set accessor
- };
-
- // Act & Assert
- var exception = Assert.Throws (() => configProperty.Apply ());
- }
-
- [Fact]
- public void GetJsonPropertyName_ReturnsJsonPropertyNameAttributeValue ()
- {
- // Arrange
- var propertyInfo = typeof (TestConfiguration).GetProperty (nameof (TestConfiguration.TestStringProperty));
-
- // Act
- var jsonPropertyName = ConfigProperty.GetJsonPropertyName (propertyInfo!);
-
- // Assert
- Assert.Equal ("TestStringProperty", jsonPropertyName);
- }
- [Fact]
- public void UpdateFrom_NullSource_ReturnsExistingValue()
- {
- // Arrange
- TestConfiguration.TestStringProperty = "CurrentValue";
- var propertyInfo = typeof(TestConfiguration).GetProperty(nameof(TestConfiguration.TestStringProperty));
- var configProperty = new ConfigProperty
- {
- PropertyInfo = propertyInfo,
- PropertyValue = "ExistingValue"
- };
-
- // Act
- var result = configProperty.UpdateFrom(null);
-
- // Assert
- Assert.Equal("ExistingValue", result);
- Assert.Equal("ExistingValue", configProperty.PropertyValue);
- }
-
- [Fact]
- public void UpdateFrom_InvalidType_ThrowsArgumentException()
- {
- // Arrange
- var propertyInfo = typeof(TestConfiguration).GetProperty(nameof(TestConfiguration.TestStringProperty));
- var configProperty = new ConfigProperty
- {
- PropertyInfo = propertyInfo,
- PropertyValue = "ExistingValue"
- };
-
- // Act & Assert
- Assert.Throws(() => configProperty.UpdateFrom(123));
- }
-
- [Fact]
- public void UpdateFrom_ConfigPropertySource_CopiesValue()
- {
- // Arrange
- var propertyInfo = typeof(TestConfiguration).GetProperty(nameof(TestConfiguration.TestStringProperty));
- var configProperty = new ConfigProperty
- {
- PropertyInfo = propertyInfo,
- PropertyValue = "ExistingValue"
- };
-
- var sourceConfigProperty = new ConfigProperty
- {
- PropertyValue = "SourceValue",
- HasValue = true
- };
-
- // Act
- var result = configProperty.UpdateFrom(sourceConfigProperty);
-
- // Assert
- Assert.Equal("SourceValue", result);
- Assert.Equal("SourceValue", configProperty.PropertyValue);
- }
-
- [Fact]
- public void UpdateFrom_ConfigPropertySource_WithoutValue_KeepsExistingValue()
- {
- // Arrange
- var propertyInfo = typeof(TestConfiguration).GetProperty(nameof(TestConfiguration.TestStringProperty));
- var configProperty = new ConfigProperty
- {
- PropertyInfo = propertyInfo,
- PropertyValue = "ExistingValue"
- };
-
- var sourceConfigProperty = new ConfigProperty
- {
- HasValue = false
- };
-
- // Act
- var result = configProperty.UpdateFrom(sourceConfigProperty);
-
- // Assert
- Assert.Equal("ExistingValue", result);
- Assert.Equal("ExistingValue", configProperty.PropertyValue);
- }
-
- [Fact]
- public void UpdateFrom_ConcurrentDictionaryOfThemeScopes_UpdatesValues()
- {
- // Arrange
- var propertyInfo = typeof(TestConfiguration).GetProperty(nameof(TestConfiguration.TestDictionaryProperty));
-
- // Create a destination dictionary
- var destinationDict = new ConcurrentDictionary(StringComparer.InvariantCultureIgnoreCase);
- destinationDict.TryAdd("theme1", new ThemeScope());
-
- var configProperty = new ConfigProperty
- {
- PropertyInfo = propertyInfo,
- PropertyValue = destinationDict
- };
-
- // Create a source dictionary with one matching key and one new key
- var sourceDict = new ConcurrentDictionary(StringComparer.InvariantCultureIgnoreCase);
- var sourceTheme1 = new ThemeScope();
- var sourceTheme2 = new ThemeScope();
-
- // Add a property to sourceTheme1 to verify it gets updated
- var keyProperty = typeof(TestConfiguration).GetProperty(nameof(TestConfiguration.TestKeyProperty));
- if (sourceTheme1.TryAdd("TestKey", new ConfigProperty { PropertyInfo = keyProperty, PropertyValue = Key.A.WithCtrl, HasValue = true }))
- {
- // Successfully added
- }
-
- sourceDict.TryAdd("theme1", sourceTheme1);
- sourceDict.TryAdd("theme2", sourceTheme2);
-
- // Act
- var result = configProperty.UpdateFrom(sourceDict);
-
- // Assert
- var resultDict = result as ConcurrentDictionary;
- Assert.NotNull(resultDict);
- Assert.Equal(2, resultDict.Count);
- Assert.True(resultDict.ContainsKey("theme1"));
- Assert.True(resultDict.ContainsKey("theme2"));
-
- // Verify the theme1 was updated with the property
- Assert.True(resultDict["theme1"].ContainsKey("TestKey"));
- Assert.Equal(Key.A.WithCtrl, resultDict["theme1"]["TestKey"].PropertyValue);
- }
-
- [Fact]
- public void UpdateFrom_ConcurrentDictionaryOfConfigProperties_UpdatesValues()
- {
- // Arrange
- var propertyInfo = typeof(TestConfiguration).GetProperty(nameof(TestConfiguration.TestConfigDictionaryProperty));
-
- // Create a destination dictionary
- var destinationDict = new ConcurrentDictionary(StringComparer.InvariantCultureIgnoreCase);
- destinationDict.TryAdd("prop1", new ConfigProperty { PropertyValue = "Original", HasValue = true });
-
- var configProperty = new ConfigProperty
- {
- PropertyInfo = propertyInfo,
- PropertyValue = destinationDict
- };
-
- // Create a source dictionary with one matching key and one new key
- var sourceDict = new ConcurrentDictionary(StringComparer.InvariantCultureIgnoreCase);
- sourceDict.TryAdd("prop1", new ConfigProperty { PropertyValue = "Updated", HasValue = true });
- sourceDict.TryAdd("prop2", new ConfigProperty { PropertyValue = "New", HasValue = true });
-
- // Act
- var result = configProperty.UpdateFrom(sourceDict);
-
- // Assert
- var resultDict = result as ConcurrentDictionary;
- Assert.NotNull(resultDict);
- Assert.Equal(2, resultDict.Count);
- Assert.True(resultDict.ContainsKey("prop1"));
- Assert.True(resultDict.ContainsKey("prop2"));
- Assert.Equal("Updated", resultDict["prop1"].PropertyValue);
- Assert.Equal("New", resultDict["prop2"].PropertyValue);
- }
-
- [Fact]
- public void UpdateFrom_DictionaryOfConfigProperties_UpdatesValues()
- {
- // Arrange
- var propertyInfo = typeof(TestConfiguration).GetProperty(nameof(TestConfiguration.TestConfigDictionaryProperty));
-
- // Create a destination dictionary
- var destinationDict = new Dictionary(StringComparer.InvariantCultureIgnoreCase);
- destinationDict.Add("prop1", new ConfigProperty { PropertyValue = "Original", HasValue = true });
-
- var configProperty = new ConfigProperty
- {
- PropertyInfo = propertyInfo,
- PropertyValue = destinationDict
- };
-
- // Create a source dictionary with one matching key and one new key
- var sourceDict = new Dictionary(StringComparer.InvariantCultureIgnoreCase);
- sourceDict.Add("prop1", new ConfigProperty { PropertyValue = "Updated", HasValue = true });
- sourceDict.Add("prop2", new ConfigProperty { PropertyValue = "New", HasValue = true });
-
- // Act
- var result = configProperty.UpdateFrom(sourceDict);
-
- // Assert
- var resultDict = result as Dictionary;
- Assert.NotNull(resultDict);
- Assert.Equal(2, resultDict.Count);
- Assert.True(resultDict.ContainsKey("prop1"));
- Assert.True(resultDict.ContainsKey("prop2"));
- Assert.Equal("Updated", resultDict["prop1"].PropertyValue);
- Assert.Equal("New", resultDict["prop2"].PropertyValue);
- }
-
- [Fact]
- public void PropertyValue_SetWhenImmutable_ThrowsException()
- {
- // Arrange
- var propertyInfo = typeof(TestConfiguration).GetProperty(nameof(TestConfiguration.TestStringProperty));
- var configProperty = new ConfigProperty
- {
- PropertyInfo = propertyInfo,
- Immutable = true
- };
-
- // Act & Assert
- var exception = Assert.Throws(() => configProperty.PropertyValue = "New Value");
- Assert.Contains("immutable", exception.Message);
- }
-
- [Fact]
- public void CreateWithAttributeInfo_ReturnsConfigPropertyWithCorrectValues()
- {
- // Arrange
- var propertyInfo = typeof(TestConfiguration).GetProperty(nameof(TestConfiguration.TestStringProperty));
-
- // Act
- var configProperty = ConfigProperty.CreateImmutableWithAttributeInfo(propertyInfo!);
-
- // Assert
- Assert.Equal(propertyInfo, configProperty.PropertyInfo);
- Assert.False(configProperty.OmitClassName);
- Assert.True(configProperty.Immutable);
- Assert.Null(configProperty.PropertyValue);
- Assert.False(configProperty.HasValue);
- }
-
- [Fact]
- public void HasConfigurationPropertyAttribute_ReturnsTrue_ForDecoratedProperty()
- {
- // Arrange
- var propertyInfo = typeof(TestConfiguration).GetProperty(nameof(TestConfiguration.TestStringProperty));
-
- // Act
- var result = ConfigProperty.HasConfigurationPropertyAttribute(propertyInfo!);
-
- // Assert
- Assert.True(result);
- }
-
- [Fact]
- public void HasConfigurationPropertyAttribute_ReturnsFalse_ForNonDecoratedProperty()
- {
- // Arrange
- var propertyInfo = typeof(TestConfiguration).GetProperty(nameof(TestConfiguration.TestStringPropertySetCount));
-
- // Act
- var result = ConfigProperty.HasConfigurationPropertyAttribute(propertyInfo!);
-
- // Assert
- Assert.False(result);
- }
- public class TestConfiguration
- {
- private static string _testStringProperty = "Default";
- public static int TestStringPropertySetCount { get; set; }
-
- [ConfigurationProperty]
- public static string TestStringProperty
- {
- get => _testStringProperty;
- set
- {
- TestStringPropertySetCount++;
- _testStringProperty = value ?? throw new ArgumentNullException (nameof (value));
- }
- }
-
- private static Key _testKeyProperty = Key.Esc;
- public static int TestKeyPropertySetCount { get; set; }
-
- [ConfigurationProperty]
- public static Key TestKeyProperty
- {
- get => _testKeyProperty;
- set
- {
- TestKeyPropertySetCount++;
- _testKeyProperty = value ?? throw new ArgumentNullException (nameof (value));
- }
- }
-
- // Add these new properties for testing dictionaries
- [ConfigurationProperty]
- public static ConcurrentDictionary? TestDictionaryProperty { get; set; }
-
- [ConfigurationProperty]
- public static Dictionary? TestRegularDictionaryProperty { get; set; }
-
- [ConfigurationProperty]
- public static ConcurrentDictionary? TestConfigDictionaryProperty { get; set; }
-
- [ConfigurationProperty]
- public static Scheme? TestSchemeProperty { get; set; }
-
-
- public static void Reset ()
- {
- TestStringPropertySetCount = 0;
- TestKeyPropertySetCount = 0;
- TestDictionaryProperty = null;
- TestRegularDictionaryProperty = null;
- TestConfigDictionaryProperty = null;
- TestSchemeProperty = null;
- }
- }
-
- [Fact]
- public void UpdateFrom_SchemeSource_UpdatesValue ()
- {
- // Arrange
- PropertyInfo? propertyInfo = typeof (TestConfiguration).GetProperty (nameof (TestConfiguration.TestSchemeProperty));
- Scheme sourceScheme = new (new Attribute (Color.Red, Color.Blue, TextStyle.Bold));
-
- var configProperty = new ConfigProperty
- {
- PropertyInfo = propertyInfo!,
- PropertyValue = new Scheme (new Attribute (Color.White, Color.Black, TextStyle.None))
- };
-
- // Act
- object? result = configProperty.UpdateFrom (sourceScheme);
-
- // Assert
- Assert.Equal (sourceScheme, result);
- Assert.Equal (sourceScheme, configProperty.PropertyValue);
- Assert.NotSame (sourceScheme, configProperty.PropertyValue); // Prove it's a clone, not a ref
- }
-}
diff --git a/Tests/UnitTests/Configuration/KeyJsonConverterTests.cs b/Tests/UnitTests/Configuration/KeyJsonConverterTests.cs
deleted file mode 100644
index 8f3e6f973a..0000000000
--- a/Tests/UnitTests/Configuration/KeyJsonConverterTests.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-using System.Text;
-using System.Text.Encodings.Web;
-using System.Text.Json;
-using System.Text.Unicode;
-
-namespace UnitTests.ConfigurationTests;
-
-public class KeyJsonConverterTests
-{
-
- [Fact]
- public void Separator_Property_Set_Changes_Serialization_Format ()
- {
- Rune savedSeparator = Key.Separator;
-
- // Act
- // NOTE: This means this test can't be parallelized
- Key.Separator = (Rune)'*';
- string json = JsonSerializer.Serialize (Key.Separator, ConfigurationManager.SerializerContext.Options);
-
- // Assert
- Assert.Equal ("\"*\"", json);
- Key.Separator = savedSeparator;
- }
-
- [Theory]
- [InlineData ('A', '+', "\"Ctrl+Alt+A\"")]
- [InlineData ('A', '-', "\"Ctrl+Alt+A\"")]
- [InlineData ('A', '*', "\"Ctrl+Alt+A\"")]
- [InlineData ('A', '@', "\"Ctrl+Alt+A\"")]
- [InlineData ('A', '+', "\"Ctrl@Alt@A\"")]
- [InlineData ('A', '-', "\"Ctrl@Alt@A\"")]
- [InlineData ('A', '*', "\"Ctrl@Alt@A\"")]
- [InlineData ('A', '@', "\"Ctrl@Alt@A\"")]
- [InlineData ('+', '+', "\"Ctrl+Alt++\"")]
- [InlineData ('+', '-', "\"Ctrl+Alt++\"")]
- [InlineData ('+', '*', "\"Ctrl+Alt++\"")]
- [InlineData ('+', '@', "\"Ctrl+Alt++\"")]
- [InlineData ('+', '+', "\"Ctrl@Alt@+\"")]
- [InlineData ('+', '-', "\"Ctrl@Alt@+\"")]
- [InlineData ('+', '*', "\"Ctrl@Alt@+\"")]
- [InlineData ('+', '@', "\"Ctrl@Alt@+\"")]
- public void Separator_Property_Set_Deserialization_Works_With_Any (char keyChar, char separator, string json)
- {
- Rune savedSeparator = Key.Separator;
-
- // Act
- // NOTE: This means this test can't be parallelized
- Key.Separator = (Rune)separator;
-
- Key deserializedKey = JsonSerializer.Deserialize (json, ConfigurationManager.SerializerContext.Options);
-
- Key expectedKey = new Key ((KeyCode)keyChar).WithCtrl.WithAlt;
- // Assert
- Assert.Equal (expectedKey, deserializedKey);
- Key.Separator = savedSeparator;
- }
-}
\ No newline at end of file
diff --git a/Tests/UnitTests/Configuration/MemorySizeEstimator.cs b/Tests/UnitTests/Configuration/MemorySizeEstimator.cs
deleted file mode 100644
index 7562650d2b..0000000000
--- a/Tests/UnitTests/Configuration/MemorySizeEstimator.cs
+++ /dev/null
@@ -1,253 +0,0 @@
-#nullable enable
-
-namespace UnitTests.ConfigurationTests;
-
-using System;
-using System.Collections;
-using System.Collections.Concurrent;
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Text;
-
-public static class MemorySizeEstimator
-{
- public static long EstimateSize (T? source)
- {
- if (source is null)
- {
- return 0;
- }
-
- ConcurrentDictionary