Skip to content

Commit 61c26df

Browse files
committed
Merge branch 'logs'
2 parents 9be6eca + 2574ac3 commit 61c26df

File tree

4 files changed

+105
-13
lines changed

4 files changed

+105
-13
lines changed

Sprout.fs

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ let mutable debug: string -> unit = ignore
55

66
type HookFunction = unit -> unit
77
type EachFunction = Before of f: HookFunction | After of f: HookFunction
8+
type LogLevel = Debug of string | Info of string
89

910
type EachBuilder(factory: (unit -> unit) -> EachFunction) =
1011
member _.Zero() = ()
@@ -35,16 +36,20 @@ type ItBuilder(name: string) =
3536
let it name = ItBuilder name
3637
let pending name = It.Pending name
3738

39+
type DescribeStep =
40+
| It of It
41+
| LogStatement of LogLevel
42+
3843
type Describe = {
3944
Name: string
40-
TestCases: It list
45+
Steps: DescribeStep list
4146
Each: EachFunction list
4247
Children: Describe list
4348
}
4449
with
4550
static member Empty name = {
4651
Name = name
47-
TestCases = []
52+
Steps = []
4853
Each = []
4954
Children = []
5055
}
@@ -54,16 +59,18 @@ type DescribeBuilder(name) =
5459
member _.Yield(each: EachFunction) =
5560
{ Describe.Empty name with Each = [each] }
5661
member _.Yield(tc: It) =
57-
{ Describe.Empty name with TestCases = [tc] }
58-
member _.Yield(sub: Describe) =
59-
{ Describe.Empty name with Children = [sub] }
62+
{ Describe.Empty name with Steps = [It tc] }
63+
member _.Yield(log: LogLevel) =
64+
{ Describe.Empty name with Steps = [LogStatement log] }
65+
member _.Yield(describe: Describe) =
66+
{ Describe.Empty name with Children = [describe] }
6067
member _.Combine(a, b) =
6168
{
6269
Describe.Empty name
6370
with
6471
Each = a.Each @ b.Each
6572
Children = a.Children @ b.Children
66-
TestCases = a.TestCases @ b.TestCases
73+
Steps = a.Steps @ b.Steps
6774
}
6875
member _.Delay(f: unit -> Describe) = f()
6976
member this.For(sequence: seq<'T>, body: 'T -> Describe) =
@@ -76,6 +83,8 @@ type DescribeBuilder(name) =
7683

7784
let describe name = DescribeBuilder name
7885

86+
type LogState = { Messages: string list }
87+
7988
type Path = Path of string list
8089
with
8190
member this.Length =
@@ -107,9 +116,13 @@ module Reporters =
107116
let white = "\u001b[37m"
108117
let reset = "\u001b[0m"
109118

110-
type ConsoleReporter() =
119+
type ConsoleReporter(passedChar, failedChar, pendingChar) =
111120
let sw = Stopwatch.StartNew()
112121
let indent (path: Path) = String.replicate ((path.Length - 1) * 2) " "
122+
123+
new() =
124+
ConsoleReporter("", "", "")
125+
113126
interface ITestReporter with
114127
member _.BeginSuite(name, path) =
115128
let indent = indent path
@@ -119,11 +132,11 @@ module Reporters =
119132
let indent = indent path
120133
match result with
121134
| Passed (_, name) ->
122-
printfn $"%s{indent}%s{AnsiColours.green} passed: %s{name}%s{AnsiColours.reset}"
135+
printfn $"%s{indent}%s{AnsiColours.green} %s{passedChar} passed: %s{name}%s{AnsiColours.reset}"
123136
| Failed (_, name, ex) ->
124-
printfn $"%s{indent}%s{AnsiColours.red} failed: %s{name} - %s{ex.Message}%s{AnsiColours.reset}"
137+
printfn $"%s{indent}%s{AnsiColours.red} %s{failedChar} failed: %s{name} - %s{ex.Message}%s{AnsiColours.reset}"
125138
| Pending (_, name) ->
126-
printfn $"%s{indent}%s{AnsiColours.grey} pending: %s{name}%s{AnsiColours.reset}"
139+
printfn $"%s{indent}%s{AnsiColours.grey} %s{pendingChar} pending: %s{name}%s{AnsiColours.reset}"
127140

