mirror of
https://github.com/Smaug123/unofficial-nunit-runner
synced 2025-10-12 20:18:41 +00:00
Support Repeat attribute (#5)
This commit is contained in:
@@ -23,6 +23,7 @@ type SingleTestMethod =
|
|||||||
Kind : TestKind
|
Kind : TestKind
|
||||||
Modifiers : Modifier list
|
Modifiers : Modifier list
|
||||||
Categories : string list
|
Categories : string list
|
||||||
|
Repeat : int option
|
||||||
}
|
}
|
||||||
|
|
||||||
member this.Name = this.Method.Name
|
member this.Name = this.Method.Name
|
||||||
@@ -30,26 +31,26 @@ type SingleTestMethod =
|
|||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
module SingleTestMethod =
|
module SingleTestMethod =
|
||||||
let parse (parentCategories : string list) (method : MethodInfo) : SingleTestMethod option =
|
let parse (parentCategories : string list) (method : MethodInfo) : SingleTestMethod option =
|
||||||
let isTest, hasSource, hasData, modifiers, categories =
|
let isTest, hasSource, hasData, modifiers, categories, repeat =
|
||||||
((false, None, None, [], []), method.CustomAttributes)
|
((false, None, None, [], [], None), method.CustomAttributes)
|
||||||
||> Seq.fold (fun (isTest, hasSource, hasData, mods, cats) attr ->
|
||> Seq.fold (fun (isTest, hasSource, hasData, mods, cats, repeat) attr ->
|
||||||
match attr.AttributeType.FullName with
|
match attr.AttributeType.FullName with
|
||||||
| "NUnit.Framework.TestAttribute" ->
|
| "NUnit.Framework.TestAttribute" ->
|
||||||
if attr.ConstructorArguments.Count > 0 then
|
if attr.ConstructorArguments.Count > 0 then
|
||||||
failwith "Unexpectedly got arguments to the Test attribute"
|
failwith "Unexpectedly got arguments to the Test attribute"
|
||||||
|
|
||||||
(true, hasSource, hasData, mods, cats)
|
(true, hasSource, hasData, mods, cats, repeat)
|
||||||
| "NUnit.Framework.TestCaseAttribute" ->
|
| "NUnit.Framework.TestCaseAttribute" ->
|
||||||
let args = attr.ConstructorArguments |> Seq.map _.Value |> Seq.toList
|
let args = attr.ConstructorArguments |> Seq.map _.Value |> Seq.toList
|
||||||
|
|
||||||
match hasData with
|
match hasData with
|
||||||
| None -> (isTest, hasSource, Some [ List.ofSeq args ], mods, cats)
|
| None -> (isTest, hasSource, Some [ List.ofSeq args ], mods, cats, repeat)
|
||||||
| Some existing -> (isTest, hasSource, Some ((List.ofSeq args) :: existing), mods, cats)
|
| Some existing -> (isTest, hasSource, Some ((List.ofSeq args) :: existing), mods, cats, repeat)
|
||||||
| "NUnit.Framework.TestCaseSourceAttribute" ->
|
| "NUnit.Framework.TestCaseSourceAttribute" ->
|
||||||
let arg = attr.ConstructorArguments |> Seq.exactlyOne |> _.Value |> unbox<string>
|
let arg = attr.ConstructorArguments |> Seq.exactlyOne |> _.Value |> unbox<string>
|
||||||
|
|
||||||
match hasSource with
|
match hasSource with
|
||||||
| None -> (isTest, Some arg, hasData, mods, cats)
|
| None -> (isTest, Some arg, hasData, mods, cats, repeat)
|
||||||
| Some existing ->
|
| Some existing ->
|
||||||
failwith
|
failwith
|
||||||
$"Unexpectedly got multiple different sources for test %s{method.Name} (%s{existing}, %s{arg})"
|
$"Unexpectedly got multiple different sources for test %s{method.Name} (%s{existing}, %s{arg})"
|
||||||
@@ -59,53 +60,63 @@ module SingleTestMethod =
|
|||||||
|> Seq.tryHead
|
|> Seq.tryHead
|
||||||
|> Option.map (_.Value >> unbox<string>)
|
|> Option.map (_.Value >> unbox<string>)
|
||||||
|
|
||||||
(isTest, hasSource, hasData, (Modifier.Explicit reason) :: mods, cats)
|
(isTest, hasSource, hasData, (Modifier.Explicit reason) :: mods, cats, repeat)
|
||||||
| "NUnit.Framework.IgnoreAttribute" ->
|
| "NUnit.Framework.IgnoreAttribute" ->
|
||||||
let reason =
|
let reason =
|
||||||
attr.ConstructorArguments
|
attr.ConstructorArguments
|
||||||
|> Seq.tryHead
|
|> Seq.tryHead
|
||||||
|> Option.map (_.Value >> unbox<string>)
|
|> Option.map (_.Value >> unbox<string>)
|
||||||
|
|
||||||
(isTest, hasSource, hasData, (Modifier.Ignored reason) :: mods, cats)
|
(isTest, hasSource, hasData, (Modifier.Ignored reason) :: mods, cats, repeat)
|
||||||
| "NUnit.Framework.CategoryAttribute" ->
|
| "NUnit.Framework.CategoryAttribute" ->
|
||||||
let category =
|
let category =
|
||||||
attr.ConstructorArguments |> Seq.exactlyOne |> _.Value |> unbox<string>
|
attr.ConstructorArguments |> Seq.exactlyOne |> _.Value |> unbox<string>
|
||||||
|
|
||||||
(isTest, hasSource, hasData, mods, category :: cats)
|
(isTest, hasSource, hasData, mods, category :: cats, repeat)
|
||||||
|
| "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>
|
||||||
|
(isTest, hasSource, hasData, mods, cats, Some repeat)
|
||||||
| s when s.StartsWith ("NUnit.Framework", StringComparison.Ordinal) ->
|
| s when s.StartsWith ("NUnit.Framework", StringComparison.Ordinal) ->
|
||||||
failwith $"Unrecognised attribute on function %s{method.Name}: %s{attr.AttributeType.FullName}"
|
failwith $"Unrecognised attribute on function %s{method.Name}: %s{attr.AttributeType.FullName}"
|
||||||
| _ -> (isTest, hasSource, hasData, mods, cats)
|
| _ -> (isTest, hasSource, hasData, mods, cats, repeat)
|
||||||
)
|
)
|
||||||
|
|
||||||
match isTest, hasSource, hasData, modifiers, categories with
|
match isTest, hasSource, hasData, modifiers, categories, repeat with
|
||||||
| _, Some _, Some _, _, _ ->
|
| _, Some _, Some _, _, _, _ ->
|
||||||
failwith $"Test %s{method.Name} unexpectedly has both TestData and TestCaseSource; not currently supported"
|
failwith $"Test %s{method.Name} unexpectedly has both TestData and TestCaseSource; not currently supported"
|
||||||
| false, None, None, [], _ -> None
|
| false, None, None, [], _, _ -> None
|
||||||
| _, Some source, None, mods, categories ->
|
| _, Some source, None, mods, categories, repeat ->
|
||||||
{
|
{
|
||||||
Kind = TestKind.Source source
|
Kind = TestKind.Source source
|
||||||
Method = method
|
Method = method
|
||||||
Modifiers = mods
|
Modifiers = mods
|
||||||
Categories = categories @ parentCategories
|
Categories = categories @ parentCategories
|
||||||
|
Repeat = repeat
|
||||||
}
|
}
|
||||||
|> Some
|
|> Some
|
||||||
| _, None, Some data, mods, categories ->
|
| _, None, Some data, mods, categories, repeat ->
|
||||||
{
|
{
|
||||||
Kind = TestKind.Data data
|
Kind = TestKind.Data data
|
||||||
Method = method
|
Method = method
|
||||||
Modifiers = mods
|
Modifiers = mods
|
||||||
Categories = categories @ parentCategories
|
Categories = categories @ parentCategories
|
||||||
|
Repeat = repeat
|
||||||
}
|
}
|
||||||
|> Some
|
|> Some
|
||||||
| true, None, None, mods, categories ->
|
| true, None, None, mods, categories, repeat ->
|
||||||
{
|
{
|
||||||
Kind = TestKind.Single
|
Kind = TestKind.Single
|
||||||
Method = method
|
Method = method
|
||||||
Modifiers = mods
|
Modifiers = mods
|
||||||
Categories = categories @ parentCategories
|
Categories = categories @ parentCategories
|
||||||
|
Repeat = repeat
|
||||||
}
|
}
|
||||||
|> Some
|
|> Some
|
||||||
| false, None, None, _ :: _, _ ->
|
| false, None, None, _ :: _, _, _ ->
|
||||||
failwith
|
failwith
|
||||||
$"Unexpectedly got test modifiers but no test settings on '%s{method.Name}', which you probably didn't intend."
|
$"Unexpectedly got test modifiers but no test settings on '%s{method.Name}', which you probably didn't intend."
|
||||||
|
|
||||||
@@ -172,22 +183,27 @@ module TestFixture =
|
|||||||
[]
|
[]
|
||||||
else
|
else
|
||||||
|
|
||||||
match test.Kind with
|
Seq.init
|
||||||
| TestKind.Data data -> data |> List.map (fun args -> runOne test.Method (Array.ofList args))
|
(Option.defaultValue 1 test.Repeat)
|
||||||
| TestKind.Single -> [ runOne test.Method [||] ]
|
(fun _ ->
|
||||||
| TestKind.Source s ->
|
match test.Kind with
|
||||||
let args = test.Method.DeclaringType.GetProperty s
|
| TestKind.Data data -> data |> Seq.map (fun args -> runOne test.Method (Array.ofList args))
|
||||||
|
| TestKind.Single -> Seq.singleton (runOne test.Method [||])
|
||||||
|
| TestKind.Source s ->
|
||||||
|
let args = test.Method.DeclaringType.GetProperty s
|
||||||
|
|
||||||
args.GetValue null :?> IEnumerable<obj>
|
args.GetValue null :?> IEnumerable<obj>
|
||||||
|> Seq.map (fun arg ->
|
|> Seq.map (fun arg ->
|
||||||
match arg with
|
match arg with
|
||||||
| :? TestCaseData as tcd -> runOne test.Method tcd.Arguments
|
| :? TestCaseData as tcd -> runOne test.Method tcd.Arguments
|
||||||
| :? Tuple<obj, obj> as (a, b) -> runOne test.Method [| a ; b |]
|
| :? Tuple<obj, obj> as (a, b) -> runOne test.Method [| a ; b |]
|
||||||
| :? Tuple<obj, obj, obj> as (a, b, c) -> runOne test.Method [| a ; b ; c |]
|
| :? Tuple<obj, obj, obj> as (a, b, c) -> runOne test.Method [| a ; b ; c |]
|
||||||
| :? Tuple<obj, obj, obj, obj> as (a, b, c, d) -> runOne test.Method [| a ; b ; c ; d |]
|
| :? Tuple<obj, obj, obj, obj> as (a, b, c, d) -> runOne test.Method [| a ; b ; c ; d |]
|
||||||
| arg -> runOne test.Method [| arg |]
|
| arg -> runOne test.Method [| arg |]
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|> List.ofSeq
|
|> Seq.concat
|
||||||
|
|> Seq.toList
|
||||||
|
|
||||||
let rec shouldRun (filter : Filter) : TestFixture -> SingleTestMethod -> bool =
|
let rec shouldRun (filter : Filter) : TestFixture -> SingleTestMethod -> bool =
|
||||||
match filter with
|
match filter with
|
||||||
|
Reference in New Issue
Block a user