Rename from the rather bland "TestRunner" (#61)

This commit is contained in:
Patrick Stevens
2024-06-10 23:25:33 +01:00
committed by GitHub
parent 181063afcd
commit ebcf0ed589
34 changed files with 602 additions and 594 deletions

View File

@@ -0,0 +1,20 @@
namespace WoofWare.NUnitTestRunner
[<RequireQualifiedAccess>]
module internal Array =
let allOkOrError<'o, 'e> (a : Result<'o, 'e>[]) : Result<'o[], 'o[] * 'e[]> =
let oks = ResizeArray ()
let errors = ResizeArray ()
for i in a do
match i with
| Error e -> errors.Add e
| Ok o -> oks.Add o
let oks = oks.ToArray ()
if errors.Count = 0 then
Ok oks
else
Error (oks, errors.ToArray ())

View File

@@ -0,0 +1,7 @@
namespace WoofWare.NUnitTestRunner.AssemblyInfo
open System.Runtime.CompilerServices
[<assembly : InternalsVisibleTo("WoofWare.NUnitTestRunner.Test")>]
do ()

View File

@@ -0,0 +1,178 @@
namespace WoofWare.NUnitTestRunner
open System.Reflection
/// A modifier on whether a given test should be run.
[<RequireQualifiedAccess>]
type Modifier =
/// This test is Explicit: it can only be run by an explicit instruction to do so.
/// (As of this writing, the console runner will never run such tests.)
| Explicit of reason : string option
/// This test is Ignored: it will never be run by the harness.
| Ignored of reason : string option
/// Describes where data comes from, if any, to provide the args to this test.
[<RequireQualifiedAccess>]
type TestKind =
/// This test takes no arguments.
| Single
/// This test has arguments supplied by TestCaseSource (i.e. we look for members with the given names, and
/// populate the args from those).
| Source of string list
/// This test has arguments supplied by TestCase attributes.
| Data of obj list list
/// Determines whether a set of `[<Value>]`s will be combined elementwise or Cartesian-product-wise.
type Combinatorial =
/// Combine `[<Value>]`s to produce every possible combination of args drawn from the respective sets.
| Combinatorial
/// Combine `[<Value>]`s such that one test is "the first Value from each", one test is "the second Value from
/// each", and so on. Spare slots are filled with `Unchecked.defaultof<_>`.
| Sequential
/// A single method or member which holds some tests. (Often such a member will represent only one test, but e.g.
/// if it has [<TestCaseSource>] then it represents multiple tests.)
type SingleTestMethod =
{
/// The method which we need to invoke, possibly some args, to run the test.
Method : MethodInfo
/// Where the data comes from to populate the args for this method.
Kind : TestKind
/// Any statements about whether the runner should run this test.
/// (This does not include use of `--filter`s.)
Modifiers : Modifier list
/// `[<Category>]`s this test is in.
Categories : string list
/// Whether we should run this test repeatedly, and if so, how many times.
Repeat : int option
/// If this test has data supplied by `[<Value>]` annotations, specifies how those annotations are combined
/// to produce the complete collection of args.
Combinatorial : Combinatorial option
}
/// Human-readable name of this test method.
member this.Name = this.Method.Name
/// A test fixture (usually represented by the [<TestFixture>]` attribute), which may contain many tests,
/// each of which may run many times.
type TestFixture =
{
/// The assembly which contains this TestFixture, loaded into a separate context.
ContainingAssembly : Assembly
/// Fully-qualified name of this fixture (e.g. MyThing.Test.Foo for `[<TestFixture>] module Foo` in the
/// `MyThing.Test` assembly).
Name : string
/// A method which is run once when this test fixture starts, before any other setup logic and before
/// any tests run. If this method fails, no tests will run and no per-test setup/teardown logic will run,
/// but OneTimeTearDown will run.
OneTimeSetUp : MethodInfo option
/// A method which is run once, after any other tear-down logic and after all tests run, even if everything
/// else failed before this (i.e. even if OneTimeSetUp failed, even if all tests failed, etc).
OneTimeTearDown : MethodInfo option
/// Methods which are run in some arbitrary order before each individual test. If any of these fail, the test
/// will not run, but the TearDown methods will still run, and OneTimeTearDown will still run at the end of
/// the fixture. If the first SetUp we run fails, we don't define whether the other SetUps run before
/// we proceed directly to running all the TearDowns.
SetUp : MethodInfo list
/// Methods which are run in some arbitrary order after each individual test, even if the test or its setup
/// failed. If the first TearDown we run fails, we don't define whether the other TearDowns run.
TearDown : MethodInfo list
/// The individual test methods present within this fixture.
Tests : SingleTestMethod list
}
/// A test fixture about which we know nothing. No tests, no setup/teardown.
static member Empty (containingAssembly : Assembly) (name : string) =
{
ContainingAssembly = containingAssembly
Name = name
OneTimeSetUp = None
OneTimeTearDown = None
SetUp = []
TearDown = []
Tests = []
}
/// User code in the unit under test has failed somehow.
[<RequireQualifiedAccess>]
type UserMethodFailure =
/// A method ran to completion and returned a value, when it was expected to return nothing.
| ReturnedNonUnit of name : string * result : obj
/// A method threw.
| Threw of name : string * exn
/// Human-readable representation of the user failure.
override this.ToString () =
match this with
| UserMethodFailure.ReturnedNonUnit (method, ret) ->
$"User-defined method '%s{method}' returned a non-unit: %O{ret}"
| UserMethodFailure.Threw (method, exc) ->
$"User-defined method '%s{method}' threw: %s{exc.Message}\n %s{exc.StackTrace}"
/// Name (not fully-qualified) of the method which failed.
member this.Name =
match this with
| UserMethodFailure.Threw (name, _)
| UserMethodFailure.ReturnedNonUnit (name, _) -> name
/// Represents the failure of a single run of one test. An error signalled this way is a user error: the unit under
/// test has misbehaved.
[<RequireQualifiedAccess>]
type TestFailure =
/// The test itself failed. (Setup must have succeeded if you get this.)
| TestFailed of UserMethodFailure
/// We failed to set up the test (e.g. its SetUp failed). If this happens, we won't proceed
/// to running the test or running any TearDown for that test.
| SetUpFailed of UserMethodFailure
/// We failed to tear down the test (e.g. its TearDown failed). This can happen even if the test failed,
/// because we always run tear-downs, even after failed tests.
| TearDownFailed of UserMethodFailure
/// Name (not fully-qualified) of the method which failed.
member this.Name =
match this with
| TestFailure.TestFailed f
| TestFailure.SetUpFailed f
| TestFailure.TearDownFailed f -> f.Name
/// Human-readable string representation.
override this.ToString () =
match this with
| TestFailure.TestFailed f -> $"execution: %O{f}"
| TestFailure.SetUpFailed f -> $"Setup failed, and we did not attempt to run test: %O{f}"
| TestFailure.TearDownFailed f -> $"Tear-down failed: %O{f}"
/// Represents the result of a test that didn't fail.
[<RequireQualifiedAccess>]
type TestMemberSuccess =
/// The test passed.
| Ok
/// We didn't run the test, because it's [<Ignore>].
| Ignored of reason : string option
/// We didn't run the test, because it's [<Explicit>].
| Explicit of reason : string option
/// We ran the test, and it performed Assert.Inconclusive.
| Inconclusive of reason : string option
/// Represents the failure of a test.
[<RequireQualifiedAccess>]
type TestMemberFailure =
/// We couldn't run this test because it was somehow malformed in a way we detected up front.
| Malformed of reasons : string list
/// We tried to run the test, but it failed. (A single test can fail many times, e.g. if it failed and also
/// the tear-down logic failed afterwards.)
| Failed of TestFailure list
/// Human-readable string representation
override this.ToString () : string =
match this with
| TestMemberFailure.Malformed reasons ->
let reasons = reasons |> String.concat "; "
$"Could not run test because it was malformed: %s{reasons}"
| TestMemberFailure.Failed errors ->
let errors =
errors
|> Seq.map (fun failure -> (failure : TestFailure).ToString ())
|> String.concat "\n"
$"Test failed: %s{errors}"

View File

@@ -0,0 +1,300 @@
namespace WoofWare.NUnitTestRunner
open System
open System.IO
open PrattParser
// Documentation:
// https://learn.microsoft.com/en-us/dotnet/core/testing/selective-unit-tests?pivots=mstest
[<RequireQualifiedAccess>]
type internal ParsedFilter =
| FullyQualifiedName
| Name
| TestCategory
| Not of ParsedFilter
| Or of ParsedFilter * ParsedFilter
| And of ParsedFilter * ParsedFilter
| Equal of ParsedFilter * ParsedFilter
| Contains of ParsedFilter * ParsedFilter
| String of string
[<RequireQualifiedAccess>]
type internal TokenType =
| FullyQualifiedName
| Name
| TestCategory
| OpenParen
| CloseParen
| And
| Or
| Not
| Equal
| NotEqual
| Contains
| NotContains
| String
| QuotedString
static member canTerminateUnquotedString (t : TokenType) : bool =
// Here we essentially choose that unquoted strings can only appear on the RHS of an operation.
match t with
| TokenType.CloseParen
| TokenType.And
| TokenType.Or -> true
| _ -> false
type internal Token =
{
Type : TokenType
Trivia : int * int
}
[<RequireQualifiedAccess>]
module internal Token =
let inline standalone (ty : TokenType) (charPos : int) : Token =
{
Type = ty
Trivia = charPos, 1
}
let inline single (ty : TokenType) (start : int) (len : int) : Token =
{
Type = ty
Trivia = start, len
}
let (|SingleChar|_|) (i : int, c : char) : Token option =
match c with
| '(' -> Some (standalone TokenType.OpenParen i)
| ')' -> Some (standalone TokenType.CloseParen i)
| '~' -> Some (standalone TokenType.Contains i)
| '=' -> Some (standalone TokenType.Equal i)
| '&' -> Some (standalone TokenType.And i)
| '|' -> Some (standalone TokenType.Or i)
| '!' -> Some (standalone TokenType.Not i)
| _ -> None
[<RequireQualifiedAccess>]
module internal Lexer =
type State =
| UnquotedString of startPos : int
| Awaiting
| QuotedString of startPos : int
let lex (s : string) : Token seq =
seq {
let mutable i = 0
let mutable state = State.Awaiting
while i < s.Length do
match (i, s.[i]), state with
| (endI, '"'), State.QuotedString startI ->
yield Token.single TokenType.QuotedString startI (endI - startI)
i <- i + 1
state <- State.Awaiting
| _, State.QuotedString _ -> i <- i + 1
// This one has to come before the check for prefix Not
| (startI, '!'), State.Awaiting when i + 1 < s.Length ->
i <- i + 1
match s.[i] with
| '~' ->
yield Token.single TokenType.NotContains startI 2
i <- i + 1
| '=' ->
yield Token.single TokenType.NotEqual startI 2
i <- i + 1
| _ ->
yield Token.single TokenType.Not startI 1
i <- i + 1
| Token.SingleChar token, State.Awaiting ->
i <- i + 1
yield token
| Token.SingleChar t, State.UnquotedString stringStart ->
if TokenType.canTerminateUnquotedString t.Type then
yield Token.single TokenType.String stringStart (i - stringStart)
// don't increment `i`, we'll just do the match again
state <- State.Awaiting
else
i <- i + 1
| (_, 'F'), State.Awaiting when
i + 1 < s.Length
&& s.[i + 1 ..].StartsWith ("ullyQualifiedName", StringComparison.Ordinal)
->
yield Token.single TokenType.FullyQualifiedName i "FullyQualifiedName".Length
i <- i + "FullyQualifiedName".Length
| (_, 'N'), State.Awaiting when
i + 1 < s.Length && s.[i + 1 ..].StartsWith ("ame", StringComparison.Ordinal)
->
yield Token.single TokenType.Name i "Name".Length
i <- i + "Name".Length
| (_, 'T'), State.Awaiting when
i + 1 < s.Length
&& s.[i + 1 ..].StartsWith ("estCategory", StringComparison.Ordinal)
->
yield Token.single TokenType.TestCategory i "TestCategory".Length
i <- i + "TestCategory".Length
| (_, ' '), State.Awaiting -> i <- i + 1
| (_, '"'), State.Awaiting ->
state <- State.QuotedString i
i <- i + 1
| (_, _), State.Awaiting ->
state <- State.UnquotedString i
i <- i + 1
| (_, _), State.UnquotedString _ -> i <- i + 1
match state with
| State.Awaiting -> ()
| State.UnquotedString start -> yield Token.single TokenType.String start (s.Length - start)
| State.QuotedString i ->
failwith $"Parse failed: we never closed the string which started at position %i{i}"
}
[<RequireQualifiedAccess>]
module internal ParsedFilter =
let private unescape (s : string) : string =
System.Xml.XmlReader
.Create(new StringReader ("<r>" + s + "</r>"))
.ReadElementString ()
let private atom (inputString : string) (token : Token) : ParsedFilter option =
let start, len = token.Trivia
match token.Type with
| TokenType.QuotedString ->
// +1 and -1, because the trivia contains the initial and terminal quote mark
inputString.Substring (start + 1, len - 1)
|> unescape
|> ParsedFilter.String
|> Some
| TokenType.String -> Some (ParsedFilter.String (inputString.Substring (start, len)))
| TokenType.FullyQualifiedName -> Some ParsedFilter.FullyQualifiedName
| TokenType.Name -> Some ParsedFilter.Name
| TokenType.TestCategory -> Some ParsedFilter.TestCategory
| TokenType.OpenParen -> None
| TokenType.CloseParen -> None
| TokenType.And -> None
| TokenType.Or -> None
| TokenType.Not -> None
| TokenType.NotEqual -> None
| TokenType.Equal -> None
| TokenType.NotContains -> None
| TokenType.Contains -> None
let parser =
Parser.make<_, Token, ParsedFilter> _.Type atom
|> Parser.withInfix TokenType.And (10, 11) (fun a b -> ParsedFilter.And (a, b))
|> Parser.withInfix TokenType.Equal (15, 16) (fun a b -> ParsedFilter.Equal (a, b))
|> Parser.withInfix TokenType.NotEqual (15, 16) (fun a b -> ParsedFilter.Not (ParsedFilter.Equal (a, b)))
|> Parser.withInfix TokenType.Contains (15, 16) (fun a b -> ParsedFilter.Contains (a, b))
|> Parser.withInfix TokenType.NotContains (15, 16) (fun a b -> ParsedFilter.Not (ParsedFilter.Contains (a, b)))
|> Parser.withInfix TokenType.Or (5, 6) (fun a b -> ParsedFilter.Or (a, b))
|> Parser.withUnaryPrefix TokenType.Not ((), 13) ParsedFilter.Not
|> Parser.withBracketLike
TokenType.OpenParen
{
ConsumeBeforeInitialToken = false
ConsumeAfterFinalToken = false
BoundaryTokens = [ TokenType.CloseParen ]
Construct = List.exactlyOne
}
let parse (s : string) : ParsedFilter =
let tokens = Lexer.lex s |> Seq.toList
let parsed, remaining = Parser.execute parser s tokens
if not remaining.IsEmpty then
failwith $"Leftover tokens: %O{remaining}"
match parsed with
| ParsedFilter.String _ -> ParsedFilter.Contains (ParsedFilter.FullyQualifiedName, parsed)
| _ -> parsed
/// The type of matching which this filter will perform.
type Match =
/// This filter will only match if its argument is exactly (case-sensitively) equal to this.
| Exact of string
/// This filter will match if its argument (case-sensitively) contains this substring.
| Contains of string
/// A filter which is to be applied when running tests, to determine which tests to run.
[<RequireQualifiedAccess>]
type Filter =
/// The fully qualified name of the test must match this.
| FullyQualifiedName of Match
/// The name (without its assembly prepended) of the test must match this.
| Name of Match
/// The test must be in a matching category.
| TestCategory of Match
/// The test must not match this filter.
| Not of Filter
/// The test must match at least one of these filters.
| Or of Filter * Filter
/// The test must match both of these filters.
| And of Filter * Filter
/// Methods for manipulating filters.
[<RequireQualifiedAccess>]
module Filter =
let rec internal makeParsed (fi : ParsedFilter) : Filter =
match fi with
| ParsedFilter.Not x -> Filter.Not (makeParsed x)
| ParsedFilter.FullyQualifiedName -> failwith "malformed filter: found FullyQualifiedName with no operand"
| ParsedFilter.Name -> failwith "malformed filter: found Name with no operand"
| ParsedFilter.TestCategory -> failwith "malformed filter: found TestCategory with no operand"
| ParsedFilter.Or (a, b) -> Filter.Or (makeParsed a, makeParsed b)
| ParsedFilter.And (a, b) -> Filter.And (makeParsed a, makeParsed b)
| ParsedFilter.Equal (key, value) ->
let value =
match value with
| ParsedFilter.String s -> s
| _ -> failwith $"malformed filter: found non-string operand on RHS of equality, '%O{value}'"
match key with
| ParsedFilter.TestCategory -> Filter.TestCategory (Match.Exact value)
| ParsedFilter.FullyQualifiedName -> Filter.FullyQualifiedName (Match.Exact value)
| ParsedFilter.Name -> Filter.Name (Match.Exact value)
| _ -> failwith $"Malformed filter: left-hand side of Equals clause must be e.g. TestCategory, was %O{key}"
| ParsedFilter.Contains (key, value) ->
let value =
match value with
| ParsedFilter.String s -> s
| _ -> failwith $"malformed filter: found non-string operand on RHS of containment, '%O{value}'"
match key with
| ParsedFilter.TestCategory -> Filter.TestCategory (Match.Contains value)
| ParsedFilter.FullyQualifiedName -> Filter.FullyQualifiedName (Match.Contains value)
| ParsedFilter.Name -> Filter.Name (Match.Contains value)
| _ ->
failwith $"Malformed filter: left-hand side of Contains clause must be e.g. TestCategory, was %O{key}"
| ParsedFilter.String s -> failwith $"Malformed filter: got verbatim string %s{s} when expected an operation"
/// Parse the input string, e.g. the `foo` one might get from `dotnet test --filter foo`.
/// Verbatim strings are assumed to be XML-escaped.
let parse (s : string) : Filter = ParsedFilter.parse s |> makeParsed
/// Convert the representation of a test filter into a function that decides whether to run any given test.
let rec shouldRun (filter : Filter) : TestFixture -> SingleTestMethod -> bool =
match filter with
| Filter.Not filter ->
let inner = shouldRun filter
fun a b -> not (inner a b)
| Filter.And (a, b) ->
let inner1 = shouldRun a
let inner2 = shouldRun b
fun a b -> inner1 a b && inner2 a b
| Filter.Or (a, b) ->
let inner1 = shouldRun a
let inner2 = shouldRun b
fun a b -> inner1 a b || inner2 a b
| Filter.Name (Match.Exact m) -> fun _fixture method -> method.Method.Name = m
| Filter.Name (Match.Contains m) -> fun _fixture method -> method.Method.Name.Contains m
| Filter.FullyQualifiedName (Match.Exact m) ->
fun _fixture method -> (method.Method.DeclaringType.FullName + "." + method.Method.Name) = m
| Filter.FullyQualifiedName (Match.Contains m) ->
fun _fixture method -> (method.Method.DeclaringType.FullName + "." + method.Method.Name).Contains m
| Filter.TestCategory (Match.Contains m) ->
fun _fixture method -> method.Categories |> List.exists (fun cat -> cat.Contains m)
| Filter.TestCategory (Match.Exact m) -> fun _fixture method -> method.Categories |> List.contains m

View File

@@ -0,0 +1,15 @@
namespace WoofWare.NUnitTestRunner
[<RequireQualifiedAccess>]
module internal List =
/// Given e.g. [[1,2],[4,5,6]], returns:
/// [1;4] ; [1;5] ; [1;6] ; [2;4] ; [2;5] ; [2;6]
/// in some order.
/// This is like allPairs but more so.
let rec combinations (s : 'a list list) : 'a list list =
match s with
| [] -> [ [] ]
| head :: s ->
let sub = combinations s
head |> List.collect (fun head -> sub |> List.map (fun tail -> head :: tail))

View File

@@ -0,0 +1,30 @@
namespace WoofWare.NUnitTestRunner
[<RequireQualifiedAccess>]
module internal Result =
let inline getError<'r, 'e> (r : Result<'r, 'e>) : 'e option =
match r with
| Ok _ -> None
| Error e -> Some e
let get<'r, 'e> (r : Result<'r, 'e>) : 'r option =
match r with
| Ok r -> Some r
| Error _ -> None
let allOkOrError<'o, 'e> (a : Result<'o, 'e> list) : Result<'o list, 'o list * 'e list> =
let oks = ResizeArray ()
let errors = ResizeArray ()
for i in a do
match i with
| Error e -> errors.Add e
| Ok o -> oks.Add o
let oks = oks |> Seq.toList
if errors.Count = 0 then
Ok oks
else
Error (oks, Seq.toList errors)

View File

@@ -0,0 +1,123 @@
namespace WoofWare.NUnitTestRunner
open System
open System.Reflection
/// A single method or member which holds some tests. (Often such a member will represent only one test, but e.g.
/// if it has [<TestCaseSource>] then it represents multiple tests.)
[<RequireQualifiedAccess>]
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module SingleTestMethod =
/// Extract a SingleTestMethod from the given MethodInfo that we think represents a test.
/// You pass us the attributes you still haven't parsed from this MethodInfo, and we give you back the sub-list
/// of attributes we were also unable to interpret.
/// You also give us the list of categories with which the containing TestFixture is tagged.
let parse
(parentCategories : string list)
(method : MethodInfo)
(attrs : CustomAttributeData list)
: SingleTestMethod option * CustomAttributeData list
=
let remaining, isTest, sources, hasData, modifiers, categories, repeat, comb =
(([], false, [], None, [], [], None, None), attrs)
||> List.fold (fun (remaining, isTest, sources, hasData, mods, cats, repeat, comb) attr ->
match attr.AttributeType.FullName with
| "NUnit.Framework.TestAttribute" ->
if attr.ConstructorArguments.Count > 0 then
failwith "Unexpectedly got arguments to the Test attribute"
(remaining, true, sources, hasData, mods, cats, repeat, comb)
| "NUnit.Framework.TestCaseAttribute" ->
let args = attr.ConstructorArguments |> Seq.map _.Value |> Seq.toList
match hasData with
| None -> (remaining, isTest, sources, Some [ List.ofSeq args ], mods, cats, repeat, comb)
| Some existing ->
(remaining, isTest, sources, Some ((List.ofSeq args) :: existing), mods, cats, repeat, comb)
| "NUnit.Framework.TestCaseSourceAttribute" ->
let arg = attr.ConstructorArguments |> Seq.exactlyOne |> _.Value |> unbox<string>
(remaining, isTest, arg :: sources, hasData, mods, cats, repeat, comb)
| "NUnit.Framework.ExplicitAttribute" ->
let reason =
attr.ConstructorArguments
|> Seq.tryHead
|> Option.map (_.Value >> unbox<string>)
(remaining, isTest, sources, hasData, (Modifier.Explicit reason) :: mods, cats, repeat, comb)
| "NUnit.Framework.IgnoreAttribute" ->
let reason =
attr.ConstructorArguments
|> Seq.tryHead
|> Option.map (_.Value >> unbox<string>)
(remaining, isTest, sources, hasData, (Modifier.Ignored reason) :: mods, cats, repeat, comb)
| "NUnit.Framework.CategoryAttribute" ->
let category =
attr.ConstructorArguments |> Seq.exactlyOne |> _.Value |> unbox<string>
(remaining, isTest, sources, hasData, mods, category :: cats, repeat, comb)
| "NUnit.Framework.RepeatAttribute" ->
match repeat with
| Some _ -> failwith $"Got RepeatAttribute multiple times on %s{method.Name}"
| None ->
let repeat = attr.ConstructorArguments |> Seq.exactlyOne |> _.Value |> unbox<int>
(remaining, isTest, sources, hasData, mods, cats, Some repeat, comb)
| "NUnit.Framework.CombinatorialAttribute" ->
match comb with
| Some _ ->
failwith $"Got CombinatorialAttribute or SequentialAttribute multiple times on %s{method.Name}"
| None ->
(remaining, isTest, sources, hasData, mods, cats, repeat, Some Combinatorial.Combinatorial)
| "NUnit.Framework.SequentialAttribute" ->
match comb with
| Some _ ->
failwith $"Got CombinatorialAttribute or SequentialAttribute multiple times on %s{method.Name}"
| None -> (remaining, isTest, sources, hasData, mods, cats, repeat, Some Combinatorial.Sequential)
| s when s.StartsWith ("NUnit.Framework", StringComparison.Ordinal) ->
failwith $"Unrecognised attribute on function %s{method.Name}: %s{attr.AttributeType.FullName}"
| _ -> (attr :: remaining, isTest, sources, hasData, mods, cats, repeat, comb)
)
let test =
match isTest, sources, hasData, modifiers, categories, repeat, comb with
| _, _ :: _, Some _, _, _, _, _ ->
failwith
$"Test '%s{method.Name}' unexpectedly has both TestData and TestCaseSource; not currently supported"
| false, [], None, [], _, _, _ -> None
| _, _ :: _, None, mods, categories, repeat, comb ->
{
Kind = TestKind.Source sources
Method = method
Modifiers = mods
Categories = categories @ parentCategories
Repeat = repeat
Combinatorial = comb
}
|> Some
| _, [], Some data, mods, categories, repeat, comb ->
{
Kind = TestKind.Data data
Method = method
Modifiers = mods
Categories = categories @ parentCategories
Repeat = repeat
Combinatorial = comb
}
|> Some
| true, [], None, mods, categories, repeat, comb ->
{
Kind = TestKind.Single
Method = method
Modifiers = mods
Categories = categories @ parentCategories
Repeat = repeat
Combinatorial = comb
}
|> Some
| false, [], None, _ :: _, _, _, _ ->
failwith
$"Unexpectedly got test modifiers but no test settings on '%s{method.Name}', which you probably didn't intend."
test, remaining

View File

@@ -0,0 +1,531 @@
WoofWare.NUnitTestRunner.Combinatorial inherit obj, implements WoofWare.NUnitTestRunner.Combinatorial System.IEquatable, System.Collections.IStructuralEquatable, WoofWare.NUnitTestRunner.Combinatorial System.IComparable, System.IComparable, System.Collections.IStructuralComparable - union type with 2 cases
WoofWare.NUnitTestRunner.Combinatorial+Tags inherit obj
WoofWare.NUnitTestRunner.Combinatorial+Tags.Combinatorial [static field]: int = 0
WoofWare.NUnitTestRunner.Combinatorial+Tags.Sequential [static field]: int = 1
WoofWare.NUnitTestRunner.Combinatorial.Combinatorial [static property]: [read-only] WoofWare.NUnitTestRunner.Combinatorial
WoofWare.NUnitTestRunner.Combinatorial.get_Combinatorial [static method]: unit -> WoofWare.NUnitTestRunner.Combinatorial
WoofWare.NUnitTestRunner.Combinatorial.get_IsCombinatorial [method]: unit -> bool
WoofWare.NUnitTestRunner.Combinatorial.get_IsSequential [method]: unit -> bool
WoofWare.NUnitTestRunner.Combinatorial.get_Sequential [static method]: unit -> WoofWare.NUnitTestRunner.Combinatorial
WoofWare.NUnitTestRunner.Combinatorial.get_Tag [method]: unit -> int
WoofWare.NUnitTestRunner.Combinatorial.IsCombinatorial [property]: [read-only] bool
WoofWare.NUnitTestRunner.Combinatorial.IsSequential [property]: [read-only] bool
WoofWare.NUnitTestRunner.Combinatorial.Sequential [static property]: [read-only] WoofWare.NUnitTestRunner.Combinatorial
WoofWare.NUnitTestRunner.Combinatorial.Tag [property]: [read-only] int
WoofWare.NUnitTestRunner.Filter inherit obj, implements WoofWare.NUnitTestRunner.Filter System.IEquatable, System.Collections.IStructuralEquatable, WoofWare.NUnitTestRunner.Filter System.IComparable, System.IComparable, System.Collections.IStructuralComparable - union type with 6 cases
WoofWare.NUnitTestRunner.Filter+And inherit WoofWare.NUnitTestRunner.Filter
WoofWare.NUnitTestRunner.Filter+And.get_Item1 [method]: unit -> WoofWare.NUnitTestRunner.Filter
WoofWare.NUnitTestRunner.Filter+And.get_Item2 [method]: unit -> WoofWare.NUnitTestRunner.Filter
WoofWare.NUnitTestRunner.Filter+And.Item1 [property]: [read-only] WoofWare.NUnitTestRunner.Filter
WoofWare.NUnitTestRunner.Filter+And.Item2 [property]: [read-only] WoofWare.NUnitTestRunner.Filter
WoofWare.NUnitTestRunner.Filter+FullyQualifiedName inherit WoofWare.NUnitTestRunner.Filter
WoofWare.NUnitTestRunner.Filter+FullyQualifiedName.get_Item [method]: unit -> WoofWare.NUnitTestRunner.Match
WoofWare.NUnitTestRunner.Filter+FullyQualifiedName.Item [property]: [read-only] WoofWare.NUnitTestRunner.Match
WoofWare.NUnitTestRunner.Filter+Name inherit WoofWare.NUnitTestRunner.Filter
WoofWare.NUnitTestRunner.Filter+Name.get_Item [method]: unit -> WoofWare.NUnitTestRunner.Match
WoofWare.NUnitTestRunner.Filter+Name.Item [property]: [read-only] WoofWare.NUnitTestRunner.Match
WoofWare.NUnitTestRunner.Filter+Not inherit WoofWare.NUnitTestRunner.Filter
WoofWare.NUnitTestRunner.Filter+Not.get_Item [method]: unit -> WoofWare.NUnitTestRunner.Filter
WoofWare.NUnitTestRunner.Filter+Not.Item [property]: [read-only] WoofWare.NUnitTestRunner.Filter
WoofWare.NUnitTestRunner.Filter+Or inherit WoofWare.NUnitTestRunner.Filter
WoofWare.NUnitTestRunner.Filter+Or.get_Item1 [method]: unit -> WoofWare.NUnitTestRunner.Filter
WoofWare.NUnitTestRunner.Filter+Or.get_Item2 [method]: unit -> WoofWare.NUnitTestRunner.Filter
WoofWare.NUnitTestRunner.Filter+Or.Item1 [property]: [read-only] WoofWare.NUnitTestRunner.Filter
WoofWare.NUnitTestRunner.Filter+Or.Item2 [property]: [read-only] WoofWare.NUnitTestRunner.Filter
WoofWare.NUnitTestRunner.Filter+Tags inherit obj
WoofWare.NUnitTestRunner.Filter+Tags.And [static field]: int = 5
WoofWare.NUnitTestRunner.Filter+Tags.FullyQualifiedName [static field]: int = 0
WoofWare.NUnitTestRunner.Filter+Tags.Name [static field]: int = 1
WoofWare.NUnitTestRunner.Filter+Tags.Not [static field]: int = 3
WoofWare.NUnitTestRunner.Filter+Tags.Or [static field]: int = 4
WoofWare.NUnitTestRunner.Filter+Tags.TestCategory [static field]: int = 2
WoofWare.NUnitTestRunner.Filter+TestCategory inherit WoofWare.NUnitTestRunner.Filter
WoofWare.NUnitTestRunner.Filter+TestCategory.get_Item [method]: unit -> WoofWare.NUnitTestRunner.Match
WoofWare.NUnitTestRunner.Filter+TestCategory.Item [property]: [read-only] WoofWare.NUnitTestRunner.Match
WoofWare.NUnitTestRunner.Filter.get_IsAnd [method]: unit -> bool
WoofWare.NUnitTestRunner.Filter.get_IsFullyQualifiedName [method]: unit -> bool
WoofWare.NUnitTestRunner.Filter.get_IsName [method]: unit -> bool
WoofWare.NUnitTestRunner.Filter.get_IsNot [method]: unit -> bool
WoofWare.NUnitTestRunner.Filter.get_IsOr [method]: unit -> bool
WoofWare.NUnitTestRunner.Filter.get_IsTestCategory [method]: unit -> bool
WoofWare.NUnitTestRunner.Filter.get_Tag [method]: unit -> int
WoofWare.NUnitTestRunner.Filter.IsAnd [property]: [read-only] bool
WoofWare.NUnitTestRunner.Filter.IsFullyQualifiedName [property]: [read-only] bool
WoofWare.NUnitTestRunner.Filter.IsName [property]: [read-only] bool
WoofWare.NUnitTestRunner.Filter.IsNot [property]: [read-only] bool
WoofWare.NUnitTestRunner.Filter.IsOr [property]: [read-only] bool
WoofWare.NUnitTestRunner.Filter.IsTestCategory [property]: [read-only] bool
WoofWare.NUnitTestRunner.Filter.NewAnd [static method]: (WoofWare.NUnitTestRunner.Filter, WoofWare.NUnitTestRunner.Filter) -> WoofWare.NUnitTestRunner.Filter
WoofWare.NUnitTestRunner.Filter.NewFullyQualifiedName [static method]: WoofWare.NUnitTestRunner.Match -> WoofWare.NUnitTestRunner.Filter
WoofWare.NUnitTestRunner.Filter.NewName [static method]: WoofWare.NUnitTestRunner.Match -> WoofWare.NUnitTestRunner.Filter
WoofWare.NUnitTestRunner.Filter.NewNot [static method]: WoofWare.NUnitTestRunner.Filter -> WoofWare.NUnitTestRunner.Filter
WoofWare.NUnitTestRunner.Filter.NewOr [static method]: (WoofWare.NUnitTestRunner.Filter, WoofWare.NUnitTestRunner.Filter) -> WoofWare.NUnitTestRunner.Filter
WoofWare.NUnitTestRunner.Filter.NewTestCategory [static method]: WoofWare.NUnitTestRunner.Match -> WoofWare.NUnitTestRunner.Filter
WoofWare.NUnitTestRunner.Filter.Tag [property]: [read-only] int
WoofWare.NUnitTestRunner.FilterModule inherit obj
WoofWare.NUnitTestRunner.FilterModule.parse [static method]: string -> WoofWare.NUnitTestRunner.Filter
WoofWare.NUnitTestRunner.FilterModule.shouldRun [static method]: WoofWare.NUnitTestRunner.Filter -> (WoofWare.NUnitTestRunner.TestFixture -> WoofWare.NUnitTestRunner.SingleTestMethod -> bool)
WoofWare.NUnitTestRunner.FixtureRunResults inherit obj, implements WoofWare.NUnitTestRunner.FixtureRunResults System.IEquatable, System.Collections.IStructuralEquatable
WoofWare.NUnitTestRunner.FixtureRunResults..ctor [constructor]: ((WoofWare.NUnitTestRunner.TestMemberFailure * WoofWare.NUnitTestRunner.IndividualTestRunMetadata) list, (WoofWare.NUnitTestRunner.SingleTestMethod * WoofWare.NUnitTestRunner.TestMemberSuccess * WoofWare.NUnitTestRunner.IndividualTestRunMetadata) list, (WoofWare.NUnitTestRunner.UserMethodFailure * WoofWare.NUnitTestRunner.IndividualTestRunMetadata) list)
WoofWare.NUnitTestRunner.FixtureRunResults.Failed [property]: [read-only] (WoofWare.NUnitTestRunner.TestMemberFailure * WoofWare.NUnitTestRunner.IndividualTestRunMetadata) list
WoofWare.NUnitTestRunner.FixtureRunResults.get_Failed [method]: unit -> (WoofWare.NUnitTestRunner.TestMemberFailure * WoofWare.NUnitTestRunner.IndividualTestRunMetadata) list
WoofWare.NUnitTestRunner.FixtureRunResults.get_IndividualTestRunMetadata [method]: unit -> (WoofWare.NUnitTestRunner.IndividualTestRunMetadata * Microsoft.FSharp.Core.FSharpChoice<WoofWare.NUnitTestRunner.TestMemberFailure, WoofWare.NUnitTestRunner.TestMemberSuccess, WoofWare.NUnitTestRunner.UserMethodFailure>) list
WoofWare.NUnitTestRunner.FixtureRunResults.get_OtherFailures [method]: unit -> (WoofWare.NUnitTestRunner.UserMethodFailure * WoofWare.NUnitTestRunner.IndividualTestRunMetadata) list
WoofWare.NUnitTestRunner.FixtureRunResults.get_Success [method]: unit -> (WoofWare.NUnitTestRunner.SingleTestMethod * WoofWare.NUnitTestRunner.TestMemberSuccess * WoofWare.NUnitTestRunner.IndividualTestRunMetadata) list
WoofWare.NUnitTestRunner.FixtureRunResults.IndividualTestRunMetadata [property]: [read-only] (WoofWare.NUnitTestRunner.IndividualTestRunMetadata * Microsoft.FSharp.Core.FSharpChoice<WoofWare.NUnitTestRunner.TestMemberFailure, WoofWare.NUnitTestRunner.TestMemberSuccess, WoofWare.NUnitTestRunner.UserMethodFailure>) list
WoofWare.NUnitTestRunner.FixtureRunResults.OtherFailures [property]: [read-only] (WoofWare.NUnitTestRunner.UserMethodFailure * WoofWare.NUnitTestRunner.IndividualTestRunMetadata) list
WoofWare.NUnitTestRunner.FixtureRunResults.Success [property]: [read-only] (WoofWare.NUnitTestRunner.SingleTestMethod * WoofWare.NUnitTestRunner.TestMemberSuccess * WoofWare.NUnitTestRunner.IndividualTestRunMetadata) list
WoofWare.NUnitTestRunner.IndividualTestRunMetadata inherit obj, implements WoofWare.NUnitTestRunner.IndividualTestRunMetadata System.IEquatable, System.Collections.IStructuralEquatable, WoofWare.NUnitTestRunner.IndividualTestRunMetadata System.IComparable, System.IComparable, System.Collections.IStructuralComparable
WoofWare.NUnitTestRunner.IndividualTestRunMetadata..ctor [constructor]: (System.TimeSpan, System.DateTimeOffset, System.DateTimeOffset, string, System.Guid, System.Guid, string, string, string option, string option)
WoofWare.NUnitTestRunner.IndividualTestRunMetadata.ClassName [property]: [read-only] string
WoofWare.NUnitTestRunner.IndividualTestRunMetadata.ComputerName [property]: [read-only] string
WoofWare.NUnitTestRunner.IndividualTestRunMetadata.End [property]: [read-only] System.DateTimeOffset
WoofWare.NUnitTestRunner.IndividualTestRunMetadata.ExecutionId [property]: [read-only] System.Guid
WoofWare.NUnitTestRunner.IndividualTestRunMetadata.get_ClassName [method]: unit -> string
WoofWare.NUnitTestRunner.IndividualTestRunMetadata.get_ComputerName [method]: unit -> string
WoofWare.NUnitTestRunner.IndividualTestRunMetadata.get_End [method]: unit -> System.DateTimeOffset
WoofWare.NUnitTestRunner.IndividualTestRunMetadata.get_ExecutionId [method]: unit -> System.Guid
WoofWare.NUnitTestRunner.IndividualTestRunMetadata.get_Start [method]: unit -> System.DateTimeOffset
WoofWare.NUnitTestRunner.IndividualTestRunMetadata.get_StdErr [method]: unit -> string option
WoofWare.NUnitTestRunner.IndividualTestRunMetadata.get_StdOut [method]: unit -> string option
WoofWare.NUnitTestRunner.IndividualTestRunMetadata.get_TestId [method]: unit -> System.Guid
WoofWare.NUnitTestRunner.IndividualTestRunMetadata.get_TestName [method]: unit -> string
WoofWare.NUnitTestRunner.IndividualTestRunMetadata.get_Total [method]: unit -> System.TimeSpan
WoofWare.NUnitTestRunner.IndividualTestRunMetadata.Start [property]: [read-only] System.DateTimeOffset
WoofWare.NUnitTestRunner.IndividualTestRunMetadata.StdErr [property]: [read-only] string option
WoofWare.NUnitTestRunner.IndividualTestRunMetadata.StdOut [property]: [read-only] string option
WoofWare.NUnitTestRunner.IndividualTestRunMetadata.TestId [property]: [read-only] System.Guid
WoofWare.NUnitTestRunner.IndividualTestRunMetadata.TestName [property]: [read-only] string
WoofWare.NUnitTestRunner.IndividualTestRunMetadata.Total [property]: [read-only] System.TimeSpan
WoofWare.NUnitTestRunner.ITestProgress - interface with 5 member(s)
WoofWare.NUnitTestRunner.ITestProgress.OnTestFailed [method]: string -> WoofWare.NUnitTestRunner.TestMemberFailure -> unit
WoofWare.NUnitTestRunner.ITestProgress.OnTestFixtureStart [method]: string -> int -> unit
WoofWare.NUnitTestRunner.ITestProgress.OnTestMemberFinished [method]: string -> unit
WoofWare.NUnitTestRunner.ITestProgress.OnTestMemberSkipped [method]: string -> unit
WoofWare.NUnitTestRunner.ITestProgress.OnTestMemberStart [method]: string -> unit
WoofWare.NUnitTestRunner.Match inherit obj, implements WoofWare.NUnitTestRunner.Match System.IEquatable, System.Collections.IStructuralEquatable, WoofWare.NUnitTestRunner.Match System.IComparable, System.IComparable, System.Collections.IStructuralComparable - union type with 2 cases
WoofWare.NUnitTestRunner.Match+Contains inherit WoofWare.NUnitTestRunner.Match
WoofWare.NUnitTestRunner.Match+Contains.get_Item [method]: unit -> string
WoofWare.NUnitTestRunner.Match+Contains.Item [property]: [read-only] string
WoofWare.NUnitTestRunner.Match+Exact inherit WoofWare.NUnitTestRunner.Match
WoofWare.NUnitTestRunner.Match+Exact.get_Item [method]: unit -> string
WoofWare.NUnitTestRunner.Match+Exact.Item [property]: [read-only] string
WoofWare.NUnitTestRunner.Match+Tags inherit obj
WoofWare.NUnitTestRunner.Match+Tags.Contains [static field]: int = 1
WoofWare.NUnitTestRunner.Match+Tags.Exact [static field]: int = 0
WoofWare.NUnitTestRunner.Match.get_IsContains [method]: unit -> bool
WoofWare.NUnitTestRunner.Match.get_IsExact [method]: unit -> bool
WoofWare.NUnitTestRunner.Match.get_Tag [method]: unit -> int
WoofWare.NUnitTestRunner.Match.IsContains [property]: [read-only] bool
WoofWare.NUnitTestRunner.Match.IsExact [property]: [read-only] bool
WoofWare.NUnitTestRunner.Match.NewContains [static method]: string -> WoofWare.NUnitTestRunner.Match
WoofWare.NUnitTestRunner.Match.NewExact [static method]: string -> WoofWare.NUnitTestRunner.Match
WoofWare.NUnitTestRunner.Match.Tag [property]: [read-only] int
WoofWare.NUnitTestRunner.Modifier inherit obj, implements WoofWare.NUnitTestRunner.Modifier System.IEquatable, System.Collections.IStructuralEquatable, WoofWare.NUnitTestRunner.Modifier System.IComparable, System.IComparable, System.Collections.IStructuralComparable - union type with 2 cases
WoofWare.NUnitTestRunner.Modifier+Explicit inherit WoofWare.NUnitTestRunner.Modifier
WoofWare.NUnitTestRunner.Modifier+Explicit.get_reason [method]: unit -> string option
WoofWare.NUnitTestRunner.Modifier+Explicit.reason [property]: [read-only] string option
WoofWare.NUnitTestRunner.Modifier+Ignored inherit WoofWare.NUnitTestRunner.Modifier
WoofWare.NUnitTestRunner.Modifier+Ignored.get_reason [method]: unit -> string option
WoofWare.NUnitTestRunner.Modifier+Ignored.reason [property]: [read-only] string option
WoofWare.NUnitTestRunner.Modifier+Tags inherit obj
WoofWare.NUnitTestRunner.Modifier+Tags.Explicit [static field]: int = 0
WoofWare.NUnitTestRunner.Modifier+Tags.Ignored [static field]: int = 1
WoofWare.NUnitTestRunner.Modifier.get_IsExplicit [method]: unit -> bool
WoofWare.NUnitTestRunner.Modifier.get_IsIgnored [method]: unit -> bool
WoofWare.NUnitTestRunner.Modifier.get_Tag [method]: unit -> int
WoofWare.NUnitTestRunner.Modifier.IsExplicit [property]: [read-only] bool
WoofWare.NUnitTestRunner.Modifier.IsIgnored [property]: [read-only] bool
WoofWare.NUnitTestRunner.Modifier.NewExplicit [static method]: string option -> WoofWare.NUnitTestRunner.Modifier
WoofWare.NUnitTestRunner.Modifier.NewIgnored [static method]: string option -> WoofWare.NUnitTestRunner.Modifier
WoofWare.NUnitTestRunner.Modifier.Tag [property]: [read-only] int
WoofWare.NUnitTestRunner.SingleTestMethod inherit obj, implements WoofWare.NUnitTestRunner.SingleTestMethod System.IEquatable, System.Collections.IStructuralEquatable
WoofWare.NUnitTestRunner.SingleTestMethod..ctor [constructor]: (System.Reflection.MethodInfo, WoofWare.NUnitTestRunner.TestKind, WoofWare.NUnitTestRunner.Modifier list, string list, int option, WoofWare.NUnitTestRunner.Combinatorial option)
WoofWare.NUnitTestRunner.SingleTestMethod.Categories [property]: [read-only] string list
WoofWare.NUnitTestRunner.SingleTestMethod.Combinatorial [property]: [read-only] WoofWare.NUnitTestRunner.Combinatorial option
WoofWare.NUnitTestRunner.SingleTestMethod.get_Categories [method]: unit -> string list
WoofWare.NUnitTestRunner.SingleTestMethod.get_Combinatorial [method]: unit -> WoofWare.NUnitTestRunner.Combinatorial option
WoofWare.NUnitTestRunner.SingleTestMethod.get_Kind [method]: unit -> WoofWare.NUnitTestRunner.TestKind
WoofWare.NUnitTestRunner.SingleTestMethod.get_Method [method]: unit -> System.Reflection.MethodInfo
WoofWare.NUnitTestRunner.SingleTestMethod.get_Modifiers [method]: unit -> WoofWare.NUnitTestRunner.Modifier list
WoofWare.NUnitTestRunner.SingleTestMethod.get_Name [method]: unit -> string
WoofWare.NUnitTestRunner.SingleTestMethod.get_Repeat [method]: unit -> int option
WoofWare.NUnitTestRunner.SingleTestMethod.Kind [property]: [read-only] WoofWare.NUnitTestRunner.TestKind
WoofWare.NUnitTestRunner.SingleTestMethod.Method [property]: [read-only] System.Reflection.MethodInfo
WoofWare.NUnitTestRunner.SingleTestMethod.Modifiers [property]: [read-only] WoofWare.NUnitTestRunner.Modifier list
WoofWare.NUnitTestRunner.SingleTestMethod.Name [property]: [read-only] string
WoofWare.NUnitTestRunner.SingleTestMethod.Repeat [property]: [read-only] int option
WoofWare.NUnitTestRunner.SingleTestMethodModule inherit obj
WoofWare.NUnitTestRunner.SingleTestMethodModule.parse [static method]: string list -> System.Reflection.MethodInfo -> System.Reflection.CustomAttributeData list -> (WoofWare.NUnitTestRunner.SingleTestMethod option * System.Reflection.CustomAttributeData list)
WoofWare.NUnitTestRunner.TestFailure inherit obj, implements WoofWare.NUnitTestRunner.TestFailure System.IEquatable, System.Collections.IStructuralEquatable - union type with 3 cases
WoofWare.NUnitTestRunner.TestFailure+SetUpFailed inherit WoofWare.NUnitTestRunner.TestFailure
WoofWare.NUnitTestRunner.TestFailure+SetUpFailed.get_Item [method]: unit -> WoofWare.NUnitTestRunner.UserMethodFailure
WoofWare.NUnitTestRunner.TestFailure+SetUpFailed.Item [property]: [read-only] WoofWare.NUnitTestRunner.UserMethodFailure
WoofWare.NUnitTestRunner.TestFailure+Tags inherit obj
WoofWare.NUnitTestRunner.TestFailure+Tags.SetUpFailed [static field]: int = 1
WoofWare.NUnitTestRunner.TestFailure+Tags.TearDownFailed [static field]: int = 2
WoofWare.NUnitTestRunner.TestFailure+Tags.TestFailed [static field]: int = 0
WoofWare.NUnitTestRunner.TestFailure+TearDownFailed inherit WoofWare.NUnitTestRunner.TestFailure
WoofWare.NUnitTestRunner.TestFailure+TearDownFailed.get_Item [method]: unit -> WoofWare.NUnitTestRunner.UserMethodFailure
WoofWare.NUnitTestRunner.TestFailure+TearDownFailed.Item [property]: [read-only] WoofWare.NUnitTestRunner.UserMethodFailure
WoofWare.NUnitTestRunner.TestFailure+TestFailed inherit WoofWare.NUnitTestRunner.TestFailure
WoofWare.NUnitTestRunner.TestFailure+TestFailed.get_Item [method]: unit -> WoofWare.NUnitTestRunner.UserMethodFailure
WoofWare.NUnitTestRunner.TestFailure+TestFailed.Item [property]: [read-only] WoofWare.NUnitTestRunner.UserMethodFailure
WoofWare.NUnitTestRunner.TestFailure.get_IsSetUpFailed [method]: unit -> bool
WoofWare.NUnitTestRunner.TestFailure.get_IsTearDownFailed [method]: unit -> bool
WoofWare.NUnitTestRunner.TestFailure.get_IsTestFailed [method]: unit -> bool
WoofWare.NUnitTestRunner.TestFailure.get_Name [method]: unit -> string
WoofWare.NUnitTestRunner.TestFailure.get_Tag [method]: unit -> int
WoofWare.NUnitTestRunner.TestFailure.IsSetUpFailed [property]: [read-only] bool
WoofWare.NUnitTestRunner.TestFailure.IsTearDownFailed [property]: [read-only] bool
WoofWare.NUnitTestRunner.TestFailure.IsTestFailed [property]: [read-only] bool
WoofWare.NUnitTestRunner.TestFailure.Name [property]: [read-only] string
WoofWare.NUnitTestRunner.TestFailure.NewSetUpFailed [static method]: WoofWare.NUnitTestRunner.UserMethodFailure -> WoofWare.NUnitTestRunner.TestFailure
WoofWare.NUnitTestRunner.TestFailure.NewTearDownFailed [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.TestFixture inherit obj, implements WoofWare.NUnitTestRunner.TestFixture System.IEquatable, System.Collections.IStructuralEquatable
WoofWare.NUnitTestRunner.TestFixture..ctor [constructor]: (System.Reflection.Assembly, string, System.Reflection.MethodInfo option, System.Reflection.MethodInfo option, System.Reflection.MethodInfo list, System.Reflection.MethodInfo list, WoofWare.NUnitTestRunner.SingleTestMethod list)
WoofWare.NUnitTestRunner.TestFixture.ContainingAssembly [property]: [read-only] System.Reflection.Assembly
WoofWare.NUnitTestRunner.TestFixture.Empty [static method]: System.Reflection.Assembly -> string -> WoofWare.NUnitTestRunner.TestFixture
WoofWare.NUnitTestRunner.TestFixture.get_ContainingAssembly [method]: unit -> System.Reflection.Assembly
WoofWare.NUnitTestRunner.TestFixture.get_Name [method]: unit -> string
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_SetUp [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.Name [property]: [read-only] string
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.SetUp [property]: [read-only] System.Reflection.MethodInfo list
WoofWare.NUnitTestRunner.TestFixture.TearDown [property]: [read-only] System.Reflection.MethodInfo list
WoofWare.NUnitTestRunner.TestFixture.Tests [property]: [read-only] WoofWare.NUnitTestRunner.SingleTestMethod list
WoofWare.NUnitTestRunner.TestFixtureModule inherit obj
WoofWare.NUnitTestRunner.TestFixtureModule.parse [static method]: System.Type -> WoofWare.NUnitTestRunner.TestFixture
WoofWare.NUnitTestRunner.TestFixtureModule.run [static method]: WoofWare.NUnitTestRunner.ITestProgress -> (WoofWare.NUnitTestRunner.TestFixture -> WoofWare.NUnitTestRunner.SingleTestMethod -> bool) -> WoofWare.NUnitTestRunner.TestFixture -> WoofWare.NUnitTestRunner.FixtureRunResults
WoofWare.NUnitTestRunner.TestKind inherit obj, implements WoofWare.NUnitTestRunner.TestKind System.IEquatable, System.Collections.IStructuralEquatable - union type with 3 cases
WoofWare.NUnitTestRunner.TestKind+Data inherit WoofWare.NUnitTestRunner.TestKind
WoofWare.NUnitTestRunner.TestKind+Data.get_Item [method]: unit -> obj list list
WoofWare.NUnitTestRunner.TestKind+Data.Item [property]: [read-only] obj list list
WoofWare.NUnitTestRunner.TestKind+Source inherit WoofWare.NUnitTestRunner.TestKind
WoofWare.NUnitTestRunner.TestKind+Source.get_Item [method]: unit -> string list
WoofWare.NUnitTestRunner.TestKind+Source.Item [property]: [read-only] string list
WoofWare.NUnitTestRunner.TestKind+Tags inherit obj
WoofWare.NUnitTestRunner.TestKind+Tags.Data [static field]: int = 2
WoofWare.NUnitTestRunner.TestKind+Tags.Single [static field]: int = 0
WoofWare.NUnitTestRunner.TestKind+Tags.Source [static field]: int = 1
WoofWare.NUnitTestRunner.TestKind.get_IsData [method]: unit -> bool
WoofWare.NUnitTestRunner.TestKind.get_IsSingle [method]: unit -> bool
WoofWare.NUnitTestRunner.TestKind.get_IsSource [method]: unit -> bool
WoofWare.NUnitTestRunner.TestKind.get_Single [static method]: unit -> WoofWare.NUnitTestRunner.TestKind
WoofWare.NUnitTestRunner.TestKind.get_Tag [method]: unit -> int
WoofWare.NUnitTestRunner.TestKind.IsData [property]: [read-only] bool
WoofWare.NUnitTestRunner.TestKind.IsSingle [property]: [read-only] bool
WoofWare.NUnitTestRunner.TestKind.IsSource [property]: [read-only] bool
WoofWare.NUnitTestRunner.TestKind.NewData [static method]: obj list list -> WoofWare.NUnitTestRunner.TestKind
WoofWare.NUnitTestRunner.TestKind.NewSource [static method]: string list -> WoofWare.NUnitTestRunner.TestKind
WoofWare.NUnitTestRunner.TestKind.Single [static property]: [read-only] WoofWare.NUnitTestRunner.TestKind
WoofWare.NUnitTestRunner.TestKind.Tag [property]: [read-only] int
WoofWare.NUnitTestRunner.TestMemberFailure inherit obj, implements WoofWare.NUnitTestRunner.TestMemberFailure System.IEquatable, System.Collections.IStructuralEquatable - union type with 2 cases
WoofWare.NUnitTestRunner.TestMemberFailure+Failed inherit WoofWare.NUnitTestRunner.TestMemberFailure
WoofWare.NUnitTestRunner.TestMemberFailure+Failed.get_Item [method]: unit -> WoofWare.NUnitTestRunner.TestFailure list
WoofWare.NUnitTestRunner.TestMemberFailure+Failed.Item [property]: [read-only] WoofWare.NUnitTestRunner.TestFailure list
WoofWare.NUnitTestRunner.TestMemberFailure+Malformed inherit WoofWare.NUnitTestRunner.TestMemberFailure
WoofWare.NUnitTestRunner.TestMemberFailure+Malformed.get_reasons [method]: unit -> string list
WoofWare.NUnitTestRunner.TestMemberFailure+Malformed.reasons [property]: [read-only] string list
WoofWare.NUnitTestRunner.TestMemberFailure+Tags inherit obj
WoofWare.NUnitTestRunner.TestMemberFailure+Tags.Failed [static field]: int = 1
WoofWare.NUnitTestRunner.TestMemberFailure+Tags.Malformed [static field]: int = 0
WoofWare.NUnitTestRunner.TestMemberFailure.get_IsFailed [method]: unit -> bool
WoofWare.NUnitTestRunner.TestMemberFailure.get_IsMalformed [method]: unit -> bool
WoofWare.NUnitTestRunner.TestMemberFailure.get_Tag [method]: unit -> int
WoofWare.NUnitTestRunner.TestMemberFailure.IsFailed [property]: [read-only] bool
WoofWare.NUnitTestRunner.TestMemberFailure.IsMalformed [property]: [read-only] bool
WoofWare.NUnitTestRunner.TestMemberFailure.NewFailed [static method]: WoofWare.NUnitTestRunner.TestFailure list -> WoofWare.NUnitTestRunner.TestMemberFailure
WoofWare.NUnitTestRunner.TestMemberFailure.NewMalformed [static method]: string list -> WoofWare.NUnitTestRunner.TestMemberFailure
WoofWare.NUnitTestRunner.TestMemberFailure.Tag [property]: [read-only] int
WoofWare.NUnitTestRunner.TestMemberSuccess inherit obj, implements WoofWare.NUnitTestRunner.TestMemberSuccess System.IEquatable, System.Collections.IStructuralEquatable, WoofWare.NUnitTestRunner.TestMemberSuccess System.IComparable, System.IComparable, System.Collections.IStructuralComparable - union type with 4 cases
WoofWare.NUnitTestRunner.TestMemberSuccess+Explicit inherit WoofWare.NUnitTestRunner.TestMemberSuccess
WoofWare.NUnitTestRunner.TestMemberSuccess+Explicit.get_reason [method]: unit -> string option
WoofWare.NUnitTestRunner.TestMemberSuccess+Explicit.reason [property]: [read-only] string option
WoofWare.NUnitTestRunner.TestMemberSuccess+Ignored inherit WoofWare.NUnitTestRunner.TestMemberSuccess
WoofWare.NUnitTestRunner.TestMemberSuccess+Ignored.get_reason [method]: unit -> string option
WoofWare.NUnitTestRunner.TestMemberSuccess+Ignored.reason [property]: [read-only] string option
WoofWare.NUnitTestRunner.TestMemberSuccess+Inconclusive inherit WoofWare.NUnitTestRunner.TestMemberSuccess
WoofWare.NUnitTestRunner.TestMemberSuccess+Inconclusive.get_reason [method]: unit -> string option
WoofWare.NUnitTestRunner.TestMemberSuccess+Inconclusive.reason [property]: [read-only] string option
WoofWare.NUnitTestRunner.TestMemberSuccess+Tags inherit obj
WoofWare.NUnitTestRunner.TestMemberSuccess+Tags.Explicit [static field]: int = 2
WoofWare.NUnitTestRunner.TestMemberSuccess+Tags.Ignored [static field]: int = 1
WoofWare.NUnitTestRunner.TestMemberSuccess+Tags.Inconclusive [static field]: int = 3
WoofWare.NUnitTestRunner.TestMemberSuccess+Tags.Ok [static field]: int = 0
WoofWare.NUnitTestRunner.TestMemberSuccess.get_IsExplicit [method]: unit -> bool
WoofWare.NUnitTestRunner.TestMemberSuccess.get_IsIgnored [method]: unit -> bool
WoofWare.NUnitTestRunner.TestMemberSuccess.get_IsInconclusive [method]: unit -> bool
WoofWare.NUnitTestRunner.TestMemberSuccess.get_IsOk [method]: unit -> bool
WoofWare.NUnitTestRunner.TestMemberSuccess.get_Ok [static method]: unit -> WoofWare.NUnitTestRunner.TestMemberSuccess
WoofWare.NUnitTestRunner.TestMemberSuccess.get_Tag [method]: unit -> int
WoofWare.NUnitTestRunner.TestMemberSuccess.IsExplicit [property]: [read-only] bool
WoofWare.NUnitTestRunner.TestMemberSuccess.IsIgnored [property]: [read-only] bool
WoofWare.NUnitTestRunner.TestMemberSuccess.IsInconclusive [property]: [read-only] bool
WoofWare.NUnitTestRunner.TestMemberSuccess.IsOk [property]: [read-only] bool
WoofWare.NUnitTestRunner.TestMemberSuccess.NewExplicit [static method]: string option -> WoofWare.NUnitTestRunner.TestMemberSuccess
WoofWare.NUnitTestRunner.TestMemberSuccess.NewIgnored [static method]: string option -> WoofWare.NUnitTestRunner.TestMemberSuccess
WoofWare.NUnitTestRunner.TestMemberSuccess.NewInconclusive [static method]: string option -> WoofWare.NUnitTestRunner.TestMemberSuccess
WoofWare.NUnitTestRunner.TestMemberSuccess.Ok [static property]: [read-only] WoofWare.NUnitTestRunner.TestMemberSuccess
WoofWare.NUnitTestRunner.TestMemberSuccess.Tag [property]: [read-only] int
WoofWare.NUnitTestRunner.TestProgress inherit obj
WoofWare.NUnitTestRunner.TestProgress.toStderr [static method]: unit -> WoofWare.NUnitTestRunner.ITestProgress
WoofWare.NUnitTestRunner.TrxCounters inherit obj, implements WoofWare.NUnitTestRunner.TrxCounters System.IEquatable, System.Collections.IStructuralEquatable
WoofWare.NUnitTestRunner.TrxCounters..ctor [constructor]: (System.UInt32, System.UInt32, System.UInt32, System.UInt32, System.UInt32, System.UInt32, System.UInt32, System.UInt32, System.UInt32, System.UInt32, System.UInt32, System.UInt32, System.UInt32, System.UInt32, System.UInt32, System.UInt32)
WoofWare.NUnitTestRunner.TrxCounters.Aborted [property]: [read-only] System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.AddFailed [method]: unit -> WoofWare.NUnitTestRunner.TrxCounters
WoofWare.NUnitTestRunner.TrxCounters.AddInconclusive [method]: unit -> WoofWare.NUnitTestRunner.TrxCounters
WoofWare.NUnitTestRunner.TrxCounters.AddNotExecuted [method]: unit -> WoofWare.NUnitTestRunner.TrxCounters
WoofWare.NUnitTestRunner.TrxCounters.AddPassed [method]: unit -> WoofWare.NUnitTestRunner.TrxCounters
WoofWare.NUnitTestRunner.TrxCounters.Completed [property]: [read-only] System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.Disconnected [property]: [read-only] System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.Errors [property]: [read-only] System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.Executed [property]: [read-only] System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.Failed [property]: [read-only] System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.get_Aborted [method]: unit -> System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.get_Completed [method]: unit -> System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.get_Disconnected [method]: unit -> System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.get_Errors [method]: unit -> System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.get_Executed [method]: unit -> System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.get_Failed [method]: unit -> System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.get_Inconclusive [method]: unit -> System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.get_InProgress [method]: unit -> System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.get_NotExecuted [method]: unit -> System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.get_NotRunnable [method]: unit -> System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.get_Passed [method]: unit -> System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.get_PassedButRunAborted [method]: unit -> System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.get_Pending [method]: unit -> System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.get_Timeout [method]: unit -> System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.get_Total [method]: unit -> System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.get_Warning [method]: unit -> System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.get_Zero [static method]: unit -> WoofWare.NUnitTestRunner.TrxCounters
WoofWare.NUnitTestRunner.TrxCounters.Inconclusive [property]: [read-only] System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.InProgress [property]: [read-only] System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.NotExecuted [property]: [read-only] System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.NotRunnable [property]: [read-only] System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.Passed [property]: [read-only] System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.PassedButRunAborted [property]: [read-only] System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.Pending [property]: [read-only] System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.Timeout [property]: [read-only] System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.Total [property]: [read-only] System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.Warning [property]: [read-only] System.UInt32
WoofWare.NUnitTestRunner.TrxCounters.Zero [static property]: [read-only] WoofWare.NUnitTestRunner.TrxCounters
WoofWare.NUnitTestRunner.TrxDeployment inherit obj, implements WoofWare.NUnitTestRunner.TrxDeployment System.IEquatable, System.Collections.IStructuralEquatable
WoofWare.NUnitTestRunner.TrxDeployment..ctor [constructor]: string
WoofWare.NUnitTestRunner.TrxDeployment.get_RunDeploymentRoot [method]: unit -> string
WoofWare.NUnitTestRunner.TrxDeployment.RunDeploymentRoot [property]: [read-only] string
WoofWare.NUnitTestRunner.TrxErrorInfo inherit obj, implements WoofWare.NUnitTestRunner.TrxErrorInfo System.IEquatable, System.Collections.IStructuralEquatable
WoofWare.NUnitTestRunner.TrxErrorInfo..ctor [constructor]: (string option, string option)
WoofWare.NUnitTestRunner.TrxErrorInfo.get_Message [method]: unit -> string option
WoofWare.NUnitTestRunner.TrxErrorInfo.get_StackTrace [method]: unit -> string option
WoofWare.NUnitTestRunner.TrxErrorInfo.Message [property]: [read-only] string option
WoofWare.NUnitTestRunner.TrxErrorInfo.StackTrace [property]: [read-only] string option
WoofWare.NUnitTestRunner.TrxExecution inherit obj, implements WoofWare.NUnitTestRunner.TrxExecution System.IEquatable, System.Collections.IStructuralEquatable
WoofWare.NUnitTestRunner.TrxExecution..ctor [constructor]: System.Guid
WoofWare.NUnitTestRunner.TrxExecution.get_Id [method]: unit -> System.Guid
WoofWare.NUnitTestRunner.TrxExecution.Id [property]: [read-only] System.Guid
WoofWare.NUnitTestRunner.TrxOutcome inherit obj, implements WoofWare.NUnitTestRunner.TrxOutcome System.IEquatable, System.Collections.IStructuralEquatable - union type with 3 cases
WoofWare.NUnitTestRunner.TrxOutcome+Tags inherit obj
WoofWare.NUnitTestRunner.TrxOutcome+Tags.Completed [static field]: int = 0
WoofWare.NUnitTestRunner.TrxOutcome+Tags.Failed [static field]: int = 2
WoofWare.NUnitTestRunner.TrxOutcome+Tags.Warning [static field]: int = 1
WoofWare.NUnitTestRunner.TrxOutcome.Completed [static property]: [read-only] WoofWare.NUnitTestRunner.TrxOutcome
WoofWare.NUnitTestRunner.TrxOutcome.Failed [static property]: [read-only] WoofWare.NUnitTestRunner.TrxOutcome
WoofWare.NUnitTestRunner.TrxOutcome.get_Completed [static method]: unit -> WoofWare.NUnitTestRunner.TrxOutcome
WoofWare.NUnitTestRunner.TrxOutcome.get_Failed [static method]: unit -> WoofWare.NUnitTestRunner.TrxOutcome
WoofWare.NUnitTestRunner.TrxOutcome.get_IsCompleted [method]: unit -> bool
WoofWare.NUnitTestRunner.TrxOutcome.get_IsFailed [method]: unit -> bool
WoofWare.NUnitTestRunner.TrxOutcome.get_IsWarning [method]: unit -> bool
WoofWare.NUnitTestRunner.TrxOutcome.get_Tag [method]: unit -> int
WoofWare.NUnitTestRunner.TrxOutcome.get_Warning [static method]: unit -> WoofWare.NUnitTestRunner.TrxOutcome
WoofWare.NUnitTestRunner.TrxOutcome.IsCompleted [property]: [read-only] bool
WoofWare.NUnitTestRunner.TrxOutcome.IsFailed [property]: [read-only] bool
WoofWare.NUnitTestRunner.TrxOutcome.IsWarning [property]: [read-only] bool
WoofWare.NUnitTestRunner.TrxOutcome.Parse [static method]: string -> WoofWare.NUnitTestRunner.TrxOutcome option
WoofWare.NUnitTestRunner.TrxOutcome.Tag [property]: [read-only] int
WoofWare.NUnitTestRunner.TrxOutcome.Warning [static property]: [read-only] WoofWare.NUnitTestRunner.TrxOutcome
WoofWare.NUnitTestRunner.TrxOutput inherit obj, implements WoofWare.NUnitTestRunner.TrxOutput System.IEquatable, System.Collections.IStructuralEquatable
WoofWare.NUnitTestRunner.TrxOutput..ctor [constructor]: (string option, WoofWare.NUnitTestRunner.TrxErrorInfo option)
WoofWare.NUnitTestRunner.TrxOutput.ErrorInfo [property]: [read-only] WoofWare.NUnitTestRunner.TrxErrorInfo option
WoofWare.NUnitTestRunner.TrxOutput.get_ErrorInfo [method]: unit -> WoofWare.NUnitTestRunner.TrxErrorInfo option
WoofWare.NUnitTestRunner.TrxOutput.get_StdOut [method]: unit -> string option
WoofWare.NUnitTestRunner.TrxOutput.StdOut [property]: [read-only] string option
WoofWare.NUnitTestRunner.TrxReport inherit obj, implements WoofWare.NUnitTestRunner.TrxReport System.IEquatable, System.Collections.IStructuralEquatable
WoofWare.NUnitTestRunner.TrxReport..ctor [constructor]: (System.Guid, string, WoofWare.NUnitTestRunner.TrxReportTimes, WoofWare.NUnitTestRunner.TrxTestSettings, WoofWare.NUnitTestRunner.TrxUnitTestResult list, WoofWare.NUnitTestRunner.TrxUnitTest list, WoofWare.NUnitTestRunner.TrxTestEntry list, WoofWare.NUnitTestRunner.TrxTestListEntry list, WoofWare.NUnitTestRunner.TrxResultsSummary)
WoofWare.NUnitTestRunner.TrxReport.get_Id [method]: unit -> System.Guid
WoofWare.NUnitTestRunner.TrxReport.get_Name [method]: unit -> string
WoofWare.NUnitTestRunner.TrxReport.get_Results [method]: unit -> WoofWare.NUnitTestRunner.TrxUnitTestResult list
WoofWare.NUnitTestRunner.TrxReport.get_ResultsSummary [method]: unit -> WoofWare.NUnitTestRunner.TrxResultsSummary
WoofWare.NUnitTestRunner.TrxReport.get_Settings [method]: unit -> WoofWare.NUnitTestRunner.TrxTestSettings
WoofWare.NUnitTestRunner.TrxReport.get_TestDefinitions [method]: unit -> WoofWare.NUnitTestRunner.TrxUnitTest list
WoofWare.NUnitTestRunner.TrxReport.get_TestEntries [method]: unit -> WoofWare.NUnitTestRunner.TrxTestEntry list
WoofWare.NUnitTestRunner.TrxReport.get_TestLists [method]: unit -> WoofWare.NUnitTestRunner.TrxTestListEntry list
WoofWare.NUnitTestRunner.TrxReport.get_Times [method]: unit -> WoofWare.NUnitTestRunner.TrxReportTimes
WoofWare.NUnitTestRunner.TrxReport.Id [property]: [read-only] System.Guid
WoofWare.NUnitTestRunner.TrxReport.Name [property]: [read-only] string
WoofWare.NUnitTestRunner.TrxReport.Results [property]: [read-only] WoofWare.NUnitTestRunner.TrxUnitTestResult list
WoofWare.NUnitTestRunner.TrxReport.ResultsSummary [property]: [read-only] WoofWare.NUnitTestRunner.TrxResultsSummary
WoofWare.NUnitTestRunner.TrxReport.Settings [property]: [read-only] WoofWare.NUnitTestRunner.TrxTestSettings
WoofWare.NUnitTestRunner.TrxReport.TestDefinitions [property]: [read-only] WoofWare.NUnitTestRunner.TrxUnitTest list
WoofWare.NUnitTestRunner.TrxReport.TestEntries [property]: [read-only] WoofWare.NUnitTestRunner.TrxTestEntry list
WoofWare.NUnitTestRunner.TrxReport.TestLists [property]: [read-only] WoofWare.NUnitTestRunner.TrxTestListEntry list
WoofWare.NUnitTestRunner.TrxReport.Times [property]: [read-only] WoofWare.NUnitTestRunner.TrxReportTimes
WoofWare.NUnitTestRunner.TrxReportModule inherit obj
WoofWare.NUnitTestRunner.TrxReportModule.parse [static method]: string -> Microsoft.FSharp.Core.FSharpResult<WoofWare.NUnitTestRunner.TrxReport, string>
WoofWare.NUnitTestRunner.TrxReportModule.toXml [static method]: WoofWare.NUnitTestRunner.TrxReport -> System.Xml.XmlDocument
WoofWare.NUnitTestRunner.TrxReportTimes inherit obj, implements WoofWare.NUnitTestRunner.TrxReportTimes System.IEquatable, System.Collections.IStructuralEquatable
WoofWare.NUnitTestRunner.TrxReportTimes..ctor [constructor]: (System.DateTimeOffset, System.DateTimeOffset, System.DateTimeOffset, System.DateTimeOffset)
WoofWare.NUnitTestRunner.TrxReportTimes.Creation [property]: [read-only] System.DateTimeOffset
WoofWare.NUnitTestRunner.TrxReportTimes.Finish [property]: [read-only] System.DateTimeOffset
WoofWare.NUnitTestRunner.TrxReportTimes.get_Creation [method]: unit -> System.DateTimeOffset
WoofWare.NUnitTestRunner.TrxReportTimes.get_Finish [method]: unit -> System.DateTimeOffset
WoofWare.NUnitTestRunner.TrxReportTimes.get_Queuing [method]: unit -> System.DateTimeOffset
WoofWare.NUnitTestRunner.TrxReportTimes.get_Start [method]: unit -> System.DateTimeOffset
WoofWare.NUnitTestRunner.TrxReportTimes.Queuing [property]: [read-only] System.DateTimeOffset
WoofWare.NUnitTestRunner.TrxReportTimes.Start [property]: [read-only] System.DateTimeOffset
WoofWare.NUnitTestRunner.TrxResultsSummary inherit obj, implements WoofWare.NUnitTestRunner.TrxResultsSummary System.IEquatable, System.Collections.IStructuralEquatable
WoofWare.NUnitTestRunner.TrxResultsSummary..ctor [constructor]: (WoofWare.NUnitTestRunner.TrxOutcome, WoofWare.NUnitTestRunner.TrxCounters, WoofWare.NUnitTestRunner.TrxOutput, WoofWare.NUnitTestRunner.TrxRunInfo list)
WoofWare.NUnitTestRunner.TrxResultsSummary.Counters [property]: [read-only] WoofWare.NUnitTestRunner.TrxCounters
WoofWare.NUnitTestRunner.TrxResultsSummary.get_Counters [method]: unit -> WoofWare.NUnitTestRunner.TrxCounters
WoofWare.NUnitTestRunner.TrxResultsSummary.get_Outcome [method]: unit -> WoofWare.NUnitTestRunner.TrxOutcome
WoofWare.NUnitTestRunner.TrxResultsSummary.get_Output [method]: unit -> WoofWare.NUnitTestRunner.TrxOutput
WoofWare.NUnitTestRunner.TrxResultsSummary.get_RunInfos [method]: unit -> WoofWare.NUnitTestRunner.TrxRunInfo list
WoofWare.NUnitTestRunner.TrxResultsSummary.Outcome [property]: [read-only] WoofWare.NUnitTestRunner.TrxOutcome
WoofWare.NUnitTestRunner.TrxResultsSummary.Output [property]: [read-only] WoofWare.NUnitTestRunner.TrxOutput
WoofWare.NUnitTestRunner.TrxResultsSummary.RunInfos [property]: [read-only] WoofWare.NUnitTestRunner.TrxRunInfo list
WoofWare.NUnitTestRunner.TrxRunInfo inherit obj, implements WoofWare.NUnitTestRunner.TrxRunInfo System.IEquatable, System.Collections.IStructuralEquatable
WoofWare.NUnitTestRunner.TrxRunInfo..ctor [constructor]: (string, WoofWare.NUnitTestRunner.TrxOutcome, System.DateTimeOffset, string)
WoofWare.NUnitTestRunner.TrxRunInfo.ComputerName [property]: [read-only] string
WoofWare.NUnitTestRunner.TrxRunInfo.get_ComputerName [method]: unit -> string
WoofWare.NUnitTestRunner.TrxRunInfo.get_Outcome [method]: unit -> WoofWare.NUnitTestRunner.TrxOutcome
WoofWare.NUnitTestRunner.TrxRunInfo.get_Text [method]: unit -> string
WoofWare.NUnitTestRunner.TrxRunInfo.get_Timestamp [method]: unit -> System.DateTimeOffset
WoofWare.NUnitTestRunner.TrxRunInfo.Outcome [property]: [read-only] WoofWare.NUnitTestRunner.TrxOutcome
WoofWare.NUnitTestRunner.TrxRunInfo.Text [property]: [read-only] string
WoofWare.NUnitTestRunner.TrxRunInfo.Timestamp [property]: [read-only] System.DateTimeOffset
WoofWare.NUnitTestRunner.TrxTestEntry inherit obj, implements WoofWare.NUnitTestRunner.TrxTestEntry System.IEquatable, System.Collections.IStructuralEquatable
WoofWare.NUnitTestRunner.TrxTestEntry..ctor [constructor]: (System.Guid, System.Guid, System.Guid)
WoofWare.NUnitTestRunner.TrxTestEntry.ExecutionId [property]: [read-only] System.Guid
WoofWare.NUnitTestRunner.TrxTestEntry.get_ExecutionId [method]: unit -> System.Guid
WoofWare.NUnitTestRunner.TrxTestEntry.get_TestId [method]: unit -> System.Guid
WoofWare.NUnitTestRunner.TrxTestEntry.get_TestListId [method]: unit -> System.Guid
WoofWare.NUnitTestRunner.TrxTestEntry.TestId [property]: [read-only] System.Guid
WoofWare.NUnitTestRunner.TrxTestEntry.TestListId [property]: [read-only] System.Guid
WoofWare.NUnitTestRunner.TrxTestListEntry inherit obj, implements WoofWare.NUnitTestRunner.TrxTestListEntry System.IEquatable, System.Collections.IStructuralEquatable
WoofWare.NUnitTestRunner.TrxTestListEntry..ctor [constructor]: (string, System.Guid)
WoofWare.NUnitTestRunner.TrxTestListEntry.get_Id [method]: unit -> System.Guid
WoofWare.NUnitTestRunner.TrxTestListEntry.get_Name [method]: unit -> string
WoofWare.NUnitTestRunner.TrxTestListEntry.Id [property]: [read-only] System.Guid
WoofWare.NUnitTestRunner.TrxTestListEntry.Name [property]: [read-only] string
WoofWare.NUnitTestRunner.TrxTestMethod inherit obj, implements WoofWare.NUnitTestRunner.TrxTestMethod System.IEquatable, System.Collections.IStructuralEquatable
WoofWare.NUnitTestRunner.TrxTestMethod..ctor [constructor]: (string, System.Uri, string, string)
WoofWare.NUnitTestRunner.TrxTestMethod.AdapterTypeName [property]: [read-only] System.Uri
WoofWare.NUnitTestRunner.TrxTestMethod.ClassName [property]: [read-only] string
WoofWare.NUnitTestRunner.TrxTestMethod.CodeBase [property]: [read-only] string
WoofWare.NUnitTestRunner.TrxTestMethod.get_AdapterTypeName [method]: unit -> System.Uri
WoofWare.NUnitTestRunner.TrxTestMethod.get_ClassName [method]: unit -> string
WoofWare.NUnitTestRunner.TrxTestMethod.get_CodeBase [method]: unit -> string
WoofWare.NUnitTestRunner.TrxTestMethod.get_Name [method]: unit -> string
WoofWare.NUnitTestRunner.TrxTestMethod.Name [property]: [read-only] string
WoofWare.NUnitTestRunner.TrxTestOutcome inherit obj, implements WoofWare.NUnitTestRunner.TrxTestOutcome System.IEquatable, System.Collections.IStructuralEquatable - union type with 4 cases
WoofWare.NUnitTestRunner.TrxTestOutcome+Tags inherit obj
WoofWare.NUnitTestRunner.TrxTestOutcome+Tags.Failed [static field]: int = 1
WoofWare.NUnitTestRunner.TrxTestOutcome+Tags.Inconclusive [static field]: int = 3
WoofWare.NUnitTestRunner.TrxTestOutcome+Tags.NotExecuted [static field]: int = 2
WoofWare.NUnitTestRunner.TrxTestOutcome+Tags.Passed [static field]: int = 0
WoofWare.NUnitTestRunner.TrxTestOutcome.Failed [static property]: [read-only] WoofWare.NUnitTestRunner.TrxTestOutcome
WoofWare.NUnitTestRunner.TrxTestOutcome.get_Failed [static method]: unit -> WoofWare.NUnitTestRunner.TrxTestOutcome
WoofWare.NUnitTestRunner.TrxTestOutcome.get_Inconclusive [static method]: unit -> WoofWare.NUnitTestRunner.TrxTestOutcome
WoofWare.NUnitTestRunner.TrxTestOutcome.get_IsFailed [method]: unit -> bool
WoofWare.NUnitTestRunner.TrxTestOutcome.get_IsInconclusive [method]: unit -> bool
WoofWare.NUnitTestRunner.TrxTestOutcome.get_IsNotExecuted [method]: unit -> bool
WoofWare.NUnitTestRunner.TrxTestOutcome.get_IsPassed [method]: unit -> bool
WoofWare.NUnitTestRunner.TrxTestOutcome.get_NotExecuted [static method]: unit -> WoofWare.NUnitTestRunner.TrxTestOutcome
WoofWare.NUnitTestRunner.TrxTestOutcome.get_Passed [static method]: unit -> WoofWare.NUnitTestRunner.TrxTestOutcome
WoofWare.NUnitTestRunner.TrxTestOutcome.get_Tag [method]: unit -> int
WoofWare.NUnitTestRunner.TrxTestOutcome.Inconclusive [static property]: [read-only] WoofWare.NUnitTestRunner.TrxTestOutcome
WoofWare.NUnitTestRunner.TrxTestOutcome.IsFailed [property]: [read-only] bool
WoofWare.NUnitTestRunner.TrxTestOutcome.IsInconclusive [property]: [read-only] bool
WoofWare.NUnitTestRunner.TrxTestOutcome.IsNotExecuted [property]: [read-only] bool
WoofWare.NUnitTestRunner.TrxTestOutcome.IsPassed [property]: [read-only] bool
WoofWare.NUnitTestRunner.TrxTestOutcome.NotExecuted [static property]: [read-only] WoofWare.NUnitTestRunner.TrxTestOutcome
WoofWare.NUnitTestRunner.TrxTestOutcome.Parse [static method]: string -> WoofWare.NUnitTestRunner.TrxTestOutcome option
WoofWare.NUnitTestRunner.TrxTestOutcome.Passed [static property]: [read-only] WoofWare.NUnitTestRunner.TrxTestOutcome
WoofWare.NUnitTestRunner.TrxTestOutcome.Tag [property]: [read-only] int
WoofWare.NUnitTestRunner.TrxTestSettings inherit obj, implements WoofWare.NUnitTestRunner.TrxTestSettings System.IEquatable, System.Collections.IStructuralEquatable
WoofWare.NUnitTestRunner.TrxTestSettings..ctor [constructor]: (string, System.Guid, WoofWare.NUnitTestRunner.TrxDeployment)
WoofWare.NUnitTestRunner.TrxTestSettings.Deployment [property]: [read-only] WoofWare.NUnitTestRunner.TrxDeployment
WoofWare.NUnitTestRunner.TrxTestSettings.get_Deployment [method]: unit -> WoofWare.NUnitTestRunner.TrxDeployment
WoofWare.NUnitTestRunner.TrxTestSettings.get_Id [method]: unit -> System.Guid
WoofWare.NUnitTestRunner.TrxTestSettings.get_Name [method]: unit -> string
WoofWare.NUnitTestRunner.TrxTestSettings.Id [property]: [read-only] System.Guid
WoofWare.NUnitTestRunner.TrxTestSettings.Name [property]: [read-only] string
WoofWare.NUnitTestRunner.TrxUnitTest inherit obj, implements WoofWare.NUnitTestRunner.TrxUnitTest System.IEquatable, System.Collections.IStructuralEquatable
WoofWare.NUnitTestRunner.TrxUnitTest..ctor [constructor]: (string, string, System.Guid, WoofWare.NUnitTestRunner.TrxExecution, WoofWare.NUnitTestRunner.TrxTestMethod)
WoofWare.NUnitTestRunner.TrxUnitTest.Execution [property]: [read-only] WoofWare.NUnitTestRunner.TrxExecution
WoofWare.NUnitTestRunner.TrxUnitTest.get_Execution [method]: unit -> WoofWare.NUnitTestRunner.TrxExecution
WoofWare.NUnitTestRunner.TrxUnitTest.get_Id [method]: unit -> System.Guid
WoofWare.NUnitTestRunner.TrxUnitTest.get_Name [method]: unit -> string
WoofWare.NUnitTestRunner.TrxUnitTest.get_Storage [method]: unit -> string
WoofWare.NUnitTestRunner.TrxUnitTest.get_TestMethod [method]: unit -> WoofWare.NUnitTestRunner.TrxTestMethod
WoofWare.NUnitTestRunner.TrxUnitTest.Id [property]: [read-only] System.Guid
WoofWare.NUnitTestRunner.TrxUnitTest.Name [property]: [read-only] string
WoofWare.NUnitTestRunner.TrxUnitTest.Storage [property]: [read-only] string
WoofWare.NUnitTestRunner.TrxUnitTest.TestMethod [property]: [read-only] WoofWare.NUnitTestRunner.TrxTestMethod
WoofWare.NUnitTestRunner.TrxUnitTestResult inherit obj, implements WoofWare.NUnitTestRunner.TrxUnitTestResult System.IEquatable, System.Collections.IStructuralEquatable
WoofWare.NUnitTestRunner.TrxUnitTestResult..ctor [constructor]: (System.Guid, System.Guid, string, string, System.TimeSpan, System.DateTimeOffset, System.DateTimeOffset, System.Guid, WoofWare.NUnitTestRunner.TrxTestOutcome, System.Guid, string, WoofWare.NUnitTestRunner.TrxOutput option)
WoofWare.NUnitTestRunner.TrxUnitTestResult.ComputerName [property]: [read-only] string
WoofWare.NUnitTestRunner.TrxUnitTestResult.Duration [property]: [read-only] System.TimeSpan
WoofWare.NUnitTestRunner.TrxUnitTestResult.EndTime [property]: [read-only] System.DateTimeOffset
WoofWare.NUnitTestRunner.TrxUnitTestResult.ExecutionId [property]: [read-only] System.Guid
WoofWare.NUnitTestRunner.TrxUnitTestResult.get_ComputerName [method]: unit -> string
WoofWare.NUnitTestRunner.TrxUnitTestResult.get_Duration [method]: unit -> System.TimeSpan
WoofWare.NUnitTestRunner.TrxUnitTestResult.get_EndTime [method]: unit -> System.DateTimeOffset
WoofWare.NUnitTestRunner.TrxUnitTestResult.get_ExecutionId [method]: unit -> System.Guid
WoofWare.NUnitTestRunner.TrxUnitTestResult.get_Outcome [method]: unit -> WoofWare.NUnitTestRunner.TrxTestOutcome
WoofWare.NUnitTestRunner.TrxUnitTestResult.get_Output [method]: unit -> WoofWare.NUnitTestRunner.TrxOutput option
WoofWare.NUnitTestRunner.TrxUnitTestResult.get_RelativeResultsDirectory [method]: unit -> string
WoofWare.NUnitTestRunner.TrxUnitTestResult.get_StartTime [method]: unit -> System.DateTimeOffset
WoofWare.NUnitTestRunner.TrxUnitTestResult.get_TestId [method]: unit -> System.Guid
WoofWare.NUnitTestRunner.TrxUnitTestResult.get_TestListId [method]: unit -> System.Guid
WoofWare.NUnitTestRunner.TrxUnitTestResult.get_TestName [method]: unit -> string
WoofWare.NUnitTestRunner.TrxUnitTestResult.get_TestType [method]: unit -> System.Guid
WoofWare.NUnitTestRunner.TrxUnitTestResult.Outcome [property]: [read-only] WoofWare.NUnitTestRunner.TrxTestOutcome
WoofWare.NUnitTestRunner.TrxUnitTestResult.Output [property]: [read-only] WoofWare.NUnitTestRunner.TrxOutput option
WoofWare.NUnitTestRunner.TrxUnitTestResult.RelativeResultsDirectory [property]: [read-only] string
WoofWare.NUnitTestRunner.TrxUnitTestResult.StartTime [property]: [read-only] System.DateTimeOffset
WoofWare.NUnitTestRunner.TrxUnitTestResult.TestId [property]: [read-only] System.Guid
WoofWare.NUnitTestRunner.TrxUnitTestResult.TestListId [property]: [read-only] System.Guid
WoofWare.NUnitTestRunner.TrxUnitTestResult.TestName [property]: [read-only] string
WoofWare.NUnitTestRunner.TrxUnitTestResult.TestType [property]: [read-only] System.Guid
WoofWare.NUnitTestRunner.UserMethodFailure inherit obj, implements WoofWare.NUnitTestRunner.UserMethodFailure System.IEquatable, System.Collections.IStructuralEquatable - union type with 2 cases
WoofWare.NUnitTestRunner.UserMethodFailure+ReturnedNonUnit inherit WoofWare.NUnitTestRunner.UserMethodFailure
WoofWare.NUnitTestRunner.UserMethodFailure+ReturnedNonUnit.get_name [method]: unit -> string
WoofWare.NUnitTestRunner.UserMethodFailure+ReturnedNonUnit.get_result [method]: unit -> obj
WoofWare.NUnitTestRunner.UserMethodFailure+ReturnedNonUnit.name [property]: [read-only] string
WoofWare.NUnitTestRunner.UserMethodFailure+ReturnedNonUnit.result [property]: [read-only] obj
WoofWare.NUnitTestRunner.UserMethodFailure+Tags inherit obj
WoofWare.NUnitTestRunner.UserMethodFailure+Tags.ReturnedNonUnit [static field]: int = 0
WoofWare.NUnitTestRunner.UserMethodFailure+Tags.Threw [static field]: int = 1
WoofWare.NUnitTestRunner.UserMethodFailure+Threw inherit WoofWare.NUnitTestRunner.UserMethodFailure
WoofWare.NUnitTestRunner.UserMethodFailure+Threw.get_Item2 [method]: unit -> System.Exception
WoofWare.NUnitTestRunner.UserMethodFailure+Threw.get_name [method]: unit -> string
WoofWare.NUnitTestRunner.UserMethodFailure+Threw.Item2 [property]: [read-only] System.Exception
WoofWare.NUnitTestRunner.UserMethodFailure+Threw.name [property]: [read-only] string
WoofWare.NUnitTestRunner.UserMethodFailure.get_IsReturnedNonUnit [method]: unit -> bool
WoofWare.NUnitTestRunner.UserMethodFailure.get_IsThrew [method]: unit -> bool
WoofWare.NUnitTestRunner.UserMethodFailure.get_Name [method]: unit -> string
WoofWare.NUnitTestRunner.UserMethodFailure.get_Tag [method]: unit -> int
WoofWare.NUnitTestRunner.UserMethodFailure.IsReturnedNonUnit [property]: [read-only] bool
WoofWare.NUnitTestRunner.UserMethodFailure.IsThrew [property]: [read-only] bool
WoofWare.NUnitTestRunner.UserMethodFailure.Name [property]: [read-only] string
WoofWare.NUnitTestRunner.UserMethodFailure.NewReturnedNonUnit [static method]: (string, obj) -> WoofWare.NUnitTestRunner.UserMethodFailure
WoofWare.NUnitTestRunner.UserMethodFailure.NewThrew [static method]: (string, System.Exception) -> WoofWare.NUnitTestRunner.UserMethodFailure
WoofWare.NUnitTestRunner.UserMethodFailure.Tag [property]: [read-only] int

View File

@@ -0,0 +1,620 @@
namespace WoofWare.NUnitTestRunner
open System
open System.Diagnostics
open System.IO
open System.Reflection
open System.Threading
open Microsoft.FSharp.Core
type private StdoutSetter (newStdout : StreamWriter, newStderr : StreamWriter) =
let oldStdout = Console.Out
let oldStderr = Console.Error
do
Console.SetOut newStdout
Console.SetError newStderr
interface IDisposable with
member _.Dispose () =
Console.SetOut oldStdout
Console.SetError oldStderr
/// Information about the circumstances of a run of a single test.
type IndividualTestRunMetadata =
{
/// How long the test took.
Total : TimeSpan
/// When the test started.
Start : DateTimeOffset
/// When the test ended.
End : DateTimeOffset
/// The Environment.MachineName of the computer on which the run happened.
ComputerName : string
/// An identifier for this run of this test.
ExecutionId : Guid
/// An identifier for this test (possibly shared across repeats of this exact test with the same args).
TestId : Guid
/// Human-readable string representing this individual single test run, including any parameters.
TestName : string
/// Name of the class from which this test derived
ClassName : string
/// Anything that was printed to stdout while the test ran.
StdOut : string option
/// Anything that was printed to stderr while the test ran.
StdErr : string option
}
/// The results of running a single TestFixture.
type FixtureRunResults =
{
/// These tests failed.
/// TODO: domain is squiffy, the TestMemberFailure wants to be instead a TestFailure
Failed : (TestMemberFailure * IndividualTestRunMetadata) list
/// These tests succeeded.
/// A given test method may appear many times in this list, if it represented many tests.
Success : (SingleTestMethod * TestMemberSuccess * IndividualTestRunMetadata) list
/// These failures occurred outside the context of a test - e.g. in setup or tear-down logic.
OtherFailures : (UserMethodFailure * IndividualTestRunMetadata) list
}
/// Another view on the data contained in this object, transposed.
member this.IndividualTestRunMetadata
: (IndividualTestRunMetadata * Choice<TestMemberFailure, TestMemberSuccess, UserMethodFailure>) list =
[
for a, d in this.Failed do
yield d, Choice1Of3 a
for _, a, d in this.Success do
yield d, Choice2Of3 a
for a, d in this.OtherFailures do
yield d, Choice3Of3 a
]
/// A test fixture (usually represented by the [<TestFixture>]` attribute), which may contain many tests,
/// each of which may run many times.
[<RequireQualifiedAccess>]
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module TestFixture =
/// It's possible for multiple things to fail about a test: e.g. the test failed and also the tear-down failed.
///
/// This function does not throw.
let private runOne
(setUp : MethodInfo list)
(tearDown : MethodInfo list)
(testId : Guid)
(test : MethodInfo)
(containingObject : obj)
(args : obj[])
: Result<TestMemberSuccess, TestFailure list> * IndividualTestRunMetadata
=
let rec runMethods
(wrap : UserMethodFailure -> TestFailure)
(toRun : MethodInfo list)
(args : obj[])
: Result<unit, _>
=
match toRun with
| [] -> Ok ()
| head :: rest ->
let result =
try
head.Invoke (containingObject, args) |> Ok
with :? TargetInvocationException as e ->
Error (UserMethodFailure.Threw (head.Name, e.InnerException))
match result with
| Error e -> Error (wrap e)
| Ok result ->
match result with
| :? unit -> runMethods wrap rest args
| ret -> UserMethodFailure.ReturnedNonUnit (head.Name, ret) |> wrap |> Error
let start = DateTimeOffset.Now
use stdOutStream = new MemoryStream ()
use stdErrStream = new MemoryStream ()
use stdOut = new StreamWriter (stdOutStream)
use stdErr = new StreamWriter (stdErrStream)
use _ = new StdoutSetter (stdOut, stdErr)
let sw = Stopwatch.StartNew ()
let metadata () =
let name =
if args.Length = 0 then
test.Name
else
let argsStr = args |> Seq.map string<obj> |> String.concat ","
$"%s{test.Name}(%s{argsStr})"
{
End = DateTimeOffset.Now
Start = start
Total = sw.Elapsed
ComputerName = Environment.MachineName
ExecutionId = Guid.NewGuid ()
TestId = testId
TestName = name
ClassName = test.DeclaringType.FullName
StdOut =
match stdOutStream.ToArray () with
| [||] -> None
| arr -> Console.OutputEncoding.GetString arr |> Some
StdErr =
match stdErrStream.ToArray () with
| [||] -> None
| arr -> Console.OutputEncoding.GetString arr |> Some
}
let setUpResult = runMethods TestFailure.SetUpFailed setUp [||]
sw.Stop ()
match setUpResult with
| Error e -> Error [ e ], metadata ()
| Ok () ->
sw.Start ()
let result =
let result = runMethods TestFailure.TestFailed [ test ] args
sw.Stop ()
match result with
| Ok () -> Ok None
| Error (TestFailure.TestFailed (UserMethodFailure.Threw (_, exc)) as orig) ->
match exc.GetType().FullName with
| "NUnit.Framework.SuccessException" -> Ok None
| "NUnit.Framework.IgnoreException" -> Ok (Some (TestMemberSuccess.Ignored (Option.ofObj exc.Message)))
| "NUnit.Framework.InconclusiveException" ->
Ok (Some (TestMemberSuccess.Inconclusive (Option.ofObj exc.Message)))
| s when s.StartsWith ("NUnit.Framework.", StringComparison.Ordinal) ->
failwith $"Unrecognised special exception: %s{s}"
| _ -> Error orig
| Error orig -> Error orig
// Unconditionally run TearDown after tests, even if tests failed.
sw.Start ()
let tearDownResult = runMethods TestFailure.TearDownFailed tearDown [||]
sw.Stop ()
let metadata = metadata ()
match result, tearDownResult with
| Ok None, Ok () -> Ok TestMemberSuccess.Ok, metadata
| Ok (Some s), Ok () -> Ok s, metadata
| Error e, Ok ()
| Ok _, Error e -> Error [ e ], metadata
| Error e1, Error e2 -> Error [ e1 ; e2 ], metadata
let private getValues (test : SingleTestMethod) =
let valuesAttrs =
test.Method.GetParameters ()
|> Array.map (fun i ->
i.CustomAttributes
|> Seq.choose (fun i ->
if i.AttributeType.FullName = "NUnit.Framework.ValuesAttribute" then
Some i.ConstructorArguments
else
None
)
|> Seq.toList
|> function
| [] -> Ok None
| [ x ] -> Ok (Some x)
| _ :: _ :: _ ->
"Multiple Values attributes on a parameter. Exactly one per parameter please."
|> Error
)
|> Array.allOkOrError
match valuesAttrs with
| Error (_, e) -> Error (TestMemberFailure.Malformed (List.ofArray e))
| Ok valuesAttrs ->
if valuesAttrs |> Array.exists (fun l -> l.IsSome) then
if valuesAttrs |> Array.exists (fun l -> l.IsNone) then
failwith
$"Test '%s{test.Name}' has a parameter with the Values attribute and a parameter without. All parameters must have Values if any one does."
Some (valuesAttrs |> Array.map Option.get) |> Ok
else
Ok None
/// This method should never throw: it only throws if there's a critical logic error in the runner.
/// Exceptions from the units under test are wrapped up and passed out.
let private runTestsFromMember
(setUp : MethodInfo list)
(tearDown : MethodInfo list)
(containingObject : obj)
(test : SingleTestMethod)
: (Result<TestMemberSuccess, TestMemberFailure> * IndividualTestRunMetadata) list
=
if test.Method.ContainsGenericParameters then
let failureMetadata =
{
Total = TimeSpan.Zero
Start = DateTimeOffset.Now
End = DateTimeOffset.Now
ComputerName = Environment.MachineName
ExecutionId = Guid.NewGuid ()
TestId = Guid.NewGuid ()
TestName = test.Name
ClassName = test.Method.DeclaringType.FullName
StdErr = None
StdOut = None
}
let error =
TestMemberFailure.Malformed [ "Test contained generic parameters; generics are not supported." ]
(Error error, failureMetadata) |> List.singleton
else
let resultPreRun =
(None, test.Modifiers)
||> List.fold (fun _result modifier ->
// TODO: would be nice not to throw away the accumulation,
// and also when we get to being able to run Explicit tests we should discriminate exactly whether
// there was an Ignore
match modifier with
| Modifier.Explicit reason ->
// TODO: have a mode where we can run explicit tests
Some (TestMemberSuccess.Explicit reason)
| Modifier.Ignored reason -> Some (TestMemberSuccess.Ignored reason)
)
let sw = Stopwatch.StartNew ()
let startTime = DateTimeOffset.Now
match resultPreRun with
| Some result ->
sw.Stop ()
let failureMetadata =
{
Total = sw.Elapsed
Start = startTime
End = DateTimeOffset.Now
ComputerName = Environment.MachineName
ExecutionId = Guid.NewGuid ()
// No need to keep these test GUIDs stable: no point trying to run an explicit test multiple times.
TestId = Guid.NewGuid ()
TestName = test.Name
ClassName = test.Method.DeclaringType.FullName
StdErr = None
StdOut = None
}
[ Ok result, failureMetadata ]
| None ->
let individualTests =
let values = getValues test
match values with
| Error e -> Error e
| Ok values ->
match test.Kind, values with
| TestKind.Data data, None -> data |> List.map (fun args -> Guid.NewGuid (), Array.ofList args) |> Ok
| TestKind.Data _, Some _ ->
[
"Test has both the TestCase and Values attributes. Specify one or the other."
]
|> TestMemberFailure.Malformed
|> Error
| TestKind.Single, None -> (Guid.NewGuid (), [||]) |> List.singleton |> Ok
| TestKind.Single, Some vals ->
let combinatorial =
Option.defaultValue Combinatorial.Combinatorial test.Combinatorial
match combinatorial with
| Combinatorial.Combinatorial ->
vals
|> Seq.map (fun l -> l |> Seq.map (fun v -> v.Value) |> Seq.toList)
|> Seq.toList
|> List.combinations
|> List.map (fun args -> Guid.NewGuid (), Array.ofList args)
|> Ok
| Combinatorial.Sequential ->
let maxLength = vals |> Seq.map (fun i -> i.Count) |> Seq.max
List.init
maxLength
(fun i ->
let args =
vals
|> Array.map (fun param -> if i >= param.Count then null else param.[i].Value)
Guid.NewGuid (), args
)
|> Ok
| TestKind.Source _, Some _ ->
[
"Test has both the TestCaseSource and Values attributes. Specify one or the other."
]
|> TestMemberFailure.Malformed
|> Error
| TestKind.Source sources, None ->
[
for source in sources do
let args =
test.Method.DeclaringType.GetProperty (
source,
BindingFlags.Public
||| BindingFlags.NonPublic
||| BindingFlags.Instance
||| BindingFlags.Static
)
// Might not be an IEnumerable of a reference type.
// Concretely, `FSharpList<HttpStatusCode> :> IEnumerable<obj>` fails.
for arg in args.GetValue (null : obj) :?> System.Collections.IEnumerable do
yield
Guid.NewGuid (),
match arg with
| null -> [| (null : obj) |]
| :? Tuple<obj, obj> as (a, b) -> [| a ; b |]
| :? Tuple<obj, obj, obj> as (a, b, c) -> [| a ; b ; c |]
| :? Tuple<obj, obj, obj, obj> as (a, b, c, d) -> [| a ; b ; c ; d |]
| arg ->
let argTy = arg.GetType ()
if argTy.FullName = "NUnit.Framework.TestCaseData" then
let argsMem =
argTy.GetMethod (
"get_Arguments",
BindingFlags.Public
||| BindingFlags.Instance
||| BindingFlags.FlattenHierarchy
)
if isNull argsMem then
failwith "Unexpectedly could not call `.Arguments` on TestCaseData"
(argsMem.Invoke (arg, [||]) |> unbox<obj[]>)
else
[| arg |]
]
|> Ok
sw.Stop ()
match individualTests with
| Error e ->
let failureMetadata =
{
Total = sw.Elapsed
Start = startTime
End = DateTimeOffset.Now
ComputerName = Environment.MachineName
ExecutionId = Guid.NewGuid ()
// No need to keep these test GUIDs stable: we're not going to run them multiple times,
// because we're not going to run anything at all.
TestId = Guid.NewGuid ()
TestName = test.Name
ClassName = test.Method.DeclaringType.FullName
StdErr = None
StdOut = None
}
[ Error e, failureMetadata ]
| Ok individualTests ->
let count = test.Repeat |> Option.defaultValue 1
Seq.init count (fun _ -> individualTests)
|> Seq.concat
|> Seq.map (fun (testGuid, args) ->
let results, summary =
runOne setUp tearDown testGuid test.Method containingObject args
match results with
| Ok results -> Ok results, summary
| Error e -> Error (TestMemberFailure.Failed e), summary
)
|> Seq.toList
/// Run every test (except those which fail the `filter`) in this test fixture, as well as the
/// appropriate setup and tear-down logic.
let run
(progress : ITestProgress)
(filter : TestFixture -> SingleTestMethod -> bool)
(tests : TestFixture)
: FixtureRunResults
=
progress.OnTestFixtureStart tests.Name tests.Tests.Length
let containingObject =
let methods =
seq {
match tests.OneTimeSetUp with
| None -> ()
| Some t -> yield t
match tests.OneTimeTearDown with
| None -> ()
| Some t -> yield t
yield! tests.Tests |> Seq.map (fun t -> t.Method)
}
methods
|> Seq.tryPick (fun mi ->
if not mi.IsStatic then
Some (Activator.CreateInstance mi.DeclaringType)
else
None
)
|> Option.toObj
let oldWorkDir = Environment.CurrentDirectory
Environment.CurrentDirectory <- FileInfo(tests.ContainingAssembly.Location).Directory.FullName
let sw = Stopwatch.StartNew ()
let startTime = DateTimeOffset.UtcNow
use stdOutStream = new MemoryStream ()
use stdOut = new StreamWriter (stdOutStream)
use stdErrStream = new MemoryStream ()
use stdErr = new StreamWriter (stdErrStream)
use _ = new StdoutSetter (stdOut, stdErr)
let endMetadata () =
let stdOut = stdOutStream.ToArray () |> Console.OutputEncoding.GetString
let stdErr = stdErrStream.ToArray () |> Console.OutputEncoding.GetString
{
Total = sw.Elapsed
Start = startTime
End = DateTimeOffset.UtcNow
ComputerName = Environment.MachineName
ExecutionId = Guid.NewGuid ()
TestId = Guid.NewGuid ()
// This one is a bit dubious, because we don't actually have a test name at all
TestName = tests.Name
ClassName = tests.Name
StdOut = if String.IsNullOrEmpty stdOut then None else Some stdOut
StdErr = if String.IsNullOrEmpty stdErr then None else Some stdErr
}
let setupResult =
match tests.OneTimeSetUp with
| Some su ->
try
match su.Invoke (containingObject, [||]) with
| :? unit -> None
| ret -> Some (UserMethodFailure.ReturnedNonUnit (su.Name, ret), endMetadata ())
with :? TargetInvocationException as e ->
Some (UserMethodFailure.Threw (su.Name, e.InnerException), endMetadata ())
| _ -> None
let testFailures = ResizeArray<TestMemberFailure * IndividualTestRunMetadata> ()
let successes =
ResizeArray<SingleTestMethod * TestMemberSuccess * IndividualTestRunMetadata> ()
match setupResult with
| Some _ ->
// Don't run any tests if setup failed.
()
| None ->
for test in tests.Tests do
if filter tests test then
progress.OnTestMemberStart test.Name
let testSuccess = ref 0
let results = runTestsFromMember tests.SetUp tests.TearDown containingObject test
for result, report in results do
match result with
| Error failure ->
testFailures.Add (failure, report)
progress.OnTestFailed test.Name failure
| Ok result ->
Interlocked.Increment testSuccess |> ignore<int>
lock successes (fun () -> successes.Add (test, result, report))
progress.OnTestMemberFinished test.Name
else
progress.OnTestMemberSkipped test.Name
// Unconditionally run OneTimeTearDown if it exists.
let tearDownError =
match tests.OneTimeTearDown with
| Some td ->
try
match td.Invoke (containingObject, [||]) with
| null -> None
| ret -> Some (UserMethodFailure.ReturnedNonUnit (td.Name, ret), endMetadata ())
with :? TargetInvocationException as e ->
Some (UserMethodFailure.Threw (td.Name, e), endMetadata ())
| _ -> None
Environment.CurrentDirectory <- oldWorkDir
{
Failed = testFailures |> Seq.toList
Success = successes |> Seq.toList
OtherFailures = [ tearDownError ; setupResult ] |> List.choose id
}
/// 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.
let parse (parentType : Type) : TestFixture =
let categories =
parentType.CustomAttributes
|> Seq.filter (fun attr -> attr.AttributeType.FullName = "NUnit.Framework.CategoryAttribute")
|> Seq.map (fun attr -> attr.ConstructorArguments |> Seq.exactlyOne |> _.Value |> unbox<string>)
|> Seq.toList
(TestFixture.Empty parentType.Assembly parentType.Name, parentType.GetRuntimeMethods ())
||> Seq.fold (fun state mi ->
((state, []), mi.CustomAttributes)
||> Seq.fold (fun (state, unrecognisedAttrs) attr ->
match attr.AttributeType.FullName with
| "NUnit.Framework.OneTimeSetUpAttribute" ->
match state.OneTimeSetUp with
| Some _existing -> failwith "Multiple OneTimeSetUp methods found"
| None ->
{ state with
OneTimeSetUp = Some mi
},
unrecognisedAttrs
| "NUnit.Framework.OneTimeTearDownAttribute" ->
match state.OneTimeTearDown with
| Some _existing -> failwith "Multiple OneTimeTearDown methods found"
| None ->
{ state with
OneTimeTearDown = Some mi
},
unrecognisedAttrs
| "NUnit.Framework.TearDownAttribute" ->
{ state with
TearDown = mi :: state.TearDown
},
unrecognisedAttrs
| "NUnit.Framework.SetUpAttribute" ->
{ state with
SetUp = mi :: state.SetUp
},
unrecognisedAttrs
| "NUnit.Framework.TestFixtureSetUpAttribute" ->
failwith "TestFixtureSetUp is not supported (upstream has deprecated it; use OneTimeSetUp)"
| "NUnit.Framework.TestFixtureTearDownAttribute" ->
failwith "TestFixtureTearDown is not supported (upstream has deprecated it; use OneTimeTearDown)"
| "NUnit.Framework.RetryAttribute" ->
failwith "RetryAttribute is not supported. Don't write flaky tests."
| "NUnit.Framework.RandomAttribute" ->
failwith "RandomAttribute is not supported. Use a property-based testing framework like FsCheck."
| "NUnit.Framework.AuthorAttribute"
| "NUnit.Framework.CultureAttribute"
| "NUnit.Framework.DescriptionAttribute" ->
// ignoring for now: metadata only
state, unrecognisedAttrs
| _ -> state, attr :: unrecognisedAttrs
)
|> fun (state, unrecognised) ->
let state, unrecognised =
match SingleTestMethod.parse categories mi unrecognised with
| Some test, unrecognised ->
{ state with
Tests = test :: state.Tests
},
unrecognised
| None, unrecognised -> state, unrecognised
unrecognised
|> List.filter (fun attr ->
attr.AttributeType.FullName.StartsWith ("NUnit.Framework.", StringComparison.Ordinal)
)
|> function
| [] -> ()
| unrecognised ->
unrecognised
|> Seq.map (fun x -> x.AttributeType.FullName)
|> String.concat ", "
|> failwithf "Unrecognised attributes: %s"
state
)

View File

@@ -0,0 +1,45 @@
namespace WoofWare.NUnitTestRunner
open System
/// Represents something which knows how to report progress through a test suite.
/// Note that we don't guarantee anything about parallelism; you must make sure
/// all implementations are safe to run concurrently.
type ITestProgress =
/// 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.
abstract OnTestFixtureStart : name : string -> testCount : int -> unit
/// Called just before we start executing the test(s) indicated by a particular method.
abstract OnTestMemberStart : name : string -> unit
/// Called when a test fails. (This may be called repeatedly with the same `name`, e.g. if the test
/// is run multiple times with different combinations of test data.)
abstract OnTestFailed : name : string -> failure : TestMemberFailure -> unit
/// Called when we've finished every test indicated by a particular method. (The test may have been run
/// multiple times, e.g. with different combinations of test data.)
abstract OnTestMemberFinished : name : string -> unit
/// Called when we decide not to run the test(s) indicated by a particular method (e.g. because it's
/// marked [<Explicit>]).
abstract OnTestMemberSkipped : name : string -> unit
/// Methods for constructing specific ITestProgress objects.
[<RequireQualifiedAccess>]
module TestProgress =
/// An ITestProgress which logs to stderr.
let toStderr () : ITestProgress =
{ new ITestProgress with
member _.OnTestFixtureStart name testCount =
let plural = if testCount = 1 then "" else "s"
Console.Error.WriteLine $"Running test fixture: %s{name} (%i{testCount} test%s{plural} to run)"
member _.OnTestMemberStart name =
Console.Error.WriteLine $"Running test: %s{name}"
member _.OnTestFailed name failure =
Console.Error.WriteLine $"Test failed: %O{failure}"
member _.OnTestMemberFinished name =
Console.Error.WriteLine $"Finished test %s{name}"
member _.OnTestMemberSkipped name =
Console.Error.WriteLine $"Skipping test due to filter: %s{name}"
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,43 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<Authors>Patrick Stevens</Authors>
<Copyright>Copyright (c) Patrick Stevens 2024</Copyright>
<Description>Library with primitives to allow you to run NUnit tests.</Description>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/Smaug123/unofficial-nunit-runner</RepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageTags>nunit;test;runner</PackageTags>
<PackageId>WoofWare.NUnitTestRunner.Lib</PackageId>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarnOn>FS3559</WarnOn>
</PropertyGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.fs" />
<Compile Include="Array.fs" />
<Compile Include="List.fs" />
<Compile Include="Result.fs" />
<Compile Include="Domain.fs" />
<Compile Include="Filter.fs" />
<Compile Include="SingleTestMethod.fs" />
<Compile Include="TestProgress.fs" />
<Compile Include="TestFixture.fs" />
<Compile Include="Xml.fs" />
<Compile Include="TrxReport.fs" />
<None Include="..\README.md">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
<EmbeddedResource Include="SurfaceBaseline.txt" />
<EmbeddedResource Include="version.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="WoofWare.PrattParser" Version="0.1.2" />
<PackageReference Update="FSharp.Core" Version="6.0.0" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,47 @@
namespace WoofWare.NUnitTestRunner
open System.Xml
[<AutoOpen>]
module internal XmlPatterns =
[<return : Struct>]
let (|NodeWithChildren|_|) (expectedName : string) (node : XmlNode) : unit voption =
if node.Name = expectedName && node.HasChildNodes then
ValueSome ()
else
ValueNone
let (|NodeWithNamedChild|_|) (childName : string) (node : XmlNode) : XmlNode option =
if node.HasChildNodes then
node.ChildNodes
|> Seq.cast<XmlNode>
|> Seq.tryFind (fun n -> n.Name = childName)
else
None
let (|OneChildNode|_|) (expectedName : string) (node : XmlNode) : XmlNode option =
if node.Name = expectedName && node.HasChildNodes && node.ChildNodes.Count = 1 then
Some node.FirstChild
else
None
let (|NoChildrenNode|_|) (node : XmlNode) : string option =
if node.HasChildNodes then None else Some node.Value
[<return : Struct>]
let (|NamedNoChildren|_|) (name : string) (node : XmlNode) : unit voption =
if node.HasChildNodes then ValueNone
elif node.Name = name then ValueSome ()
else ValueNone
[<return : Struct>]
let (|Int64|_|) (s : string) : int64 voption =
match System.Int64.TryParse s with
| false, _ -> ValueNone
| true, v -> ValueSome v
[<return : Struct>]
let (|Int|_|) (s : string) : int voption =
match System.Int32.TryParse s with
| false, _ -> ValueNone
| true, v -> ValueSome v

View File

@@ -0,0 +1,11 @@
{
"version": "0.8",
"publicReleaseRefSpec": [
"^refs/heads/main$"
],
"pathFilters": [
"./",
":/Directory.Build.props",
":/README.md"
]
}