From bc961f6ba3a25ee9c6da88eb0bdabdf56be93e7f Mon Sep 17 00:00:00 2001 From: Tom Hicks Date: Tue, 28 Mar 2023 01:45:05 -0700 Subject: [PATCH] Cleans up the way tests work in test.cpp. --- sbf-cpp/test.cpp | 349 +++++++++++++++++++++++++++-------------------- 1 file changed, 198 insertions(+), 151 deletions(-) diff --git a/sbf-cpp/test.cpp b/sbf-cpp/test.cpp index bfa48c8..ac3cd49 100644 --- a/sbf-cpp/test.cpp +++ b/sbf-cpp/test.cpp @@ -3,116 +3,210 @@ #include #include #include +#include using namespace std; +using std::wcout; -int32_t get_index_of(wstring text, wstring search, uint32_t start); -int32_t get_index_of(const wchar_t* text, size_t size, const wchar_t* search, uint32_t start); -wstring make_wrap_lines(wstring text, int maxWidth, int maxLines); +typedef tuple test_method_result; + +size_t get_index_of(const wstring& text, const wstring& search, size_t start); wstring word_wrap(const wstring& text, int maxWidth); -wstring get_substring(wstring text, int32_t var1, int32_t var2); -wstring make_fit_l(wstring text, size_t length, wchar_t paddCh); -wstring left(wstring text, size_t length); -wstring stringDollar(size_t length, wchar_t ch); +wstring get_substring(const wstring& text, int32_t var1, int32_t var2); +wstring make_fit_l(const wstring& text, size_t length, wchar_t paddCh); +wstring left(const wstring& text, size_t length); +wstring string_dollar(size_t length, wchar_t ch); +void do_pass_fail(bool passed, uint32_t& failureCount); + +uint32_t do_pass_fail(bool passed) { + if (passed) { + wcout << "Result: PASS" << endl; + return 0; + } else { + wcout << "Result: FAILURE" << endl; + return 1; + } +} + +// Want to call with something like r = test_fn(L"AAAAA", 5, L'A'); +// template +// test_method_result test_fn(vector>> tests) { +// size_t testsRun = 0; +// uint32_t failures = 0; +// wcout << "Testing function " << "..." << endl; +// for_each(tests.begin(), tests.end(), [testsRun, failures](pair<_T1, tuple<_T2...>> data) { +// const auto& expected = pair.first; +// // TODO: expand _T2/data.second into a series of parameters to use when calling _F1. +// const auto& actual = _F1(get<0>(data)...);//get_index_of(get<0>(pair.second), get<1>(pair.second), get<2>(pair.second)); +// wcout << "Expected: " << expected << endl; +// wcout << "Actual: " << actual << endl; +// failureCount += do_pass_fail(expected == actual); +// }); +// wcout << failures << " failures" << endl; +// return make_tuple(testsRun, failures); +// } + +test_method_result test_get_index_of() { + wstring longText = L"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."; + uint32_t failureCount = 0; + vector>> tests = { + pair(22, make_tuple(longText, L"dummy", 0)), + pair(-1, make_tuple(longText, L"acid", 0)), + pair(120, make_tuple(longText, L"dummy", 100)), + pair(-1, make_tuple(longText, L"dummy", longText.size())), + pair(6, make_tuple(L"these are words", L"are", 0)), + pair(4, make_tuple(L"one two one two", L"two", 0)), + pair(12, make_tuple(L"one two one two", L"two", 5)), + }; + + wcout << "Testing function get_index_of(const wstring&, const wstring&, size_t)" << endl; + for_each(tests.begin(), tests.end(), [&failureCount](const pair>& pair) { + const auto& expected = pair.first; + const auto& actual = get_index_of(get<0>(pair.second), get<1>(pair.second), get<2>(pair.second)); + wcout << "Expected: " << expected << endl; + wcout << "Actual: " << actual << endl; + failureCount += do_pass_fail(expected == actual); + }); + wcout << failureCount << " failures" << endl; + + return make_tuple(tests.size(), failureCount); +} + +test_method_result test_string_dollar() { + uint32_t failureCount = 0; + vector>> tests = { + pair(L"AAAAA", make_tuple(5, L'A')), + }; + + wcout << "Testing function string_dollar(size_t, wchar_t)" << endl; + for_each(tests.begin(), tests.end(), [&failureCount](const pair>& pair) { + const auto& expected = pair.first; + const auto& actual = string_dollar(get<0>(pair.second), get<1>(pair.second)); + wcout << "Expected " << expected << endl; + wcout << "Actual: " << actual << endl; + failureCount += do_pass_fail(expected == actual); + }); + wcout << failureCount << " failures" << endl; + + return make_tuple(tests.size(), failureCount); +} + +test_method_result test_left() { + uint32_t failureCount = 0; + vector>> tests = { + pair(L"Micro", make_tuple(L"Microsoft QBasic", 5)), + }; + + wcout << "Testing function left(wstring, size_t)" << endl; + for_each(tests.begin(), tests.end(), [&failureCount](const pair>& pair) { + const auto& expected = pair.first; + const auto& actual = left(get<0>(pair.second), get<1>(pair.second)); + wcout << "Expected: " << expected << endl; + wcout << "Actual: " << actual << endl; + failureCount += do_pass_fail(expected == actual); + }); + wcout << failureCount << " failures" << endl; + + return make_tuple(tests.size(), failureCount); +} + +test_method_result test_make_fit_l() { + uint32_t failureCount = 0; + vector>> tests = { + pair(L"12___", make_tuple(L"12", 5, L'_')), + }; + + wcout << "Testing function make_fit_l(const wstring&, size_t, const wchar_t)" << endl; + for_each(tests.begin(), tests.end(), [&failureCount](const pair>& pair) { + const auto& expected = pair.first; + const auto& actual = make_fit_l(get<0>(pair.second), get<1>(pair.second), get<2>(pair.second)); + wcout << "Expected: " << expected << endl; + wcout << "Actual: " << actual << endl; + failureCount += do_pass_fail(expected == actual); + }); + wcout << failureCount << " failures" << endl; + + return make_tuple(tests.size(), failureCount); +} + +test_method_result test_get_substring() { + uint32_t failureCount = 0; + vector>> tests = { + pair(L"234", make_tuple(L"1234567890", 1, 3)), + pair(L"Paris", make_tuple(L"Where is Paris?", 10-1, 5)), + }; + + wcout << "Testing function get_substring(const wstring&, const size_t, const size_t)" << endl; + for_each(tests.begin(), tests.end(), [&failureCount](const pair>& pair) { + const auto& expected = pair.first; + const auto& actual = get_substring(get<0>(pair.second), get<1>(pair.second), get<2>(pair.second)); + wcout << "Expected: " << expected << endl; + wcout << "Actual: " << actual; + failureCount += do_pass_fail(expected == actual); + }); + wcout << failureCount << " failures" << endl; + + return make_tuple(tests.size(), failureCount); +} + +test_method_result test_word_wrap() { + uint32_t failureCount = 0; + wstring output = L""; + vector> tests = { + {L"0123_", L"0123"}, + {L"01234", L"01234"}, + {L"01234\n5____", L"012345"}, + {L"01234\n56789\n0____", L"01234567890"}, + {L"01 23\n45 67\n89 01", L"01 23 45 67 89 01"}, + {L"01 34\n67 90\n23 56\n89___", L"01 34 67 90 23 56 89 "}, + }; + + wcout << "Testing function word_wrap(const wstring&, const size_t)" << endl; + int maxWidth = 5; + for_each(tests.begin(), tests.end(), [&failureCount, maxWidth](const pair& pair ) { + const auto& expected = pair.first; + const auto& actual = word_wrap(pair.second, maxWidth); + wcout << "Expected:" << endl << expected << endl; + wcout << "Actual:" << endl << actual << endl; + failureCount += do_pass_fail(expected == actual); + }); + wcout << failureCount << " failures" << endl; + return make_tuple(tests.size(), failureCount); +} + +test_method_result operator+(const test_method_result& first, const test_method_result second) { + return make_tuple(get<0>(first) + get<0>(second), get<1>(first) + get<1>(second)); +} int main(int argc, char* argv[]) { + // TODO: Come up with a good way to enable/disable tests. + // Maybe replace the expected, params pairs with another tuple for enabled, expected, params. + // Maybe have the test functions take an enabled bool param. setlocale(LC_ALL, ""); - /* - auto longText = L"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."; - auto shortText = L"dummy"; - auto len = wcslen(longText); - auto firstIndex = get_index_of(longText, len, shortText, 0); - auto secondIndex = get_index_of(longText, len, L"acid", 0); - auto thirdIndex = get_index_of(longText, len, shortText, 100); - auto fourthIndex = get_index_of(longText, len, shortText, len); - auto pattern = L"test 1: %03i, test 2: %03i, test 3: %03i, test 4: %03i"; - wchar_t expectedOutput[2048] = {0}; - wchar_t actualOutput[2048] = {0}; - swprintf(expectedOutput, sizeof(expectedOutput), pattern, 22, -1, 120, -1); - swprintf(actualOutput, sizeof(actualOutput), pattern, firstIndex, secondIndex, thirdIndex, fourthIndex); + // TODO: Define operator+= for test_method_result + test_method_result results; + results = results + test_get_index_of(); + results = results + test_word_wrap(); + results = results + test_get_substring(); + results = results + test_make_fit_l(); + results = results + test_left(); + results = results + test_string_dollar(); - wcout << "Expected: " << expectedOutput << endl; - wcout << "Actual: " << actualOutput << endl; - */ - - // wcout << stringDollar(5, L'A') << endl; // Expected "AAAAA" - // wcout << left(L"Microsoft QBasic", 5) << endl; // Expected "Micro" - // wcout << make_fit_l(L"12", 5, L'_') << endl; // Expected "12___" - // wcout << get_substring(L"1234567890", 1, 3) << endl; // Expected "234" - // wcout << get_substring(L"Where is Paris?", 10-1, 5) << endl; // Expected "Paris" - // wstring s1 = L"these are words"; - // wstring t1 = L"are"; - // wstring s2 = L"one two one two"; - // wstring t2 = L"two"; - // wcout << get_index_of(s1, t1, 0) << endl; // Expected 6 - // wcout << get_index_of(s1.c_str(), s1.size(), t1.c_str(), 0) << endl; // Expected 6 - // wcout << get_index_of(s2, t2, 0) << endl; // Expected 4 - // wcout << get_index_of(s2, t2, 5) << endl; // Expected 12 - // wcout << get_index_of(s2.c_str(), s2.size(), t2.c_str(), 0) << endl; // Expected 4 - // wcout << get_index_of(s2.c_str(), s2.size(), t2.c_str(), 5) << endl; // Expected 12 - - wstring output = L""; - wstring testStrings[] = { - L"0123", - L"01234", - L"012345", - L"01234567890", - L"01 23 45 67 89 01", - L"01 34 67 90 23 56 89", - }; - int maxWidth = 5; - int maxLines = 3; - - size_t i = 0; - for (i=0; i<6; i++) { - output = make_wrap_lines(testStrings[i], maxWidth, maxLines); - wcout << output << endl; - } + // TODO Count the tests. Have the test_* functions return a pair or tuple of total, failures or total/pass/fail/error or exception. + // 18 tests + wcout << "Total tests ran: " << get<0>(results) << endl; + wcout << "Total failures: " << get<1>(results) << endl; return 0; } -int32_t get_index_of(const wchar_t* text, size_t size, const wchar_t* search, uint32_t start) { - if (start >= size) { return -1;} - const wchar_t* base = text + start; - auto substr = wcsstr(base, search); - if (substr == nullptr) { return -1; } - auto index = substr - text; - return index; -} - -int32_t get_index_of(wstring text, wstring search, uint32_t start) { +size_t get_index_of(const wstring& text, const wstring& search, size_t start) { return text.find(search, start); } wstring word_wrap(const wstring& text, int maxWidth) { - return L""; -} - -/* -uint32_t word_wrap(wchar_t* dest, size_t size, const wchar_t* text, uint32_t columns) { - uint32_t lineCount = 0; - uint32_t thisLineStartPosition = 0; - uint32_t thisLineCurrentPosition = 0; - int32_t nextSpace = -1; - size_t textLength = wcslen(text); - wchar_t thisLine[2048] = {0}; - wchar_t nextChunk[2048] = {0}; - - bool done = false; - while (!done) { - nextSpace = get_index_of(text, size, L" ", thisLineCurrentPosition); - done = true; - } - - return 0; -*/ - -wstring make_wrap_lines(wstring text, int maxWidth, int maxLines) { - // ReDim output(maxLines) As String wstring output = L""; - int32_t lineCount = 0; wstring thisLine = L""; wstring nextChunk = L""; int32_t thisLineStartPosition = 0; @@ -121,7 +215,9 @@ wstring make_wrap_lines(wstring text, int maxWidth, int maxLines) { int32_t textLength = text.size(); size_t thisLineLength = 0; - while (lineCount < maxLines) { + bool done = false; + + while (!done) { nextSpace = get_index_of(text, L" ", thisLineCurrentPosition); if (nextSpace < 0) { nextSpace = textLength; @@ -150,9 +246,11 @@ wstring make_wrap_lines(wstring text, int maxWidth, int maxLines) { thisLineCurrentPosition = nextSpace + 1; } if (thisLineLength >= maxWidth || thisLineCurrentPosition > textLength) { + if (thisLineCurrentPosition > textLength) { + done = true; + } thisLine = make_fit_l(thisLine, maxWidth, L'_'); - output += thisLine + L"\n"; - lineCount = lineCount + 1; + output += thisLine + (done ? L"" : L"\n"); thisLine = L""; thisLineLength = thisLine.size(); thisLineStartPosition = thisLineCurrentPosition; @@ -162,57 +260,7 @@ wstring make_wrap_lines(wstring text, int maxWidth, int maxLines) { return output; } -/* -// Sub MakeWrapLines (lines() As String, text As String, maxWidth As Integer, maxLines As Integer) -// ReDim lines(maxLines) As String -// lineCount = 0 -// thisLine$ = "" -// nextChunk$ = "" -// thisLineStartPosition = 0 -// thisLineCurrentPosition = 0 -// nextSpace = -1 -// textLength = Len(text) - -// While (lineCount < maxLines) -// nextSpace = GetIndexOf(text, " ", thisLineCurrentPosition) -// If nextSpace < 0 Then nextSpace = textLength -// nextChunk$ = GetSubstring(text, thisLineCurrentPosition, nextSpace - thisLineCurrentPosition) -// nextChunkLength = Len(nextChunk$) -// If nextChunkLength > 0 Then -// needsSpace = Len(thisLine$) > 0 -// If needsSpace Then -// thisLine$ = thisLine$ + " " -// End If -// thisLineLength = Len(thisLine$) -// If nextChunkLength > maxWidth Then -// nextChunk$ = GetSubstring(text, thisLineCurrentPosition, maxWidth - thisLineLength) -// nextSpace = thisLineStartPosition + maxWidth -// thisLine$ = thisLine$ + nextChunk$ -// thisLineCurrentPosition = nextSpace -// ElseIf thisLineLength + nextChunkLength > maxWidth Then -// thisLine$ = MakeFitL$(thisLine$, maxWidth, " ") -// Else -// thisLine$ = thisLine$ + nextChunk$ -// thisLineCurrentPosition = nextSpace + 1 -// End If -// thisLineLength = Len(thisLine$) -// Else -// thisLineCurrentPosition = nextSpace + 1 -// End If -// If thisLineLength >= maxWidth Or thisLineCurrentPosition > textLength Then -// thisLine$ = MakeFitL$(thisLine$, maxWidth, "_") -// lines(lineCount) = thisLine$ -// lineCount = lineCount + 1 -// thisLine$ = "" -// thisLineLength = Len(thisLine$) -// thisLineStartPosition = thisLineCurrentPosition -// End If -// Wend -// End Sub -} -*/ - -wstring stringDollar(size_t length, wchar_t ch) { +wstring string_dollar(size_t length, wchar_t ch) { wstring str = L""; for (size_t i = 0; i(var1, text.length()-1), std::max(var2, 0)); }