Skip to content

Commit

Permalink
feat: add support for test filters (#133)
Browse files Browse the repository at this point in the history
* feat: add support for test filters

* fix: null-reference when no filters provided
  • Loading branch information
Alxandr authored Aug 9, 2023
1 parent 197cc94 commit ae26d0c
Show file tree
Hide file tree
Showing 5 changed files with 216 additions and 98 deletions.
12 changes: 12 additions & 0 deletions .config/dotnet-tools.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"version": 1,
"isRoot": true,
"tools": {
"fantomas": {
"version": "6.1.2",
"commands": [
"fantomas"
]
}
}
}
31 changes: 27 additions & 4 deletions src/YoloDev.Expecto.TestSdk/adapter.fs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,22 @@ open Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging
type VsTestAdapter() =
let cts = new CancellationTokenSource()

member x.WaitForDebugger() =
if not Debugger.IsAttached then
Debugger.Launch() |> ignore

while (not cts.IsCancellationRequested && not Debugger.IsAttached) do
printfn "Waiting for debugger to attach to process: %d" (Process.GetCurrentProcess().Id)
Thread.Sleep 1000

Debugger.Break()

member x.Breakpoint() =
if
System.Environment.GetEnvironmentVariable("DEBUG_EXPECTO_TESTSDK", System.EnvironmentVariableTarget.Process) = "1"
then
x.WaitForDebugger()

interface System.IDisposable with
member x.Dispose() =
match cts with
Expand All @@ -24,6 +40,8 @@ type VsTestAdapter() =

interface ITestDiscoverer with
member x.DiscoverTests(sources, discoveryContext, logger, discoverySink) =
x.Breakpoint()

let sources = Guard.argNotNull "sources" sources
let logger = Guard.argNotNull "logger" logger
let discoverySink = Guard.argNotNull "discoverySink" discoverySink
Expand All @@ -44,7 +62,8 @@ type VsTestAdapter() =
interface ITestExecutor with
member x.Cancel() = cts.Cancel()

member x.RunTests(tests: TestCase seq, runContext: IRunContext, frameworkHandle: IFrameworkHandle): unit =
member x.RunTests(tests: TestCase seq, runContext: IRunContext, frameworkHandle: IFrameworkHandle) : unit =
x.Breakpoint()
let tests = Guard.argNotNull "tests" tests
let runContext = Guard.argNotNull "runContext" runContext
let frameworkHandle = Guard.argNotNull "frameworkHandle" frameworkHandle
Expand All @@ -58,9 +77,11 @@ type VsTestAdapter() =
|> Option.map (RunSettings.read logger)
|> Option.defaultValue RunSettings.defaultSettings

Execution.runSpecifiedTests logger runSettings frameworkHandle tests |> Async.RunSynchronously
Execution.runSpecifiedTests logger runSettings frameworkHandle tests
|> Async.RunSynchronously

member x.RunTests(sources: string seq, runContext: IRunContext, frameworkHandle: IFrameworkHandle): unit =
member x.RunTests(sources: string seq, runContext: IRunContext, frameworkHandle: IFrameworkHandle) : unit =
x.Breakpoint()
let sources = Guard.argNotNull "sources" sources
let runContext = Guard.argNotNull "runContext" runContext
let frameworkHandle = Guard.argNotNull "frameworkHandle" frameworkHandle
Expand All @@ -72,10 +93,12 @@ type VsTestAdapter() =
Option.ofObj runContext
|> Option.bind (fun c -> Option.ofObj c.RunSettings)
|> Option.map (RunSettings.read logger)
|> Option.map (RunSettings.filter runContext)
|> Option.defaultValue RunSettings.defaultSettings

let testPlatformContext =
{ requireSourceInformation = runSettings.collectSourceInformation
requireTestProperty = true }

Execution.runTests logger runSettings frameworkHandle sources |> Async.RunSynchronously
Execution.runTests logger runSettings frameworkHandle sources
|> Async.RunSynchronously
96 changes: 54 additions & 42 deletions src/YoloDev.Expecto.TestSdk/execution.fs
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,22 @@ module private LogAdapter =
match map l with
| None -> async.Zero()
| Some level ->
async {
use writer = new System.IO.StringWriter()
let writerLogger =
Expecto.Logging.TextWriterTarget(Array.empty, Expecto.Logging.LogLevel.Info, writer) :> Expecto.Logging.Logger
async {
use writer = new System.IO.StringWriter()

do! fn writerLogger l
Logger.send level assembly (string writer) logger
}
let writerLogger =
Expecto.Logging.TextWriterTarget(Array.empty, Expecto.Logging.LogLevel.Info, writer)
:> Expecto.Logging.Logger

let log l fn = withLogger l <| fun logger l -> logger.log l fn
do! fn writerLogger l
Logger.send level assembly (string writer) logger
}

