From 5a9eea1ccb7f6f6ae44243a001ac3c7266614b5c Mon Sep 17 00:00:00 2001 From: Tom Hicks Date: Sun, 2 Apr 2023 23:31:16 -0700 Subject: [PATCH] Makes the example more Jasmine-like. --- JTest.cpp | 0 examples/JTest.cpp | 83 +++++++++++++++++++++++++++++++++---- examples/JTest.h | 58 ++++++++++++++++++++++---- examples/example.cpp | 99 ++++++++++++++++++++++++++++++++++++-------- 4 files changed, 206 insertions(+), 34 deletions(-) create mode 100644 JTest.cpp diff --git a/JTest.cpp b/JTest.cpp new file mode 100644 index 0000000..e69de29 diff --git a/examples/JTest.cpp b/examples/JTest.cpp index 84a255c..4b78bf8 100644 --- a/examples/JTest.cpp +++ b/examples/JTest.cpp @@ -1,18 +1,26 @@ #include "JTest.h" +#include namespace JTest { using std::wostream; using std::endl; + using std::vector; + using std::wstring; + using std::runtime_error; + using std::string; + using std::optional; - // typedef struct { - // uint32_t total; - // uint32_t skipped; - // uint32_t passed; - // uint32_t failed; - // // vector errors; - // // vector failures; - // // vector skipped; - // } testresults_t; + runtime_error unimplemented_function_error(string method_name) { + return runtime_error("Unimplemented function: " + method_name); + } + + runtime_error unimplemented_method_error(string class_name, string method_name) { + return runtime_error("Unimplemented method in class " + class_name + ": " + method_name); + } + + runtime_error unimplemented_feature_error(string feature_name) { + return runtime_error("Unimplemented feature: " + feature_name); + } testresults_t make_testresults() { return {0, 0, 0, 0}; @@ -30,4 +38,61 @@ namespace JTest { out << L"Tests: " << results.total << endl; out << L"Failed: " << results.failed << ", Passed: " << results.passed << ", Skipped: " << results.skipped << endl; } + + testresults_t operator+(const testresults_t& left, const testresults_t& right) { + return add(left, right); + } + + testresults_t& operator+=(testresults_t& left, const testresults_t& right) { + left = left + right; + return left; + } + + testbundle_t make_testbundle(const vector&, const describeoptions_t& options) { + throw unimplemented_function_error("make_testbundle(const vector&, const describeoptions_t&)"); + } + + describeoptions_t& describeoptions_t::beforeEach(configure_fn) { + throw unimplemented_method_error("describeoptions_t", "beforeEach(configure_fn)"); + } + + describeoptions_t& describeoptions_t::afterEach(configure_fn) { + throw unimplemented_method_error("describeoptions_t", "afterEach(configure_fn)"); + } + describeoptions_t& describeoptions_t::beforeAll(configure_fn) { + throw unimplemented_method_error("describeoptions_t", "beforeAll(configure_fn)"); + } + describeoptions_t& describeoptions_t::afterAll(configure_fn) { + throw unimplemented_method_error("describeoptions_t", "afterAll(configure_fn)"); + } + describeoptions_t make_describeoptions() { + return {}; + } + + testbundle_t it(const wstring& label, const make_test_fn& test_method, optional options) { + throw unimplemented_function_error("it(const wstring&, const make_test_fn&, optional)"); + } + + testresults_t execute(testbundle_t tests) { + throw unimplemented_function_error("execute(testbundle_t)"); + } + + testbundle_t describe(const wstring& label, const make_testbundle_fn& make_tests, optional options) { + throw unimplemented_function_error("describe(const wstring&, const make_testbundle_fn&, optional)"); + } + + // TODO: Use these to make the unimplemented_* errors simpler to call. + // For this function + // testbundle_t describe(const std::wstring& label, const make_testbundle_fn& make_tests, std::optional options) + // __PRETTY_FUNCTION__ + // Unimplemented function: JTest::testbundle_t JTest::describe(const std::wstring &, const JTest::make_testbundle_fn &, std::optional) + // __FUNCSIG__ is not defined on clang++ + // __func__ + // describe + // __LINE__ is an integer + // + // __FILE__ + // examples/JSTest.cpp + // __FUNCTION__ + // describe } diff --git a/examples/JTest.h b/examples/JTest.h index 339e880..0c83c37 100644 --- a/examples/JTest.h +++ b/examples/JTest.h @@ -15,18 +15,60 @@ namespace JTest { }; testresults_t operator+(const testresults_t& left, const testresults_t& right); - testresults_t operator+(const testresults_t& left, const testresults_t& right) { - return add(left, right); - } testresults_t& operator+=(testresults_t& left, const testresults_t& right); - testresults_t& operator+=(testresults_t& left, const testresults_t& right) { - left = left + right; - return left; - } - + testresults_t make_testresults(); testresults_t make_testresults(uint32_t total, uint32_t skipped, uint32_t passed, uint32_t failed); testresults_t add(const testresults_t&, const testresults_t&); void print_test_results(const testresults_t&, wostream&); + + struct testbundle_t {}; + + // Executes the tests in tests. Possibly in parallel. Will block until all async tests have completed. + testresults_t execute(testbundle_t tests); + + + typedef std::function make_testbundle_fn; + + typedef std::function configure_fn; + struct describeoptions_t { + // TODO: Should these configure_fn params be const and/or &? + describeoptions_t& beforeEach(configure_fn); + describeoptions_t& afterEach(configure_fn); + describeoptions_t& beforeAll(configure_fn); + describeoptions_t& afterAll(configure_fn); + private: + configure_fn _beforeEach; + configure_fn _afterEach; + configure_fn _beforeAll; + configure_fn _afterAll; + }; + + // + testbundle_t describe(const std::wstring& label, const make_testbundle_fn& make_tests, std::optional options = std::nullopt); + + struct testoptions_t {}; + + + struct test_t {}; + + testbundle_t make_testbundle(const std::vector& tests, const describeoptions_t& options); + // testbundle_t make_testbundle( initializer_list tests, const testoptions_t& options); + + typedef std::function make_test_fn; + + // TODO: Make this return a test_t instead. + // TOOD: Bake make_test_fn not need to return testresults_t. Method calls should be surrounded with try/catch. + // The label should be extracted from the test_t it returns. + // The testresults_t should be constructed based on the try/catch block and whether this was called as it/xit. + testbundle_t it(const std::wstring& label, const make_test_fn& test_method, std::optional options = std::nullopt); + + describeoptions_t make_describeoptions(); + + + + + + } diff --git a/examples/example.cpp b/examples/example.cpp index 946dd3a..848853c 100644 --- a/examples/example.cpp +++ b/examples/example.cpp @@ -4,7 +4,7 @@ #include #include #include - +#include using namespace JTest; using namespace MyNS; @@ -12,40 +12,105 @@ using namespace MyNS; using std::wstring; using std::vector; using std::wcout; +using std::exception; +using std::endl; // const vector& might stop being a reference testresults_t test_ClassToTest_main(int argc, const vector& argv) { - auto results = describe(L"ClassToTest", [](){ - auto results = make_testresults(); + return execute( + describe(L"ClassToTest", [](){ + return make_testbundle( + { + it(L"should do the thing", [](){ + // Throw exception if somethings goes wrong - results += it(L"should do the thing", [](){ - }); + // TODO: This unnecessary, by throwing exceptions. + return (test_t){}; + }), - results += it(L"should do the other thing", [](){ + it(L"should do the other thing", [](){ + return (test_t){}; + }), - }); + it(L"should not do the bad thing", [](){ + return (test_t){}; + }), - results += it(L"should not do the bad thing", [](){ + it(L"should throw an exception if we do the other bad thing", [](){ + return (test_t){}; + }), + }, + make_describeoptions() + .beforeEach([](){}) + .afterEach([](){}) + .beforeAll([](){}) + .afterAll([](){})); + }) + ); +} - }); +testresults_t test_temp(int argc, const vector& argv) { + return execute( + describe(L"ClassToTest", [](){ + return make_testbundle({ + describe(L"FeatureToTest", [](){ + return make_testbundle({ + // it(L"should do the thing", [](){ - results += it(L"should throw an exception if we do the other bad thing", [](){ + // }), + // it(L"should not do the other thing", [](){ - }); + // }), + }, make_describeoptions()); + }), + }, make_describeoptions()); + }) + ); +} - return results; - }, make_describe_options().beforeEach([](){}).afterEach([](){}).beforeAll([](){}).afterAll([](){})); - return results; +// Exmple of nested describes. +testresults_t test_something(int argc, const vector& argv) { + return execute( + describe(L"", [](){ + return make_testbundle({ + describe(L"", [](){ + return make_testbundle({ + + }, make_describeoptions()); + }, make_describeoptions()), + }, make_describeoptions()); + }) + ); +} + +testresults_t test_ClassToTest_2(int argc, const vector& argv) { + return execute( + describe(L"ClassToTest", [](){ + return make_testbundle({ + }, + make_describeoptions() + .beforeEach([](){}) + .afterEach([](){}) + .beforeAll([](){}) + .afterAll([](){})); + }) + ); } // Dummy test harness int main(int argc, char* argv[]) { - testresults_t results = make_testresults(); + try { + testresults_t results = make_testresults(); - results = add(results, test_ClassToTest_main(0, vector())); + results = add(results, test_ClassToTest_main(0, vector())); - print_test_results(results, wcout); + print_test_results(results, wcout); + } + catch (std::runtime_error ex) { + std::cout << ex.what() << endl; + // wcout << L"Unhandled exception: " << ex.what() << endl; + } return 0; }