#[allow(unused_macros)]
macro_rules! expect {
    ($e:expr, status => $s:expr) => {{
	let res = $e;

	assert_eq!(res.as_status(), $s);
    }};

    ($e:expr) => {
	expect!($e, status => crate::TestStatus::Pass);
    };
}

#[test]
fn test_00() {
    use crate::*;

    let p = PlanRunner::new();

    p.run("top-00", |_| {});
    p.run("top-01", |_| {});

    assert_eq!(unsafe { p.override_status(TestStatus::Pass) },
	       TestStatus::Pass);
}

#[test]
fn test_01() {
    use crate::*;

    let p = PlanRunner::new();

    p.run("test-01", |p| {
	assert_eq!(TestStatus::Fail, p.run("subinit", |p| {
	    expect!(p.ok("ok-0", || { true }));
	    p.comment("this consumes a lot of memory...");
	    expect!(p.fail("fail-0", || false));
	    expect!(p.panic("panic-0", || assert!(false)));
	    p.skip("skip-0");

	    expect!(p.ok("ok-1/fail",       || false),  status => TestStatus::Fail);
	    expect!(p.fail("fail-1/fail",   || true),   status => TestStatus::Fail);
	    expect!(p.panic("panic-1/fail", || true),   status => TestStatus::Fail);
	    expect!(p.panic("panic-2/fail", || false),  status => TestStatus::Fail);

	    expect!(p.eq("eq-0",      1, || 1));
	    expect!(p.eq("eq-0/fail", 1, || 2), status => TestStatus::Fail);

	    expect!(p.ne("ne-0",      1, || 2));
	    expect!(p.ne("ne-0/fail", 1, || 1), status => TestStatus::Fail);

	    expect!(p.new_case("custom-0").run(|| true));
	    expect!(p.new_case("custom-1")
		    .set_description("custom-1 testcase")
		    .set_comment("should succeed")
		    .set_expect(Expect::Pass, false)
		    .run(|| true));
	    expect!(p.new_case("custom-2")
		    .set_expect(Expect::Fail, false)
		    .run(|| false), status => TestStatus::Pass);
	    expect!(p.new_case("custom-3/degraded")
		    .set_expect(Expect::Fail, true)
		    .run(|| true), status => TestStatus::Degraded);
	    expect!(p.new_case("custom-4/degraded")
		    .set_expect(Expect::Pass, true)
		    .run(|| false), status => TestStatus::Degraded);
	    expect!(p.new_case("custom-5/skip")
		    .set_skip(true)
		    .run(|| panic!("should never be executed")), status => TestStatus::Skip);
	}));

	assert_eq!(TestStatus::Panic, p.run("abort", |p| {
	    expect!(p.ok("ok-0/abort", || assert!(false)), status => TestStatus::Panic);
	}));

	assert_eq!(TestStatus::Fail, p.run("fail", |p| {
	    expect!(p.ok("ok-0/fail", || false), status => TestStatus::Fail);
	}));

	assert_eq!(TestStatus::Pass, p.run("skip", |p| {
	    p.skip("skip-0")
	}));

	assert_eq!(TestStatus::Pass, p.run("empty", |_| {
	}));

	assert_eq!(TestStatus::Degraded, p.run("degraded", |p| {
	    p.new_case("degraded")
		.set_expect(Expect::Pass, true)
		.run(|| false);
	}));
    });

    assert_eq!(unsafe { p.override_status(TestStatus::Pass) },
	       TestStatus::Panic);
}

#[test]
fn test_02() {
    use crate::*;

    let p = PlanRunner::new();

    p.run("test-02", |p| {
	p.run("subinit", |p| {
	    p.ok("ok-0", || { true });
	    p.comment("this consumes a lot of memory...");
	    p.fail("fail-0", || false);
	    p.panic("panic-0", || assert!(false));
	    p.skip("skip-0");

	    p.ok("ok-1/fail",       || false);
	    p.fail("fail-1/fail",   || true);
	    p.panic("panic-1/fail", || true);
	    p.panic("panic-2/fail", || false);

	    p.eq("eq-0",      1, || 1);
	    p.eq("eq-0/fail", 1, || 2);

	    p.ne("ne-0",      1, || 2);
	    p.ne("ne-0/fail", 1, || 1);
	});
    });

    assert_eq!(unsafe { p.override_status(TestStatus::Pass) },
	       TestStatus::Fail);
}

#[test]
fn test_03() {
    use crate::*;

    let p = PlanRunner::new();

    p.run("test-03", |p| {
	assert_eq!(TestStatus::Pass, p.new_plan("subtest")
		   .set_comment("total count matches")
		   .set_total_count(2)
		   .run(|p| {
		       p.ok("ok-0", || true);
		       p.ok("ok-1", || true);
		   }));

	assert_eq!(TestStatus::Fail, p.new_plan("subtest")
		   .set_comment("total count mismatch")
		   .set_total_count(20)
		   .run(|p| {
		       p.ok("ok-0", || true);
		   }));
    });

    assert_eq!(unsafe { p.override_status(TestStatus::Pass) },
	       TestStatus::Fail);
}

#[test]
fn test_04_00() {
    use crate::*;

    let p = PlanRunner::new();

    p.run("test-04_00", |p| {
	p.run("ok", |p| {
	    p.ok("ok-0", || TestStatus::Pass);
	});
    });

    assert_eq!(unsafe { p.override_status(TestStatus::Pass) },
	       TestStatus::Pass);
}

#[test]
fn test_04_01() {
    use crate::*;

    let p = PlanRunner::new();

    p.run("test-04_00", |p| {
	p.run("ok", |p| {
	    p.ok("ok-0/fail", || TestStatus::Fail);
	    p.ok("ok-1",      || TestStatus::Pass);
	});
    });

    assert_eq!(unsafe { p.override_status(TestStatus::Pass) },
	       TestStatus::Fail);
}

#[test]
fn test_04_02() {
    use crate::*;

    let p = PlanRunner::new();

    p.run("test-04_02", |p| {
	p.run("ok", |p| {
	    p.ok("ok-0/fail",  || TestStatus::Fail);
	    p.ok("ok-0/panic", || assert!(false));
	    p.ok("ok-1",       || TestStatus::Pass);
	});
    });

    assert_eq!(unsafe { p.override_status(TestStatus::Pass) },
	       TestStatus::Panic);
}

#[test]
fn test_04_03() {
    use crate::*;

    let p = PlanRunner::new();

    p.run("test-04_03", |p| {
	p.run("ok", |p| {
	    p.ok("ok-0/fail",  || TestStatus::Fail);
	    p.abort("irrecoverable situation");
	    p.ok("ok-0/panic", || assert!(false));
	    p.ok("ok-1",       || TestStatus::Pass);
	});
    });

    assert_eq!(unsafe { p.override_status(TestStatus::Pass) },
	       TestStatus::Abort);
}
