let mutable section = ""
let mutable status  = 0
let mutable count   = 0

exception Fail of string

let run (name: string) test =
    try
        test ()
        count <- count + 1
    with
    | Fail reason ->
        status <- 1
        stderr.WriteLine("FAIL: {0}.{1} -- {2}", section, name, reason)
    | e ->
        status <- 1
        stderr.WriteLine("FAIL: {0}.{1}", section, name)
        stderr.WriteLine(e)

type Test(name: string) =
    member this.Delay(f : unit -> unit) = run name f
    member this.Zero() = ()

let Section name =
    section <- name

let Throws<'T when 'T :> exn> f =
    try
        f ()
        raise (Fail (sprintf "Does not throw: %O" typeof<'T>))
    with
    | :? 'T ->
        ()

let ( =? ) a b =
    if a <> b then
        raise (Fail (sprintf "Expected %A and got %A." a b))

let ( <>? ) a b =
    if a = b then
        raise (Fail (sprintf "Unexpected %A." a))

let runTests () =
    Section "Arithmetic"

    Test "addition" {
        1 + 1 =? 2
        1 + 0 =? 0
    }

[<EntryPoint>]
let main args =
    runTests ()
    if status = 0 then
        stdout.WriteLine("OK, {0} tests passed.", count)
    status