128141
member _.EndSuite(_, _) = ()
129142
member _.Debug(message: string, path: Path): unit =
@@ -169,7 +182,6 @@ with
169182
}
170183

171184
type TestSuiteRunner = Describe -> TestContext -> unit
172-
type private LogLevel = Debug of string | Info of string
173185

174186
let private runTestCase path (testCase: It) beforeHooks afterHooks =
175187
// setup logging functions
@@ -207,8 +219,14 @@ let rec private doRunTestSuite (suite: Describe) (context: TestContext): TestRes
207219
let afterHooks = context.ParentAfterHooks |> List.append (List.rev afterHooks)
208220

209221
let testResults = [
210-
for testCase in suite.TestCases do
211-
runTestCase context.Path testCase beforeHooks afterHooks
222+
for testCase in suite.Steps do
223+
match testCase with
224+
| It itCase ->
225+
runTestCase context.Path itCase beforeHooks afterHooks
226+
| LogStatement logStatement ->
227+
match logStatement with
228+
| Info message -> context.Reporter.Info(message, context.Path)
229+
| Debug message -> context.Reporter.Debug(message, context.Path)
212230
]
213231

214232
for result, logs in testResults do
@@ -248,3 +266,11 @@ module Constraints =
248266
let shouldNotEqual unexpected actual =
249267
if unexpected = actual then
250268
failwithf "Expected not to be %A but got %A" unexpected actual
269+
270+
let shouldBeTrue condition =
271+
if not condition then
272+
failwith "Expected condition to be true"
273+
274+
let shouldBeFalse condition =
275+
if condition then
276+
failwith "Expected condition to be false"

Tests.fsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ let s2 = describe "Suite 2" {
1515
runTestSuite (describe "Main Suite" { s1; s2 })
1616

1717
let suite = describe "A larger test suite" {
18+
Info "Top level info message"
1819
beforeEach {
1920
debug "Before each test"
2021
}
@@ -35,6 +36,7 @@ let suite = describe "A larger test suite" {
3536
pending "This is a pending test"
3637

3738
describe "Nested suite" {
39+
Debug "Use beforeEach and afterEach for setup and teardown"
3840
it "should also pass" {
3941
info "Nested test passes"
4042
}

out.png

-54.5 KB
Loading

sample.fsx

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#load "Sprout.fs"
2+
3+
open Sprout
4+
5+
let suite = describe "A test suite" {
6+
it "should pass" {
7+
info "This test passes"
8+
}
9+
10+
it "should fail" {
11+
info "This test fails"
12+
failwith "Intentional failure"
13+
}
14+
15+
pending "This is a pending test"
16+
17+
describe "Nested suite" {
18+
info "Use beforeEach and afterEach for setup and teardown"
19+
beforeEach {
20+
debug "Before each test"
21+
}
22+
23+
afterEach {
24+
debug "After each test"
25+
}
26+
it "should also pass" {
27+
info "Nested test passes"
28+
}
29+
}
30+
31+
describe "Arithmetic" {
32+
describe "Addition" {
33+
it "should add two numbers correctly" {
34+
let result = 2 + 2
35+
result |> shouldEqual 4
36+
}
37+
}
38+
39+
describe "Multiplication" {
40+
it "should multiply two numbers correctly" {
41+
let result = 3 * 3
42+
result |> shouldEqual 9
43+
}
44+
}
45+
}
46+
47+
describe "Comparisons" {
48+
debug "Testing comparisons"
49+
it "should compare numbers correctly" {
50+
5 > 3 |> shouldBeTrue
51+
}
52+
}
53+
54+
describe "Parameterized Tests" {
55+
info "Simply embed test cases and loop over them"
56+
let numbers = [1; 2; 3; 4; 5]
57+
for n in numbers do
58+
it $"should handle number {n}" {
59+
n > 0 |> shouldBeTrue
60+
}
61+
}
62+
}
63+
64+
runTestSuiteWithContext suite { TestContext.Empty with Reporter = Reporters.ConsoleReporter("v", "x", "?") :> ITestReporter }

0 commit comments

Comments
 (0)