mirror of
https://github.com/Smaug123/unofficial-nunit-runner
synced 2025-10-07 10:18:38 +00:00
Compare commits
45 Commits
WoofWare.N
...
WoofWare.N
Author | SHA1 | Date | |
---|---|---|---|
|
fcfdcef6cf | ||
|
eeada219f6 | ||
|
99e0fdff08 | ||
|
fda4e7ba60 | ||
|
dfdfa84733 | ||
|
c218110749 | ||
|
309968721c | ||
|
876ca9e625 | ||
|
59f9789cdc | ||
|
c8c28b9a32 | ||
|
6d87610017 | ||
|
9f28334b7f | ||
|
5cf2261d7f | ||
|
c3589820c3 | ||
|
5d0c205f21 | ||
|
16135fbd56 | ||
|
cbc51cde14 | ||
|
6a4b900aa9 | ||
|
4169289ded | ||
|
7df58d5309 | ||
|
ac4c8c245e | ||
|
3e79e79978 | ||
|
c16e7dd1ee | ||
|
cd66617ce7 | ||
|
144f71a417 | ||
|
3673fc56ee | ||
|
5f74b41825 | ||
|
2068007da0 | ||
|
6fd824c065 | ||
|
0480d5c151 | ||
|
9107b1b502 | ||
|
6583b9e025 | ||
|
48f7302391 | ||
|
d1fa66a2e8 | ||
|
e75c584a43 | ||
|
d7bdd38253 | ||
|
b7d87459d9 | ||
|
992679d8ca | ||
|
011a5129cc | ||
|
46a13d1583 | ||
|
1a291a2ac7 | ||
|
fd34215461 | ||
|
eda120332a | ||
|
799e5c8c3a | ||
|
172865b2a1 |
@@ -3,13 +3,13 @@
|
|||||||
"isRoot": true,
|
"isRoot": true,
|
||||||
"tools": {
|
"tools": {
|
||||||
"fantomas": {
|
"fantomas": {
|
||||||
"version": "7.0.0",
|
"version": "7.0.3",
|
||||||
"commands": [
|
"commands": [
|
||||||
"fantomas"
|
"fantomas"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"fsharp-analyzers": {
|
"fsharp-analyzers": {
|
||||||
"version": "0.29.0",
|
"version": "0.32.0",
|
||||||
"commands": [
|
"commands": [
|
||||||
"fsharp-analyzers"
|
"fsharp-analyzers"
|
||||||
]
|
]
|
||||||
|
28
.github/workflows/dotnet.yaml
vendored
28
.github/workflows/dotnet.yaml
vendored
@@ -29,7 +29,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v30
|
uses: cachix/install-nix-action@v31
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -48,7 +48,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v30
|
uses: cachix/install-nix-action@v31
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -85,7 +85,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v30
|
uses: cachix/install-nix-action@v31
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -113,7 +113,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v30
|
uses: cachix/install-nix-action@v31
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -130,7 +130,7 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v30
|
uses: cachix/install-nix-action@v31
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -145,7 +145,7 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v30
|
uses: cachix/install-nix-action@v31
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -158,7 +158,7 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v30
|
uses: cachix/install-nix-action@v31
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -171,7 +171,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@master
|
- uses: actions/checkout@master
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v30
|
uses: cachix/install-nix-action@v31
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -184,7 +184,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@master
|
- uses: actions/checkout@master
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v30
|
uses: cachix/install-nix-action@v31
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -198,7 +198,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v30
|
uses: cachix/install-nix-action@v31
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -264,7 +264,7 @@ jobs:
|
|||||||
name: nuget-package-lib
|
name: nuget-package-lib
|
||||||
path: packed
|
path: packed
|
||||||
- name: Attest Build Provenance
|
- name: Attest Build Provenance
|
||||||
uses: actions/attest-build-provenance@520d128f165991a6c774bcb264f323e3d70747f4 # v2.2.0
|
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0
|
||||||
with:
|
with:
|
||||||
subject-path: "packed/*.nupkg"
|
subject-path: "packed/*.nupkg"
|
||||||
|
|
||||||
@@ -283,7 +283,7 @@ jobs:
|
|||||||
name: nuget-package-tool
|
name: nuget-package-tool
|
||||||
path: packed
|
path: packed
|
||||||
- name: Attest Build Provenance
|
- name: Attest Build Provenance
|
||||||
uses: actions/attest-build-provenance@520d128f165991a6c774bcb264f323e3d70747f4 # v2.2.0
|
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0
|
||||||
with:
|
with:
|
||||||
subject-path: "packed/*.nupkg"
|
subject-path: "packed/*.nupkg"
|
||||||
|
|
||||||
@@ -299,7 +299,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v30
|
uses: cachix/install-nix-action@v31
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -331,7 +331,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v30
|
uses: cachix/install-nix-action@v31
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
|
2
.github/workflows/flake_update.yaml
vendored
2
.github/workflows/flake_update.yaml
vendored
@@ -32,7 +32,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Create token
|
- name: Create token
|
||||||
id: generate-token
|
id: generate-token
|
||||||
uses: actions/create-github-app-token@v1
|
uses: actions/create-github-app-token@v2
|
||||||
with:
|
with:
|
||||||
# https://github.com/actions/create-github-app-token/issues/136
|
# https://github.com/actions/create-github-app-token/issues/136
|
||||||
app-id: ${{ secrets.APP_ID }}
|
app-id: ${{ secrets.APP_ID }}
|
||||||
|
@@ -10,6 +10,8 @@
|
|||||||
<Compile Include="NoAttribute.fs" />
|
<Compile Include="NoAttribute.fs" />
|
||||||
<Compile Include="Inconclusive.fs" />
|
<Compile Include="Inconclusive.fs" />
|
||||||
<Compile Include="RunSubProcess.fs" />
|
<Compile Include="RunSubProcess.fs" />
|
||||||
|
<Compile Include="TestAsync.fs" />
|
||||||
|
<Compile Include="TestExplicit.fs" />
|
||||||
<Compile Include="TestNonParallel.fs" />
|
<Compile Include="TestNonParallel.fs" />
|
||||||
<Compile Include="TestParallel.fs" />
|
<Compile Include="TestParallel.fs" />
|
||||||
<Compile Include="TestParallelIndividualTest.fs" />
|
<Compile Include="TestParallelIndividualTest.fs" />
|
||||||
@@ -26,8 +28,8 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FsUnit" Version="7.0.1" />
|
<PackageReference Include="FsUnit" Version="7.1.1" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0"/>
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1"/>
|
||||||
<PackageReference Include="NUnit" Version="4.3.2"/>
|
<PackageReference Include="NUnit" Version="4.3.2"/>
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="5.0.0"/>
|
<PackageReference Include="NUnit3TestAdapter" Version="5.0.0"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
23
Consumer/TestAsync.fs
Normal file
23
Consumer/TestAsync.fs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
namespace Consumer
|
||||||
|
|
||||||
|
open System
|
||||||
|
open System.Threading.Tasks
|
||||||
|
open FsUnitTyped
|
||||||
|
open NUnit.Framework
|
||||||
|
|
||||||
|
[<TestFixture>]
|
||||||
|
module TestAsync =
|
||||||
|
|
||||||
|
[<Test>]
|
||||||
|
let ``an async test`` () =
|
||||||
|
async {
|
||||||
|
do! Async.Sleep (TimeSpan.FromMilliseconds 20.0)
|
||||||
|
1 |> shouldEqual 1
|
||||||
|
}
|
||||||
|
|
||||||
|
[<Test>]
|
||||||
|
let ``an async test, task-based`` () =
|
||||||
|
task {
|
||||||
|
do! Task.Delay (TimeSpan.FromMilliseconds 20.0)
|
||||||
|
1 |> shouldEqual 1
|
||||||
|
}
|
24
Consumer/TestExplicit.fs
Normal file
24
Consumer/TestExplicit.fs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
namespace Consumer
|
||||||
|
|
||||||
|
open NUnit.Framework
|
||||||
|
|
||||||
|
[<TestFixture>]
|
||||||
|
module TestExplicitIndividual =
|
||||||
|
|
||||||
|
[<Explicit>]
|
||||||
|
[<Test>]
|
||||||
|
let ``This test should not be run`` () = failwith<unit> "should not call"
|
||||||
|
|
||||||
|
[<Explicit>]
|
||||||
|
[<TestFixture>]
|
||||||
|
module TestExplicitModule =
|
||||||
|
|
||||||
|
[<OneTimeSetUp>]
|
||||||
|
let setUp () = failwith<unit> "should not call: setup"
|
||||||
|
|
||||||
|
[<OneTimeTearDown>]
|
||||||
|
let tearDown () =
|
||||||
|
failwith<unit> "should not call: teardown"
|
||||||
|
|
||||||
|
[<Test>]
|
||||||
|
let ``This test should not be run because its module is explicit`` () = failwith<unit> "should not call: test"
|
@@ -10,7 +10,7 @@
|
|||||||
<WarnOn>FS3388,FS3559</WarnOn>
|
<WarnOn>FS3388,FS3559</WarnOn>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Nerdbank.GitVersioning" Version="3.7.115" PrivateAssets="all"/>
|
<PackageReference Include="Nerdbank.GitVersioning" Version="3.8.38-alpha" PrivateAssets="all" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Condition="'$(GITHUB_ACTION)' != ''">
|
<PropertyGroup Condition="'$(GITHUB_ACTION)' != ''">
|
||||||
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
|
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
@@ -11,8 +11,8 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FsUnit" Version="7.0.1" />
|
<PackageReference Include="FsUnit" Version="7.1.1" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0"/>
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1"/>
|
||||||
<PackageReference Include="NUnit" Version="4.3.2"/>
|
<PackageReference Include="NUnit" Version="4.3.2"/>
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="5.0.0"/>
|
<PackageReference Include="NUnit3TestAdapter" Version="5.0.0"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@@ -10,20 +10,14 @@ open System.Threading
|
|||||||
|
|
||||||
type internal OutputStreamId = | OutputStreamId of Guid
|
type internal OutputStreamId = | OutputStreamId of Guid
|
||||||
|
|
||||||
type private ThreadAwareWriter
|
type private ThreadAwareWriter (local : AsyncLocal<OutputStreamId>, underlying : Dictionary<OutputStreamId, TextWriter>)
|
||||||
(
|
|
||||||
local : AsyncLocal<OutputStreamId>,
|
|
||||||
underlying : Dictionary<OutputStreamId, TextWriter>,
|
|
||||||
mem : Dictionary<OutputStreamId, MemoryStream>
|
|
||||||
)
|
|
||||||
=
|
=
|
||||||
inherit TextWriter ()
|
inherit TextWriter ()
|
||||||
override _.get_Encoding () = Encoding.Default
|
override _.get_Encoding () = Encoding.Default
|
||||||
|
|
||||||
override this.Write (v : char) : unit =
|
override this.Write (v : char) : unit =
|
||||||
use prev = ExecutionContext.Capture ()
|
lock
|
||||||
|
underlying
|
||||||
(fun _ ->
|
|
||||||
(fun () ->
|
(fun () ->
|
||||||
match underlying.TryGetValue local.Value with
|
match underlying.TryGetValue local.Value with
|
||||||
| true, output -> output.Write v
|
| true, output -> output.Write v
|
||||||
@@ -31,16 +25,12 @@ type private ThreadAwareWriter
|
|||||||
let wanted =
|
let wanted =
|
||||||
underlying |> Seq.map (fun (KeyValue (a, b)) -> $"%O{a}") |> String.concat "\n"
|
underlying |> Seq.map (fun (KeyValue (a, b)) -> $"%O{a}") |> String.concat "\n"
|
||||||
|
|
||||||
failwith $"no such context: %O{local.Value}\nwanted:\n"
|
failwith $"no such context: %O{local.Value}\nwanted:\n{wanted}"
|
||||||
)
|
)
|
||||||
|> lock underlying
|
|
||||||
)
|
|
||||||
|> fun action -> ExecutionContext.Run (prev, action, ())
|
|
||||||
|
|
||||||
override this.WriteLine (v : string) : unit =
|
override this.WriteLine (v : string) : unit =
|
||||||
use prev = ExecutionContext.Capture ()
|
lock
|
||||||
|
underlying
|
||||||
(fun _ ->
|
|
||||||
(fun () ->
|
(fun () ->
|
||||||
match underlying.TryGetValue local.Value with
|
match underlying.TryGetValue local.Value with
|
||||||
| true, output -> output.WriteLine v
|
| true, output -> output.WriteLine v
|
||||||
@@ -48,16 +38,13 @@ type private ThreadAwareWriter
|
|||||||
let wanted =
|
let wanted =
|
||||||
underlying |> Seq.map (fun (KeyValue (a, b)) -> $"%O{a}") |> String.concat "\n"
|
underlying |> Seq.map (fun (KeyValue (a, b)) -> $"%O{a}") |> String.concat "\n"
|
||||||
|
|
||||||
failwith $"no such context: %O{local.Value}\nwanted:\n"
|
failwith $"no such context: %O{local.Value}\nwanted:\n{wanted}"
|
||||||
)
|
)
|
||||||
|> lock underlying
|
|
||||||
)
|
|
||||||
|> fun action -> ExecutionContext.Run (prev, action, ())
|
|
||||||
|
|
||||||
/// Wraps up the necessary context to intercept global state.
|
/// Wraps up the necessary context to intercept global state.
|
||||||
[<NoEquality ; NoComparison>]
|
[<NoEquality ; NoComparison>]
|
||||||
type TestContexts =
|
type TestContexts =
|
||||||
private
|
internal
|
||||||
{
|
{
|
||||||
/// Accesses to this must be locked on StdOutWriters.
|
/// Accesses to this must be locked on StdOutWriters.
|
||||||
StdOuts : Dictionary<OutputStreamId, MemoryStream>
|
StdOuts : Dictionary<OutputStreamId, MemoryStream>
|
||||||
@@ -77,8 +64,8 @@ type TestContexts =
|
|||||||
let stdoutWriters = Dictionary ()
|
let stdoutWriters = Dictionary ()
|
||||||
let stderrWriters = Dictionary ()
|
let stderrWriters = Dictionary ()
|
||||||
let local = AsyncLocal ()
|
let local = AsyncLocal ()
|
||||||
let stdoutWriter = new ThreadAwareWriter (local, stdoutWriters, stdouts)
|
let stdoutWriter = new ThreadAwareWriter (local, stdoutWriters)
|
||||||
let stderrWriter = new ThreadAwareWriter (local, stderrWriters, stderrs)
|
let stderrWriter = new ThreadAwareWriter (local, stderrWriters)
|
||||||
|
|
||||||
{
|
{
|
||||||
StdOuts = stdouts
|
StdOuts = stdouts
|
||||||
|
@@ -138,10 +138,17 @@ type TestFixture =
|
|||||||
Tests : SingleTestMethod list
|
Tests : SingleTestMethod list
|
||||||
/// If this fixture has declared a parallelisability, that goes here.
|
/// If this fixture has declared a parallelisability, that goes here.
|
||||||
Parallelize : Parallelizable<ClassParallelScope> option
|
Parallelize : Parallelizable<ClassParallelScope> option
|
||||||
|
/// It is possible to mark a fixture as "Explicit" or "Ignored", for example.
|
||||||
|
Modifiers : Modifier list
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A test fixture about which we know nothing. No tests, no setup/teardown.
|
/// A test fixture about which we know nothing. No tests, no setup/teardown.
|
||||||
static member Empty (ty : Type) (par : Parallelizable<ClassParallelScope> option) (args : obj list list) =
|
static member Empty
|
||||||
|
(ty : Type)
|
||||||
|
(par : Parallelizable<ClassParallelScope> option)
|
||||||
|
(modifiers : Modifier list)
|
||||||
|
(args : obj list list)
|
||||||
|
=
|
||||||
{
|
{
|
||||||
ContainingAssembly = ty.Assembly
|
ContainingAssembly = ty.Assembly
|
||||||
Type = ty
|
Type = ty
|
||||||
@@ -153,6 +160,7 @@ type TestFixture =
|
|||||||
Parameters = args
|
Parameters = args
|
||||||
Tests = []
|
Tests = []
|
||||||
Parallelize = par
|
Parallelize = par
|
||||||
|
Modifiers = modifiers
|
||||||
}
|
}
|
||||||
|
|
||||||
/// User code in the unit under test has failed somehow.
|
/// User code in the unit under test has failed somehow.
|
||||||
|
10
WoofWare.NUnitTestRunner.Lib/Exception.fs
Normal file
10
WoofWare.NUnitTestRunner.Lib/Exception.fs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace WoofWare.NUnitTestRunner
|
||||||
|
|
||||||
|
open System.Runtime.ExceptionServices
|
||||||
|
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
|
module internal Exception =
|
||||||
|
let reraiseWithOriginalStackTrace<'a> (e : exn) : 'a =
|
||||||
|
let edi = ExceptionDispatchInfo.Capture e
|
||||||
|
edi.Throw ()
|
||||||
|
failwith "unreachable"
|
@@ -4,16 +4,16 @@ open System
|
|||||||
open System.Threading
|
open System.Threading
|
||||||
open System.Threading.Tasks
|
open System.Threading.Tasks
|
||||||
|
|
||||||
type private ThunkEvaluator<'ret> =
|
type private AsyncThunkEvaluator<'ret> =
|
||||||
abstract Eval<'a> : (unit -> 'a) -> AsyncReplyChannel<'a> -> 'ret
|
abstract Eval<'a> : (unit -> Async<'a>) -> AsyncReplyChannel<Result<'a, exn>> -> 'ret
|
||||||
|
|
||||||
type private ThunkCrate =
|
type private AsyncThunkCrate =
|
||||||
abstract Apply<'ret> : ThunkEvaluator<'ret> -> 'ret
|
abstract Apply<'ret> : AsyncThunkEvaluator<'ret> -> 'ret
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
module private ThunkCrate =
|
module private AsyncThunkCrate =
|
||||||
let make<'a> (t : unit -> 'a) (rc : AsyncReplyChannel<'a>) : ThunkCrate =
|
let make<'a> (t : unit -> Async<'a>) (rc : AsyncReplyChannel<Result<'a, exn>>) : AsyncThunkCrate =
|
||||||
{ new ThunkCrate with
|
{ new AsyncThunkCrate with
|
||||||
member _.Apply e = e.Eval t rc
|
member _.Apply e = e.Eval t rc
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,7 +41,11 @@ type private MailboxMessage =
|
|||||||
| Quit of AsyncReplyChannel<unit>
|
| Quit of AsyncReplyChannel<unit>
|
||||||
/// Check current state, see if we need to start more tests, etc.
|
/// Check current state, see if we need to start more tests, etc.
|
||||||
| Reconcile
|
| Reconcile
|
||||||
| RunTest of within : TestFixture * Parallelizable<unit> option * test : ThunkCrate
|
| RunTestAsync of
|
||||||
|
within : TestFixture *
|
||||||
|
Parallelizable<unit> option *
|
||||||
|
test : AsyncThunkCrate *
|
||||||
|
context : ExecutionContext
|
||||||
| BeginTestFixture of TestFixture * AsyncReplyChannel<TestFixtureRunningToken>
|
| BeginTestFixture of TestFixture * AsyncReplyChannel<TestFixtureRunningToken>
|
||||||
| EndTestFixture of TestFixtureTearDownToken * AsyncReplyChannel<unit>
|
| EndTestFixture of TestFixtureTearDownToken * AsyncReplyChannel<unit>
|
||||||
|
|
||||||
@@ -310,21 +314,31 @@ type ParallelQueue
|
|||||||
rc.Reply ()
|
rc.Reply ()
|
||||||
m.Post MailboxMessage.Reconcile
|
m.Post MailboxMessage.Reconcile
|
||||||
return! processTask (Running state) m
|
return! processTask (Running state) m
|
||||||
| MailboxMessage.RunTest (withinFixture, par, message) ->
|
| MailboxMessage.RunTestAsync (withinFixture, par, message, capturedContext) ->
|
||||||
let t () =
|
let t () =
|
||||||
{ new ThunkEvaluator<_> with
|
{ new AsyncThunkEvaluator<_> with
|
||||||
member _.Eval<'b> (t : unit -> 'b) rc =
|
member _.Eval<'b> (t : unit -> Async<'b>) rc =
|
||||||
let tcs = TaskCompletionSource TaskCreationOptions.RunContinuationsAsynchronously
|
let tcs = TaskCompletionSource TaskCreationOptions.RunContinuationsAsynchronously
|
||||||
use ec = ExecutionContext.Capture ()
|
|
||||||
|
|
||||||
fun () ->
|
fun () ->
|
||||||
ExecutionContext.Run (
|
ExecutionContext.Run (
|
||||||
ec,
|
capturedContext,
|
||||||
(fun _ ->
|
(fun _ ->
|
||||||
let result = t ()
|
async {
|
||||||
|
let! result =
|
||||||
|
async {
|
||||||
|
try
|
||||||
|
let! r = t ()
|
||||||
|
return Ok r
|
||||||
|
with e ->
|
||||||
|
return Error e
|
||||||
|
}
|
||||||
|
|
||||||
tcs.SetResult ()
|
tcs.SetResult ()
|
||||||
m.Post MailboxMessage.Reconcile
|
m.Post MailboxMessage.Reconcile
|
||||||
rc.Reply result
|
rc.Reply result
|
||||||
|
}
|
||||||
|
|> Async.StartImmediate
|
||||||
),
|
),
|
||||||
()
|
()
|
||||||
)
|
)
|
||||||
@@ -348,17 +362,36 @@ type ParallelQueue
|
|||||||
let mb = new MailboxProcessor<_> (processTask MailboxState.Idle)
|
let mb = new MailboxProcessor<_> (processTask MailboxState.Idle)
|
||||||
do mb.Start ()
|
do mb.Start ()
|
||||||
|
|
||||||
|
/// Request to run the given async action, freely in parallel with other running tests.
|
||||||
|
/// The resulting Task will return when the action has completed.
|
||||||
|
member _.RunAsync<'a>
|
||||||
|
(TestFixtureSetupToken parent)
|
||||||
|
(scope : Parallelizable<unit> option)
|
||||||
|
(action : unit -> Async<'a>)
|
||||||
|
: 'a Task
|
||||||
|
=
|
||||||
|
let ec = ExecutionContext.Capture ()
|
||||||
|
|
||||||
|
task {
|
||||||
|
let! result =
|
||||||
|
(fun rc -> MailboxMessage.RunTestAsync (parent, scope, AsyncThunkCrate.make action rc, ec))
|
||||||
|
|> mb.PostAndAsyncReply
|
||||||
|
|> Async.StartAsTask
|
||||||
|
|
||||||
|
match result with
|
||||||
|
| Ok o -> return o
|
||||||
|
| Error e -> return Exception.reraiseWithOriginalStackTrace e
|
||||||
|
}
|
||||||
|
|
||||||
/// Request to run the given action, freely in parallel with other running tests.
|
/// Request to run the given action, freely in parallel with other running tests.
|
||||||
/// The resulting Task will return when the action has completed.
|
/// The resulting Task will return when the action has completed.
|
||||||
member _.Run<'a>
|
member this.Run<'a>
|
||||||
(TestFixtureSetupToken parent)
|
(parent : TestFixtureSetupToken)
|
||||||
(scope : Parallelizable<unit> option)
|
(scope : Parallelizable<unit> option)
|
||||||
(action : unit -> 'a)
|
(action : unit -> 'a)
|
||||||
: 'a Task
|
: 'a Task
|
||||||
=
|
=
|
||||||
(fun rc -> MailboxMessage.RunTest (parent, scope, ThunkCrate.make action rc))
|
this.RunAsync parent scope (fun () -> async.Return (action ()))
|
||||||
|> mb.PostAndAsyncReply
|
|
||||||
|> Async.StartAsTask
|
|
||||||
|
|
||||||
/// Declare that we wish to start the given test fixture. The resulting Task will return
|
/// Declare that we wish to start the given test fixture. The resulting Task will return
|
||||||
/// when you are allowed to start running tests from that fixture.
|
/// when you are allowed to start running tests from that fixture.
|
||||||
@@ -379,11 +412,22 @@ type ParallelQueue
|
|||||||
| Parallelizable.Yes _ -> Parallelizable.Yes ()
|
| Parallelizable.Yes _ -> Parallelizable.Yes ()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
let ec = ExecutionContext.Capture ()
|
||||||
|
|
||||||
let! response =
|
let! response =
|
||||||
(fun rc -> MailboxMessage.RunTest (parent, par, ThunkCrate.make action rc))
|
(fun rc ->
|
||||||
|
MailboxMessage.RunTestAsync (
|
||||||
|
parent,
|
||||||
|
par,
|
||||||
|
AsyncThunkCrate.make (fun () -> async.Return (action ())) rc,
|
||||||
|
ec
|
||||||
|
)
|
||||||
|
)
|
||||||
|> mb.PostAndAsyncReply
|
|> mb.PostAndAsyncReply
|
||||||
|
|
||||||
return response, TestFixtureSetupToken parent
|
match response with
|
||||||
|
| Ok response -> return response, TestFixtureSetupToken parent
|
||||||
|
| Error e -> return Exception.reraiseWithOriginalStackTrace e
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run the given one-time tear-down for the test fixture.
|
/// Run the given one-time tear-down for the test fixture.
|
||||||
@@ -401,11 +445,22 @@ type ParallelQueue
|
|||||||
| Parallelizable.Yes _ -> Parallelizable.Yes ()
|
| Parallelizable.Yes _ -> Parallelizable.Yes ()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
let ec = ExecutionContext.Capture ()
|
||||||
|
|
||||||
let! response =
|
let! response =
|
||||||
(fun rc -> MailboxMessage.RunTest (parent, par, ThunkCrate.make action rc))
|
(fun rc ->
|
||||||
|
MailboxMessage.RunTestAsync (
|
||||||
|
parent,
|
||||||
|
par,
|
||||||
|
AsyncThunkCrate.make (fun () -> async.Return (action ())) rc,
|
||||||
|
ec
|
||||||
|
)
|
||||||
|
)
|
||||||
|> mb.PostAndAsyncReply
|
|> mb.PostAndAsyncReply
|
||||||
|
|
||||||
return response, TestFixtureTearDownToken parent
|
match response with
|
||||||
|
| Ok response -> return response, TestFixtureTearDownToken parent
|
||||||
|
| Error e -> return Exception.reraiseWithOriginalStackTrace e
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Declare that we have finished submitting requests to run in the given test fixture.
|
/// Declare that we have finished submitting requests to run in the given test fixture.
|
||||||
|
@@ -1,16 +1,15 @@
|
|||||||
namespace WoofWare.NUnitTestRunner
|
namespace WoofWare.NUnitTestRunner
|
||||||
|
|
||||||
open System
|
open System
|
||||||
open WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
[<JsonParse>]
|
// Myriad runs the JsonParse generator on this
|
||||||
type internal FrameworkDescription =
|
type internal FrameworkDescription =
|
||||||
{
|
{
|
||||||
Name : string
|
Name : string
|
||||||
Version : string
|
Version : string
|
||||||
}
|
}
|
||||||
|
|
||||||
[<JsonParse>]
|
// Myriad runs the JsonParse generator on this
|
||||||
type internal RuntimeOptions =
|
type internal RuntimeOptions =
|
||||||
{
|
{
|
||||||
Tfm : string
|
Tfm : string
|
||||||
@@ -21,7 +20,7 @@ type internal RuntimeOptions =
|
|||||||
RollForward : string option
|
RollForward : string option
|
||||||
}
|
}
|
||||||
|
|
||||||
[<JsonParse>]
|
// Myriad runs the JsonParse generator on this
|
||||||
type internal RuntimeConfig =
|
type internal RuntimeConfig =
|
||||||
{
|
{
|
||||||
RuntimeOptions : RuntimeOptions
|
RuntimeOptions : RuntimeOptions
|
||||||
|
@@ -170,8 +170,9 @@ WoofWare.NUnitTestRunner.IndividualTestRunMetadata.StdOut [property]: [read-only
|
|||||||
WoofWare.NUnitTestRunner.IndividualTestRunMetadata.TestId [property]: [read-only] System.Guid
|
WoofWare.NUnitTestRunner.IndividualTestRunMetadata.TestId [property]: [read-only] System.Guid
|
||||||
WoofWare.NUnitTestRunner.IndividualTestRunMetadata.TestName [property]: [read-only] string
|
WoofWare.NUnitTestRunner.IndividualTestRunMetadata.TestName [property]: [read-only] string
|
||||||
WoofWare.NUnitTestRunner.IndividualTestRunMetadata.Total [property]: [read-only] System.TimeSpan
|
WoofWare.NUnitTestRunner.IndividualTestRunMetadata.Total [property]: [read-only] System.TimeSpan
|
||||||
WoofWare.NUnitTestRunner.ITestProgress - interface with 5 member(s)
|
WoofWare.NUnitTestRunner.ITestProgress - interface with 6 member(s)
|
||||||
WoofWare.NUnitTestRunner.ITestProgress.OnTestFailed [method]: string -> WoofWare.NUnitTestRunner.TestMemberFailure -> unit
|
WoofWare.NUnitTestRunner.ITestProgress.OnTestFailed [method]: string -> WoofWare.NUnitTestRunner.TestMemberFailure -> unit
|
||||||
|
WoofWare.NUnitTestRunner.ITestProgress.OnTestFixtureSkipped [method]: string -> string -> unit
|
||||||
WoofWare.NUnitTestRunner.ITestProgress.OnTestFixtureStart [method]: string -> int -> unit
|
WoofWare.NUnitTestRunner.ITestProgress.OnTestFixtureStart [method]: string -> int -> unit
|
||||||
WoofWare.NUnitTestRunner.ITestProgress.OnTestMemberFinished [method]: string -> unit
|
WoofWare.NUnitTestRunner.ITestProgress.OnTestMemberFinished [method]: string -> unit
|
||||||
WoofWare.NUnitTestRunner.ITestProgress.OnTestMemberSkipped [method]: string -> unit
|
WoofWare.NUnitTestRunner.ITestProgress.OnTestMemberSkipped [method]: string -> unit
|
||||||
@@ -255,6 +256,7 @@ WoofWare.NUnitTestRunner.ParallelQueue inherit obj, implements IDisposable
|
|||||||
WoofWare.NUnitTestRunner.ParallelQueue..ctor [constructor]: (int option, WoofWare.NUnitTestRunner.AssemblyParallelScope WoofWare.NUnitTestRunner.Parallelizable option, System.Threading.CancellationToken option)
|
WoofWare.NUnitTestRunner.ParallelQueue..ctor [constructor]: (int option, WoofWare.NUnitTestRunner.AssemblyParallelScope WoofWare.NUnitTestRunner.Parallelizable option, System.Threading.CancellationToken option)
|
||||||
WoofWare.NUnitTestRunner.ParallelQueue.EndTestFixture [method]: WoofWare.NUnitTestRunner.TestFixtureTearDownToken -> unit System.Threading.Tasks.Task
|
WoofWare.NUnitTestRunner.ParallelQueue.EndTestFixture [method]: WoofWare.NUnitTestRunner.TestFixtureTearDownToken -> unit System.Threading.Tasks.Task
|
||||||
WoofWare.NUnitTestRunner.ParallelQueue.Run [method]: WoofWare.NUnitTestRunner.TestFixtureSetupToken -> unit WoofWare.NUnitTestRunner.Parallelizable option -> (unit -> 'a) -> 'a System.Threading.Tasks.Task
|
WoofWare.NUnitTestRunner.ParallelQueue.Run [method]: WoofWare.NUnitTestRunner.TestFixtureSetupToken -> unit WoofWare.NUnitTestRunner.Parallelizable option -> (unit -> 'a) -> 'a System.Threading.Tasks.Task
|
||||||
|
WoofWare.NUnitTestRunner.ParallelQueue.RunAsync [method]: WoofWare.NUnitTestRunner.TestFixtureSetupToken -> unit WoofWare.NUnitTestRunner.Parallelizable option -> (unit -> 'a Microsoft.FSharp.Control.FSharpAsync) -> 'a System.Threading.Tasks.Task
|
||||||
WoofWare.NUnitTestRunner.ParallelQueue.RunTestSetup [method]: WoofWare.NUnitTestRunner.TestFixtureRunningToken -> (unit -> 'a) -> ('a * WoofWare.NUnitTestRunner.TestFixtureSetupToken) System.Threading.Tasks.Task
|
WoofWare.NUnitTestRunner.ParallelQueue.RunTestSetup [method]: WoofWare.NUnitTestRunner.TestFixtureRunningToken -> (unit -> 'a) -> ('a * WoofWare.NUnitTestRunner.TestFixtureSetupToken) System.Threading.Tasks.Task
|
||||||
WoofWare.NUnitTestRunner.ParallelQueue.RunTestTearDown [method]: WoofWare.NUnitTestRunner.TestFixtureSetupToken -> (unit -> 'a) -> ('a * WoofWare.NUnitTestRunner.TestFixtureTearDownToken) System.Threading.Tasks.Task
|
WoofWare.NUnitTestRunner.ParallelQueue.RunTestTearDown [method]: WoofWare.NUnitTestRunner.TestFixtureSetupToken -> (unit -> 'a) -> ('a * WoofWare.NUnitTestRunner.TestFixtureTearDownToken) System.Threading.Tasks.Task
|
||||||
WoofWare.NUnitTestRunner.ParallelQueue.StartTestFixture [method]: WoofWare.NUnitTestRunner.TestFixture -> WoofWare.NUnitTestRunner.TestFixtureRunningToken System.Threading.Tasks.Task
|
WoofWare.NUnitTestRunner.ParallelQueue.StartTestFixture [method]: WoofWare.NUnitTestRunner.TestFixture -> WoofWare.NUnitTestRunner.TestFixtureRunningToken System.Threading.Tasks.Task
|
||||||
@@ -346,11 +348,12 @@ WoofWare.NUnitTestRunner.TestFailure.NewTearDownFailed [static method]: WoofWare
|
|||||||
WoofWare.NUnitTestRunner.TestFailure.NewTestFailed [static method]: WoofWare.NUnitTestRunner.UserMethodFailure -> WoofWare.NUnitTestRunner.TestFailure
|
WoofWare.NUnitTestRunner.TestFailure.NewTestFailed [static method]: WoofWare.NUnitTestRunner.UserMethodFailure -> WoofWare.NUnitTestRunner.TestFailure
|
||||||
WoofWare.NUnitTestRunner.TestFailure.Tag [property]: [read-only] int
|
WoofWare.NUnitTestRunner.TestFailure.Tag [property]: [read-only] int
|
||||||
WoofWare.NUnitTestRunner.TestFixture inherit obj, implements WoofWare.NUnitTestRunner.TestFixture System.IEquatable, System.Collections.IStructuralEquatable
|
WoofWare.NUnitTestRunner.TestFixture inherit obj, implements WoofWare.NUnitTestRunner.TestFixture System.IEquatable, System.Collections.IStructuralEquatable
|
||||||
WoofWare.NUnitTestRunner.TestFixture..ctor [constructor]: (System.Reflection.Assembly, string, System.Type, System.Reflection.MethodInfo option, System.Reflection.MethodInfo option, System.Reflection.MethodInfo list, System.Reflection.MethodInfo list, obj list list, WoofWare.NUnitTestRunner.SingleTestMethod list, WoofWare.NUnitTestRunner.ClassParallelScope WoofWare.NUnitTestRunner.Parallelizable option)
|
WoofWare.NUnitTestRunner.TestFixture..ctor [constructor]: (System.Reflection.Assembly, string, System.Type, System.Reflection.MethodInfo option, System.Reflection.MethodInfo option, System.Reflection.MethodInfo list, System.Reflection.MethodInfo list, obj list list, WoofWare.NUnitTestRunner.SingleTestMethod list, WoofWare.NUnitTestRunner.ClassParallelScope WoofWare.NUnitTestRunner.Parallelizable option, WoofWare.NUnitTestRunner.Modifier list)
|
||||||
WoofWare.NUnitTestRunner.TestFixture.ContainingAssembly [property]: [read-only] System.Reflection.Assembly
|
WoofWare.NUnitTestRunner.TestFixture.ContainingAssembly [property]: [read-only] System.Reflection.Assembly
|
||||||
WoofWare.NUnitTestRunner.TestFixture.Empty [static method]: System.Type -> WoofWare.NUnitTestRunner.ClassParallelScope WoofWare.NUnitTestRunner.Parallelizable option -> obj list list -> WoofWare.NUnitTestRunner.TestFixture
|
WoofWare.NUnitTestRunner.TestFixture.Empty [static method]: System.Type -> WoofWare.NUnitTestRunner.ClassParallelScope WoofWare.NUnitTestRunner.Parallelizable option -> WoofWare.NUnitTestRunner.Modifier list -> obj list list -> WoofWare.NUnitTestRunner.TestFixture
|
||||||
WoofWare.NUnitTestRunner.TestFixture.Equals [method]: (WoofWare.NUnitTestRunner.TestFixture, System.Collections.IEqualityComparer) -> bool
|
WoofWare.NUnitTestRunner.TestFixture.Equals [method]: (WoofWare.NUnitTestRunner.TestFixture, System.Collections.IEqualityComparer) -> bool
|
||||||
WoofWare.NUnitTestRunner.TestFixture.get_ContainingAssembly [method]: unit -> System.Reflection.Assembly
|
WoofWare.NUnitTestRunner.TestFixture.get_ContainingAssembly [method]: unit -> System.Reflection.Assembly
|
||||||
|
WoofWare.NUnitTestRunner.TestFixture.get_Modifiers [method]: unit -> WoofWare.NUnitTestRunner.Modifier list
|
||||||
WoofWare.NUnitTestRunner.TestFixture.get_Name [method]: unit -> string
|
WoofWare.NUnitTestRunner.TestFixture.get_Name [method]: unit -> string
|
||||||
WoofWare.NUnitTestRunner.TestFixture.get_OneTimeSetUp [method]: unit -> System.Reflection.MethodInfo option
|
WoofWare.NUnitTestRunner.TestFixture.get_OneTimeSetUp [method]: unit -> System.Reflection.MethodInfo option
|
||||||
WoofWare.NUnitTestRunner.TestFixture.get_OneTimeTearDown [method]: unit -> System.Reflection.MethodInfo option
|
WoofWare.NUnitTestRunner.TestFixture.get_OneTimeTearDown [method]: unit -> System.Reflection.MethodInfo option
|
||||||
@@ -360,6 +363,7 @@ WoofWare.NUnitTestRunner.TestFixture.get_SetUp [method]: unit -> System.Reflecti
|
|||||||
WoofWare.NUnitTestRunner.TestFixture.get_TearDown [method]: unit -> System.Reflection.MethodInfo list
|
WoofWare.NUnitTestRunner.TestFixture.get_TearDown [method]: unit -> System.Reflection.MethodInfo list
|
||||||
WoofWare.NUnitTestRunner.TestFixture.get_Tests [method]: unit -> WoofWare.NUnitTestRunner.SingleTestMethod list
|
WoofWare.NUnitTestRunner.TestFixture.get_Tests [method]: unit -> WoofWare.NUnitTestRunner.SingleTestMethod list
|
||||||
WoofWare.NUnitTestRunner.TestFixture.get_Type [method]: unit -> System.Type
|
WoofWare.NUnitTestRunner.TestFixture.get_Type [method]: unit -> System.Type
|
||||||
|
WoofWare.NUnitTestRunner.TestFixture.Modifiers [property]: [read-only] WoofWare.NUnitTestRunner.Modifier list
|
||||||
WoofWare.NUnitTestRunner.TestFixture.Name [property]: [read-only] string
|
WoofWare.NUnitTestRunner.TestFixture.Name [property]: [read-only] string
|
||||||
WoofWare.NUnitTestRunner.TestFixture.OneTimeSetUp [property]: [read-only] System.Reflection.MethodInfo option
|
WoofWare.NUnitTestRunner.TestFixture.OneTimeSetUp [property]: [read-only] System.Reflection.MethodInfo option
|
||||||
WoofWare.NUnitTestRunner.TestFixture.OneTimeTearDown [property]: [read-only] System.Reflection.MethodInfo option
|
WoofWare.NUnitTestRunner.TestFixture.OneTimeTearDown [property]: [read-only] System.Reflection.MethodInfo option
|
||||||
|
@@ -76,22 +76,24 @@ module TestFixture =
|
|||||||
(test : MethodInfo)
|
(test : MethodInfo)
|
||||||
(containingObject : obj)
|
(containingObject : obj)
|
||||||
(args : obj[])
|
(args : obj[])
|
||||||
: Result<TestMemberSuccess, TestFailure list> * IndividualTestRunMetadata
|
: Async<Result<TestMemberSuccess, TestFailure list> * IndividualTestRunMetadata>
|
||||||
=
|
=
|
||||||
let rec runMethods
|
let rec runMethods
|
||||||
(wrap : UserMethodFailure -> TestFailure)
|
(wrap : UserMethodFailure -> TestFailure)
|
||||||
(toRun : MethodInfo list)
|
(toRun : MethodInfo list)
|
||||||
(args : obj[])
|
(args : obj[])
|
||||||
: Result<unit, _>
|
: Result<unit, TestFailure> Async
|
||||||
=
|
=
|
||||||
match toRun with
|
match toRun with
|
||||||
| [] -> Ok ()
|
| [] -> async.Return (Ok ())
|
||||||
| head :: rest ->
|
| head :: rest ->
|
||||||
|
async {
|
||||||
let result =
|
let result =
|
||||||
try
|
try
|
||||||
head.Invoke (containingObject, args) |> Ok
|
head.Invoke (containingObject, args) |> Ok
|
||||||
with
|
with
|
||||||
| :? TargetInvocationException as e -> Error (UserMethodFailure.Threw (head.Name, e.InnerException))
|
| :? TargetInvocationException as e ->
|
||||||
|
Error (UserMethodFailure.Threw (head.Name, e.InnerException))
|
||||||
| :? TargetParameterCountException ->
|
| :? TargetParameterCountException ->
|
||||||
UserMethodFailure.BadParameters (
|
UserMethodFailure.BadParameters (
|
||||||
head.Name,
|
head.Name,
|
||||||
@@ -100,13 +102,72 @@ module TestFixture =
|
|||||||
)
|
)
|
||||||
|> Error
|
|> Error
|
||||||
|
|
||||||
|
let! ct = Async.CancellationToken
|
||||||
|
|
||||||
|
let! result =
|
||||||
match result with
|
match result with
|
||||||
| Error e -> Error (wrap e)
|
| Error e -> async.Return (Error (wrap e))
|
||||||
| Ok result ->
|
| Ok result ->
|
||||||
match result with
|
match result with
|
||||||
| :? unit -> runMethods wrap rest args
|
| :? unit -> runMethods wrap rest args
|
||||||
| ret -> UserMethodFailure.ReturnedNonUnit (head.Name, ret) |> wrap |> Error
|
| :? Task as result ->
|
||||||
|
async {
|
||||||
|
let mutable exc = None
|
||||||
|
|
||||||
|
try
|
||||||
|
do! Async.AwaitTask result
|
||||||
|
with e ->
|
||||||
|
exc <- Some e
|
||||||
|
|
||||||
|
match exc with
|
||||||
|
| None -> return! runMethods wrap rest args
|
||||||
|
| Some e -> return Error (UserMethodFailure.Threw (head.Name, e) |> wrap)
|
||||||
|
}
|
||||||
|
// We'd like to do this type-test:
|
||||||
|
// | :? Async<unit> as result ->
|
||||||
|
// but instead we have to do all this reflective nonsense, because FSharpAsync is not part
|
||||||
|
// of the .NET runtime, so is instead in a different AssemblyLoadContext to us!
|
||||||
|
// It's in the user-code context, not ours.
|
||||||
|
| ret ->
|
||||||
|
let ty = ret.GetType ()
|
||||||
|
|
||||||
|
if ty.Namespace = "Microsoft.FSharp.Control" && ty.Name = "FSharpAsync`1" then
|
||||||
|
match ty.GenericTypeArguments |> Array.map (fun t -> t.FullName) with
|
||||||
|
| [| "Microsoft.FSharp.Core.Unit" |] ->
|
||||||
|
let asyncModule = ty.Assembly.GetType ("Microsoft.FSharp.Control.FSharpAsync")
|
||||||
|
// let catch = asyncModule.GetMethod("Catch").MakeGenericMethod [| ty.GenericTypeArguments.[0] |]
|
||||||
|
// let caught = catch.Invoke ((null: obj), [| ret |])
|
||||||
|
let startAsTask =
|
||||||
|
asyncModule.GetMethod("StartAsTask").MakeGenericMethod
|
||||||
|
[| ty.GenericTypeArguments.[0] |]
|
||||||
|
|
||||||
|
let started =
|
||||||
|
startAsTask.Invoke ((null : obj), [| ret ; (null : obj) ; (null : obj) |])
|
||||||
|
|> unbox<Task>
|
||||||
|
|
||||||
|
async {
|
||||||
|
let! res = Async.AwaitTask started |> Async.Catch
|
||||||
|
|
||||||
|
match res with
|
||||||
|
| Choice1Of2 () -> return! runMethods wrap rest args
|
||||||
|
| Choice2Of2 e ->
|
||||||
|
return
|
||||||
|
Error (
|
||||||
|
UserMethodFailure.Threw (head.Name, started.Exception) |> wrap
|
||||||
|
)
|
||||||
|
}
|
||||||
|
| _ ->
|
||||||
|
UserMethodFailure.ReturnedNonUnit (head.Name, ret)
|
||||||
|
|> wrap
|
||||||
|
|> Error
|
||||||
|
|> async.Return
|
||||||
|
else
|
||||||
|
async.Return (UserMethodFailure.ReturnedNonUnit (head.Name, ret) |> wrap |> Error)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
async {
|
||||||
let start = DateTimeOffset.Now
|
let start = DateTimeOffset.Now
|
||||||
|
|
||||||
let sw = Stopwatch.StartNew ()
|
let sw = Stopwatch.StartNew ()
|
||||||
@@ -138,25 +199,25 @@ module TestFixture =
|
|||||||
| v -> Some v
|
| v -> Some v
|
||||||
}
|
}
|
||||||
|
|
||||||
let setUpResult = runMethods TestFailure.SetUpFailed setUp [||]
|
let! setUpResult = runMethods TestFailure.SetUpFailed setUp [||]
|
||||||
sw.Stop ()
|
sw.Stop ()
|
||||||
|
|
||||||
match setUpResult with
|
match setUpResult with
|
||||||
| Error e -> Error [ e ], metadata ()
|
| Error e -> return Error [ e ], metadata ()
|
||||||
| Ok () ->
|
| Ok () ->
|
||||||
|
|
||||||
sw.Start ()
|
sw.Start ()
|
||||||
|
let! result = runMethods TestFailure.TestFailed [ test ] args
|
||||||
let result =
|
|
||||||
let result = runMethods TestFailure.TestFailed [ test ] args
|
|
||||||
sw.Stop ()
|
sw.Stop ()
|
||||||
|
|
||||||
|
let result =
|
||||||
match result with
|
match result with
|
||||||
| Ok () -> Ok None
|
| Ok () -> Ok None
|
||||||
| Error (TestFailure.TestFailed (UserMethodFailure.Threw (_, exc)) as orig) ->
|
| Error (TestFailure.TestFailed (UserMethodFailure.Threw (_, exc)) as orig) ->
|
||||||
match exc.GetType().FullName with
|
match exc.GetType().FullName with
|
||||||
| "NUnit.Framework.SuccessException" -> Ok None
|
| "NUnit.Framework.SuccessException" -> Ok None
|
||||||
| "NUnit.Framework.IgnoreException" -> Ok (Some (TestMemberSuccess.Ignored (Option.ofObj exc.Message)))
|
| "NUnit.Framework.IgnoreException" ->
|
||||||
|
Ok (Some (TestMemberSuccess.Ignored (Option.ofObj exc.Message)))
|
||||||
| "NUnit.Framework.InconclusiveException" ->
|
| "NUnit.Framework.InconclusiveException" ->
|
||||||
Ok (Some (TestMemberSuccess.Inconclusive (Option.ofObj exc.Message)))
|
Ok (Some (TestMemberSuccess.Inconclusive (Option.ofObj exc.Message)))
|
||||||
| _ -> Error orig
|
| _ -> Error orig
|
||||||
@@ -164,17 +225,19 @@ module TestFixture =
|
|||||||
|
|
||||||
// Unconditionally run TearDown after tests, even if tests failed.
|
// Unconditionally run TearDown after tests, even if tests failed.
|
||||||
sw.Start ()
|
sw.Start ()
|
||||||
let tearDownResult = runMethods TestFailure.TearDownFailed tearDown [||]
|
let! tearDownResult = runMethods TestFailure.TearDownFailed tearDown [||]
|
||||||
sw.Stop ()
|
sw.Stop ()
|
||||||
|
|
||||||
let metadata = metadata ()
|
let metadata = metadata ()
|
||||||
|
|
||||||
|
return
|
||||||
match result, tearDownResult with
|
match result, tearDownResult with
|
||||||
| Ok None, Ok () -> Ok TestMemberSuccess.Ok, metadata
|
| Ok None, Ok () -> Ok TestMemberSuccess.Ok, metadata
|
||||||
| Ok (Some s), Ok () -> Ok s, metadata
|
| Ok (Some s), Ok () -> Ok s, metadata
|
||||||
| Error e, Ok ()
|
| Error e, Ok ()
|
||||||
| Ok _, Error e -> Error [ e ], metadata
|
| Ok _, Error e -> Error [ e ], metadata
|
||||||
| Error e1, Error e2 -> Error [ e1 ; e2 ], metadata
|
| Error e1, Error e2 -> Error [ e1 ; e2 ], metadata
|
||||||
|
}
|
||||||
|
|
||||||
let private getValues (test : SingleTestMethod) =
|
let private getValues (test : SingleTestMethod) =
|
||||||
let valuesAttrs =
|
let valuesAttrs =
|
||||||
@@ -395,20 +458,22 @@ module TestFixture =
|
|||||||
|> Seq.map (fun (testGuid, args) ->
|
|> Seq.map (fun (testGuid, args) ->
|
||||||
task {
|
task {
|
||||||
let runMe () =
|
let runMe () =
|
||||||
|
async {
|
||||||
progress.OnTestMemberStart test.Name
|
progress.OnTestMemberStart test.Name
|
||||||
let oldValue = contexts.AsyncLocal.Value
|
let oldValue = contexts.AsyncLocal.Value
|
||||||
let outputId = contexts.NewOutputs ()
|
let outputId = contexts.NewOutputs ()
|
||||||
contexts.AsyncLocal.Value <- outputId
|
contexts.AsyncLocal.Value <- outputId
|
||||||
|
|
||||||
let result, meta =
|
let! result, meta =
|
||||||
runOne outputId contexts setUp tearDown testGuid test.Method containingObject args
|
runOne outputId contexts setUp tearDown testGuid test.Method containingObject args
|
||||||
|
|
||||||
contexts.AsyncLocal.Value <- oldValue
|
contexts.AsyncLocal.Value <- oldValue
|
||||||
progress.OnTestMemberFinished test.Name
|
progress.OnTestMemberFinished test.Name
|
||||||
|
|
||||||
result, meta
|
return result, meta
|
||||||
|
}
|
||||||
|
|
||||||
let! results, summary = par.Run running test.Parallelize runMe
|
let! results, summary = par.RunAsync running test.Parallelize runMe
|
||||||
|
|
||||||
match results with
|
match results with
|
||||||
| Ok results -> return Ok results, summary
|
| Ok results -> return Ok results, summary
|
||||||
@@ -597,15 +662,15 @@ module TestFixture =
|
|||||||
/// Interpret this type as a [<TestFixture>], extracting the test members from it and annotating them with all
|
/// Interpret this type as a [<TestFixture>], extracting the test members from it and annotating them with all
|
||||||
/// relevant information about how we should run them.
|
/// relevant information about how we should run them.
|
||||||
let parse (parentType : Type) : TestFixture =
|
let parse (parentType : Type) : TestFixture =
|
||||||
let categories, args, par =
|
let categories, args, mods, par =
|
||||||
(([], [], None), parentType.CustomAttributes)
|
(([], [], [], None), parentType.CustomAttributes)
|
||||||
||> Seq.fold (fun (categories, args, par) attr ->
|
||> Seq.fold (fun (categories, args, mods, par) attr ->
|
||||||
match attr.AttributeType.FullName with
|
match attr.AttributeType.FullName with
|
||||||
| "NUnit.Framework.SetUpFixtureAttribute" ->
|
| "NUnit.Framework.SetUpFixtureAttribute" ->
|
||||||
failwith "This test runner does not support SetUpFixture. Please shout if you want this."
|
failwith "This test runner does not support SetUpFixture. Please shout if you want this."
|
||||||
| "NUnit.Framework.CategoryAttribute" ->
|
| "NUnit.Framework.CategoryAttribute" ->
|
||||||
let cat = attr.ConstructorArguments |> Seq.exactlyOne |> _.Value |> unbox<string>
|
let cat = attr.ConstructorArguments |> Seq.exactlyOne |> _.Value |> unbox<string>
|
||||||
cat :: categories, args, par
|
cat :: categories, args, mods, par
|
||||||
| "NUnit.Framework.TestFixtureAttribute" ->
|
| "NUnit.Framework.TestFixtureAttribute" ->
|
||||||
let newArgs =
|
let newArgs =
|
||||||
match attr.ConstructorArguments |> Seq.map _.Value |> Seq.toList with
|
match attr.ConstructorArguments |> Seq.map _.Value |> Seq.toList with
|
||||||
@@ -613,38 +678,52 @@ module TestFixture =
|
|||||||
x |> Seq.cast<CustomAttributeTypedArgument> |> Seq.map _.Value |> Seq.toList
|
x |> Seq.cast<CustomAttributeTypedArgument> |> Seq.map _.Value |> Seq.toList
|
||||||
| xs -> xs
|
| xs -> xs
|
||||||
|
|
||||||
categories, newArgs :: args, par
|
categories, newArgs :: args, mods, par
|
||||||
| "NUnit.Framework.NonParallelizableAttribute" ->
|
| "NUnit.Framework.NonParallelizableAttribute" ->
|
||||||
match par with
|
match par with
|
||||||
| Some _ -> failwith $"Got multiple parallelism attributes on %s{parentType.FullName}"
|
| Some _ -> failwith $"Got multiple parallelism attributes on %s{parentType.FullName}"
|
||||||
| None -> categories, args, Some Parallelizable.No
|
| None -> categories, args, mods, Some Parallelizable.No
|
||||||
| "NUnit.Framework.ParallelizableAttribute" ->
|
| "NUnit.Framework.ParallelizableAttribute" ->
|
||||||
match par with
|
match par with
|
||||||
| Some _ -> failwith $"Got multiple parallelism attributes on %s{parentType.FullName}"
|
| Some _ -> failwith $"Got multiple parallelism attributes on %s{parentType.FullName}"
|
||||||
| None ->
|
| None ->
|
||||||
match attr.ConstructorArguments |> Seq.toList with
|
match attr.ConstructorArguments |> Seq.toList with
|
||||||
| [] -> categories, args, Some (Parallelizable.Yes ClassParallelScope.Self)
|
| [] -> categories, args, mods, Some (Parallelizable.Yes ClassParallelScope.Self)
|
||||||
| [ v ] ->
|
| [ v ] ->
|
||||||
match v.Value with
|
match v.Value with
|
||||||
| :? int as v ->
|
| :? int as v ->
|
||||||
match ParallelScope.ofInt v with
|
match ParallelScope.ofInt v with
|
||||||
| ParallelScope.Fixtures ->
|
| ParallelScope.Fixtures ->
|
||||||
categories, args, Some (Parallelizable.Yes ClassParallelScope.Fixtures)
|
categories, args, mods, Some (Parallelizable.Yes ClassParallelScope.Fixtures)
|
||||||
| ParallelScope.Children ->
|
| ParallelScope.Children ->
|
||||||
categories, args, Some (Parallelizable.Yes ClassParallelScope.Children)
|
categories, args, mods, Some (Parallelizable.Yes ClassParallelScope.Children)
|
||||||
| ParallelScope.All ->
|
| ParallelScope.All ->
|
||||||
categories, args, Some (Parallelizable.Yes ClassParallelScope.All)
|
categories, args, mods, Some (Parallelizable.Yes ClassParallelScope.All)
|
||||||
| ParallelScope.Self ->
|
| ParallelScope.Self ->
|
||||||
categories, args, Some (Parallelizable.Yes ClassParallelScope.Self)
|
categories, args, mods, Some (Parallelizable.Yes ClassParallelScope.Self)
|
||||||
| ParallelScope.None -> categories, args, Some Parallelizable.No
|
| ParallelScope.None -> categories, args, mods, Some Parallelizable.No
|
||||||
| v ->
|
| v ->
|
||||||
failwith
|
failwith
|
||||||
$"Unexpectedly non-int value %O{v} of parallel scope in %s{parentType.FullName}"
|
$"Unexpectedly non-int value %O{v} of parallel scope in %s{parentType.FullName}"
|
||||||
| _ -> failwith $"unexpectedly got multiple args to Parallelizable on %s{parentType.FullName}"
|
| _ -> failwith $"unexpectedly got multiple args to Parallelizable on %s{parentType.FullName}"
|
||||||
| _ -> categories, args, par
|
| "NUnit.Framework.ExplicitAttribute" ->
|
||||||
|
let reason =
|
||||||
|
attr.ConstructorArguments
|
||||||
|
|> Seq.tryHead
|
||||||
|
|> Option.map (_.Value >> unbox<string>)
|
||||||
|
|
||||||
|
categories, args, Modifier.Explicit reason :: mods, par
|
||||||
|
| "NUnit.Framework.IgnoreAttribute" ->
|
||||||
|
let reason =
|
||||||
|
attr.ConstructorArguments
|
||||||
|
|> Seq.tryHead
|
||||||
|
|> Option.map (_.Value >> unbox<string>)
|
||||||
|
|
||||||
|
categories, args, Modifier.Ignored reason :: mods, par
|
||||||
|
| _ -> categories, args, mods, par
|
||||||
)
|
)
|
||||||
|
|
||||||
(TestFixture.Empty parentType par args, parentType.GetRuntimeMethods ())
|
(TestFixture.Empty parentType par mods args, parentType.GetRuntimeMethods ())
|
||||||
||> Seq.fold (fun state mi ->
|
||> Seq.fold (fun state mi ->
|
||||||
((state, []), mi.CustomAttributes)
|
((state, []), mi.CustomAttributes)
|
||||||
||> Seq.fold (fun (state, unrecognisedAttrs) attr ->
|
||> Seq.fold (fun (state, unrecognisedAttrs) attr ->
|
||||||
@@ -717,6 +796,8 @@ module TestFixture =
|
|||||||
|
|
||||||
/// Run every test (except those which fail the `filter`) in this test fixture, as well as the
|
/// Run every test (except those which fail the `filter`) in this test fixture, as well as the
|
||||||
/// appropriate setup and tear-down logic.
|
/// appropriate setup and tear-down logic.
|
||||||
|
///
|
||||||
|
/// If the TestFixture has modifiers that specify no tests should be run, we don't run any tests.
|
||||||
let run
|
let run
|
||||||
(contexts : TestContexts)
|
(contexts : TestContexts)
|
||||||
(par : ParallelQueue)
|
(par : ParallelQueue)
|
||||||
@@ -725,6 +806,26 @@ module TestFixture =
|
|||||||
(tests : TestFixture)
|
(tests : TestFixture)
|
||||||
: FixtureRunResults list Task
|
: FixtureRunResults list Task
|
||||||
=
|
=
|
||||||
|
match
|
||||||
|
tests.Modifiers
|
||||||
|
|> List.tryFind (
|
||||||
|
function
|
||||||
|
| Modifier.Explicit _
|
||||||
|
| Modifier.Ignored _ -> true
|
||||||
|
)
|
||||||
|
with
|
||||||
|
| Some modifier ->
|
||||||
|
let reason =
|
||||||
|
match modifier with
|
||||||
|
| Modifier.Explicit (Some reason) -> reason
|
||||||
|
| Modifier.Ignored (Some reason) -> reason
|
||||||
|
| Modifier.Ignored None -> "test fixture marked Ignore"
|
||||||
|
| Modifier.Explicit None -> "test fixture marked Explicit"
|
||||||
|
|
||||||
|
progress.OnTestFixtureSkipped tests.Name reason
|
||||||
|
Task.FromResult []
|
||||||
|
| None ->
|
||||||
|
|
||||||
match tests.Parameters with
|
match tests.Parameters with
|
||||||
| [] -> [ null ]
|
| [] -> [ null ]
|
||||||
| args -> args |> List.map List.toArray
|
| args -> args |> List.map List.toArray
|
||||||
|
@@ -10,6 +10,8 @@ type ITestProgress =
|
|||||||
/// Called just before we start executing the setup logic for the given test fixture.
|
/// Called just before we start executing the setup logic for the given test fixture.
|
||||||
/// We tell you how many test methods there are in the fixture.
|
/// We tell you how many test methods there are in the fixture.
|
||||||
abstract OnTestFixtureStart : name : string -> testCount : int -> unit
|
abstract OnTestFixtureStart : name : string -> testCount : int -> unit
|
||||||
|
/// Called when skipping the test fixture with the given name, e.g. because it's `[<Explicit>]`.
|
||||||
|
abstract OnTestFixtureSkipped : name : string -> reason : string -> unit
|
||||||
/// Called just before we start executing the test(s) indicated by a particular method.
|
/// Called just before we start executing the test(s) indicated by a particular method.
|
||||||
abstract OnTestMemberStart : name : string -> unit
|
abstract OnTestMemberStart : name : string -> unit
|
||||||
/// Called when a test fails. (This may be called repeatedly with the same `name`, e.g. if the test
|
/// Called when a test fails. (This may be called repeatedly with the same `name`, e.g. if the test
|
||||||
@@ -32,6 +34,9 @@ module TestProgress =
|
|||||||
let plural = if testCount = 1 then "" else "s"
|
let plural = if testCount = 1 then "" else "s"
|
||||||
writer.WriteLine $"Running test fixture: %s{name} (%i{testCount} test%s{plural} to run)"
|
writer.WriteLine $"Running test fixture: %s{name} (%i{testCount} test%s{plural} to run)"
|
||||||
|
|
||||||
|
member _.OnTestFixtureSkipped name reason =
|
||||||
|
writer.WriteLine $"Skipping test fixture (%s{reason}): %s{name}"
|
||||||
|
|
||||||
member _.OnTestMemberStart name =
|
member _.OnTestMemberStart name =
|
||||||
writer.WriteLine $"Running test: %s{name}"
|
writer.WriteLine $"Running test: %s{name}"
|
||||||
|
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
<PackageId>WoofWare.NUnitTestRunner.Lib</PackageId>
|
<PackageId>WoofWare.NUnitTestRunner.Lib</PackageId>
|
||||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
<WarnOn>FS3559</WarnOn>
|
<WarnOn>FS3559</WarnOn>
|
||||||
<WoofWareMyriadPluginVersion>4.0.12</WoofWareMyriadPluginVersion>
|
<WoofWareMyriadPluginVersion>8.0.5</WoofWareMyriadPluginVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -22,10 +22,16 @@
|
|||||||
<Compile Include="RuntimeConfig.fs" />
|
<Compile Include="RuntimeConfig.fs" />
|
||||||
<Compile Include="GeneratedRuntimeConfig.fs">
|
<Compile Include="GeneratedRuntimeConfig.fs">
|
||||||
<MyriadFile>RuntimeConfig.fs</MyriadFile>
|
<MyriadFile>RuntimeConfig.fs</MyriadFile>
|
||||||
|
<MyriadParams>
|
||||||
|
<RuntimeOptions>JsonParse</RuntimeOptions>
|
||||||
|
<RuntimeConfig>JsonParse</RuntimeConfig>
|
||||||
|
<FrameworkDescription>JsonParse</FrameworkDescription>
|
||||||
|
</MyriadParams>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="ParallelScope.fs" />
|
<Compile Include="ParallelScope.fs" />
|
||||||
<Compile Include="DotnetRuntime.fs" />
|
<Compile Include="DotnetRuntime.fs" />
|
||||||
<Compile Include="Array.fs" />
|
<Compile Include="Array.fs" />
|
||||||
|
<Compile Include="Exception.fs" />
|
||||||
<Compile Include="List.fs" />
|
<Compile Include="List.fs" />
|
||||||
<Compile Include="Result.fs" />
|
<Compile Include="Result.fs" />
|
||||||
<Compile Include="Domain.fs" />
|
<Compile Include="Domain.fs" />
|
||||||
@@ -48,10 +54,9 @@
|
|||||||
<EmbeddedResource Include="version.json" />
|
<EmbeddedResource Include="version.json" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="WoofWare.PrattParser" Version="0.2.3" />
|
<PackageReference Include="WoofWare.PrattParser" Version="0.2.4" />
|
||||||
<PackageReference Update="FSharp.Core" Version="6.0.1" />
|
<PackageReference Update="FSharp.Core" Version="6.0.1" />
|
||||||
<PackageReference Include="WoofWare.DotnetRuntimeLocator" Version="0.1.11" />
|
<PackageReference Include="WoofWare.DotnetRuntimeLocator" Version="0.1.12" />
|
||||||
<PackageReference Include="WoofWare.Myriad.Plugins.Attributes" Version="3.6.7" />
|
|
||||||
<PackageReference Include="Myriad.SDK" Version="0.8.3" PrivateAssets="all" />
|
<PackageReference Include="Myriad.SDK" Version="0.8.3" PrivateAssets="all" />
|
||||||
<PackageReference Include="WoofWare.Myriad.Plugins" Version="$(WoofWareMyriadPluginVersion)" PrivateAssets="all" />
|
<PackageReference Include="WoofWare.Myriad.Plugins" Version="$(WoofWareMyriadPluginVersion)" PrivateAssets="all" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "0.20",
|
"version": "0.22",
|
||||||
"publicReleaseRefSpec": [
|
"publicReleaseRefSpec": [
|
||||||
"^refs/heads/main$"
|
"^refs/heads/main$"
|
||||||
],
|
],
|
||||||
|
@@ -13,6 +13,10 @@ module Progress =
|
|||||||
member _.OnTestFixtureStart name testCount =
|
member _.OnTestFixtureStart name testCount =
|
||||||
console.MarkupLine $"[white]Running tests: %s{Markup.Escape name}[/]"
|
console.MarkupLine $"[white]Running tests: %s{Markup.Escape name}[/]"
|
||||||
|
|
||||||
|
member _.OnTestFixtureSkipped name reason =
|
||||||
|
console.MarkupLine
|
||||||
|
$"[yellow]Skipping test fixture (%s{Markup.Escape reason}): %s{Markup.Escape name}[/]"
|
||||||
|
|
||||||
member _.OnTestMemberFinished name =
|
member _.OnTestMemberFinished name =
|
||||||
console.MarkupLine $"[gray]Finished test: %s{Markup.Escape name}[/]"
|
console.MarkupLine $"[gray]Finished test: %s{Markup.Escape name}[/]"
|
||||||
|
|
||||||
|
@@ -0,0 +1,396 @@
|
|||||||
|
namespace WoofWare.NUnitTestRunner.Test
|
||||||
|
|
||||||
|
open System
|
||||||
|
open System.Text
|
||||||
|
open System.Threading
|
||||||
|
open System.Threading.Tasks
|
||||||
|
open NUnit.Framework
|
||||||
|
open FsUnitTyped
|
||||||
|
open WoofWare.NUnitTestRunner
|
||||||
|
|
||||||
|
[<TestFixture>]
|
||||||
|
module TestSynchronizationContext =
|
||||||
|
|
||||||
|
[<Test>]
|
||||||
|
let ``ExecutionContext flows correctly through synchronous operations`` () =
|
||||||
|
task {
|
||||||
|
let dummyFixture =
|
||||||
|
TestFixture.Empty typeof<obj> (Some (Parallelizable.Yes ClassParallelScope.All)) [] []
|
||||||
|
|
||||||
|
use contexts = TestContexts.Empty ()
|
||||||
|
use queue = new ParallelQueue (Some 4, None)
|
||||||
|
|
||||||
|
// Track which context values we see during execution
|
||||||
|
let contextValues = System.Collections.Concurrent.ConcurrentBag<Guid * Guid> ()
|
||||||
|
|
||||||
|
// Start the fixture
|
||||||
|
let! running = queue.StartTestFixture dummyFixture
|
||||||
|
let! _, setup = queue.RunTestSetup running (fun () -> ())
|
||||||
|
|
||||||
|
// Create several synchronous operations with different context values
|
||||||
|
let tasks =
|
||||||
|
[ 1..10 ]
|
||||||
|
|> List.map (fun _ ->
|
||||||
|
task {
|
||||||
|
do! Task.Yield ()
|
||||||
|
// Set a unique context value
|
||||||
|
let outputId = contexts.NewOutputs ()
|
||||||
|
let (OutputStreamId expectedId) = outputId
|
||||||
|
contexts.AsyncLocal.Value <- outputId
|
||||||
|
|
||||||
|
// Run a synchronous operation that checks the context
|
||||||
|
let! actualId =
|
||||||
|
queue.Run
|
||||||
|
setup
|
||||||
|
None
|
||||||
|
(fun () ->
|
||||||
|
// Check context immediately
|
||||||
|
let immediate = contexts.AsyncLocal.Value
|
||||||
|
let (OutputStreamId immediateGuid) = immediate
|
||||||
|
contextValues.Add (expectedId, immediateGuid)
|
||||||
|
|
||||||
|
// Do some work that might cause context issues
|
||||||
|
Thread.Sleep 10
|
||||||
|
|
||||||
|
// Check context after work
|
||||||
|
let afterWork = contexts.AsyncLocal.Value
|
||||||
|
let (OutputStreamId afterWorkGuid) = afterWork
|
||||||
|
contextValues.Add (expectedId, afterWorkGuid)
|
||||||
|
|
||||||
|
// Simulate calling into framework code that might use ExecutionContext
|
||||||
|
let mutable capturedValue = Guid.Empty
|
||||||
|
|
||||||
|
ExecutionContext.Run (
|
||||||
|
ExecutionContext.Capture (),
|
||||||
|
(fun _ ->
|
||||||
|
let current = contexts.AsyncLocal.Value
|
||||||
|
let (OutputStreamId currentGuid) = current
|
||||||
|
capturedValue <- currentGuid
|
||||||
|
),
|
||||||
|
()
|
||||||
|
)
|
||||||
|
|
||||||
|
contextValues.Add (expectedId, capturedValue)
|
||||||
|
|
||||||
|
afterWorkGuid
|
||||||
|
)
|
||||||
|
|
||||||
|
// Verify the returned value matches what we set
|
||||||
|
actualId |> shouldEqual expectedId
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Wait for all tasks
|
||||||
|
let! results = Task.WhenAll tasks
|
||||||
|
results |> Array.iter id
|
||||||
|
|
||||||
|
// Verify all context values were correct
|
||||||
|
let allValues = contextValues |> Seq.toList
|
||||||
|
allValues |> shouldHaveLength 30 // 3 checks per operation * 10 operations
|
||||||
|
|
||||||
|
// Every captured value should match its expected value
|
||||||
|
allValues
|
||||||
|
|> List.iter (fun (expected, actual) -> actual |> shouldEqual expected)
|
||||||
|
|
||||||
|
// Clean up
|
||||||
|
let! _, teardown = queue.RunTestTearDown setup (fun () -> ())
|
||||||
|
do! queue.EndTestFixture teardown
|
||||||
|
}
|
||||||
|
|
||||||
|
[<Test>]
|
||||||
|
let ``ExecutionContext isolation between concurrent synchronous operations`` () =
|
||||||
|
task {
|
||||||
|
let dummyFixture =
|
||||||
|
TestFixture.Empty typeof<obj> (Some (Parallelizable.Yes ClassParallelScope.All)) [] []
|
||||||
|
|
||||||
|
use contexts = TestContexts.Empty ()
|
||||||
|
use queue = new ParallelQueue (Some 4, None)
|
||||||
|
|
||||||
|
let! running = queue.StartTestFixture dummyFixture
|
||||||
|
let! _, setup = queue.RunTestSetup running (fun () -> ())
|
||||||
|
|
||||||
|
// Use a barrier to ensure operations run concurrently
|
||||||
|
let barrier = new Barrier (3)
|
||||||
|
let seenValues = System.Collections.Concurrent.ConcurrentBag<int * Guid> ()
|
||||||
|
let outputIds = System.Collections.Concurrent.ConcurrentBag<OutputStreamId> ()
|
||||||
|
|
||||||
|
// Create operations that will definitely run concurrently
|
||||||
|
let tasks =
|
||||||
|
[ 1..3 ]
|
||||||
|
|> List.map (fun i ->
|
||||||
|
task {
|
||||||
|
// Each task sets its own context value
|
||||||
|
let outputId = contexts.NewOutputs ()
|
||||||
|
let (OutputStreamId myId) = outputId
|
||||||
|
contexts.AsyncLocal.Value <- outputId
|
||||||
|
outputIds.Add outputId
|
||||||
|
|
||||||
|
let! result =
|
||||||
|
queue.Run
|
||||||
|
setup
|
||||||
|
(Some (Parallelizable.Yes ()))
|
||||||
|
(fun () ->
|
||||||
|
// Wait for all tasks to reach this point
|
||||||
|
barrier.SignalAndWait ()
|
||||||
|
|
||||||
|
// Now check what value we see
|
||||||
|
let currentValue = contexts.AsyncLocal.Value
|
||||||
|
|
||||||
|
match currentValue with
|
||||||
|
| OutputStreamId guid -> seenValues.Add (i, guid)
|
||||||
|
|
||||||
|
// Do some synchronous work
|
||||||
|
Thread.Sleep 5
|
||||||
|
|
||||||
|
// Check again after work
|
||||||
|
let afterWork = contexts.AsyncLocal.Value
|
||||||
|
|
||||||
|
match afterWork with
|
||||||
|
| OutputStreamId guid ->
|
||||||
|
// Also verify we can write to the correct streams
|
||||||
|
contexts.Stdout.WriteLine $"Task %i{i} sees context %O{guid}"
|
||||||
|
guid
|
||||||
|
)
|
||||||
|
|
||||||
|
// Each task should see its own value
|
||||||
|
result |> shouldEqual myId
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
let! results = Task.WhenAll tasks
|
||||||
|
results |> Array.iter id
|
||||||
|
|
||||||
|
// Verify we saw 3 different values (one per task)
|
||||||
|
let values = seenValues |> Seq.toList
|
||||||
|
values |> shouldHaveLength 3
|
||||||
|
|
||||||
|
// All seen values should be different (no context bleeding)
|
||||||
|
let uniqueValues = values |> List.map snd |> List.distinct
|
||||||
|
uniqueValues |> shouldHaveLength 3
|
||||||
|
|
||||||
|
let! _, teardown = queue.RunTestTearDown setup (fun () -> ())
|
||||||
|
do! queue.EndTestFixture teardown
|
||||||
|
|
||||||
|
// Verify stdout content for each task
|
||||||
|
let collectedOutputs = outputIds |> Seq.toList
|
||||||
|
collectedOutputs |> shouldHaveLength 3
|
||||||
|
|
||||||
|
for outputId in collectedOutputs do
|
||||||
|
let content = contexts.DumpStdout outputId
|
||||||
|
content |> shouldNotEqual ""
|
||||||
|
let (OutputStreamId guid) = outputId
|
||||||
|
content |> shouldContainText (guid.ToString ())
|
||||||
|
}
|
||||||
|
|
||||||
|
[<Test>]
|
||||||
|
let ``ExecutionContext flows correctly through nested synchronous operations`` () =
|
||||||
|
task {
|
||||||
|
let dummyFixture =
|
||||||
|
TestFixture.Empty typeof<obj> (Some (Parallelizable.Yes ClassParallelScope.All)) [] []
|
||||||
|
|
||||||
|
use contexts = TestContexts.Empty ()
|
||||||
|
use queue = new ParallelQueue (Some 4, None)
|
||||||
|
|
||||||
|
let! running = queue.StartTestFixture dummyFixture
|
||||||
|
let! _, setup = queue.RunTestSetup running (fun () -> ())
|
||||||
|
|
||||||
|
// Set an initial context
|
||||||
|
let outputId = contexts.NewOutputs ()
|
||||||
|
let (OutputStreamId outerGuid) = outputId
|
||||||
|
contexts.AsyncLocal.Value <- outputId
|
||||||
|
|
||||||
|
let! result =
|
||||||
|
queue.Run
|
||||||
|
setup
|
||||||
|
None
|
||||||
|
(fun () ->
|
||||||
|
// Check we have the outer context
|
||||||
|
let outer = contexts.AsyncLocal.Value
|
||||||
|
let (OutputStreamId outerSeen) = outer
|
||||||
|
outerSeen |> shouldEqual outerGuid
|
||||||
|
|
||||||
|
// Now change the context for a nested operation
|
||||||
|
let innerOutputId = contexts.NewOutputs ()
|
||||||
|
let (OutputStreamId innerGuid) = innerOutputId
|
||||||
|
contexts.AsyncLocal.Value <- innerOutputId
|
||||||
|
|
||||||
|
// Use Task.Run to potentially hop threads
|
||||||
|
let innerResult =
|
||||||
|
Task
|
||||||
|
.Run(fun () ->
|
||||||
|
let inner = contexts.AsyncLocal.Value
|
||||||
|
let (OutputStreamId innerSeen) = inner
|
||||||
|
innerSeen |> shouldEqual innerGuid
|
||||||
|
innerSeen
|
||||||
|
)
|
||||||
|
.Result
|
||||||
|
|
||||||
|
// After the nested operation, we should still have our inner context
|
||||||
|
let afterNested = contexts.AsyncLocal.Value
|
||||||
|
let (OutputStreamId afterNestedGuid) = afterNested
|
||||||
|
afterNestedGuid |> shouldEqual innerGuid
|
||||||
|
|
||||||
|
(outerSeen, innerResult, afterNestedGuid)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Unpack results
|
||||||
|
let seenOuter, seenInner, seenAfter = result
|
||||||
|
seenOuter |> shouldEqual outerGuid
|
||||||
|
seenInner |> shouldNotEqual outerGuid
|
||||||
|
seenAfter |> shouldEqual seenInner
|
||||||
|
|
||||||
|
let! _, teardown = queue.RunTestTearDown setup (fun () -> ())
|
||||||
|
do! queue.EndTestFixture teardown
|
||||||
|
}
|
||||||
|
|
||||||
|
[<Test>]
|
||||||
|
let ``ExecutionContext flows correctly through async operations`` () =
|
||||||
|
task {
|
||||||
|
// Create a test fixture
|
||||||
|
let dummyFixture =
|
||||||
|
TestFixture.Empty typeof<obj> (Some (Parallelizable.Yes ClassParallelScope.All)) [] []
|
||||||
|
|
||||||
|
use contexts = TestContexts.Empty ()
|
||||||
|
use queue = new ParallelQueue (Some 4, None)
|
||||||
|
|
||||||
|
// Track which context values we see during execution
|
||||||
|
let contextValues = System.Collections.Concurrent.ConcurrentBag<Guid * Guid> ()
|
||||||
|
|
||||||
|
// Start the fixture
|
||||||
|
let! running = queue.StartTestFixture dummyFixture
|
||||||
|
let! _, setup = queue.RunTestSetup running (fun () -> ())
|
||||||
|
|
||||||
|
// Create several async operations with different context values
|
||||||
|
let tasks =
|
||||||
|
[ 1..10 ]
|
||||||
|
|> List.map (fun i ->
|
||||||
|
task {
|
||||||
|
// Set a unique context value
|
||||||
|
let expectedId = Guid.NewGuid ()
|
||||||
|
let outputId = OutputStreamId expectedId
|
||||||
|
contexts.AsyncLocal.Value <- outputId
|
||||||
|
|
||||||
|
// Run an async operation that checks the context at multiple points
|
||||||
|
let! actualId =
|
||||||
|
queue.RunAsync
|
||||||
|
setup
|
||||||
|
None
|
||||||
|
(fun () ->
|
||||||
|
async {
|
||||||
|
// Check context immediately
|
||||||
|
let immediate = contexts.AsyncLocal.Value
|
||||||
|
let (OutputStreamId immediateGuid) = immediate
|
||||||
|
contextValues.Add (expectedId, immediateGuid)
|
||||||
|
|
||||||
|
// Yield to allow potential context loss
|
||||||
|
do! Async.Sleep 10
|
||||||
|
|
||||||
|
// Check context after yield
|
||||||
|
let afterYield = contexts.AsyncLocal.Value
|
||||||
|
let (OutputStreamId afterYieldGuid) = afterYield
|
||||||
|
contextValues.Add (expectedId, afterYieldGuid)
|
||||||
|
|
||||||
|
// Do some actual async work
|
||||||
|
do! Task.Delay (10) |> Async.AwaitTask
|
||||||
|
|
||||||
|
// Check context after task
|
||||||
|
let afterTask = contexts.AsyncLocal.Value
|
||||||
|
let (OutputStreamId afterTaskGuid) = afterTask
|
||||||
|
contextValues.Add (expectedId, afterTaskGuid)
|
||||||
|
|
||||||
|
return afterTaskGuid
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Verify the returned value matches what we set
|
||||||
|
actualId |> shouldEqual expectedId
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Wait for all tasks
|
||||||
|
let! results = Task.WhenAll (tasks)
|
||||||
|
results |> Array.iter id
|
||||||
|
|
||||||
|
// Verify all context values were correct
|
||||||
|
let allValues = contextValues |> Seq.toList
|
||||||
|
allValues |> shouldHaveLength 30 // 3 checks per operation * 10 operations
|
||||||
|
|
||||||
|
// Every captured value should match its expected value
|
||||||
|
allValues
|
||||||
|
|> List.iter (fun (expected, actual) -> actual |> shouldEqual expected)
|
||||||
|
|
||||||
|
// Clean up
|
||||||
|
let! _, teardown = queue.RunTestTearDown setup (fun () -> ())
|
||||||
|
do! queue.EndTestFixture teardown
|
||||||
|
}
|
||||||
|
|
||||||
|
[<Test>]
|
||||||
|
let ``ExecutionContext isolation between concurrent operations`` () =
|
||||||
|
task {
|
||||||
|
let dummyFixture =
|
||||||
|
TestFixture.Empty typeof<obj> (Some (Parallelizable.Yes ClassParallelScope.All)) [] []
|
||||||
|
|
||||||
|
use contexts = TestContexts.Empty ()
|
||||||
|
use queue = new ParallelQueue (Some 4, None)
|
||||||
|
|
||||||
|
let! running = queue.StartTestFixture dummyFixture
|
||||||
|
let! _, setup = queue.RunTestSetup running (fun () -> ())
|
||||||
|
|
||||||
|
// Use a barrier to ensure operations run concurrently
|
||||||
|
let barrier = new Barrier (3)
|
||||||
|
let seenValues = System.Collections.Concurrent.ConcurrentBag<int * Guid> ()
|
||||||
|
|
||||||
|
// Create operations that will definitely run concurrently
|
||||||
|
let tasks =
|
||||||
|
[ 1..3 ]
|
||||||
|
|> List.map (fun i ->
|
||||||
|
task {
|
||||||
|
// Each task sets its own context value
|
||||||
|
let myId = Guid.NewGuid ()
|
||||||
|
contexts.AsyncLocal.Value <- OutputStreamId myId
|
||||||
|
|
||||||
|
let! result =
|
||||||
|
queue.RunAsync
|
||||||
|
setup
|
||||||
|
(Some (Parallelizable.Yes ()))
|
||||||
|
(fun () ->
|
||||||
|
async {
|
||||||
|
// Wait for all tasks to reach this point
|
||||||
|
barrier.SignalAndWait () |> ignore
|
||||||
|
|
||||||
|
// Now check what value we see
|
||||||
|
let currentValue = contexts.AsyncLocal.Value
|
||||||
|
|
||||||
|
match currentValue with
|
||||||
|
| OutputStreamId guid -> seenValues.Add (i, guid)
|
||||||
|
|
||||||
|
// Do some async work
|
||||||
|
do! Async.Sleep 5
|
||||||
|
|
||||||
|
// Check again after async work
|
||||||
|
let afterAsync = contexts.AsyncLocal.Value
|
||||||
|
|
||||||
|
match afterAsync with
|
||||||
|
| OutputStreamId guid -> return guid
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Each task should see its own value
|
||||||
|
result |> shouldEqual myId
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
let! results = Task.WhenAll (tasks)
|
||||||
|
results |> Array.iter id
|
||||||
|
|
||||||
|
// Verify we saw 3 different values (one per task)
|
||||||
|
let values = seenValues |> Seq.toList
|
||||||
|
values |> shouldHaveLength 3
|
||||||
|
|
||||||
|
// All seen values should be different (no context bleeding)
|
||||||
|
let uniqueValues = values |> List.map snd |> List.distinct
|
||||||
|
uniqueValues |> shouldHaveLength 3
|
||||||
|
|
||||||
|
let! _, teardown = queue.RunTestTearDown setup (fun () -> ())
|
||||||
|
do! queue.EndTestFixture teardown
|
||||||
|
}
|
@@ -11,15 +11,16 @@
|
|||||||
<Compile Include="TestFilter.fs" />
|
<Compile Include="TestFilter.fs" />
|
||||||
<Compile Include="TestList.fs" />
|
<Compile Include="TestList.fs" />
|
||||||
<Compile Include="TestSurface.fs" />
|
<Compile Include="TestSurface.fs" />
|
||||||
|
<Compile Include="TestSynchronizationContext.fs" />
|
||||||
<Compile Include="TestTrx.fs" />
|
<Compile Include="TestTrx.fs" />
|
||||||
<EmbeddedResource Include="Example1.trx" />
|
<EmbeddedResource Include="Example1.trx" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ApiSurface" Version="4.1.17" />
|
<PackageReference Include="ApiSurface" Version="4.1.22" />
|
||||||
<PackageReference Include="FsCheck" Version="3.1.0" />
|
<PackageReference Include="FsCheck" Version="3.3.0" />
|
||||||
<PackageReference Include="FsUnit" Version="7.0.1" />
|
<PackageReference Include="FsUnit" Version="7.1.1" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||||
<PackageReference Include="NUnit" Version="4.3.2" />
|
<PackageReference Include="NUnit" Version="4.3.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="5.0.0"/>
|
<PackageReference Include="NUnit3TestAdapter" Version="5.0.0"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@@ -35,7 +35,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Spectre.Console" Version="0.49.1" />
|
<PackageReference Include="Spectre.Console" Version="0.50.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageDownload Include="G-Research.FSharp.Analyzers" Version="[0.13.0]" />
|
<PackageDownload Include="G-Research.FSharp.Analyzers" Version="[0.17.0]" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
6
flake.lock
generated
6
flake.lock
generated
@@ -20,11 +20,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1739451785,
|
"lastModified": 1753432016,
|
||||||
"narHash": "sha256-3ebRdThRic9bHMuNi2IAA/ek9b32bsy8F5R4SvGTIog=",
|
"narHash": "sha256-cnL5WWn/xkZoyH/03NNUS7QgW5vI7D1i74g48qplCvg=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "1128e89fd5e11bb25aedbfc287733c6502202ea9",
|
"rev": "6027c30c8e9810896b92429f0092f624f7b1aace",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
107
nix/deps.json
107
nix/deps.json
@@ -1,13 +1,13 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"pname": "ApiSurface",
|
"pname": "ApiSurface",
|
||||||
"version": "4.1.17",
|
"version": "4.1.22",
|
||||||
"hash": "sha256-ZYIW++7vXYV/7TTNUkV36QDN6yJbHymsKcxTUscTnvA="
|
"hash": "sha256-voj9m3YmyJ95FAMLV4sWzQMod3Em0mTjzf0LBUUFOso="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "fantomas",
|
"pname": "fantomas",
|
||||||
"version": "7.0.0",
|
"version": "7.0.3",
|
||||||
"hash": "sha256-v4bXmvjZOYxl5RSIHuqVfDzBQdRz5SrmzZtD6SeEYTY="
|
"hash": "sha256-0XlfV7SxXPDnk/CjkUesJSaH0cxlNHJ+Jj86zNUhkNA="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "Fantomas.Core",
|
"pname": "Fantomas.Core",
|
||||||
@@ -21,13 +21,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "FsCheck",
|
"pname": "FsCheck",
|
||||||
"version": "3.1.0",
|
"version": "3.3.0",
|
||||||
"hash": "sha256-u0Ha94EjClJ8evNSHu8d6+Dx9qYM3kV3sl1PEq9gF8s="
|
"hash": "sha256-TFDR/uAGv4OqrMX8/reQ4faaAhH9hxTHr1T/YkNPCCU="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "fsharp-analyzers",
|
"pname": "fsharp-analyzers",
|
||||||
"version": "0.29.0",
|
"version": "0.32.0",
|
||||||
"hash": "sha256-e4G7/5DwwSZYvVE9yy+g8n1easPLC6/fDszioIsT7Dw="
|
"hash": "sha256-MnhsK5tOeexL6uQhsV4nTRz8CGbz2o8VyHwAK8x91pE="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "FSharp.Core",
|
"pname": "FSharp.Core",
|
||||||
@@ -41,8 +41,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "FsUnit",
|
"pname": "FsUnit",
|
||||||
"version": "7.0.1",
|
"version": "7.1.1",
|
||||||
"hash": "sha256-K85CIdxMeFSHEKZk6heIXp/oFjWAn7dBILKrw49pJUY="
|
"hash": "sha256-UMCEGKxQ4ytjmPuVpiNaAPbi3RQH9gqa61JJIUS/6hg="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "Microsoft.ApplicationInsights",
|
"pname": "Microsoft.ApplicationInsights",
|
||||||
@@ -76,13 +76,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "Microsoft.CodeCoverage",
|
"pname": "Microsoft.CodeCoverage",
|
||||||
"version": "17.13.0",
|
"version": "17.14.1",
|
||||||
"hash": "sha256-GKrIxeyQo5Az1mztfQgea1kGtJwonnNOrXK/0ULfu8o="
|
"hash": "sha256-f8QytG8GvRoP47rO2KEmnDLxIpyesaq26TFjDdW40Gs="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "Microsoft.NET.Test.Sdk",
|
"pname": "Microsoft.NET.Test.Sdk",
|
||||||
"version": "17.13.0",
|
"version": "17.14.1",
|
||||||
"hash": "sha256-sc2wvyV8cGm1FrNP2GGHEI584RCvRPu15erYCsgw5QY="
|
"hash": "sha256-mZUzDFvFp7x1nKrcnRd0hhbNu5g8EQYt8SKnRgdhT/A="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "Microsoft.NETCore.App.Host.linux-arm64",
|
"pname": "Microsoft.NETCore.App.Host.linux-arm64",
|
||||||
@@ -176,13 +176,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "Microsoft.TestPlatform.ObjectModel",
|
"pname": "Microsoft.TestPlatform.ObjectModel",
|
||||||
"version": "17.13.0",
|
"version": "17.14.1",
|
||||||
"hash": "sha256-6S0fjfj8vA+h6dJVNwLi6oZhYDO/I/6hBZaq2VTW+Uk="
|
"hash": "sha256-QMf6O+w0IT+16Mrzo7wn+N20f3L1/mDhs/qjmEo1rYs="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "Microsoft.TestPlatform.TestHost",
|
"pname": "Microsoft.TestPlatform.TestHost",
|
||||||
"version": "17.13.0",
|
"version": "17.14.1",
|
||||||
"hash": "sha256-L/CJzou7dhmShUgXq3aXL3CaLTJll17Q+JY2DBdUUpo="
|
"hash": "sha256-1cxHWcvHRD7orQ3EEEPPxVGEkTpxom1/zoICC9SInJs="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "Myriad.Core",
|
"pname": "Myriad.Core",
|
||||||
@@ -196,13 +196,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "Nerdbank.GitVersioning",
|
"pname": "Nerdbank.GitVersioning",
|
||||||
"version": "3.7.115",
|
"version": "3.8.38-alpha",
|
||||||
"hash": "sha256-sqn+i7vvBgBUtm7j82mH+SpApgI2hsmL5DYfLm1Z7gw="
|
"hash": "sha256-gPMrVbjOZxXoofczF/pn6eVkLhjVSJIyQrLO2oljrDc="
|
||||||
},
|
|
||||||
{
|
|
||||||
"pname": "Newtonsoft.Json",
|
|
||||||
"version": "13.0.1",
|
|
||||||
"hash": "sha256-K2tSVW4n4beRPzPu3rlVaBEMdGvWSv/3Q1fxaDh4Mjo="
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "Newtonsoft.Json",
|
"pname": "Newtonsoft.Json",
|
||||||
@@ -211,33 +206,33 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "NuGet.Common",
|
"pname": "NuGet.Common",
|
||||||
"version": "6.13.1",
|
"version": "6.14.0",
|
||||||
"hash": "sha256-uDSZzCzMETKJE2pYAh9n110YrLPVs83+cxcyNCv9V/o="
|
"hash": "sha256-jDOwt3veI1GSG8CfBnf2+dJxD3E/Nmlc+vHtD4J76Ms="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "NuGet.Configuration",
|
"pname": "NuGet.Configuration",
|
||||||
"version": "6.13.1",
|
"version": "6.14.0",
|
||||||
"hash": "sha256-fjit3Qhqu+egLgxvJRD6zQ6U2H+OxsLoy7HYcbXJgBY="
|
"hash": "sha256-1PN9s6fhCw3wd2260U6hQ4vG3jIvcG8GIn1oQgxMXA0="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "NuGet.Frameworks",
|
"pname": "NuGet.Frameworks",
|
||||||
"version": "6.13.1",
|
"version": "6.14.0",
|
||||||
"hash": "sha256-upL6cboghOYed6acdlVljMa9nCSExYoBgQlD5QcJ+ek="
|
"hash": "sha256-3ViM3R1ucQMEL2hQYsivT86kI6veMQK2xDsiAcFcVQk="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "NuGet.Packaging",
|
"pname": "NuGet.Packaging",
|
||||||
"version": "6.13.1",
|
"version": "6.14.0",
|
||||||
"hash": "sha256-khq+grMovEsO95wAhCHmauL60LB83NkWnDY5zcImXT4="
|
"hash": "sha256-Yafbnxs3maj55bJ1oKQiZ0QkntFUzXdhorL94YEUOhY="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "NuGet.Protocol",
|
"pname": "NuGet.Protocol",
|
||||||
"version": "6.13.1",
|
"version": "6.14.0",
|
||||||
"hash": "sha256-0zqowx5iNMMzTSF0HO2Zzc1qqyCB/nEhNHFH8Z0jxzc="
|
"hash": "sha256-uLDKfs+QN1MdnuQtTES8qfNzzsmYKM6XB9pwJc4G+eo="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "NuGet.Versioning",
|
"pname": "NuGet.Versioning",
|
||||||
"version": "6.13.1",
|
"version": "6.14.0",
|
||||||
"hash": "sha256-NymrrcVZUoc78elPHYIoBFG2NpdIEZYEeqk6FTdvZug="
|
"hash": "sha256-DqdOJgsphKxSvqB8b60zNPCaiLfbiu3WnUJ/90feLrY="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "NUnit",
|
"pname": "NUnit",
|
||||||
@@ -266,8 +261,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "Spectre.Console",
|
"pname": "Spectre.Console",
|
||||||
"version": "0.49.1",
|
"version": "0.50.0",
|
||||||
"hash": "sha256-tqSVojyuQjuB34lXo759NOcyLgNIw815mKXJPq5JFDo="
|
"hash": "sha256-3MNgumQSXzuXVGj7kLb5FMkTH/LoFohMvUjAZ7nyHfo="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "System.Collections.Immutable",
|
"pname": "System.Collections.Immutable",
|
||||||
@@ -286,8 +281,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "System.Formats.Asn1",
|
"pname": "System.Formats.Asn1",
|
||||||
"version": "8.0.1",
|
"version": "6.0.0",
|
||||||
"hash": "sha256-may/Wg+esmm1N14kQTG4ESMBi+GQKPp0ZrrBo/o6OXM="
|
"hash": "sha256-KaMHgIRBF7Nf3VwOo+gJS1DcD+41cJDPWFh+TDQ8ee8="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "System.IO.Abstractions",
|
"pname": "System.IO.Abstractions",
|
||||||
@@ -304,6 +299,11 @@
|
|||||||
"version": "4.5.5",
|
"version": "4.5.5",
|
||||||
"hash": "sha256-EPQ9o1Kin7KzGI5O3U3PUQAZTItSbk9h/i4rViN3WiI="
|
"hash": "sha256-EPQ9o1Kin7KzGI5O3U3PUQAZTItSbk9h/i4rViN3WiI="
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"pname": "System.Memory",
|
||||||
|
"version": "4.6.3",
|
||||||
|
"hash": "sha256-JgeK63WMmumF6L+FH5cwJgYdpqXrSDcgTQwtIgTHKVU="
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"pname": "System.Private.Uri",
|
"pname": "System.Private.Uri",
|
||||||
"version": "4.3.0",
|
"version": "4.3.0",
|
||||||
@@ -314,6 +314,11 @@
|
|||||||
"version": "1.6.0",
|
"version": "1.6.0",
|
||||||
"hash": "sha256-JJfgaPav7UfEh4yRAQdGhLZF1brr0tUWPl6qmfNWq/E="
|
"hash": "sha256-JJfgaPav7UfEh4yRAQdGhLZF1brr0tUWPl6qmfNWq/E="
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"pname": "System.Reflection.Metadata",
|
||||||
|
"version": "8.0.0",
|
||||||
|
"hash": "sha256-dQGC30JauIDWNWXMrSNOJncVa1umR1sijazYwUDdSIE="
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"pname": "System.Runtime",
|
"pname": "System.Runtime",
|
||||||
"version": "4.3.1",
|
"version": "4.3.1",
|
||||||
@@ -356,27 +361,27 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "WoofWare.DotnetRuntimeLocator",
|
"pname": "WoofWare.DotnetRuntimeLocator",
|
||||||
"version": "0.1.11",
|
"version": "0.1.12",
|
||||||
"hash": "sha256-btWYnXxZzAnEcAE3Ufvz+Z3cJqtW7EGXs5OZMEHIWr8="
|
"hash": "sha256-6pNZs0/R2LnLKSODq9DyHhGo2C+SDyz9k7D/13/78so="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "WoofWare.Myriad.Plugins",
|
"pname": "WoofWare.Myriad.Plugins",
|
||||||
"version": "4.0.12",
|
"version": "8.0.5",
|
||||||
"hash": "sha256-6o8oE5loEpKFVMRXf/rmY0YDW/iRF2Zic1lkfsOXcSo="
|
"hash": "sha256-IfTT2GM9ktUW5BQoKQGFKK39BAKeziJJnrOIL7Vs19o="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "WoofWare.Myriad.Plugins.Attributes",
|
"pname": "WoofWare.Myriad.Plugins.Attributes",
|
||||||
"version": "3.6.7",
|
"version": "3.6.12",
|
||||||
"hash": "sha256-YvrXS2ZMoMZkWgGxxcumyoqQkg4cSjGQzCrMbBCCtXM="
|
"hash": "sha256-90uiVtc5exCbkcdS8DgTmlEZZT8/AdrY0QuFzy+FHUo="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "WoofWare.PrattParser",
|
"pname": "WoofWare.PrattParser",
|
||||||
"version": "0.2.3",
|
"version": "0.2.4",
|
||||||
"hash": "sha256-PsfU33BFsaA8LwlZMkSwmoA4hLb7Vkm2gYm48MglqxY="
|
"hash": "sha256-aNTa2C300jUCsQ+iVSoothbCvBWdg7OzCJknwG5HV6g="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pname": "WoofWare.Whippet.Fantomas",
|
"pname": "WoofWare.Whippet.Fantomas",
|
||||||
"version": "0.3.1",
|
"version": "0.6.3",
|
||||||
"hash": "sha256-i5oiqcrxzM90Ocuq5MIu2Ha5lV0aYu5nCvuwmFqp6NA="
|
"hash": "sha256-FkW/HtVp8/HE2k6d7yFpnJcnP3FNNe9kGlkoIWmNgDw="
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
Reference in New Issue
Block a user