mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
* Tons of API doc updates * Removed stale test * Removed stale tests * Fixed Skipped Shadow test 1 * Fixed Skipped Shadow test 2 * Fixed Skipped Shadow test 3 * Removed stale test * Removed stale test2 * Explicit unregister of event handler on Application.Driver!.ClearedContents * Added Toplevels to dict * code cleanup * spelling error * Removed stale test3 * Removed stale test4 * Removed stale test5 * added script * tweaked script * tweaked script * Created StressTests project; moved some tests * Created IntegrationTests project; moved some tests * New yml * made old yml just unit tests * Tweaked Button_IsDefault_Raises_Accepted_Correctly * tweaked script * cleaned up ymls * tweakled up ymls * stress tests... * stress tests on ubuntu only * Fixed WindowsDriver in InvokeLeakTest * Fixed WindowsDriver in InvokeLeakTest2 * Added Directory.Packages.props. Added Directory.Build.props * Shortened StressTest time * Removed dupe file. * DemoFiles * Moved all tests to ./Tests dir. * Fixed release build issue * Fixed .sln file * Fixed .sl* files * Fixing ymls * Fixing interation tests * Create link to the file TestHelpers. * Created Tests/UnitTestsParallelizable. Moved all obviously parallelizable tests. Updated yml. * fixing logs * fixing logs2 * fixing logs3 * don't require stress to pass for PRs * Fix a failure? * tweaked script * Coudl this be it? * Moved tons of tests to parallelizable * Fixed some stuff * Script to find duplicate tests * Testing workflows * Updated to v4 * Fix RelativeBasePath issue * Replace powershell to pwsh * Add ignore projects. * Removed dupe unit tests * Code cleanup of tests * Cleaned up test warnings * yml tweak * Moved setter * tweak ymls * just randomly throwing spaghetti at a wall * Enable runing 5 test runners in par * Turned off DEBUG_DISPOSABLE for par tests * RunningUnitTests=true * code cleanup (forcing more Action runs) * DISABLE_DEBUG_IDISPOSABLE * Added View.DebugIDisposable. False by default. * Remobed bogus tareet * Remobed bogus tareet2 * fixed warning * added api doc * fixed warning * fixed warning * fixed warning2 * fixed warning3 * fixed warning4 --------- Co-authored-by: BDisp <bd.bdisp@gmail.com>
This commit is contained in:
34
.github/workflows/build-release.yml
vendored
Normal file
34
.github/workflows/build-release.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
name: Ensure that Release builds are not broken
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ v2_release, v2_develop ]
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
pull_request:
|
||||
branches: [ v2_release, v2_develop ]
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
|
||||
jobs:
|
||||
build_release:
|
||||
# Ensure that RELEASE builds are not broken
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.x
|
||||
dotnet-quality: 'ga'
|
||||
|
||||
- name: Build Release Terminal.Gui
|
||||
run: dotnet build Terminal.Gui/Terminal.Gui.csproj --configuration Release
|
||||
|
||||
- name: Pack Release Terminal.Gui
|
||||
run: dotnet pack Terminal.Gui/Terminal.Gui.csproj --configuration Release --output ./local_packages
|
||||
|
||||
- name: Build Release Solution
|
||||
run: dotnet build --configuration Release
|
||||
14
.github/workflows/check-duplicates.yml
vendored
Normal file
14
.github/workflows/check-duplicates.yml
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
name: Check for Duplicate UnitTests
|
||||
on:
|
||||
push:
|
||||
branches: [ v2_release, v2_develop ]
|
||||
pull_request:
|
||||
branches: [ v2_release, v2_develop ]
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
check-duplicates:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Run Duplicate Test Check
|
||||
run: pwsh -File ./Scripts/FindDuplicateTestMethodsInSameFileName.ps1 -solutionPath "$PWD"
|
||||
119
.github/workflows/dotnet-core.yml
vendored
119
.github/workflows/dotnet-core.yml
vendored
@@ -1,119 +0,0 @@
|
||||
name: Build & Test Terminal.Gui with .NET Core
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ v2_release, v2_develop ]
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
pull_request:
|
||||
branches: [ v2_release, v2_develop ]
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
|
||||
jobs:
|
||||
build_and_test_debug:
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
# Turn off fail-fast to let all runners run even if there are errors
|
||||
fail-fast: true
|
||||
matrix:
|
||||
os: [ ubuntu-latest, windows-latest, macos-latest ]
|
||||
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
|
||||
# Build (Debug)
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.x
|
||||
dotnet-quality: 'ga'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
dotnet restore
|
||||
|
||||
- name: Build Debug
|
||||
run: dotnet build --configuration Debug --no-restore
|
||||
|
||||
# Test
|
||||
# Note: The --blame and VSTEST_DUMP_PATH stuff is needed to diagnose the test runner crashing on ubuntu/mac
|
||||
# See https://github.com/microsoft/vstest/issues/2952 for why the --blame stuff below is needed.
|
||||
# Without it, the test runner crashes on ubuntu (but not Windows or mac)
|
||||
|
||||
- name: MacOS - Patch test runner settings to stop on fail
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
brew install gnu-sed
|
||||
gsed -i 's/"stopOnFail": false/"stopOnFail": true/g' UnitTests/xunit.runner.json
|
||||
|
||||
- name: Windows/Linux - Patch test runner settings to stop on fail
|
||||
if: runner.os != 'macOS'
|
||||
run: |
|
||||
sed -i 's/"stopOnFail": false/"stopOnFail": true/g' UnitTests/xunit.runner.json
|
||||
|
||||
- name: Set VSTEST_DUMP_PATH
|
||||
shell: bash
|
||||
run: echo "{VSTEST_DUMP_PATH}={logs/${{ runner.os }}/}" >> $GITHUB_ENV
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
dotnet test --verbosity normal --collect:"XPlat Code Coverage" --settings UnitTests/coverlet.runsettings --diag:logs/${{ runner.os }}/logs.txt --blame --blame-crash --blame-hang --blame-hang-timeout 60s --blame-crash-collect-always
|
||||
|
||||
# mv -v UnitTests/TestResults/*/*.* UnitTests/TestResults/
|
||||
|
||||
- name: Upload Test Logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: test-logs-${{ runner.os }}
|
||||
path: |
|
||||
logs/
|
||||
UnitTests/TestResults/
|
||||
|
||||
|
||||
build_release:
|
||||
# Ensure that RELEASE builds are not broken
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.x
|
||||
dotnet-quality: 'ga'
|
||||
|
||||
- name: Build Release Terminal.Gui
|
||||
run: dotnet build Terminal.Gui/Terminal.Gui.csproj --configuration Release
|
||||
|
||||
- name: Pack Release Terminal.Gui
|
||||
run: dotnet pack Terminal.Gui/Terminal.Gui.csproj --configuration Release --output ./local_packages
|
||||
|
||||
- name: Build Release Solution
|
||||
run: dotnet build --configuration Release
|
||||
|
||||
|
||||
# Note: this step is currently not writing to the gist for some reason
|
||||
# - name: Create Test Coverage Badge
|
||||
# uses: simon-k/dotnet-code-coverage-badge@v1.0.0
|
||||
# id: create_coverage_badge
|
||||
# with:
|
||||
# label: Unit Test Coverage
|
||||
# color: brightgreen
|
||||
# path: UnitTests/TestResults/coverage.opencover.xml
|
||||
# gist-filename: code-coverage.json
|
||||
# # https://gist.github.com/migueldeicaza/90ef67a684cb71db1817921a970f8d27
|
||||
# gist-id: 90ef67a684cb71db1817921a970f8d27
|
||||
# gist-auth-token: ${{ secrets.GIST_AUTH_TOKEN }}
|
||||
|
||||
# - name: Print Code Coverage
|
||||
# run: |
|
||||
# echo "Code coverage percentage: ${{steps.create_coverage_badge.outputs.percentage}}%"
|
||||
# echo "Badge data: ${{steps.create_coverage_badge.outputs.badge}}"
|
||||
60
.github/workflows/integration-tests.yml
vendored
Normal file
60
.github/workflows/integration-tests.yml
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
name: Build & Run Integration Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ v2_release, v2_develop ]
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
pull_request:
|
||||
branches: [ v2_release, v2_develop ]
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
|
||||
jobs:
|
||||
build_and_test_debug:
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
# Turn off fail-fast to let all runners run even if there are errors
|
||||
fail-fast: true
|
||||
matrix:
|
||||
os: [ ubuntu-latest, windows-latest, macos-latest ]
|
||||
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.x
|
||||
dotnet-quality: 'ga'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
dotnet restore
|
||||
|
||||
- name: Build IntegrationTests
|
||||
run: dotnet build Tests/IntegrationTests --configuration Debug --no-restore
|
||||
|
||||
- name: Set VSTEST_DUMP_PATH
|
||||
shell: bash
|
||||
run: echo "{VSTEST_DUMP_PATH}={logs/${{ runner.os }}/}" >> $GITHUB_ENV
|
||||
|
||||
- name: Run IntegrationTests
|
||||
run: |
|
||||
dotnet test Tests/IntegrationTests --no-build --verbosity normal --diag:logs/${{ runner.os }}/logs.txt --blame --blame-crash --blame-hang --blame-hang-timeout 60s --blame-crash-collect-always -- xunit.stopOnFail=true
|
||||
|
||||
# mv -v Tests/IntegrationTests/TestResults/*/*.* TestResults/IntegrationTests/
|
||||
|
||||
- name: Upload Test Logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: integration-test-logs-${{ runner.os }}
|
||||
path: |
|
||||
logs/
|
||||
TestResults/IntegrationTests/
|
||||
|
||||
51
.github/workflows/stress-tests.yml
vendored
Normal file
51
.github/workflows/stress-tests.yml
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
name: Run StressTests (for 15 minutes)
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *' # Runs every day at midnight UTC
|
||||
push:
|
||||
branches: [ v2_release, v2_develop ]
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
|
||||
jobs:
|
||||
run_stress_tests:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ ubuntu-latest ]
|
||||
|
||||
timeout-minutes: 70 # Allow some buffer time beyond the 1-hour test duration
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.x
|
||||
dotnet-quality: 'ga'
|
||||
|
||||
- name: Install dependencies
|
||||
run: dotnet restore
|
||||
|
||||
- name: Build StressTests
|
||||
run: dotnet build Tests/StressTests --configuration Debug --no-restore
|
||||
|
||||
- name: Run StressTests for 15 minutes
|
||||
run: |
|
||||
end=$((SECONDS+900))
|
||||
while [ $SECONDS -lt $end ]; do
|
||||
dotnet test Tests/StressTests --no-build --verbosity normal --diag:logs/${{ runner.os }}/logs.txt --blame --blame-crash --blame-hang --blame-hang-timeout 60s --blame-crash-collect-always -- xunit.stopOnFail=true
|
||||
done
|
||||
|
||||
- name: Upload Test Logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: stress-test-logs-${{ runner.os }}
|
||||
path: |
|
||||
logs/
|
||||
TestResults/StressTests
|
||||
|
||||
116
.github/workflows/unit-tests.yml
vendored
Normal file
116
.github/workflows/unit-tests.yml
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
name: Build & Run Unit Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ v2_release, v2_develop ]
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
pull_request:
|
||||
branches: [ v2_release, v2_develop ]
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
|
||||
jobs:
|
||||
non_parallel_unittests:
|
||||
name: Non-Parallel Unit Tests
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
# Turn off fail-fast to let all runners run even if there are errors
|
||||
fail-fast: true
|
||||
matrix:
|
||||
os: [ ubuntu-latest, windows-latest, macos-latest ]
|
||||
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.x
|
||||
dotnet-quality: 'ga'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
dotnet restore
|
||||
|
||||
- name: Build Solution Debug
|
||||
run: dotnet build --configuration Debug --no-restore
|
||||
|
||||
# Test
|
||||
# Note: The --blame and VSTEST_DUMP_PATH stuff is needed to diagnose the test runner crashing on ubuntu/mac
|
||||
# See https://github.com/microsoft/vstest/issues/2952 for why the --blame stuff below is needed.
|
||||
# Without it, the test runner crashes on ubuntu (but not Windows or mac)
|
||||
|
||||
- name: Set VSTEST_DUMP_PATH
|
||||
shell: bash
|
||||
run: echo "{VSTEST_DUMP_PATH}={logs/UnitTests/${{ runner.os }}/}" >> $GITHUB_ENV
|
||||
|
||||
- name: Run UnitTests
|
||||
run: |
|
||||
dotnet test Tests/UnitTests --no-build --verbosity normal --collect:"XPlat Code Coverage" --settings Tests/UnitTests/coverlet.runsettings --diag:logs/UnitTests/${{ runner.os }}/logs.txt --blame --blame-crash --blame-hang --blame-hang-timeout 60s --blame-crash-collect-always -- xunit.stopOnFail=true
|
||||
|
||||
# mv -v Tests/UnitTests/TestResults/*/*.* TestResults/UnitTests/
|
||||
|
||||
- name: Upload Test Logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: non_parallel_unittests-logs-${{ runner.os }}
|
||||
path: |
|
||||
logs/UnitTests
|
||||
TestResults/UnitTests/
|
||||
|
||||
parallel_unittests:
|
||||
name: Parallel Unit Tests
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
# Turn off fail-fast to let all runners run even if there are errors
|
||||
fail-fast: true
|
||||
matrix:
|
||||
os: [ ubuntu-latest, windows-latest, macos-latest ]
|
||||
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.x
|
||||
dotnet-quality: 'ga'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
dotnet restore
|
||||
|
||||
- name: Build Solution Debug
|
||||
run: dotnet build --configuration Debug --no-restore
|
||||
|
||||
# Test
|
||||
# Note: The --blame and VSTEST_DUMP_PATH stuff is needed to diagnose the test runner crashing on ubuntu/mac
|
||||
# See https://github.com/microsoft/vstest/issues/2952 for why the --blame stuff below is needed.
|
||||
# Without it, the test runner crashes on ubuntu (but not Windows or mac)
|
||||
|
||||
- name: Set VSTEST_DUMP_PATH
|
||||
shell: bash
|
||||
run: echo "{VSTEST_DUMP_PATH}={logs/UnitTestsParallelizable/${{ runner.os }}/}" >> $GITHUB_ENV
|
||||
|
||||
- name: Run UnitTestsParallelizable
|
||||
run: |
|
||||
dotnet test Tests/UnitTestsParallelizable --no-build --verbosity normal --collect:"XPlat Code Coverage" --settings Tests/UnitTestsParallelizable/coverlet.runsettings --diag:logs/UnitTestsParallelizable/${{ runner.os }}/logs.txt --blame --blame-crash --blame-hang --blame-hang-timeout 60s --blame-crash-collect-always -- xunit.stopOnFail=true
|
||||
|
||||
# mv -v Tests/UnitTestsParallelizable/TestResults/*/*.* TestResults/UnitTestsParallelizable/
|
||||
|
||||
- name: Upload UnitTestsParallelizable Logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: parallel_unittests-logs-${{ runner.os }}
|
||||
path: |
|
||||
logs/UnitTestsParallelizable/
|
||||
TestResults/UnitTestsParallelizable/
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -60,3 +60,5 @@ demo.*
|
||||
*.dotCover
|
||||
|
||||
logs/
|
||||
|
||||
log.*
|
||||
@@ -2,15 +2,13 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>Terminal.Gui.$(MSBuildProjectName.Replace(" ", "_"))</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BenchmarkDotNet" Version="0.14.0" />
|
||||
<PackageReference Include="BenchmarkDotNet" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -2,14 +2,12 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="[8.2.2,9)" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="[8,9)" />
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
|
||||
<ProjectReference Include="..\Terminal.Gui\Terminal.Gui.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
11
Directory.Build.props
Normal file
11
Directory.Build.props
Normal file
@@ -0,0 +1,11 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<!--<Nullable>enable</Nullable>-->
|
||||
<LangVersion>12</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<DisableDebugIDisposable>false</DisableDebugIDisposable>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
52
Directory.Packages.props
Normal file
52
Directory.Packages.props
Normal file
@@ -0,0 +1,52 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<!-- Enable Nuget Source Link for github -->
|
||||
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="[8,9)" />
|
||||
|
||||
<PackageVersion Include="ColorHelper" Version="[1.8.1,2)" />
|
||||
<PackageVersion Include="JetBrains.Annotations" Version="[2024.2.0,)" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis" Version="[4.10,5)" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Common" Version="[4.10,5)" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="[4.10,5)" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Logging" Version="8.0.0" />
|
||||
<PackageVersion Include="System.IO.Abstractions" Version="[21.0.22,22)" />
|
||||
<PackageVersion Include="System.Text.Json" Version="[8.0.5,9)" />
|
||||
<PackageVersion Include="Wcwidth" Version="[2,3)" />
|
||||
|
||||
<PackageVersion Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="[1.21,2)" />
|
||||
<PackageVersion Include="Serilog" Version="4.2.0" />
|
||||
<PackageVersion Include="Serilog.Extensions.Logging" Version="9.0.0" />
|
||||
<PackageVersion Include="Serilog.Sinks.Debug" Version="3.0.0" />
|
||||
<PackageVersion Include="Serilog.Sinks.File" Version="6.0.0" />
|
||||
<PackageVersion Include="SixLabors.ImageSharp" Version="[3.1.5,4)" />
|
||||
<PackageVersion Include="CsvHelper" Version="[33.0.1,34)" />
|
||||
<PackageVersion Include="Microsoft.DotNet.PlatformAbstractions" Version="[3.1.6,4)" />
|
||||
<PackageVersion Include="System.CommandLine" Version="[2.0.0-beta4.22272.1,3)" />
|
||||
|
||||
<PackageVersion Include="BenchmarkDotNet" Version="0.14.0" />
|
||||
|
||||
<PackageVersion Include="CommunityToolkit.Mvvm" Version="[8.2.2,9)" />
|
||||
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="[8,9)" />
|
||||
<PackageVersion Include="ReactiveUI" Version="[20.1.1,21)" />
|
||||
<PackageVersion Include="ReactiveMarbles.ObservableEvents.SourceGenerator" Version="[1.3.1,2)" />
|
||||
<PackageVersion Include="ReactiveUI.SourceGenerators" Version="[1.0.3,2)"/>
|
||||
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="[17.10,18)" />
|
||||
<PackageVersion Include="Moq" Version="[4.20.70,5)" />
|
||||
<PackageVersion Include="ReportGenerator" Version="[5.3.8,6)" />
|
||||
<PackageVersion Include="TestableIO.System.IO.Abstractions.TestingHelpers" Version="[21.0.29,22)" />
|
||||
<PackageVersion Include="xunit" Version="[2.9.0,3)" />
|
||||
<PackageVersion Include="Xunit.Combinatorial" Version="[1.6.24,2)" />
|
||||
<PackageVersion Include="xunit.runner.visualstudio" Version="[2.8.2,3)"/>
|
||||
<PackageVersion Include="coverlet.collector" Version="[6.0.2,7)" />
|
||||
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<PackageVersion Include="Terminal.Gui" Version="2.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,7 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<!-- Version numbers are automatically updated by gitversion when a release is released -->
|
||||
<!-- In the source tree the version will always be 1.0 for all projects. -->
|
||||
<!-- Do not modify these. -->
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
mode: ContinuousDeployment
|
||||
workflow: GitFlow/v1
|
||||
tag-prefix: '[vV]'
|
||||
continuous-delivery-fallback-tag: dev
|
||||
branches:
|
||||
develop:
|
||||
mode: ContinuousDeployment
|
||||
tag: develop
|
||||
label: develop
|
||||
regex: v2_develop
|
||||
tracks-release-branches: true
|
||||
is-source-branch-for: ['main']
|
||||
@@ -12,14 +11,14 @@ branches:
|
||||
|
||||
main:
|
||||
mode: ContinuousDeployment
|
||||
tag: prealpha
|
||||
label: prealpha
|
||||
regex: v2_release
|
||||
is-release-branch: true
|
||||
source-branches: ['develop']
|
||||
|
||||
v1_develop:
|
||||
mode: ContinuousDeployment
|
||||
tag: v1_develop
|
||||
label: v1_develop
|
||||
regex: v1_develop
|
||||
source-branches:
|
||||
- v1_release
|
||||
@@ -33,9 +32,9 @@ branches:
|
||||
|
||||
pull-request:
|
||||
mode: ContinuousDeployment
|
||||
tag: PullRequest.{BranchName}
|
||||
label: PullRequest.{BranchName}
|
||||
increment: Inherit
|
||||
tag-number-pattern: '[/-](?<number>\d+)'
|
||||
label-number-pattern: '[/-](?<number>\d+)'
|
||||
regex: ^(pull|pull\-requests|pr)[/-]
|
||||
source-branches:
|
||||
- develop
|
||||
@@ -56,13 +55,13 @@ ignore:
|
||||
# branches:
|
||||
# # v1_develop:
|
||||
# # mode: ContinuousDeployment
|
||||
# # tag: pre
|
||||
# # label: pre
|
||||
# # regex: ^v1_develop?[/-]
|
||||
# # is-release-branch: false
|
||||
# # source-branches:
|
||||
# # - v1
|
||||
# # v1:
|
||||
# # tag: rc
|
||||
# # label: rc
|
||||
# # increment: Patch
|
||||
# # regex: ^v2?[/-]
|
||||
# # is-release-branch: false
|
||||
@@ -71,7 +70,7 @@ ignore:
|
||||
|
||||
# v2_develop:
|
||||
# mode: ContinuousDeployment
|
||||
# tag: pre
|
||||
# label: pre
|
||||
# regex: ^v2_develop?[/-]
|
||||
# is-release-branch: true
|
||||
# tracks-release-branches: true
|
||||
@@ -80,13 +79,13 @@ ignore:
|
||||
# v2:
|
||||
# mode: ContinuousDeployment
|
||||
# is-release-branch: false
|
||||
# tag: alpha
|
||||
# label: alpha
|
||||
# increment: Patch
|
||||
# regex: ^v2?[/-]
|
||||
# source-branches: ['v2_develop']
|
||||
|
||||
# # feature:
|
||||
# # tag: useBranchName
|
||||
# # label: useBranchName
|
||||
# # regex: ^features?[/-]
|
||||
# # source-branches:
|
||||
# # - v1
|
||||
@@ -95,7 +94,7 @@ ignore:
|
||||
# # - v2_develop
|
||||
|
||||
# pull-request:
|
||||
# tag: PullRequest.{BranchName}
|
||||
# label: PullRequest.{BranchName}
|
||||
# increment: Inherit
|
||||
# ignore:
|
||||
# sha: []
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<PublishAot>true</PublishAot>
|
||||
<InvariantGlobalization>false</InvariantGlobalization>
|
||||
@@ -15,7 +13,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<PackageReference Include="Terminal.Gui" Version="2.0.0" />
|
||||
<PackageReference Include="Terminal.Gui" />
|
||||
<TrimmerRootAssembly Include="Terminal.Gui" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
"projects": [
|
||||
"Terminal.Gui\\Terminal.Gui.csproj",
|
||||
"UICatalog\\UICatalog.csproj",
|
||||
"UnitTests\\UnitTests.csproj"
|
||||
"Tests\\UnitTests\\UnitTests.csproj",
|
||||
"Tests\\UnitTestsParallelizable\\UnitTests.Parallelizable.csproj",
|
||||
"Tests\\IntegrationTests\\IntegrationTests.csproj",
|
||||
"Tests\\StressTests\\StressTests.csproj"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<!-- Version numbers are automatically updated by gitversion when a release is released -->
|
||||
<!-- In the source tree the version will always be 2.0 for all projects. -->
|
||||
<!-- Do not modify these. -->
|
||||
@@ -11,9 +10,9 @@
|
||||
<InformationalVersion>2.0</InformationalVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ReactiveUI" Version="[20.1.1,21)" />
|
||||
<PackageReference Include="ReactiveMarbles.ObservableEvents.SourceGenerator" Version="[1.3.1,2)" PrivateAssets="all" />
|
||||
<PackageReference Include="ReactiveUI.SourceGenerators" Version="[1.0.3,2)" PrivateAssets="all" />
|
||||
<PackageReference Include="ReactiveUI" />
|
||||
<PackageReference Include="ReactiveMarbles.ObservableEvents.SourceGenerator" PrivateAssets="all" />
|
||||
<PackageReference Include="ReactiveUI.SourceGenerators" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Terminal.Gui\Terminal.Gui.csproj" />
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
"projects": [
|
||||
"Terminal.Gui\\Terminal.Gui.csproj",
|
||||
"UICatalog\\UICatalog.csproj",
|
||||
"UnitTests\\UnitTests.csproj"
|
||||
"Tests\\UnitTests\\UnitTests.csproj",
|
||||
"Tests\\UnitTestsParallelizable\\UnitTests.Parallelizable.csproj",
|
||||
"Tests\\IntegrationTests\\IntegrationTests.csproj",
|
||||
"Tests\\StressTests\\StressTests.csproj"
|
||||
]
|
||||
}
|
||||
}
|
||||
BIN
Scripts/.testloop.sh.swp
Normal file
BIN
Scripts/.testloop.sh.swp
Normal file
Binary file not shown.
92
Scripts/FindDuplicateTestMethodsInSameFileName.ps1
Normal file
92
Scripts/FindDuplicateTestMethodsInSameFileName.ps1
Normal file
@@ -0,0 +1,92 @@
|
||||
# FindDuplicateTestMethodsInSameFileName.ps1
|
||||
param (
|
||||
[string]$solutionPath = ".\Tests"
|
||||
)
|
||||
|
||||
# Set the base path for relative paths (current directory when script is run)
|
||||
$basePath = Get-Location
|
||||
|
||||
# Define projects to ignore (add your project names or path patterns here)
|
||||
$ignoreProjects = @(
|
||||
"StressTests"
|
||||
# Add more as needed, e.g., "Tests/SubFolder/OldProject"
|
||||
)
|
||||
|
||||
# Function to extract method names from a C# file
|
||||
function Get-TestMethodNames {
|
||||
param ($filePath)
|
||||
$content = Get-Content -Path $filePath -Raw
|
||||
$testMethods = @()
|
||||
|
||||
# Match test attributes and capture method names with flexible spacing/comments
|
||||
$methodPattern = '(?s)(\[TestMethod\]|\[Test\]|\[Fact\]|\[Theory\])\s*[\s\S]*?public\s+(?:void|Task)\s+(\w+)\s*\('
|
||||
$methods = [regex]::Matches($content, $methodPattern)
|
||||
|
||||
foreach ($match in $methods) {
|
||||
$methodName = $match.Groups[2].Value # Group 2 is the method name
|
||||
if ($methodName) { # Ensure we only add non-empty method names
|
||||
$testMethods += $methodName
|
||||
}
|
||||
}
|
||||
return $testMethods
|
||||
}
|
||||
|
||||
# Collect all test files
|
||||
$testFiles = Get-ChildItem -Path $solutionPath -Recurse -Include *.cs |
|
||||
Where-Object { $_.FullName -match "Tests" -or $_.FullName -match "Test" }
|
||||
|
||||
# Group files by filename
|
||||
$fileGroups = $testFiles | Group-Object -Property Name
|
||||
|
||||
# Dictionary to track method names and their locations, scoped to same filenames
|
||||
$duplicates = @{}
|
||||
|
||||
foreach ($group in $fileGroups) {
|
||||
if ($group.Count -gt 1) { # Only process files that exist in multiple locations
|
||||
$fileName = $group.Name
|
||||
$methodMap = @{} # Track methods for this specific filename
|
||||
|
||||
foreach ($file in $group.Group) {
|
||||
# Skip files in ignored projects
|
||||
$skipFile = $false
|
||||
foreach ($ignore in $ignoreProjects) {
|
||||
if ($file.FullName -like "*$ignore*") {
|
||||
$skipFile = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
if ($skipFile) { continue }
|
||||
|
||||
$methods = Get-TestMethodNames -filePath $file.FullName
|
||||
foreach ($method in $methods) {
|
||||
if ($methodMap.ContainsKey($method)) {
|
||||
# Duplicate found for this method in the same filename
|
||||
if (-not $duplicates.ContainsKey($method)) {
|
||||
$duplicates[$method] = @($methodMap[$method])
|
||||
}
|
||||
$duplicates[$method] += $file.FullName
|
||||
} else {
|
||||
$methodMap[$method] = $file.FullName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Output results with relative paths
|
||||
if ($duplicates.Count -eq 0) {
|
||||
Write-Host "No duplicate test method names found in files with the same name across projects." -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "Duplicate test method names found in files with the same name across projects:" -ForegroundColor Yellow
|
||||
foreach ($dup in $duplicates.Keys) {
|
||||
Write-Host "Method: $dup" -ForegroundColor Cyan
|
||||
foreach ($fullPath in $duplicates[$dup]) {
|
||||
$relativePath = Resolve-Path -Path $fullPath -Relative -RelativeBasePath $basePath
|
||||
Write-Host " - $relativePath" -ForegroundColor White
|
||||
}
|
||||
}
|
||||
# Display total number of duplicate methods
|
||||
Write-Host "Total number of duplicate methods: $($duplicates.Count)" -ForegroundColor Magenta
|
||||
# Fail the pipeline by setting a non-zero exit code
|
||||
exit 1
|
||||
}
|
||||
50
Scripts/FindDuplicateTests.ps1
Normal file
50
Scripts/FindDuplicateTests.ps1
Normal file
@@ -0,0 +1,50 @@
|
||||
# Define the root directory containing test projects
|
||||
$testsDir = "./Tests"
|
||||
|
||||
# Get all subfolders in the ./Tests directory
|
||||
$subfolders = Get-ChildItem -Directory $testsDir
|
||||
|
||||
# Initialize a hashtable to track method names and their associated subfolders
|
||||
$methodMap = @{}
|
||||
|
||||
# Iterate through each subfolder
|
||||
foreach ($subfolder in $subfolders) {
|
||||
$subfolderName = $subfolder.Name
|
||||
|
||||
# Run dotnet test --list-tests to get the list of tests in the subfolder
|
||||
$output = dotnet test $subfolder.FullName --list-tests | Out-String
|
||||
|
||||
# Split the output into lines and filter for lines containing a dot (indicative of test names)
|
||||
$testLines = $output -split "`n" | Where-Object { $_ -match "\." }
|
||||
|
||||
# Process each test line to extract the method name
|
||||
foreach ($testLine in $testLines) {
|
||||
$trimmed = $testLine.Trim()
|
||||
$parts = $trimmed -split "\."
|
||||
$lastPart = $parts[-1]
|
||||
|
||||
# Handle parameterized tests by extracting the method name before any parentheses
|
||||
if ($lastPart -match "\(") {
|
||||
$methodName = $lastPart.Substring(0, $lastPart.IndexOf("("))
|
||||
} else {
|
||||
$methodName = $lastPart
|
||||
}
|
||||
|
||||
# Update the hashtable with the method name and subfolder
|
||||
if ($methodMap.ContainsKey($methodName)) {
|
||||
# Add the subfolder only if it’s not already listed for this method name
|
||||
if (-not ($methodMap[$methodName] -contains $subfolderName)) {
|
||||
$methodMap[$methodName] += $subfolderName
|
||||
}
|
||||
} else {
|
||||
$methodMap[$methodName] = @($subfolderName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Identify and display duplicated test method names
|
||||
foreach ($entry in $methodMap.GetEnumerator()) {
|
||||
if ($entry.Value.Count -gt 1) {
|
||||
Write-Output "Duplicated test: $($entry.Key) in folders: $($entry.Value -join ', ')"
|
||||
}
|
||||
}
|
||||
30
Scripts/testloop.sh
Executable file
30
Scripts/testloop.sh
Executable file
@@ -0,0 +1,30 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script runs the tests in a loop until they all pass.
|
||||
# It will exit if any test run fails.
|
||||
|
||||
dotnet build -c Debug
|
||||
|
||||
iterationCount=1
|
||||
|
||||
while true; do
|
||||
echo "Starting iteration $iterationCount..."
|
||||
|
||||
dotnet test Tests/UnitTests --no-build --diag:TestResults/UnitTests.log -- xunit.stopOnFail=true
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "UnitTests run failed on iteration $iterationCount. Exiting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dotnet test Tests/UnitTestsParallelizable --no-build --diag:TestResults/UnitTestsParallelizable.log -- xunit.stopOnFail=true
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "UnitTestsParallelizable run failed on iteration $iterationCount. Exiting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Clean up the log files
|
||||
rm log*
|
||||
|
||||
# Increment the iteration counter
|
||||
((iterationCount++))
|
||||
done
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
<TrimMode>Link</TrimMode>
|
||||
@@ -18,7 +16,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<PackageReference Include="Terminal.Gui" Version="2.0.0" />
|
||||
<PackageReference Include="Terminal.Gui" />
|
||||
<TrimmerRootAssembly Include="Terminal.Gui" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -62,7 +62,10 @@ public static partial class Application // Mouse handling
|
||||
}
|
||||
|
||||
#if DEBUG_IDISPOSABLE
|
||||
if (View.DebugIDisposable)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf (MouseGrabView.WasDisposed, MouseGrabView);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!RaiseUnGrabbingMouseEvent (MouseGrabView))
|
||||
@@ -150,7 +153,7 @@ public static partial class Application // Mouse handling
|
||||
if (deepestViewUnderMouse is { })
|
||||
{
|
||||
#if DEBUG_IDISPOSABLE
|
||||
if (deepestViewUnderMouse.WasDisposed)
|
||||
if (View.DebugIDisposable && deepestViewUnderMouse.WasDisposed)
|
||||
{
|
||||
throw new ObjectDisposedException (deepestViewUnderMouse.GetType ().FullName);
|
||||
}
|
||||
@@ -278,7 +281,7 @@ public static partial class Application // Mouse handling
|
||||
if (MouseGrabView is { })
|
||||
{
|
||||
#if DEBUG_IDISPOSABLE
|
||||
if (MouseGrabView.WasDisposed)
|
||||
if (View.DebugIDisposable && MouseGrabView.WasDisposed)
|
||||
{
|
||||
throw new ObjectDisposedException (MouseGrabView.GetType ().FullName);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#nullable enable
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.CodeAnalysis.Diagnostics;
|
||||
|
||||
namespace Terminal.Gui;
|
||||
|
||||
@@ -27,7 +25,6 @@ public static partial class Application // Run (Begin, Run, End, Stop)
|
||||
|
||||
private static Key _arrangeKey = Key.F5.WithCtrl; // Resources/config.json overrides
|
||||
|
||||
|
||||
/// <summary>Gets or sets the key to activate arranging views using the keyboard.</summary>
|
||||
[SerializableConfigurationProperty (Scope = typeof (SettingsScope))]
|
||||
public static Key ArrangeKey
|
||||
@@ -97,7 +94,7 @@ public static partial class Application // Run (Begin, Run, End, Stop)
|
||||
var rs = new RunState (toplevel);
|
||||
|
||||
#if DEBUG_IDISPOSABLE
|
||||
if (Top is { } && toplevel != Top && !TopLevels.Contains (Top))
|
||||
if (View.DebugIDisposable && Top is { } && toplevel != Top && !TopLevels.Contains (Top))
|
||||
{
|
||||
// This assertion confirm if the Top was already disposed
|
||||
Debug.Assert (Top.WasDisposed);
|
||||
@@ -174,7 +171,7 @@ public static partial class Application // Run (Begin, Run, End, Stop)
|
||||
// Force leave events for any entered views in the old Top
|
||||
if (GetLastMousePosition () is { })
|
||||
{
|
||||
RaiseMouseEnterLeaveEvents (GetLastMousePosition ()!.Value, new List<View?> ());
|
||||
RaiseMouseEnterLeaveEvents (GetLastMousePosition ()!.Value, new ());
|
||||
}
|
||||
|
||||
Top?.OnDeactivate (toplevel);
|
||||
@@ -208,7 +205,7 @@ public static partial class Application // Run (Begin, Run, End, Stop)
|
||||
NotifyNewRunState?.Invoke (toplevel, new (rs));
|
||||
|
||||
// Force an Idle event so that an Iteration (and Refresh) happen.
|
||||
Application.Invoke (() => { });
|
||||
Invoke (() => { });
|
||||
|
||||
return rs;
|
||||
}
|
||||
@@ -231,7 +228,7 @@ public static partial class Application // Run (Begin, Run, End, Stop)
|
||||
// If the view is not visible or enabled, don't position the cursor
|
||||
if (mostFocused is null || !mostFocused.Visible || !mostFocused.Enabled)
|
||||
{
|
||||
CursorVisibility current = CursorVisibility.Invisible;
|
||||
var current = CursorVisibility.Invisible;
|
||||
Driver?.GetCursorVisibility (out current);
|
||||
|
||||
if (current != CursorVisibility.Invisible)
|
||||
@@ -244,7 +241,9 @@ public static partial class Application // Run (Begin, Run, End, Stop)
|
||||
|
||||
// If the view is not visible within it's superview, don't position the cursor
|
||||
Rectangle mostFocusedViewport = mostFocused.ViewportToScreen (mostFocused.Viewport with { Location = Point.Empty });
|
||||
Rectangle superViewViewport = mostFocused.SuperView?.ViewportToScreen (mostFocused.SuperView.Viewport with { Location = Point.Empty }) ?? Driver!.Screen;
|
||||
|
||||
Rectangle superViewViewport =
|
||||
mostFocused.SuperView?.ViewportToScreen (mostFocused.SuperView.Viewport with { Location = Point.Empty }) ?? Driver!.Screen;
|
||||
|
||||
if (!superViewViewport.IntersectsWith (mostFocusedViewport))
|
||||
{
|
||||
@@ -305,8 +304,10 @@ public static partial class Application // Run (Begin, Run, End, Stop)
|
||||
/// <returns>The created <see cref="Toplevel"/> object. The caller is responsible for disposing this object.</returns>
|
||||
[RequiresUnreferencedCode ("AOT")]
|
||||
[RequiresDynamicCode ("AOT")]
|
||||
public static Toplevel Run (Func<Exception, bool>? errorHandler = null, IConsoleDriver? driver = null) =>
|
||||
ApplicationImpl.Instance.Run (errorHandler, driver);
|
||||
public static Toplevel Run (Func<Exception, bool>? errorHandler = null, IConsoleDriver? driver = null)
|
||||
{
|
||||
return ApplicationImpl.Instance.Run (errorHandler, driver);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the application by creating a <see cref="Toplevel"/>-derived object of type <c>T</c> and calling
|
||||
@@ -332,7 +333,10 @@ public static partial class Application // Run (Begin, Run, End, Stop)
|
||||
[RequiresUnreferencedCode ("AOT")]
|
||||
[RequiresDynamicCode ("AOT")]
|
||||
public static T Run<T> (Func<Exception, bool>? errorHandler = null, IConsoleDriver? driver = null)
|
||||
where T : Toplevel, new() => ApplicationImpl.Instance.Run<T> (errorHandler, driver);
|
||||
where T : Toplevel, new ()
|
||||
{
|
||||
return ApplicationImpl.Instance.Run<T> (errorHandler, driver);
|
||||
}
|
||||
|
||||
/// <summary>Runs the Application using the provided <see cref="Toplevel"/> view.</summary>
|
||||
/// <remarks>
|
||||
@@ -356,7 +360,8 @@ public static partial class Application // Run (Begin, Run, End, Stop)
|
||||
/// <see cref="RunLoop(RunState)"/> method will only process any pending events, timers, idle handlers and then
|
||||
/// return control immediately.
|
||||
/// </para>
|
||||
/// <para>When using <see cref="Run{T}"/> or
|
||||
/// <para>
|
||||
/// When using <see cref="Run{T}"/> or
|
||||
/// <see cref="Run(System.Func{System.Exception,bool},Terminal.Gui.IConsoleDriver)"/>
|
||||
/// <see cref="Init"/> will be called automatically.
|
||||
/// </para>
|
||||
@@ -372,8 +377,7 @@ public static partial class Application // Run (Begin, Run, End, Stop)
|
||||
/// RELEASE builds only: Handler for any unhandled exceptions (resumes when returns true,
|
||||
/// rethrows when null).
|
||||
/// </param>
|
||||
public static void Run (Toplevel view, Func<Exception, bool>? errorHandler = null)
|
||||
=> ApplicationImpl.Instance.Run (view, errorHandler);
|
||||
public static void Run (Toplevel view, Func<Exception, bool>? errorHandler = null) { ApplicationImpl.Instance.Run (view, errorHandler); }
|
||||
|
||||
/// <summary>Adds a timeout to the application.</summary>
|
||||
/// <remarks>
|
||||
@@ -381,7 +385,7 @@ public static partial class Application // Run (Begin, Run, End, Stop)
|
||||
/// reset, repeating the invocation. If it returns false, the timeout will stop and be removed. The returned value is a
|
||||
/// token that can be used to stop the timeout by calling <see cref="RemoveTimeout(object)"/>.
|
||||
/// </remarks>
|
||||
public static object? AddTimeout (TimeSpan time, Func<bool> callback) => ApplicationImpl.Instance.AddTimeout (time, callback);
|
||||
public static object? AddTimeout (TimeSpan time, Func<bool> callback) { return ApplicationImpl.Instance.AddTimeout (time, callback); }
|
||||
|
||||
/// <summary>Removes a previously scheduled timeout</summary>
|
||||
/// <remarks>The token parameter is the value returned by <see cref="AddTimeout"/>.</remarks>
|
||||
@@ -393,11 +397,11 @@ public static partial class Application // Run (Begin, Run, End, Stop)
|
||||
/// This method also returns
|
||||
/// <see langword="false"/>
|
||||
/// if the timeout is not found.
|
||||
public static bool RemoveTimeout (object token) => ApplicationImpl.Instance.RemoveTimeout (token);
|
||||
public static bool RemoveTimeout (object token) { return ApplicationImpl.Instance.RemoveTimeout (token); }
|
||||
|
||||
/// <summary>Runs <paramref name="action"/> on the thread that is processing events</summary>
|
||||
/// <param name="action">the action to be invoked on the main processing thread.</param>
|
||||
public static void Invoke (Action action) => ApplicationImpl.Instance.Invoke (action);
|
||||
public static void Invoke (Action action) { ApplicationImpl.Instance.Invoke (action); }
|
||||
|
||||
// TODO: Determine if this is really needed. The only code that calls WakeUp I can find
|
||||
// is ProgressBarStyles, and it's not clear it needs to.
|
||||
@@ -406,14 +410,15 @@ public static partial class Application // Run (Begin, Run, End, Stop)
|
||||
public static void Wakeup () { MainLoop?.Wakeup (); }
|
||||
|
||||
/// <summary>
|
||||
/// Causes any Toplevels that need layout to be laid out. Then draws any Toplevels that need display. Only Views that need to be laid out (see <see cref="View.NeedsLayout"/>) will be laid out.
|
||||
/// Causes any Toplevels that need layout to be laid out. Then draws any Toplevels that need display. Only Views that
|
||||
/// need to be laid out (see <see cref="View.NeedsLayout"/>) will be laid out.
|
||||
/// Only Views that need to be drawn (see <see cref="View.NeedsDraw"/>) will be drawn.
|
||||
/// </summary>
|
||||
/// <param name="forceDraw">If <see langword="true"/> the entire View hierarchy will be redrawn. The default is <see langword="false"/> and should only be overriden for testing.</param>
|
||||
public static void LayoutAndDraw (bool forceDraw = false)
|
||||
{
|
||||
ApplicationImpl.Instance.LayoutAndDraw (forceDraw);
|
||||
}
|
||||
/// <param name="forceDraw">
|
||||
/// If <see langword="true"/> the entire View hierarchy will be redrawn. The default is <see langword="false"/> and
|
||||
/// should only be overriden for testing.
|
||||
/// </param>
|
||||
public static void LayoutAndDraw (bool forceDraw = false) { ApplicationImpl.Instance.LayoutAndDraw (forceDraw); }
|
||||
|
||||
internal static void LayoutAndDrawImpl (bool forceDraw = false)
|
||||
{
|
||||
@@ -424,6 +429,7 @@ public static partial class Application // Run (Begin, Run, End, Stop)
|
||||
forceDraw = true;
|
||||
ClearScreenNextIteration = false;
|
||||
}
|
||||
|
||||
if (forceDraw)
|
||||
{
|
||||
Driver?.ClearContents ();
|
||||
@@ -521,11 +527,13 @@ public static partial class Application // Run (Begin, Run, End, Stop)
|
||||
/// <remarks>
|
||||
/// <para>This will cause <see cref="Application.Run(Toplevel, Func{Exception, bool})"/> to return.</para>
|
||||
/// <para>
|
||||
/// Calling <see cref="RequestStop(Terminal.Gui.Toplevel)"/> is equivalent to setting the <see cref="Toplevel.Running"/>
|
||||
/// Calling <see cref="RequestStop(Terminal.Gui.Toplevel)"/> is equivalent to setting the
|
||||
/// <see cref="Toplevel.Running"/>
|
||||
/// property on the currently running <see cref="Toplevel"/> to false.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public static void RequestStop (Toplevel? top = null) => ApplicationImpl.Instance.RequestStop (top);
|
||||
public static void RequestStop (Toplevel? top = null) { ApplicationImpl.Instance.RequestStop (top); }
|
||||
|
||||
internal static void OnNotifyStopRunState (Toplevel top)
|
||||
{
|
||||
if (EndAfterFirstIteration)
|
||||
|
||||
@@ -63,7 +63,7 @@ public static partial class Application
|
||||
{
|
||||
Rune rune = contents [r, c].Rune;
|
||||
|
||||
if (rune.DecodeSurrogatePair (out char [] sp))
|
||||
if (rune.DecodeSurrogatePair (out char []? sp))
|
||||
{
|
||||
sb.Append (sp);
|
||||
}
|
||||
@@ -152,7 +152,7 @@ public static partial class Application
|
||||
#if DEBUG_IDISPOSABLE
|
||||
|
||||
// Don't dispose the Top. It's up to caller dispose it
|
||||
if (!ignoreDisposed && Top is { })
|
||||
if (View.DebugIDisposable && !ignoreDisposed && Top is { })
|
||||
{
|
||||
Debug.Assert (Top.WasDisposed);
|
||||
|
||||
@@ -173,6 +173,7 @@ public static partial class Application
|
||||
MainThreadId = -1;
|
||||
Iteration = null;
|
||||
EndAfterFirstIteration = false;
|
||||
ClearScreenNextIteration = false;
|
||||
|
||||
// Driver stuff
|
||||
if (Driver is { })
|
||||
@@ -212,7 +213,6 @@ public static partial class Application
|
||||
|
||||
Navigation = null;
|
||||
|
||||
ClearScreenNextIteration = false;
|
||||
|
||||
KeyBindings.Clear ();
|
||||
AddKeyBindings ();
|
||||
|
||||
@@ -176,7 +176,10 @@ public class ApplicationImpl : IApplication
|
||||
if (runState.Toplevel is null)
|
||||
{
|
||||
#if DEBUG_IDISPOSABLE
|
||||
if (View.DebugIDisposable)
|
||||
{
|
||||
Debug.Assert (Application.TopLevels.Count == 0);
|
||||
}
|
||||
#endif
|
||||
runState.Dispose ();
|
||||
|
||||
|
||||
@@ -22,7 +22,10 @@ public class RunState : IDisposable
|
||||
Dispose (true);
|
||||
GC.SuppressFinalize (this);
|
||||
#if DEBUG_IDISPOSABLE
|
||||
if (View.DebugIDisposable)
|
||||
{
|
||||
WasDisposed = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -52,6 +55,12 @@ public class RunState : IDisposable
|
||||
public static List<RunState> Instances = new ();
|
||||
|
||||
/// <summary>Creates a new RunState object.</summary>
|
||||
public RunState () { Instances.Add (this); }
|
||||
public RunState ()
|
||||
{
|
||||
if (View.DebugIDisposable)
|
||||
{
|
||||
Instances.Add (this);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -326,6 +326,9 @@ public static class ConfigurationManager
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Logs any Json deserialization errors that occurred during deserialization to the logging system.
|
||||
/// </summary>
|
||||
public static void LogJsonErrors ()
|
||||
{
|
||||
if (_jsonErrors.Length > 0)
|
||||
|
||||
@@ -91,7 +91,7 @@ internal class ScopeJsonConverter<[DynamicallyAccessedMembers (DynamicallyAccess
|
||||
scope! [propertyName].PropertyValue =
|
||||
JsonSerializer.Deserialize (ref reader, propertyType!, SerializerContext);
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception)
|
||||
{
|
||||
// Logging.Trace ($"scopeT Read: {ex}");
|
||||
}
|
||||
|
||||
@@ -52,6 +52,11 @@ public class CsiKeyPattern : AnsiKeyboardParserPattern
|
||||
_pattern = new (@$"^\u001b\[(1;(\d+))?([{terms}]|\d+~)$");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
protected override Key? GetKeyImpl (string input)
|
||||
{
|
||||
Match match = _pattern.Match (input);
|
||||
@@ -66,7 +71,7 @@ public class CsiKeyPattern : AnsiKeyboardParserPattern
|
||||
|
||||
Key? key = _terminators.GetValueOrDefault (terminator);
|
||||
|
||||
if (key != null && int.TryParse (modifierGroup, out int modifier))
|
||||
if (key is {} && int.TryParse (modifierGroup, out int modifier))
|
||||
{
|
||||
key = modifier switch
|
||||
{
|
||||
|
||||
@@ -12,22 +12,24 @@
|
||||
<!-- Assembly name. -->
|
||||
<!-- Referenced throughout this file for consistency. -->
|
||||
<!-- =================================================================== -->
|
||||
<PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<AssemblyName>Terminal.Gui</AssemblyName>
|
||||
</PropertyGroup>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- =================================================================== -->
|
||||
<!-- .NET Build Settings -->
|
||||
<!-- =================================================================== -->
|
||||
<PropertyGroup>
|
||||
<!--Note - These three SHOULD be picked up from Directory.Build.props, but they are not. Not sure why. -->
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<LangVersion>12</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<!-- -->
|
||||
<RootNamespace>$(AssemblyName)</RootNamespace>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<DefineTrace>true</DefineTrace>
|
||||
<DebugType>portable</DebugType>
|
||||
<DefineConstants>$(DefineConstants);CONTRACTS_FULL;CODE_ANALYSIS</DefineConstants>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<NoLogo>true</NoLogo>
|
||||
<SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage>
|
||||
<JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
|
||||
@@ -53,17 +55,17 @@
|
||||
<!-- Dependencies -->
|
||||
<!-- =================================================================== -->
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ColorHelper" Version="[1.8.1,2)" />
|
||||
<PackageReference Include="JetBrains.Annotations" Version="[2024.2.0,)" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis" Version="[4.10,5)" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="[4.10,5)" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="[4.10,5)" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
|
||||
<PackageReference Include="ColorHelper" />
|
||||
<PackageReference Include="JetBrains.Annotations" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Common" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" />
|
||||
<PackageReference Include="System.IO.Abstractions" />
|
||||
<PackageReference Include="System.Text.Json" />
|
||||
<PackageReference Include="Wcwidth" />
|
||||
<!-- Enable Nuget Source Link for github -->
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="[8,9)" PrivateAssets="all" />
|
||||
<PackageReference Include="System.IO.Abstractions" Version="[21.0.22,22)" />
|
||||
<PackageReference Include="System.Text.Json" Version="[8.0.5,9)" />
|
||||
<PackageReference Include="Wcwidth" Version="[2,3)" />
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" />
|
||||
</ItemGroup>
|
||||
<!-- =================================================================== -->
|
||||
<!-- Global Usings and Type Aliases -->
|
||||
@@ -80,6 +82,9 @@
|
||||
<!-- =================================================================== -->
|
||||
<ItemGroup>
|
||||
<InternalsVisibleTo Include="UnitTests" />
|
||||
<InternalsVisibleTo Include="UnitTests.Parallelizable" />
|
||||
<InternalsVisibleTo Include="StressTests" />
|
||||
<InternalsVisibleTo Include="IntegrationTests" />
|
||||
<InternalsVisibleTo Include="TerminalGuiDesigner" />
|
||||
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
|
||||
</ItemGroup>
|
||||
@@ -144,7 +149,11 @@
|
||||
<EnableSourceLink>true</EnableSourceLink>
|
||||
<Authors>Miguel de Icaza, Tig Kindel (@tig), @BDisp</Authors>
|
||||
</PropertyGroup>
|
||||
<ProjectExtensions><VisualStudio><UserProperties resources_4config_1json__JsonSchema="../../docfx/schemas/tui-config-schema.json" /></VisualStudio></ProjectExtensions>
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<UserProperties resources_4config_1json__JsonSchema="../../docfx/schemas/tui-config-schema.json" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
|
||||
<Target Name="CopyNuGetPackagesToLocalPackagesFolder" AfterTargets="Pack" Condition="'$(Configuration)' == 'Release'">
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
namespace Terminal.Gui;
|
||||
|
||||
/// <summary>
|
||||
/// Tracks the region that has been drawn during <see cref="View.Draw"/>. This is primarily
|
||||
/// Tracks the region that has been drawn during <see cref="View.Draw(DrawContext?)"/>. This is primarily
|
||||
/// in support of <see cref="ViewportSettings.Transparent"/>.
|
||||
/// </summary>
|
||||
public class DrawContext
|
||||
|
||||
@@ -16,7 +16,7 @@ public class DrawEventArgs : CancelEventArgs
|
||||
/// <see cref="View"/>.
|
||||
/// </param>
|
||||
/// <param name="drawContext">
|
||||
/// Add any regions that have been drawn to during <see cref="View.Draw"/> operations to this context. This is
|
||||
/// Add any regions that have been drawn to during <see cref="View.Draw(DrawContext?)"/> operations to this context. This is
|
||||
/// primarily
|
||||
/// in support of <see cref="ViewportSettings.Transparent"/>.
|
||||
/// </param>
|
||||
@@ -34,7 +34,7 @@ public class DrawEventArgs : CancelEventArgs
|
||||
public Rectangle NewViewport { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Add any regions that have been drawn to during <see cref="View.Draw"/> operations to this context. This is
|
||||
/// Add any regions that have been drawn to during <see cref="View.Draw(DrawContext?)"/> operations to this context. This is
|
||||
/// primarily
|
||||
/// in support of <see cref="ViewportSettings.Transparent"/>.
|
||||
/// </summary>
|
||||
|
||||
@@ -762,6 +762,7 @@ public partial class View // Mouse APIs
|
||||
/// INTERNAL: Gets the Views that are under the mouse at <paramref name="location"/>, including Adornments.
|
||||
/// </summary>
|
||||
/// <param name="location"></param>
|
||||
/// <param name="ignoreTransparent"></param>
|
||||
/// <returns></returns>
|
||||
internal static List<View?> GetViewsUnderMouse (in Point location, bool ignoreTransparent = false)
|
||||
{
|
||||
|
||||
@@ -24,6 +24,83 @@ namespace Terminal.Gui;
|
||||
|
||||
public partial class View : IDisposable, ISupportInitializeNotification
|
||||
{
|
||||
private bool _disposedValue;
|
||||
|
||||
/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resource.</summary>
|
||||
public void Dispose ()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
Disposing?.Invoke (this, EventArgs.Empty);
|
||||
Dispose (true);
|
||||
GC.SuppressFinalize (this);
|
||||
#if DEBUG_IDISPOSABLE
|
||||
if (DebugIDisposable)
|
||||
{
|
||||
WasDisposed = true;
|
||||
|
||||
foreach (View? instance in Instances.Where (
|
||||
x =>
|
||||
{
|
||||
if (x is { })
|
||||
{
|
||||
return x.WasDisposed;
|
||||
}
|
||||
|
||||
return false;
|
||||
})
|
||||
.ToList ())
|
||||
{
|
||||
Instances.Remove (instance);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Riased when the <see cref="View"/> is being disposed.
|
||||
/// </summary>
|
||||
public event EventHandler? Disposing;
|
||||
|
||||
/// <summary>Pretty prints the View</summary>
|
||||
/// <returns></returns>
|
||||
public override string ToString () { return $"{GetType ().Name}({Id}){Frame}"; }
|
||||
|
||||
/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
|
||||
/// <remarks>
|
||||
/// If disposing equals true, the method has been called directly or indirectly by a user's code. Managed and
|
||||
/// unmanaged resources can be disposed. If disposing equals false, the method has been called by the runtime from
|
||||
/// inside the finalizer and you should not reference other objects. Only unmanaged resources can be disposed.
|
||||
/// </remarks>
|
||||
/// <param name="disposing"></param>
|
||||
protected virtual void Dispose (bool disposing)
|
||||
{
|
||||
LineCanvas.Dispose ();
|
||||
|
||||
DisposeMouse ();
|
||||
DisposeKeyboard ();
|
||||
DisposeAdornments ();
|
||||
DisposeScrollBars ();
|
||||
|
||||
for (int i = InternalSubviews.Count - 1; i >= 0; i--)
|
||||
{
|
||||
View subview = InternalSubviews [i];
|
||||
Remove (subview);
|
||||
subview.Dispose ();
|
||||
}
|
||||
|
||||
if (!_disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// TODO: dispose managed state (managed objects)
|
||||
}
|
||||
|
||||
_disposedValue = true;
|
||||
}
|
||||
|
||||
Debug.Assert (InternalSubviews.Count == 0);
|
||||
}
|
||||
|
||||
#region Constructors and Initialization
|
||||
|
||||
/// <summary>Gets or sets arbitrary data for the view.</summary>
|
||||
@@ -51,7 +128,10 @@ public partial class View : IDisposable, ISupportInitializeNotification
|
||||
public View ()
|
||||
{
|
||||
#if DEBUG_IDISPOSABLE
|
||||
if (DebugIDisposable)
|
||||
{
|
||||
Instances.Add (this);
|
||||
}
|
||||
#endif
|
||||
|
||||
SetupAdornments ();
|
||||
@@ -168,6 +248,7 @@ public partial class View : IDisposable, ISupportInitializeNotification
|
||||
// TODO: Figure out how to move this out of here and just depend on LayoutNeeded in Mainloop
|
||||
Layout (); // the EventLog in AllViewsTester fails to layout correctly if this is not here (convoluted Dim.Fill(Func)).
|
||||
}
|
||||
|
||||
SetNeedsLayout ();
|
||||
|
||||
Initialized?.Invoke (this, EventArgs.Empty);
|
||||
@@ -371,7 +452,7 @@ public partial class View : IDisposable, ISupportInitializeNotification
|
||||
get
|
||||
{
|
||||
#if DEBUG_IDISPOSABLE
|
||||
if (WasDisposed)
|
||||
if (DebugIDisposable && WasDisposed)
|
||||
{
|
||||
throw new ObjectDisposedException (GetType ().FullName);
|
||||
}
|
||||
@@ -381,7 +462,7 @@ public partial class View : IDisposable, ISupportInitializeNotification
|
||||
set
|
||||
{
|
||||
#if DEBUG_IDISPOSABLE
|
||||
if (WasDisposed)
|
||||
if (DebugIDisposable && WasDisposed)
|
||||
{
|
||||
throw new ObjectDisposedException (GetType ().FullName);
|
||||
}
|
||||
@@ -450,71 +531,12 @@ public partial class View : IDisposable, ISupportInitializeNotification
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>Pretty prints the View</summary>
|
||||
/// <returns></returns>
|
||||
public override string ToString () { return $"{GetType ().Name}({Id}){Frame}"; }
|
||||
|
||||
private bool _disposedValue;
|
||||
|
||||
/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
|
||||
/// <remarks>
|
||||
/// If disposing equals true, the method has been called directly or indirectly by a user's code. Managed and
|
||||
/// unmanaged resources can be disposed. If disposing equals false, the method has been called by the runtime from
|
||||
/// inside the finalizer and you should not reference other objects. Only unmanaged resources can be disposed.
|
||||
/// </remarks>
|
||||
/// <param name="disposing"></param>
|
||||
protected virtual void Dispose (bool disposing)
|
||||
{
|
||||
LineCanvas.Dispose ();
|
||||
|
||||
DisposeMouse ();
|
||||
DisposeKeyboard ();
|
||||
DisposeAdornments ();
|
||||
DisposeScrollBars ();
|
||||
|
||||
for (int i = InternalSubviews.Count - 1; i >= 0; i--)
|
||||
{
|
||||
View subview = InternalSubviews [i];
|
||||
Remove (subview);
|
||||
subview.Dispose ();
|
||||
}
|
||||
|
||||
if (!_disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// TODO: dispose managed state (managed objects)
|
||||
}
|
||||
|
||||
_disposedValue = true;
|
||||
}
|
||||
|
||||
Debug.Assert (InternalSubviews.Count == 0);
|
||||
}
|
||||
|
||||
#if DEBUG_IDISPOSABLE
|
||||
/// <summary>
|
||||
/// Riased when the <see cref="View"/> is being disposed.
|
||||
/// Set to false to disable the debug IDisposable feature.
|
||||
/// </summary>
|
||||
public event EventHandler? Disposing;
|
||||
public static bool DebugIDisposable { get; set; } = false;
|
||||
|
||||
/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resource.</summary>
|
||||
public void Dispose ()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
Disposing?.Invoke (this, EventArgs.Empty);
|
||||
Dispose (true);
|
||||
GC.SuppressFinalize (this);
|
||||
#if DEBUG_IDISPOSABLE
|
||||
WasDisposed = true;
|
||||
|
||||
foreach (View instance in Instances.Where (x => x.WasDisposed).ToList ())
|
||||
{
|
||||
Instances.Remove (instance);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if DEBUG_IDISPOSABLE
|
||||
/// <summary>For debug purposes to verify objects are being disposed properly</summary>
|
||||
public bool WasDisposed { get; set; }
|
||||
|
||||
|
||||
@@ -109,11 +109,13 @@ public class Bar : View, IOrientation, IDesignable
|
||||
set => _orientationHelper.Orientation = value;
|
||||
}
|
||||
|
||||
#pragma warning disable CS0067 // The event is never used
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<CancelEventArgs<Orientation>>? OrientationChanging;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<EventArgs<Orientation>>? OrientationChanged;
|
||||
#pragma warning restore CS0067 // The event is never used
|
||||
|
||||
/// <summary>Called when <see cref="Orientation"/> has changed.</summary>
|
||||
/// <param name="newOrientation"></param>
|
||||
|
||||
@@ -107,7 +107,7 @@ public class Dialog : Window
|
||||
get
|
||||
{
|
||||
#if DEBUG_IDISPOSABLE
|
||||
if (WasDisposed)
|
||||
if (View.DebugIDisposable && WasDisposed)
|
||||
{
|
||||
throw new ObjectDisposedException (GetType ().FullName);
|
||||
}
|
||||
@@ -117,7 +117,7 @@ public class Dialog : Window
|
||||
set
|
||||
{
|
||||
#if DEBUG_IDISPOSABLE
|
||||
if (WasDisposed)
|
||||
if (View.DebugIDisposable && WasDisposed)
|
||||
{
|
||||
throw new ObjectDisposedException (GetType ().FullName);
|
||||
}
|
||||
|
||||
@@ -33,11 +33,13 @@ public class Line : View, IOrientation
|
||||
set => _orientationHelper.Orientation = value;
|
||||
}
|
||||
|
||||
#pragma warning disable CS0067 // The event is never used
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<CancelEventArgs<Orientation>> OrientationChanging;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<EventArgs<Orientation>> OrientationChanged;
|
||||
#pragma warning restore CS0067 // The event is never used
|
||||
|
||||
/// <summary>Called when <see cref="Orientation"/> has changed.</summary>
|
||||
/// <param name="newOrientation"></param>
|
||||
|
||||
@@ -403,11 +403,13 @@ public class RadioGroup : View, IDesignable, IOrientation
|
||||
|
||||
private readonly OrientationHelper _orientationHelper;
|
||||
|
||||
#pragma warning disable CS0067 // The event is never used
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<CancelEventArgs<Orientation>>? OrientationChanging;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<EventArgs<Orientation>>? OrientationChanged;
|
||||
#pragma warning restore CS0067 // The event is never used
|
||||
|
||||
/// <summary>Called when <see cref="Orientation"/> has changed.</summary>
|
||||
/// <param name="newOrientation"></param>
|
||||
|
||||
@@ -164,11 +164,13 @@ public class ScrollBar : View, IOrientation, IDesignable
|
||||
set => _orientationHelper.Orientation = value;
|
||||
}
|
||||
|
||||
#pragma warning disable CS0067 // The event is never used
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<CancelEventArgs<Orientation>>? OrientationChanging;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<EventArgs<Orientation>>? OrientationChanged;
|
||||
#pragma warning restore CS0067 // The event is never used
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void OnOrientationChanged (Orientation newOrientation)
|
||||
|
||||
@@ -125,7 +125,7 @@ public class WizardStep : View
|
||||
{
|
||||
_contentView.Add (view);
|
||||
|
||||
if (view.CanFocus)
|
||||
if (view!.CanFocus)
|
||||
{
|
||||
CanFocus = true;
|
||||
}
|
||||
|
||||
38
Terminal.sln
38
Terminal.sln
@@ -6,8 +6,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Terminal.Gui", "Terminal.Gu
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UICatalog", "UICatalog\UICatalog.csproj", "{88979F89-9A42-448F-AE3E-3060145F6375}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests", "UnitTests\UnitTests.csproj", "{8B901EDE-8974-4820-B100-5226917E2990}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveExample", "ReactiveExample\ReactiveExample.csproj", "{44E15B48-0DB2-4560-82BD-D3B7989811C3}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example", "Example\Example.csproj", "{B0A602CD-E176-449D-8663-64238D54F857}"
|
||||
@@ -21,6 +19,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Settings", "Settings", "{B8
|
||||
.editorconfig = .editorconfig
|
||||
.filenesting.json = .filenesting.json
|
||||
.gitignore = .gitignore
|
||||
Directory.Build.props = Directory.Build.props
|
||||
Directory.Packages.props = Directory.Packages.props
|
||||
GitVersion.yml = GitVersion.yml
|
||||
global.json = global.json
|
||||
nuget.config = nuget.config
|
||||
@@ -31,9 +31,13 @@ EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GitHub", "GitHub", "{13BB2C46-B324-4B9C-92EB-CE6184D4736E}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.github\workflows\api-docs.yml = .github\workflows\api-docs.yml
|
||||
.github\workflows\dotnet-core.yml = .github\workflows\dotnet-core.yml
|
||||
.github\workflows\build-release.yml = .github\workflows\build-release.yml
|
||||
.github\workflows\check-duplicates.yml = .github\workflows\check-duplicates.yml
|
||||
GitVersion.yml = GitVersion.yml
|
||||
.github\workflows\integration-tests.yml = .github\workflows\integration-tests.yml
|
||||
.github\workflows\publish.yml = .github\workflows\publish.yml
|
||||
.github\workflows\stress-tests.yml = .github\workflows\stress-tests.yml
|
||||
.github\workflows\unit-tests.yml = .github\workflows\unit-tests.yml
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{C7A51224-5E0F-4986-AB37-A6BF89966C12}"
|
||||
@@ -50,6 +54,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NativeAot", "NativeAot\Nati
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmarks", "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}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IntegrationTests", "Tests\IntegrationTests\IntegrationTests.csproj", "{F74EC349-B988-FCFA-A1E5-967F70FB75B5}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StressTests", "Tests\StressTests\StressTests.csproj", "{96ACE8BA-2E07-7537-FBF2-E8176CCB8080}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests.Parallelizable", "Tests\UnitTestsParallelizable\UnitTests.Parallelizable.csproj", "{DE780834-190A-8277-51FD-750CC666E82D}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -64,10 +76,6 @@ Global
|
||||
{88979F89-9A42-448F-AE3E-3060145F6375}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{88979F89-9A42-448F-AE3E-3060145F6375}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{88979F89-9A42-448F-AE3E-3060145F6375}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8B901EDE-8974-4820-B100-5226917E2990}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8B901EDE-8974-4820-B100-5226917E2990}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8B901EDE-8974-4820-B100-5226917E2990}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8B901EDE-8974-4820-B100-5226917E2990}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{44E15B48-0DB2-4560-82BD-D3B7989811C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{44E15B48-0DB2-4560-82BD-D3B7989811C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{44E15B48-0DB2-4560-82BD-D3B7989811C3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
@@ -92,6 +100,22 @@ Global
|
||||
{242FBD3E-2EC6-4274-BD40-8E62AF9327B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{242FBD3E-2EC6-4274-BD40-8E62AF9327B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{242FBD3E-2EC6-4274-BD40-8E62AF9327B2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{038B09F5-EF3A-F21E-7C10-A6551866ECE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{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
|
||||
{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
|
||||
{F74EC349-B988-FCFA-A1E5-967F70FB75B5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{96ACE8BA-2E07-7537-FBF2-E8176CCB8080}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{96ACE8BA-2E07-7537-FBF2-E8176CCB8080}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{96ACE8BA-2E07-7537-FBF2-E8176CCB8080}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{96ACE8BA-2E07-7537-FBF2-E8176CCB8080}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DE780834-190A-8277-51FD-750CC666E82D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DE780834-190A-8277-51FD-750CC666E82D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DE780834-190A-8277-51FD-750CC666E82D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DE780834-190A-8277-51FD-750CC666E82D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -409,10 +409,12 @@
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002EMemberReordering_002EMigrations_002ECSharpFileLayoutPatternRemoveIsAttributeUpgrade/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Int64 x:Key="/Default/Environment/UnitTesting/ParallelProcessesCount/@EntryValue">5</s:Int64>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Justifier/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=langword/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Roslynator/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Toplevel/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Toplevels/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Ungrab/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=unsynchronized/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=BUGBUG/@EntryIndexedValue">True</s:Boolean>
|
||||
|
||||
40
Tests/IntegrationTests/IntegrationTests.csproj
Normal file
40
Tests/IntegrationTests/IntegrationTests.csproj
Normal file
@@ -0,0 +1,40 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
<DefineConstants>$(DefineConstants);JETBRAINS_ANNOTATIONS;CONTRACTS_FULL</DefineConstants>
|
||||
<DebugType>portable</DebugType>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<NoLogo>true</NoLogo>
|
||||
<SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<DefineDebug>true</DefineDebug>
|
||||
<DefineConstants>$(DefineConstants);DEBUG_IDISPOSABLE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
||||
<Optimize>true</Optimize>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" />
|
||||
<PackageReference Include="xunit" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Terminal.Gui\Terminal.Gui.csproj" />
|
||||
<ProjectReference Include="..\..\UICatalog\UICatalog.csproj" />
|
||||
<ProjectReference Include="..\UnitTests\UnitTests.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="xunit.runner.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,15 +1,19 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using Terminal.Gui;
|
||||
using UnitTests;
|
||||
using UICatalog;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace UICatalog.Tests;
|
||||
namespace IntegrationTests.UICatalog;
|
||||
|
||||
public class ScenarioTests : TestsAllViews
|
||||
{
|
||||
public ScenarioTests (ITestOutputHelper output)
|
||||
{
|
||||
#if DEBUG_IDISPOSABLE
|
||||
View.DebugIDisposable = true;
|
||||
View.Instances.Clear ();
|
||||
#endif
|
||||
_output = output;
|
||||
@@ -137,168 +141,6 @@ public class ScenarioTests : TestsAllViews
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>This runs through all Scenarios defined in UI Catalog, calling Init, Setup, and Run and measuring the perf of each.</para>
|
||||
/// </summary>
|
||||
[Theory]
|
||||
[MemberData (nameof (AllScenarioTypes))]
|
||||
public void All_Scenarios_Benchmark (Type scenarioType)
|
||||
{
|
||||
Assert.Null (_timeoutLock);
|
||||
_timeoutLock = new ();
|
||||
|
||||
// Disable any UIConfig settings
|
||||
ConfigLocations savedConfigLocations = ConfigurationManager.Locations;
|
||||
ConfigurationManager.Locations = ConfigLocations.Default;
|
||||
|
||||
// If a previous test failed, this will ensure that the Application is in a clean state
|
||||
Application.ResetState (true);
|
||||
|
||||
uint maxIterations = 1000;
|
||||
uint abortTime = 2000;
|
||||
object timeout = null;
|
||||
var initialized = false;
|
||||
var shutdown = false;
|
||||
|
||||
int iterationCount = 0;
|
||||
int clearedContentCount = 0;
|
||||
int refreshedCount = 0;
|
||||
int updatedCount = 0;
|
||||
int drawCompleteCount = 0;
|
||||
|
||||
int addedCount = 0;
|
||||
int laidOutCount = 0;
|
||||
|
||||
_output.WriteLine ($"Running Scenario '{scenarioType}'");
|
||||
var scenario = (Scenario)Activator.CreateInstance (scenarioType);
|
||||
|
||||
Stopwatch stopwatch = null;
|
||||
|
||||
Application.InitializedChanged += OnApplicationOnInitializedChanged;
|
||||
Application.ForceDriver = "FakeDriver";
|
||||
scenario!.Main ();
|
||||
scenario.Dispose ();
|
||||
scenario = null;
|
||||
Application.ForceDriver = string.Empty;
|
||||
Application.InitializedChanged -= OnApplicationOnInitializedChanged;
|
||||
|
||||
lock (_timeoutLock)
|
||||
{
|
||||
if (timeout is { })
|
||||
{
|
||||
timeout = null;
|
||||
}
|
||||
}
|
||||
|
||||
lock (_timeoutLock)
|
||||
{
|
||||
_timeoutLock = null;
|
||||
}
|
||||
|
||||
_output.WriteLine ($"Scenario {scenarioType}");
|
||||
_output.WriteLine ($" took {stopwatch.ElapsedMilliseconds} ms to run.");
|
||||
_output.WriteLine ($" called Driver.ClearContents {clearedContentCount} times.");
|
||||
_output.WriteLine ($" called Driver.Refresh {refreshedCount} times.");
|
||||
_output.WriteLine ($" which updated the screen {updatedCount} times.");
|
||||
_output.WriteLine ($" called View.Draw {drawCompleteCount} times.");
|
||||
_output.WriteLine ($" added {addedCount} views.");
|
||||
_output.WriteLine ($" called View.LayoutComplete {laidOutCount} times.");
|
||||
|
||||
// Restore the configuration locations
|
||||
ConfigurationManager.Locations = savedConfigLocations;
|
||||
ConfigurationManager.Reset ();
|
||||
|
||||
return;
|
||||
|
||||
void OnApplicationOnInitializedChanged (object s, EventArgs<bool> a)
|
||||
{
|
||||
if (a.CurrentValue)
|
||||
{
|
||||
lock (_timeoutLock)
|
||||
{
|
||||
timeout = Application.AddTimeout (TimeSpan.FromMilliseconds (abortTime), ForceCloseCallback);
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
Application.Iteration += OnApplicationOnIteration;
|
||||
Application.Driver!.ClearedContents += (sender, args) => clearedContentCount++;
|
||||
|
||||
if (Application.Driver is ConsoleDriver cd)
|
||||
{
|
||||
cd!.Refreshed += (sender, args) =>
|
||||
{
|
||||
refreshedCount++;
|
||||
|
||||
if (args.CurrentValue)
|
||||
{
|
||||
updatedCount++;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Application.NotifyNewRunState += OnApplicationNotifyNewRunState;
|
||||
|
||||
stopwatch = Stopwatch.StartNew ();
|
||||
}
|
||||
else
|
||||
{
|
||||
shutdown = true;
|
||||
Application.NotifyNewRunState -= OnApplicationNotifyNewRunState;
|
||||
Application.Iteration -= OnApplicationOnIteration;
|
||||
stopwatch!.Stop ();
|
||||
}
|
||||
_output.WriteLine ($"Initialized == {a.CurrentValue}");
|
||||
}
|
||||
|
||||
void OnApplicationOnIteration (object s, IterationEventArgs a)
|
||||
{
|
||||
iterationCount++;
|
||||
if (iterationCount > maxIterations)
|
||||
{
|
||||
// Press QuitKey
|
||||
_output.WriteLine ($"Attempting to quit scenario with RequestStop");
|
||||
Application.RequestStop ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void OnApplicationNotifyNewRunState (object sender, RunStateEventArgs e)
|
||||
{
|
||||
// Get a list of all subviews under Application.Top (and their subviews, etc.)
|
||||
// and subscribe to their DrawComplete event
|
||||
void SubscribeAllSubviews (View view)
|
||||
{
|
||||
view.DrawComplete += (s, a) => drawCompleteCount++;
|
||||
view.SubviewsLaidOut += (s, a) => laidOutCount++;
|
||||
view.Added += (s, a) => addedCount++;
|
||||
foreach (View subview in view.Subviews)
|
||||
{
|
||||
SubscribeAllSubviews (subview);
|
||||
}
|
||||
}
|
||||
|
||||
SubscribeAllSubviews (Application.Top);
|
||||
}
|
||||
|
||||
// If the scenario doesn't close within the abort time, this will force it to quit
|
||||
bool ForceCloseCallback ()
|
||||
{
|
||||
lock (_timeoutLock)
|
||||
{
|
||||
if (timeout is { })
|
||||
{
|
||||
timeout = null;
|
||||
}
|
||||
}
|
||||
|
||||
_output.WriteLine(
|
||||
$"'{scenario.GetName ()}' failed to Quit with {Application.QuitKey} after {abortTime}ms and {iterationCount} iterations. Force quit.");
|
||||
|
||||
Application.RequestStop ();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<object []> AllScenarioTypes =>
|
||||
typeof (Scenario).Assembly
|
||||
@@ -344,7 +186,7 @@ public class ScenarioTests : TestsAllViews
|
||||
|
||||
var top = new Toplevel ();
|
||||
|
||||
_viewClasses = TestHelpers.GetAllViewClasses ().ToDictionary (t => t.Name);
|
||||
_viewClasses = ViewTestHelpers.GetAllViewClasses ().ToDictionary (t => t.Name);
|
||||
|
||||
_leftPane = new ()
|
||||
{
|
||||
29
Tests/README.md
Normal file
29
Tests/README.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Terminal.Gui Tests
|
||||
|
||||
This folder contains the tests for Terminal.Gui.
|
||||
|
||||
## ./UnitTests
|
||||
|
||||
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`.
|
||||
|
||||
We should be striving to move as many tests as possible to the `./UnitTestsParallelizable` folder.
|
||||
|
||||
## ./UnitTestsParallelizable
|
||||
|
||||
This folder contains the unit tests for Terminal.Gui that can be run in parallel.
|
||||
|
||||
## ./IntegrationTests
|
||||
|
||||
This folder contains the integration tests for Terminal.Gui.
|
||||
|
||||
## ./StressTests
|
||||
|
||||
This folder contains the stress tests for Terminal.Gui.
|
||||
|
||||
## ./PerformanceTests
|
||||
|
||||
This folder WILL contain the performance tests for Terminal.Gui.
|
||||
|
||||
|
||||
See the [Testing wiki](https://github.com/gui-cs/Terminal.Gui/wiki/Testing) for details on how to add more tests.
|
||||
111
Tests/StressTests/ApplicationStressTests.cs
Normal file
111
Tests/StressTests/ApplicationStressTests.cs
Normal file
@@ -0,0 +1,111 @@
|
||||
using Terminal.Gui;
|
||||
using UnitTests;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace StressTests;
|
||||
|
||||
public class ApplicationStressTests : TestsAllViews
|
||||
{
|
||||
public ApplicationStressTests (ITestOutputHelper output)
|
||||
{
|
||||
ConsoleDriver.RunningUnitTests = true;
|
||||
ConfigurationManager.Locations = ConfigLocations.Default;
|
||||
}
|
||||
|
||||
private static volatile int _tbCounter;
|
||||
private static readonly ManualResetEventSlim _wakeUp = new (false);
|
||||
|
||||
[Theory]
|
||||
[InlineData (typeof (FakeDriver))]
|
||||
[InlineData (typeof (NetDriver), Skip = "System.IO.IOException: The handle is invalid")]
|
||||
//[InlineData (typeof (ANSIDriver))]
|
||||
[InlineData (typeof (WindowsDriver))]
|
||||
[InlineData (typeof (CursesDriver), Skip = "Unable to load DLL 'libc' or one of its dependencies: The specified module could not be found. (0x8007007E)")]
|
||||
public async Task InvokeLeakTest (Type driverType)
|
||||
{
|
||||
|
||||
Application.Init (driverName: driverType.Name);
|
||||
Random r = new ();
|
||||
TextField tf = new ();
|
||||
var top = new Toplevel ();
|
||||
top.Add (tf);
|
||||
|
||||
const int NUM_PASSES = 50;
|
||||
const int NUM_INCREMENTS = 500;
|
||||
const int POLL_MS = 100;
|
||||
_tbCounter = 0;
|
||||
|
||||
Task task = Task.Run (() => RunTest (r, tf, NUM_PASSES, NUM_INCREMENTS, POLL_MS));
|
||||
|
||||
// blocks here until the RequestStop is processed at the end of the test
|
||||
Application.Run (top);
|
||||
|
||||
await task; // Propagate exception if any occurred
|
||||
|
||||
Assert.Equal (NUM_INCREMENTS * NUM_PASSES, _tbCounter);
|
||||
top.Dispose ();
|
||||
Application.Shutdown ();
|
||||
|
||||
return;
|
||||
|
||||
static void RunTest (Random r, TextField tf, int numPasses, int numIncrements, int pollMs)
|
||||
{
|
||||
for (var j = 0; j < numPasses; j++)
|
||||
{
|
||||
_wakeUp.Reset ();
|
||||
|
||||
for (var i = 0; i < numIncrements; i++)
|
||||
{
|
||||
Launch (r, tf, (j + 1) * numIncrements);
|
||||
}
|
||||
|
||||
while (_tbCounter != (j + 1) * numIncrements) // Wait for tbCounter to reach expected value
|
||||
{
|
||||
int tbNow = _tbCounter;
|
||||
_wakeUp.Wait (pollMs);
|
||||
|
||||
if (_tbCounter != tbNow)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// No change after wait: Idle handlers added via Application.Invoke have gone missing
|
||||
Application.Invoke (() => Application.RequestStop ());
|
||||
|
||||
throw new TimeoutException (
|
||||
$"Timeout: Increment lost. _tbCounter ({_tbCounter}) didn't "
|
||||
+ $"change after waiting {pollMs} ms. Failed to reach {(j + 1) * numIncrements} on pass {j + 1}"
|
||||
);
|
||||
}
|
||||
|
||||
;
|
||||
}
|
||||
|
||||
Application.Invoke (() => Application.RequestStop ());
|
||||
}
|
||||
|
||||
static void Launch (Random r, TextField tf, int target)
|
||||
{
|
||||
Task.Run (
|
||||
() =>
|
||||
{
|
||||
Thread.Sleep (r.Next (2, 4));
|
||||
|
||||
Application.Invoke (
|
||||
() =>
|
||||
{
|
||||
tf.Text = $"index{r.Next ()}";
|
||||
Interlocked.Increment (ref _tbCounter);
|
||||
|
||||
if (target == _tbCounter)
|
||||
{
|
||||
// On last increment wake up the check
|
||||
_wakeUp.Set ();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
193
Tests/StressTests/ScenariosStressTests.cs
Normal file
193
Tests/StressTests/ScenariosStressTests.cs
Normal file
@@ -0,0 +1,193 @@
|
||||
using System.Diagnostics;
|
||||
using Terminal.Gui;
|
||||
using UICatalog;
|
||||
using UnitTests;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace StressTests;
|
||||
|
||||
public class ScenariosStressTests : TestsAllViews
|
||||
{
|
||||
public ScenariosStressTests (ITestOutputHelper output)
|
||||
{
|
||||
#if DEBUG_IDISPOSABLE
|
||||
View.DebugIDisposable = true;
|
||||
View.Instances.Clear ();
|
||||
#endif
|
||||
_output = output;
|
||||
}
|
||||
|
||||
private readonly ITestOutputHelper _output;
|
||||
|
||||
private object? _timeoutLock;
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// This runs through all Scenarios defined in UI Catalog, calling Init, Setup, and Run and measuring the perf of
|
||||
/// each.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Theory]
|
||||
[MemberData (nameof (AllScenarioTypes))]
|
||||
public void All_Scenarios_Benchmark (Type scenarioType)
|
||||
{
|
||||
Assert.Null (_timeoutLock);
|
||||
_timeoutLock = new ();
|
||||
|
||||
// Disable any UIConfig settings
|
||||
ConfigLocations savedConfigLocations = ConfigurationManager.Locations;
|
||||
ConfigurationManager.Locations = ConfigLocations.Default;
|
||||
|
||||
// If a previous test failed, this will ensure that the Application is in a clean state
|
||||
Application.ResetState (true);
|
||||
|
||||
uint maxIterations = 1000;
|
||||
uint abortTime = 2000;
|
||||
object? timeout = null;
|
||||
|
||||
var iterationCount = 0;
|
||||
var clearedContentCount = 0;
|
||||
var refreshedCount = 0;
|
||||
var updatedCount = 0;
|
||||
var drawCompleteCount = 0;
|
||||
|
||||
var addedCount = 0;
|
||||
var laidOutCount = 0;
|
||||
|
||||
_output.WriteLine ($"Running Scenario '{scenarioType}'");
|
||||
var scenario = (Scenario)Activator.CreateInstance (scenarioType)!;
|
||||
|
||||
Stopwatch? stopwatch = null;
|
||||
|
||||
Application.InitializedChanged += OnApplicationOnInitializedChanged;
|
||||
Application.ForceDriver = "FakeDriver";
|
||||
scenario!.Main ();
|
||||
scenario.Dispose ();
|
||||
scenario = null;
|
||||
Application.ForceDriver = string.Empty;
|
||||
Application.InitializedChanged -= OnApplicationOnInitializedChanged;
|
||||
|
||||
lock (_timeoutLock)
|
||||
{
|
||||
if (timeout is { })
|
||||
{
|
||||
timeout = null;
|
||||
}
|
||||
}
|
||||
|
||||
lock (_timeoutLock)
|
||||
{
|
||||
_timeoutLock = null;
|
||||
}
|
||||
|
||||
_output.WriteLine ($"Scenario {scenarioType}");
|
||||
_output.WriteLine ($" took {stopwatch!.ElapsedMilliseconds} ms to run.");
|
||||
_output.WriteLine ($" called Driver.ClearContents {clearedContentCount} times.");
|
||||
_output.WriteLine ($" called Driver.Refresh {refreshedCount} times.");
|
||||
_output.WriteLine ($" which updated the screen {updatedCount} times.");
|
||||
_output.WriteLine ($" called View.Draw {drawCompleteCount} times.");
|
||||
_output.WriteLine ($" added {addedCount} views.");
|
||||
_output.WriteLine ($" called View.LayoutComplete {laidOutCount} times.");
|
||||
|
||||
// Restore the configuration locations
|
||||
ConfigurationManager.Locations = savedConfigLocations;
|
||||
ConfigurationManager.Reset ();
|
||||
|
||||
return;
|
||||
|
||||
void OnApplicationOnInitializedChanged (object? s, EventArgs<bool> a)
|
||||
{
|
||||
if (a.CurrentValue)
|
||||
{
|
||||
lock (_timeoutLock)
|
||||
{
|
||||
timeout = Application.AddTimeout (TimeSpan.FromMilliseconds (abortTime), ForceCloseCallback);
|
||||
}
|
||||
|
||||
Application.Iteration += OnApplicationOnIteration;
|
||||
Application.Driver!.ClearedContents += (sender, args) => clearedContentCount++;
|
||||
|
||||
if (Application.Driver is ConsoleDriver cd)
|
||||
{
|
||||
cd!.Refreshed += (sender, args) =>
|
||||
{
|
||||
refreshedCount++;
|
||||
|
||||
if (args.CurrentValue)
|
||||
{
|
||||
updatedCount++;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Application.NotifyNewRunState += OnApplicationNotifyNewRunState;
|
||||
|
||||
stopwatch = Stopwatch.StartNew ();
|
||||
}
|
||||
else
|
||||
{
|
||||
Application.NotifyNewRunState -= OnApplicationNotifyNewRunState;
|
||||
Application.Iteration -= OnApplicationOnIteration;
|
||||
stopwatch!.Stop ();
|
||||
}
|
||||
|
||||
_output.WriteLine ($"Initialized == {a.CurrentValue}");
|
||||
}
|
||||
|
||||
void OnApplicationOnIteration (object? s, IterationEventArgs a)
|
||||
{
|
||||
iterationCount++;
|
||||
|
||||
if (iterationCount > maxIterations)
|
||||
{
|
||||
// Press QuitKey
|
||||
_output.WriteLine ("Attempting to quit scenario with RequestStop");
|
||||
Application.RequestStop ();
|
||||
}
|
||||
}
|
||||
|
||||
void OnApplicationNotifyNewRunState (object? sender, RunStateEventArgs e)
|
||||
{
|
||||
// Get a list of all subviews under Application.Top (and their subviews, etc.)
|
||||
// and subscribe to their DrawComplete event
|
||||
void SubscribeAllSubviews (View view)
|
||||
{
|
||||
view.DrawComplete += (s, a) => drawCompleteCount++;
|
||||
view.SubviewsLaidOut += (s, a) => laidOutCount++;
|
||||
view.Added += (s, a) => addedCount++;
|
||||
|
||||
foreach (View subview in view.Subviews)
|
||||
{
|
||||
SubscribeAllSubviews (subview);
|
||||
}
|
||||
}
|
||||
|
||||
SubscribeAllSubviews (Application.Top!);
|
||||
}
|
||||
|
||||
// If the scenario doesn't close within the abort time, this will force it to quit
|
||||
bool ForceCloseCallback ()
|
||||
{
|
||||
lock (_timeoutLock)
|
||||
{
|
||||
if (timeout is { })
|
||||
{
|
||||
timeout = null;
|
||||
}
|
||||
}
|
||||
|
||||
_output.WriteLine (
|
||||
$"'{scenario!.GetName ()}' failed to Quit with {Application.QuitKey} after {abortTime}ms and {iterationCount} iterations. Force quit.");
|
||||
|
||||
Application.RequestStop ();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<object []> AllScenarioTypes =>
|
||||
typeof (Scenario).Assembly
|
||||
.GetTypes ()
|
||||
.Where (type => type.IsClass && !type.IsAbstract && type.IsSubclassOf (typeof (Scenario)))
|
||||
.Select (type => new object [] { type });
|
||||
}
|
||||
44
Tests/StressTests/StressTests.csproj
Normal file
44
Tests/StressTests/StressTests.csproj
Normal file
@@ -0,0 +1,44 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
<DefineConstants>$(DefineConstants);JETBRAINS_ANNOTATIONS;CONTRACTS_FULL</DefineConstants>
|
||||
<DebugType>portable</DebugType>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<NoLogo>true</NoLogo>
|
||||
<SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage>
|
||||
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<DefineDebug>true</DefineDebug>
|
||||
<DefineConstants>$(DefineConstants);DEBUG_IDISPOSABLE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
||||
<Optimize>true</Optimize>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\UnitTests\TestsAllViews.cs" Link="TestsAllViews.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" />
|
||||
<PackageReference Include="xunit" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Terminal.Gui\Terminal.Gui.csproj" />
|
||||
<ProjectReference Include="..\..\UICatalog\UICatalog.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="xunit.runner.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
6
Tests/StressTests/xunit.runner.json
Normal file
6
Tests/StressTests/xunit.runner.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"$schema": "https://xunit.net/schema/current/xunit.runner.schema.json",
|
||||
"parallelizeTestCollections": false,
|
||||
"parallelizeAssembly": false,
|
||||
"stopOnFail": false
|
||||
}
|
||||
@@ -2,8 +2,14 @@
|
||||
|
||||
namespace Terminal.Gui.ApplicationTests;
|
||||
|
||||
public class ApplicationScreenTests (ITestOutputHelper output)
|
||||
public class ApplicationScreenTests
|
||||
{
|
||||
public ApplicationScreenTests (ITestOutputHelper output)
|
||||
{
|
||||
ConsoleDriver.RunningUnitTests = true;
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void ClearScreenNextIteration_Resets_To_False_After_LayoutAndDraw ()
|
||||
{
|
||||
@@ -27,12 +33,13 @@ public class ApplicationScreenTests (ITestOutputHelper output)
|
||||
{
|
||||
// Arrange
|
||||
Application.Init (new FakeDriver ());
|
||||
Application.Top = new Toplevel ();
|
||||
Application.Top = new ();
|
||||
Application.TopLevels.Push (Application.Top);
|
||||
|
||||
int clearedContentsRaised = 0;
|
||||
var clearedContentsRaised = 0;
|
||||
|
||||
Application.Driver!.ClearedContents += (e, a) => clearedContentsRaised++;
|
||||
|
||||
Application.Driver!.ClearedContents += OnClearedContents;
|
||||
|
||||
// Act
|
||||
Application.LayoutAndDraw ();
|
||||
@@ -64,9 +71,13 @@ public class ApplicationScreenTests (ITestOutputHelper output)
|
||||
// Cleanup
|
||||
Application.Top.Dispose ();
|
||||
Application.Top = null;
|
||||
Application.Driver!.ClearedContents -= OnClearedContents;
|
||||
Application.Shutdown ();
|
||||
Application.ResetState (true);
|
||||
|
||||
return;
|
||||
|
||||
void OnClearedContents (object e, EventArgs a) { clearedContentsRaised++; }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -80,7 +91,7 @@ public class ApplicationScreenTests (ITestOutputHelper output)
|
||||
Assert.Equal (new (0, 0, 25, 25), Application.Screen);
|
||||
|
||||
// Act
|
||||
(((FakeDriver)Application.Driver)!).SetBufferSize (120, 30);
|
||||
((FakeDriver)Application.Driver)!.SetBufferSize (120, 30);
|
||||
|
||||
// Assert
|
||||
Assert.Equal (new (0, 0, 120, 30), Application.Screen);
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Diagnostics;
|
||||
using UnitTests;
|
||||
using Xunit.Abstractions;
|
||||
using static Terminal.Gui.ConfigurationManager;
|
||||
|
||||
@@ -15,6 +16,7 @@ public class ApplicationTests
|
||||
Locations = ConfigLocations.Default;
|
||||
|
||||
#if DEBUG_IDISPOSABLE
|
||||
View.DebugIDisposable = true;
|
||||
View.Instances.Clear ();
|
||||
RunState.Instances.Clear ();
|
||||
#endif
|
||||
@@ -906,53 +908,6 @@ public class ApplicationTests
|
||||
Assert.Equal (3, count);
|
||||
}
|
||||
|
||||
// TODO: All Toplevel layout tests should be moved to ToplevelTests.cs
|
||||
[Fact (Skip = "#2491 - Changing focus should cause NeedsDraw = true, so bogus test?")]
|
||||
public void Run_Toplevel_With_Modal_View_Does_Not_Refresh_If_Not_Dirty ()
|
||||
{
|
||||
Init ();
|
||||
var count = 0;
|
||||
|
||||
// Don't use Dialog here as it has more layout logic. Use Window instead.
|
||||
Dialog d = null;
|
||||
Toplevel top = new ();
|
||||
top.DrawingContent += (s, a) => count++;
|
||||
int iteration = -1;
|
||||
|
||||
Application.Iteration += (s, a) =>
|
||||
{
|
||||
iteration++;
|
||||
|
||||
if (iteration == 0)
|
||||
{
|
||||
// TODO: Don't use Dialog here as it has more layout logic. Use Window instead.
|
||||
d = new ();
|
||||
d.DrawingContent += (s, a) => count++;
|
||||
Application.Run (d);
|
||||
}
|
||||
else if (iteration < 3)
|
||||
{
|
||||
Application.RaiseMouseEvent (new () { Flags = MouseFlags.ReportMousePosition });
|
||||
Assert.False (top.NeedsDraw);
|
||||
Assert.False (top.SubViewNeedsDraw);
|
||||
Assert.False (top.NeedsLayout);
|
||||
Assert.False (d.NeedsDraw);
|
||||
Assert.False (d.SubViewNeedsDraw);
|
||||
Assert.False (d.NeedsLayout);
|
||||
}
|
||||
else
|
||||
{
|
||||
Application.RequestStop ();
|
||||
}
|
||||
};
|
||||
Application.Run (top);
|
||||
top.Dispose ();
|
||||
Application.Shutdown ();
|
||||
|
||||
// 1 - First top load, 1 - Dialog load, 1 - Dialog unload, Total - 3.
|
||||
Assert.Equal (3, count);
|
||||
}
|
||||
|
||||
// TODO: All Toplevel layout tests should be moved to ToplevelTests.cs
|
||||
[Fact]
|
||||
public void Run_A_Modal_Toplevel_Refresh_Background_On_Moving ()
|
||||
@@ -1,4 +1,5 @@
|
||||
using Xunit.Abstractions;
|
||||
using UnitTests;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Terminal.Gui.ApplicationTests;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Xunit.Abstractions;
|
||||
using UnitTests;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Terminal.Gui.ApplicationTests;
|
||||
|
||||
@@ -20,119 +21,6 @@ public class KeyboardTests
|
||||
|
||||
private object _timeoutLock;
|
||||
|
||||
[Fact (Skip = "No longer valid test.")]
|
||||
[AutoInitShutdown]
|
||||
public void EnsuresTopOnFront_CanFocus_False_By_Keyboard ()
|
||||
{
|
||||
Toplevel top = new ();
|
||||
|
||||
var win = new Window
|
||||
{
|
||||
Title = "win",
|
||||
X = 0,
|
||||
Y = 0,
|
||||
Width = 20,
|
||||
Height = 10
|
||||
};
|
||||
var tf = new TextField { Width = 10 };
|
||||
win.Add (tf);
|
||||
|
||||
var win2 = new Window
|
||||
{
|
||||
Title = "win2",
|
||||
X = 22,
|
||||
Y = 0,
|
||||
Width = 20,
|
||||
Height = 10
|
||||
};
|
||||
var tf2 = new TextField { Width = 10 };
|
||||
win2.Add (tf2);
|
||||
top.Add (win, win2);
|
||||
|
||||
Application.Begin (top);
|
||||
|
||||
Assert.True (win.CanFocus);
|
||||
Assert.True (win.HasFocus);
|
||||
Assert.True (win2.CanFocus);
|
||||
Assert.False (win2.HasFocus);
|
||||
Assert.Equal ("win", ((Window)top.Subviews [^1]).Title);
|
||||
|
||||
win.CanFocus = false;
|
||||
Assert.False (win.CanFocus);
|
||||
Assert.False (win.HasFocus);
|
||||
Assert.True (win2.CanFocus);
|
||||
Assert.True (win2.HasFocus);
|
||||
Assert.Equal ("win2", ((Window)top.Subviews [^1]).Title);
|
||||
|
||||
Application.RaiseKeyDownEvent (Key.F6);
|
||||
Assert.True (win2.CanFocus);
|
||||
Assert.False (win.HasFocus);
|
||||
Assert.True (win2.CanFocus);
|
||||
Assert.True (win2.HasFocus);
|
||||
Assert.Equal ("win2", ((Window)top.Subviews [^1]).Title);
|
||||
|
||||
Application.RaiseKeyDownEvent (Key.F6);
|
||||
Assert.False (win.CanFocus);
|
||||
Assert.False (win.HasFocus);
|
||||
Assert.True (win2.CanFocus);
|
||||
Assert.True (win2.HasFocus);
|
||||
Assert.Equal ("win2", ((Window)top.Subviews [^1]).Title);
|
||||
top.Dispose ();
|
||||
}
|
||||
|
||||
[Fact (Skip = "No longer valid test.")]
|
||||
[AutoInitShutdown]
|
||||
public void EnsuresTopOnFront_CanFocus_True_By_Keyboard ()
|
||||
{
|
||||
Toplevel top = new ();
|
||||
|
||||
var win = new Window
|
||||
{
|
||||
Title = "win",
|
||||
X = 0,
|
||||
Y = 0,
|
||||
Width = 20,
|
||||
Height = 10
|
||||
};
|
||||
var tf = new TextField { Width = 10 };
|
||||
win.Add (tf);
|
||||
|
||||
var win2 = new Window
|
||||
{
|
||||
Title = "win2",
|
||||
X = 22,
|
||||
Y = 0,
|
||||
Width = 20,
|
||||
Height = 10
|
||||
};
|
||||
var tf2 = new TextField { Width = 10 };
|
||||
win2.Add (tf2);
|
||||
top.Add (win, win2);
|
||||
|
||||
Application.Begin (top);
|
||||
|
||||
Assert.True (win.CanFocus);
|
||||
Assert.True (win.HasFocus);
|
||||
Assert.True (win2.CanFocus);
|
||||
Assert.False (win2.HasFocus);
|
||||
Assert.Equal ("win", ((Window)top.Subviews [^1]).Title);
|
||||
|
||||
Application.RaiseKeyDownEvent (Key.F6);
|
||||
Assert.True (win.CanFocus);
|
||||
Assert.False (win.HasFocus);
|
||||
Assert.True (win2.CanFocus);
|
||||
Assert.True (win2.HasFocus);
|
||||
Assert.Equal ("win2", ((Window)top.Subviews [^1]).Title);
|
||||
|
||||
Application.RaiseKeyDownEvent (Key.F6);
|
||||
Assert.True (win.CanFocus);
|
||||
Assert.True (win.HasFocus);
|
||||
Assert.True (win2.CanFocus);
|
||||
Assert.False (win2.HasFocus);
|
||||
Assert.Equal ("win", ((Window)top.Subviews [^1]).Title);
|
||||
top.Dispose ();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[AutoInitShutdown]
|
||||
public void KeyBindings_Add_Adds ()
|
||||
@@ -161,7 +49,7 @@ public class KeyboardTests
|
||||
[Fact]
|
||||
public void KeyBindings_OnKeyDown ()
|
||||
{
|
||||
Application.Top = new Toplevel ();
|
||||
Application.Top = new ();
|
||||
var view = new ScopedKeyBindingView ();
|
||||
var keyWasHandled = false;
|
||||
view.KeyDownNotHandled += (s, e) => keyWasHandled = true;
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
// Alias Console to MockConsole so we don't accidentally use Console
|
||||
|
||||
@@ -8,7 +7,6 @@ namespace Terminal.Gui.ApplicationTests;
|
||||
/// <summary>Tests MainLoop using the FakeMainLoop.</summary>
|
||||
public class MainLoopTests
|
||||
{
|
||||
private static readonly ManualResetEventSlim _wakeUp = new (false);
|
||||
private static Button btn;
|
||||
private static string cancel;
|
||||
private static string clickMe;
|
||||
@@ -22,28 +20,11 @@ public class MainLoopTests
|
||||
// - wait = false
|
||||
|
||||
// TODO: Add IMainLoop tests
|
||||
private static volatile int tbCounter;
|
||||
private static int three;
|
||||
private static int total;
|
||||
private static int two;
|
||||
private static int zero;
|
||||
|
||||
public static IEnumerable<object []> TestAddIdle
|
||||
{
|
||||
get
|
||||
{
|
||||
// Goes fine
|
||||
Action a1 = StartWindow;
|
||||
|
||||
yield return new object [] { a1, "Click Me", "Cancel", "Pew Pew", 0, 1, 2, 3, 4 };
|
||||
|
||||
// Also goes fine
|
||||
Action a2 = () => Application.Invoke (StartWindow);
|
||||
|
||||
yield return new object [] { a2, "Click Me", "Cancel", "Pew Pew", 0, 1, 2, 3, 4 };
|
||||
}
|
||||
}
|
||||
|
||||
// See Also ConsoleDRivers/MainLoopDriverTests.cs for tests of the MainLoopDriver
|
||||
|
||||
// Idle Handler tests
|
||||
@@ -60,7 +41,7 @@ public class MainLoopTests
|
||||
|
||||
Assert.Equal (2, ml.TimedEvents.IdleHandlers.Count);
|
||||
Assert.Equal (fnTrue, ml.TimedEvents.IdleHandlers [0]);
|
||||
Assert.NotEqual (fnFalse, ml.TimedEvents.IdleHandlers[0]);
|
||||
Assert.NotEqual (fnFalse, ml.TimedEvents.IdleHandlers [0]);
|
||||
|
||||
Assert.True (ml.TimedEvents.RemoveIdle (fnTrue));
|
||||
Assert.Single (ml.TimedEvents.IdleHandlers);
|
||||
@@ -82,15 +63,15 @@ public class MainLoopTests
|
||||
ml.AddIdle (fnTrue);
|
||||
|
||||
Assert.Equal (2, ml.TimedEvents.IdleHandlers.Count);
|
||||
Assert.Equal (fnTrue, ml.TimedEvents.IdleHandlers[0]);
|
||||
Assert.True (ml.TimedEvents.IdleHandlers[0] ());
|
||||
Assert.Equal (fnTrue, ml.TimedEvents.IdleHandlers[1]);
|
||||
Assert.True (ml.TimedEvents.IdleHandlers[1] ());
|
||||
Assert.Equal (fnTrue, ml.TimedEvents.IdleHandlers [0]);
|
||||
Assert.True (ml.TimedEvents.IdleHandlers [0] ());
|
||||
Assert.Equal (fnTrue, ml.TimedEvents.IdleHandlers [1]);
|
||||
Assert.True (ml.TimedEvents.IdleHandlers [1] ());
|
||||
|
||||
Assert.True (ml.TimedEvents.RemoveIdle (fnTrue));
|
||||
Assert.Single (ml.TimedEvents.IdleHandlers);
|
||||
Assert.Equal (fnTrue, ml.TimedEvents.IdleHandlers[0]);
|
||||
Assert.NotEqual (fnFalse, ml.TimedEvents.IdleHandlers[0]);
|
||||
Assert.Equal (fnTrue, ml.TimedEvents.IdleHandlers [0]);
|
||||
Assert.NotEqual (fnFalse, ml.TimedEvents.IdleHandlers [0]);
|
||||
|
||||
Assert.True (ml.TimedEvents.RemoveIdle (fnTrue));
|
||||
Assert.Empty (ml.TimedEvents.IdleHandlers);
|
||||
@@ -616,41 +597,10 @@ public class MainLoopTests
|
||||
Assert.Empty (mainloop.TimedEvents.IdleHandlers);
|
||||
|
||||
Assert.NotNull (
|
||||
new Timeout { Span = new TimeSpan (), Callback = () => true }
|
||||
new Timeout { Span = new (), Callback = () => true }
|
||||
);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData (typeof (FakeDriver))]
|
||||
//[InlineData (typeof (NetDriver))] // BUGBUG: NetDriver never exits in this test
|
||||
|
||||
//[InlineData (typeof (ANSIDriver))]
|
||||
//[InlineData (typeof (WindowsDriver))] // BUGBUG: NetDriver never exits in this test
|
||||
//[InlineData (typeof (CursesDriver))] // BUGBUG: CursesDriver never exits in this test
|
||||
public async Task InvokeLeakTest (Type driverType)
|
||||
{
|
||||
Application.Init (driverName: driverType.Name);
|
||||
Random r = new ();
|
||||
TextField tf = new ();
|
||||
var top = new Toplevel ();
|
||||
top.Add (tf);
|
||||
|
||||
const int numPasses = 2;
|
||||
const int numIncrements = 500;
|
||||
const int pollMs = 2500;
|
||||
|
||||
Task task = Task.Run (() => RunTest (r, tf, numPasses, numIncrements, pollMs));
|
||||
|
||||
// blocks here until the RequestStop is processed at the end of the test
|
||||
Application.Run (top);
|
||||
|
||||
await task; // Propagate exception if any occurred
|
||||
|
||||
Assert.Equal (numIncrements * numPasses, tbCounter);
|
||||
top.Dispose ();
|
||||
Application.Shutdown ();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData (nameof (TestAddIdle))]
|
||||
public void Mainloop_Invoke_Or_AddIdle_Can_Be_Used_For_Events_Or_Actions (
|
||||
@@ -666,7 +616,7 @@ public class MainLoopTests
|
||||
)
|
||||
{
|
||||
// TODO: Expand this test to test all drivers
|
||||
Application.Init (new FakeDriver());
|
||||
Application.Init (new FakeDriver ());
|
||||
|
||||
total = 0;
|
||||
btn = null;
|
||||
@@ -779,29 +729,21 @@ public class MainLoopTests
|
||||
Assert.Equal (10, functionCalled);
|
||||
}
|
||||
|
||||
private static void Launch (Random r, TextField tf, int target)
|
||||
public static IEnumerable<object []> TestAddIdle
|
||||
{
|
||||
Task.Run (
|
||||
() =>
|
||||
get
|
||||
{
|
||||
Thread.Sleep (r.Next (2, 4));
|
||||
// Goes fine
|
||||
Action a1 = StartWindow;
|
||||
|
||||
Application.Invoke (
|
||||
() =>
|
||||
{
|
||||
tf.Text = $"index{r.Next ()}";
|
||||
Interlocked.Increment (ref tbCounter);
|
||||
yield return new object [] { a1, "Click Me", "Cancel", "Pew Pew", 0, 1, 2, 3, 4 };
|
||||
|
||||
if (target == tbCounter)
|
||||
{
|
||||
// On last increment wake up the check
|
||||
_wakeUp.Set ();
|
||||
// Also goes fine
|
||||
Action a2 = () => Application.Invoke (StartWindow);
|
||||
|
||||
yield return new object [] { a2, "Click Me", "Cancel", "Pew Pew", 0, 1, 2, 3, 4 };
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private static async void RunAsyncTest (object sender, EventArgs e)
|
||||
{
|
||||
@@ -862,40 +804,6 @@ public class MainLoopTests
|
||||
);
|
||||
}
|
||||
|
||||
private static void RunTest (Random r, TextField tf, int numPasses, int numIncrements, int pollMs)
|
||||
{
|
||||
for (var j = 0; j < numPasses; j++)
|
||||
{
|
||||
_wakeUp.Reset ();
|
||||
|
||||
for (var i = 0; i < numIncrements; i++)
|
||||
{
|
||||
Launch (r, tf, (j + 1) * numIncrements);
|
||||
}
|
||||
|
||||
while (tbCounter != (j + 1) * numIncrements) // Wait for tbCounter to reach expected value
|
||||
{
|
||||
int tbNow = tbCounter;
|
||||
_wakeUp.Wait (pollMs);
|
||||
|
||||
if (tbCounter == tbNow)
|
||||
{
|
||||
// No change after wait: Idle handlers added via Application.Invoke have gone missing
|
||||
Application.Invoke (() => Application.RequestStop ());
|
||||
|
||||
throw new TimeoutException (
|
||||
$"Timeout: Increment lost. tbCounter ({tbCounter}) didn't "
|
||||
+ $"change after waiting {pollMs} ms. Failed to reach {(j + 1) * numIncrements} on pass {j + 1}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
;
|
||||
}
|
||||
|
||||
Application.Invoke (() => Application.RequestStop ());
|
||||
}
|
||||
|
||||
private static void SetReadyToRun ()
|
||||
{
|
||||
Thread.Sleep (100);
|
||||
@@ -916,7 +824,7 @@ public class MainLoopTests
|
||||
{
|
||||
var startWindow = new Window { Modal = true };
|
||||
|
||||
btn = new Button { Text = "Click Me" };
|
||||
btn = new() { Text = "Click Me" };
|
||||
|
||||
btn.Accepting += RunAsyncTest;
|
||||
|
||||
@@ -937,8 +845,8 @@ public class MainLoopTests
|
||||
|
||||
private class MillisecondTolerance : IEqualityComparer<TimeSpan>
|
||||
{
|
||||
private readonly int _tolerance;
|
||||
public MillisecondTolerance (int tolerance) { _tolerance = tolerance; }
|
||||
private readonly int _tolerance;
|
||||
public bool Equals (TimeSpan x, TimeSpan y) { return Math.Abs (x.Milliseconds - y.Milliseconds) <= _tolerance; }
|
||||
public int GetHashCode (TimeSpan obj) { return obj.GetHashCode (); }
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Xunit.Abstractions;
|
||||
using UnitTests;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
// Alias Console to MockConsole so we don't accidentally use Console
|
||||
|
||||
@@ -8,6 +8,8 @@ public class RunStateTests
|
||||
public RunStateTests ()
|
||||
{
|
||||
#if DEBUG_IDISPOSABLE
|
||||
View.DebugIDisposable = true;
|
||||
|
||||
View.Instances.Clear ();
|
||||
RunState.Instances.Clear ();
|
||||
#endif
|
||||
@@ -1,5 +1,7 @@
|
||||
// Alias Console to MockConsole so we don't accidentally use Console
|
||||
|
||||
using UnitTests;
|
||||
|
||||
namespace Terminal.Gui.ApplicationTests;
|
||||
|
||||
public class SyncrhonizationContextTests
|
||||
140
Tests/UnitTests/AutoInitShutdownAttribute.cs
Normal file
140
Tests/UnitTests/AutoInitShutdownAttribute.cs
Normal file
@@ -0,0 +1,140 @@
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using Xunit.Sdk;
|
||||
|
||||
namespace UnitTests;
|
||||
|
||||
/// <summary>
|
||||
/// Enables test functions annotated with the [AutoInitShutdown] attribute to
|
||||
/// automatically call Application.Init at start of the test and Application.Shutdown after the
|
||||
/// test exits.
|
||||
/// This is necessary because a) Application is a singleton and Init/Shutdown must be called
|
||||
/// as a pair, and b) all unit test functions should be atomic..
|
||||
/// </summary>
|
||||
[AttributeUsage (AttributeTargets.Class | AttributeTargets.Method)]
|
||||
public class AutoInitShutdownAttribute : BeforeAfterTestAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a [AutoInitShutdown] attribute, which determines if/how Application.Init and Application.Shutdown
|
||||
/// are automatically called Before/After a test runs.
|
||||
/// </summary>
|
||||
/// <param name="autoInit">If true, Application.Init will be called Before the test runs.</param>
|
||||
/// <param name="consoleDriverType">
|
||||
/// Determines which IConsoleDriver (FakeDriver, WindowsDriver, CursesDriver, NetDriver)
|
||||
/// will be used when Application.Init is called. If null FakeDriver will be used. Only valid if
|
||||
/// <paramref name="autoInit"/> is true.
|
||||
/// </param>
|
||||
/// <param name="useFakeClipboard">
|
||||
/// If true, will force the use of <see cref="FakeDriver.FakeClipboard"/>. Only valid if
|
||||
/// <see cref="IConsoleDriver"/> == <see cref="FakeDriver"/> and <paramref name="autoInit"/> is true.
|
||||
/// </param>
|
||||
/// <param name="fakeClipboardAlwaysThrowsNotSupportedException">
|
||||
/// Only valid if <paramref name="autoInit"/> is true. Only
|
||||
/// valid if <see cref="IConsoleDriver"/> == <see cref="FakeDriver"/> and <paramref name="autoInit"/> is true.
|
||||
/// </param>
|
||||
/// <param name="fakeClipboardIsSupportedAlwaysTrue">
|
||||
/// Only valid if <paramref name="autoInit"/> is true. Only valid if
|
||||
/// <see cref="IConsoleDriver"/> == <see cref="FakeDriver"/> and <paramref name="autoInit"/> is true.
|
||||
/// </param>
|
||||
/// <param name="configLocation">Determines what config file locations <see cref="ConfigurationManager"/> will load from.</param>
|
||||
/// <param name="verifyShutdown">If true and <see cref="Application.Initialized"/> is true, the test will fail.</param>
|
||||
public AutoInitShutdownAttribute (
|
||||
bool autoInit = true,
|
||||
Type consoleDriverType = null,
|
||||
bool useFakeClipboard = true,
|
||||
bool fakeClipboardAlwaysThrowsNotSupportedException = false,
|
||||
bool fakeClipboardIsSupportedAlwaysTrue = false,
|
||||
ConfigLocations configLocation = ConfigLocations.Default, // DefaultOnly is the default for tests
|
||||
bool verifyShutdown = false
|
||||
)
|
||||
{
|
||||
AutoInit = autoInit;
|
||||
CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.GetCultureInfo ("en-US");
|
||||
_driverType = consoleDriverType ?? typeof (FakeDriver);
|
||||
FakeDriver.FakeBehaviors.UseFakeClipboard = useFakeClipboard;
|
||||
|
||||
FakeDriver.FakeBehaviors.FakeClipboardAlwaysThrowsNotSupportedException =
|
||||
fakeClipboardAlwaysThrowsNotSupportedException;
|
||||
FakeDriver.FakeBehaviors.FakeClipboardIsSupportedAlwaysFalse = fakeClipboardIsSupportedAlwaysTrue;
|
||||
ConfigurationManager.Locations = configLocation;
|
||||
_verifyShutdown = verifyShutdown;
|
||||
}
|
||||
|
||||
private readonly bool _verifyShutdown;
|
||||
private readonly Type _driverType;
|
||||
|
||||
public override void After (MethodInfo methodUnderTest)
|
||||
{
|
||||
Debug.WriteLine ($"After: {methodUnderTest.Name}");
|
||||
|
||||
// Turn off diagnostic flags in case some test left them on
|
||||
View.Diagnostics = ViewDiagnosticFlags.Off;
|
||||
|
||||
if (AutoInit)
|
||||
{
|
||||
// try
|
||||
{
|
||||
if (!_verifyShutdown)
|
||||
{
|
||||
Application.ResetState (ignoreDisposed: true);
|
||||
}
|
||||
|
||||
Application.Shutdown ();
|
||||
#if DEBUG_IDISPOSABLE
|
||||
if (View.Instances.Count == 0)
|
||||
{
|
||||
Assert.Empty (View.Instances);
|
||||
}
|
||||
else
|
||||
{
|
||||
View.Instances.Clear ();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
//catch (Exception e)
|
||||
//{
|
||||
// Assert.Fail ($"Application.Shutdown threw an exception after the test exited: {e}");
|
||||
//}
|
||||
//finally
|
||||
{
|
||||
#if DEBUG_IDISPOSABLE
|
||||
View.Instances.Clear ();
|
||||
Application.ResetState (true);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Reset to defaults
|
||||
ConfigurationManager.Locations = ConfigLocations.Default;
|
||||
ConfigurationManager.Reset ();
|
||||
|
||||
// Enable subsequent tests that call Init to get all config files (the default).
|
||||
//Locations = ConfigLocations.All;
|
||||
}
|
||||
|
||||
public override void Before (MethodInfo methodUnderTest)
|
||||
{
|
||||
Debug.WriteLine ($"Before: {methodUnderTest.Name}");
|
||||
|
||||
if (AutoInit)
|
||||
{
|
||||
#if DEBUG_IDISPOSABLE
|
||||
View.DebugIDisposable = true;
|
||||
|
||||
// Clear out any lingering Responder instances from previous tests
|
||||
if (View.Instances.Count == 0)
|
||||
{
|
||||
Assert.Empty (View.Instances);
|
||||
}
|
||||
else
|
||||
{
|
||||
View.Instances.Clear ();
|
||||
}
|
||||
#endif
|
||||
Application.Init ((IConsoleDriver)Activator.CreateInstance (_driverType));
|
||||
}
|
||||
}
|
||||
|
||||
private bool AutoInit { get; }
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Text.Json;
|
||||
using UnitTests;
|
||||
using static Terminal.Gui.ConfigurationManager;
|
||||
|
||||
namespace Terminal.Gui.ConfigurationTests;
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Text.Json;
|
||||
using UnitTests;
|
||||
|
||||
namespace Terminal.Gui.ConfigurationTests;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Text.Json;
|
||||
using UnitTests;
|
||||
|
||||
namespace Terminal.Gui.ConfigurationTests;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using UnitTests;
|
||||
using Xunit.Abstractions;
|
||||
using static Terminal.Gui.ConfigurationManager;
|
||||
#pragma warning disable IDE1006
|
||||
@@ -1,4 +1,5 @@
|
||||
using static Terminal.Gui.ConfigurationManager;
|
||||
using UnitTests;
|
||||
using static Terminal.Gui.ConfigurationManager;
|
||||
|
||||
namespace Terminal.Gui.ConfigurationTests;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Text.Json;
|
||||
using UnitTests;
|
||||
using static Terminal.Gui.ConfigurationManager;
|
||||
|
||||
namespace Terminal.Gui.ConfigurationTests;
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Text.Json;
|
||||
using UnitTests;
|
||||
using static Terminal.Gui.ConfigurationManager;
|
||||
|
||||
namespace Terminal.Gui.ConfigurationTests;
|
||||
@@ -68,22 +68,22 @@ public class AddRuneTests
|
||||
|
||||
// var s = "a\u0301\u0300\u0306";
|
||||
|
||||
// TestHelpers.AssertDriverContentsWithFrameAre (@"
|
||||
// DriverAsserts.AssertDriverContentsWithFrameAre (@"
|
||||
//ắ", output);
|
||||
|
||||
// tf.Text = "\u1eaf";
|
||||
// Application.Refresh ();
|
||||
// TestHelpers.AssertDriverContentsWithFrameAre (@"
|
||||
// DriverAsserts.AssertDriverContentsWithFrameAre (@"
|
||||
//ắ", output);
|
||||
|
||||
// tf.Text = "\u0103\u0301";
|
||||
// Application.Refresh ();
|
||||
// TestHelpers.AssertDriverContentsWithFrameAre (@"
|
||||
// DriverAsserts.AssertDriverContentsWithFrameAre (@"
|
||||
//ắ", output);
|
||||
|
||||
// tf.Text = "\u0061\u0306\u0301";
|
||||
// Application.Refresh ();
|
||||
// TestHelpers.AssertDriverContentsWithFrameAre (@"
|
||||
// DriverAsserts.AssertDriverContentsWithFrameAre (@"
|
||||
//ắ", output);
|
||||
driver.End ();
|
||||
}
|
||||
@@ -256,7 +256,7 @@ public class ConsoleDriverTests
|
||||
//└──────────────────┘
|
||||
//";
|
||||
|
||||
// var pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
|
||||
// var pos = DriverAsserts.AssertDriverContentsWithFrameAre (expected, output);
|
||||
// Assert.Equal (new (0, 0, 20, 8), pos);
|
||||
|
||||
// Assert.True (dlg.ProcessKey (new (Key.Tab)));
|
||||
@@ -273,7 +273,7 @@ public class ConsoleDriverTests
|
||||
//└──────────────────┘
|
||||
//";
|
||||
|
||||
// pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
|
||||
// pos = DriverAsserts.AssertDriverContentsWithFrameAre (expected, output);
|
||||
// Assert.Equal (new (0, 0, 20, 8), pos);
|
||||
|
||||
// win.RequestStop ();
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.Text;
|
||||
using UnitTests;
|
||||
using UnitTests;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
// Alias Console to MockConsole so we don't accidentally use Console
|
||||
@@ -28,7 +30,7 @@ public class ContentsTests
|
||||
driver.Init ();
|
||||
var expected = "\u0301!";
|
||||
driver.AddStr ("\u0301!"); // acute accent + exclamation mark
|
||||
TestHelpers.AssertDriverContentsAre (expected, output, driver);
|
||||
DriverAssert.AssertDriverContentsAre (expected, output, driver);
|
||||
|
||||
driver.End ();
|
||||
}
|
||||
@@ -50,7 +52,7 @@ public class ContentsTests
|
||||
var expected = "é";
|
||||
|
||||
driver.AddStr (combined);
|
||||
TestHelpers.AssertDriverContentsAre (expected, output, driver);
|
||||
DriverAssert.AssertDriverContentsAre (expected, output, driver);
|
||||
|
||||
// 3 char combine
|
||||
// a + ogonek + acute = <U+0061, U+0328, U+0301> ( ą́ )
|
||||
@@ -60,7 +62,7 @@ public class ContentsTests
|
||||
|
||||
driver.Move (0, 0);
|
||||
driver.AddStr (combined);
|
||||
TestHelpers.AssertDriverContentsAre (expected, output, driver);
|
||||
DriverAssert.AssertDriverContentsAre (expected, output, driver);
|
||||
|
||||
// e + ogonek + acute = <U+0061, U+0328, U+0301> ( ę́́ )
|
||||
combined = "e" + ogonek + acuteaccent;
|
||||
@@ -68,7 +70,7 @@ public class ContentsTests
|
||||
|
||||
driver.Move (0, 0);
|
||||
driver.AddStr (combined);
|
||||
TestHelpers.AssertDriverContentsAre (expected, output, driver);
|
||||
DriverAssert.AssertDriverContentsAre (expected, output, driver);
|
||||
|
||||
// i + ogonek + acute = <U+0061, U+0328, U+0301> ( į́́́ )
|
||||
combined = "i" + ogonek + acuteaccent;
|
||||
@@ -76,7 +78,7 @@ public class ContentsTests
|
||||
|
||||
driver.Move (0, 0);
|
||||
driver.AddStr (combined);
|
||||
TestHelpers.AssertDriverContentsAre (expected, output, driver);
|
||||
DriverAssert.AssertDriverContentsAre (expected, output, driver);
|
||||
|
||||
// u + ogonek + acute = <U+0061, U+0328, U+0301> ( ų́́́́ )
|
||||
combined = "u" + ogonek + acuteaccent;
|
||||
@@ -84,7 +86,7 @@ public class ContentsTests
|
||||
|
||||
driver.Move (0, 0);
|
||||
driver.AddStr (combined);
|
||||
TestHelpers.AssertDriverContentsAre (expected, output, driver);
|
||||
DriverAssert.AssertDriverContentsAre (expected, output, driver);
|
||||
|
||||
driver.End ();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user