let logWithAck l fn = withLogger l <| fun logger l -> logger.logWithAck l fn
let log l fn =
withLogger l <| fun logger l -> logger.log l fn

let logWithAck l fn =
withLogger l <| fun logger l -> logger.logWithAck l fn

{ new Expecto.Logging.Logger with
member x.name = name
Expand Down Expand Up @@ -74,7 +78,10 @@ module private PrinterAdapter =
let result = Map.find name results
result.Outcome <- TestOutcome.Skipped
result.EndTime <- DateTimeOffset.Now
result.Messages.Add <| TestResultMessage(TestResultMessage.AdditionalInfoCategory, sprintf "Skipped: %s" reason)

result.Messages.Add
<| TestResultMessage(TestResultMessage.AdditionalInfoCategory, sprintf "Skipped: %s" reason)

recordEnd result

let failed name reason duration =
Expand Down Expand Up @@ -110,15 +117,15 @@ module internal Execution =
|> Seq.toList
|> List.groupBy (fun t -> t.name)
|> List.choose (function
| _, x :: _ :: _ -> Some x.name
| _ -> None)
| _, x :: _ :: _ -> Some x.name
| _ -> None)

let private runMatchingTests
logger
(settings: RunSettings)
(test: ExpectoTest)
(cases: TestCase list)
(frameworkHandle: IFrameworkHandle)
logger
(settings: RunSettings)
(test: ExpectoTest)
(cases: TestCase list)
(frameworkHandle: IFrameworkHandle)
=
// TODO: Context passing
// TODO: fail on focused tests
Expand All @@ -133,52 +140,57 @@ module internal Execution =
let printAdapter = PrinterAdapter.create discovered frameworkHandle

let config = CLIArguments.Printer printAdapter :: settings.expectoConfig
Expecto.Logging.Global.initialise <| { Expecto.Logging.Global.defaultConfig with getLogger = getLogger }

let testNames =
cases
|> Seq.map (fun c -> c.DisplayName)
|> Set.ofSeq
Expecto.Logging.Global.initialise
<| { Expecto.Logging.Global.defaultConfig with
getLogger = getLogger }

let cases = cases |> Seq.filter (TestFilter.matches settings.filter)
let testNames = cases |> Seq.map (fun c -> c.DisplayName) |> Set.ofSeq

let tests =
ExpectoTest.test test
|> Expecto.Test.filter joinWith.asString (joinWith.format >> fun name -> Seq.contains name testNames)

let duplicates = duplicatedNames tests

match duplicates with
| [] ->
Expecto.Tests.runTestsWithCLIArgs config [||] tests |> ignore
async.Zero()
Expecto.Tests.runTestsWithCLIArgs config [||] tests |> ignore
async.Zero()
| _ ->
Logger.send LogLevel.Error (Some <| ExpectoTest.source test)
(sprintf "Found duplicated test names, these names are: %A" duplicates) logger
async.Zero()
Logger.send
LogLevel.Error
(Some <| ExpectoTest.source test)
(sprintf "Found duplicated test names, these names are: %A" duplicates)
logger

async.Zero()

let private runTestsForSource logger (settings: RunSettings) frameworkHandle source =
match Discovery.discoverTestForSource logger source with
| None -> async.Zero()
| Some test ->
let cases =
Discovery.getTestCasesFromTest logger settings test
|> Seq.map ExpectoTestCase.case
|> List.ofSeq
runMatchingTests logger settings test cases frameworkHandle
let cases =
Discovery.getTestCasesFromTest logger settings test
|> Seq.map ExpectoTestCase.case
|> List.ofSeq

runMatchingTests logger settings test cases frameworkHandle

let private runSpecifiedTestsForSource logger (settings: RunSettings) frameworkHandle source (tests: TestCase seq) =
let nameSet =
tests
|> Seq.map (fun t -> t.FullyQualifiedName)
|> Set.ofSeq
let nameSet = tests |> Seq.map (fun t -> t.FullyQualifiedName) |> Set.ofSeq

match Discovery.discoverTestForSource logger source with
| None -> async.Zero()
| Some test ->
let cases =
Discovery.getTestCasesFromTest logger settings test
|> Seq.map ExpectoTestCase.case
|> Seq.filter (fun c -> Set.contains c.FullyQualifiedName nameSet)
|> List.ofSeq
let cases =
Discovery.getTestCasesFromTest logger settings test
|> Seq.map ExpectoTestCase.case
|> Seq.filter (fun c -> Set.contains c.FullyQualifiedName nameSet)
|> List.ofSeq

runMatchingTests logger settings test cases frameworkHandle
runMatchingTests logger settings test cases frameworkHandle

let runTests logger (settings: RunSettings) frameworkHandle sources =
async {
Expand Down
Loading

0 comments on commit ae26d0c

Please sign in to comment.