Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix immediate task execution when defining test cases #492

Merged
merged 1 commit into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 15 additions & 11 deletions Expecto.Tests/Tests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1397,19 +1397,23 @@ let taskTests =
]

testList "testCaseTask" [
testCaseTask "simple" <| task {
Expect.equal 1 1 "1=1"
}
testCaseTask "simple" <| fun () ->
task {
Expect.equal 1 1 "1=1"
}

testCaseTask "let" <| task {
let! n = async { return 1 }
Expect.equal n 1 "n=1"
}
testCaseTask "let" <| fun () ->
task {
let! n = async { return 1 }
Expect.equal n 1 "n=1"
}

testCaseTask "can fail" <| task {
let! n = async { return 2 }
Expect.equal n 1 "n=1"
} |> assertTestFails
testCaseTask "can fail" <| (fun () ->
task {
let! n = async { return 2 }
Expect.equal n 1 "n=1"
})
|> assertTestFails
]

testList "testTask" [
Expand Down
23 changes: 14 additions & 9 deletions Expecto/Expecto.fs
Original file line number Diff line number Diff line change
Expand Up @@ -87,24 +87,31 @@ module Tests =
let inline testCaseWithCancel name test = TestLabel(name, TestCase (SyncWithCancel test,Normal), Normal)
/// Builds an async test case
let inline testCaseAsync name test = TestLabel(name, TestCase (Async test,Normal), Normal)

let inline private deferTaskAsAsync (taskFactory: unit -> Task<unit>) =
// Tasks are hot, they are start right away, so we need to defer the task creation
async {
do! taskFactory() |> Async.AwaitTask
}

/// Builds an async test case from a task
let inline testCaseTask name test = TestLabel(name, TestCase (Async (Async.AwaitTask test),Normal), Normal)
let inline testCaseTask name test = TestLabel(name, TestCase (Async (deferTaskAsAsync test),Normal), Normal)
/// Builds a test case that will make Expecto to ignore other unfocused tests
let inline ftestCase name test = TestLabel(name, TestCase (Sync test, Focused), Focused)
/// Builds a test case with cancel that will make Expecto to ignore other unfocused tests
let inline ftestCaseWithCancel name test = TestLabel(name, TestCase (SyncWithCancel test, Focused), Focused)
/// Builds an async test case that will make Expecto to ignore other unfocused tests
let inline ftestCaseAsync name test = TestLabel(name, TestCase (Async test, Focused), Focused)
/// Builds an async test case from a task, that will make Expecto to ignore other unfocused tests
let inline ftestCaseTask name test = TestLabel(name, TestCase (Async (Async.AwaitTask test), Focused), Focused)
let inline ftestCaseTask name test = TestLabel(name, TestCase (Async (deferTaskAsAsync test), Focused), Focused)
/// Builds a test case that will be ignored by Expecto
let inline ptestCase name test = TestLabel(name, TestCase (Sync test, Pending), Pending)
/// Builds a test case with cancel that will be ignored by Expecto
let inline ptestCaseWithCancel name test = TestLabel(name, TestCase (SyncWithCancel test, Pending), Pending)
/// Builds an async test case that will be ignored by Expecto
let inline ptestCaseAsync name test = TestLabel(name, TestCase (Async test, Pending), Pending)
/// Builds an async test case from a task, that will be ignored by Expecto
let inline ptestCaseTask name test = TestLabel(name, TestCase (Async (Async.AwaitTask test), Pending), Pending)
let inline ptestCaseTask name test = TestLabel(name, TestCase (Async (deferTaskAsAsync test), Pending), Pending)
/// Test case or list needs to run sequenced. Use for any benchmark code or
/// for tests using `Expect.isFasterThan`
let inline testSequenced test = Sequenced (Synchronous,test)
Expand Down Expand Up @@ -235,13 +242,11 @@ module Tests =
member inline __.TryFinally(p, cf) = task.TryFinally(p, cf)
member inline __.TryWith(p, cf) = task.TryWith(p, cf)
member __.Run f =
let a = task {
do! task.Run f
}
let deferred () = task.Run f
match focusState with
| Normal -> testCaseTask name a
| Focused -> ftestCaseTask name a
| Pending -> ptestCaseTask name a
| Normal -> testCaseTask name deferred
| Focused -> ftestCaseTask name deferred
| Pending -> ptestCaseTask name deferred

[<AutoOpen>]
module TestTaskExtensions =
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ test project.**
- `testTask : string -> TestTaskBuilder` - Builds a task test case in a computation expression.
- `testCase : string -> (unit -> unit) -> Test` - Builds a test case from a test function.
- `testCaseAsync : string -> Async<unit> -> Test` - Builds an async test case from an async expression.
- `testCaseTask : string -> Task<unit> -> Test` - Builds an async test case from a task expression.
- `testCaseTask : string -> (unit -> Task<unit>) -> Test` - Builds an async test case from a function returning a task. Unlike async, tasks start right away and thus must be wrapped in a function so the task doesn't start until the test is run.

### `testList` for grouping

Expand Down
Loading