From 29cfd546899ac41babe8cce69bf090bf47c752e8 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 14 Nov 2025 06:04:52 +0000 Subject: [PATCH] Add unit tests and refactor JSON output directory Co-authored-by: jacegenereux --- CMakeLists.txt | 6 +++- main.cpp | 28 +++++++++++++--- tests/test_main.cpp | 82 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 6 deletions(-) create mode 100644 tests/test_main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b46bdaa..b764684 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,10 @@ set(CURL_LIBRARY "C:/vcpkg/installed/x64-windows/lib/libcurl.a") set(CMAKE_BUILD_TYPE Debug) add_executable(main main.cpp) +add_executable(unit_tests tests/test_main.cpp) + target_link_libraries(main PRIVATE nlohmann_json::nlohmann_json) -target_link_libraries(main PRIVATE CURL::libcurl) \ No newline at end of file +target_link_libraries(main PRIVATE CURL::libcurl) + +target_link_libraries(unit_tests PRIVATE nlohmann_json::nlohmann_json) \ No newline at end of file diff --git a/main.cpp b/main.cpp index c3fbad7..6b0f72e 100644 --- a/main.cpp +++ b/main.cpp @@ -1,10 +1,14 @@ +#ifndef UNIT_TESTING #include +#endif #include #include #include #include #include +#include +#include #include using json = nlohmann::json; @@ -29,8 +33,9 @@ std::string FormatHTMLToString(const std::string &response); TestCaseResponse GetTestCases(const std::string &content); std::pair GetParamName(const std::string ¶m); -void CreateJSON(json *response, const TestCaseResponse &testCases); +void CreateJSON(json *response, const TestCaseResponse &testCases, const std::string &outputDir = "../../../Questions"); +#ifndef UNIT_TESTING int main() { std::string questionName = ""; @@ -104,6 +109,7 @@ int main() curl_easy_cleanup(curl); return 0; } +#endif // returns number of bytes in the chunk // data is set to a ptr that points to block of data recieved in this chunk @@ -369,8 +375,9 @@ TestCaseResponse GetTestCases(const std::string &content) return tests; } -void CreateJSON(json *response, const TestCaseResponse &tests) +void CreateJSON(json *response, const TestCaseResponse &tests, const std::string &outputDir) { + namespace fs = std::filesystem; // filter out invalid characters from title std::string title = (*response)["title"]; const std::string invalid_chars = "\\/:*?\"<>|"; @@ -378,14 +385,25 @@ void CreateJSON(json *response, const TestCaseResponse &tests) { std::replace(title.begin(), title.end(), c, '_'); } - std::string jsonName = "../../../Questions/" + title + ".txt"; + fs::path basePath(outputDir); + std::error_code ec; + if (!fs::exists(basePath)) + { + fs::create_directories(basePath, ec); + if (ec) + { + std::cerr << "Error creating output directory: " << ec.message() << std::endl; + return; + } + } + fs::path outputPath = basePath / (title + ".txt"); std::ofstream outputJSON; - outputJSON.open(jsonName); + outputJSON.open(outputPath); // should have to create the file so always should open if (!outputJSON.is_open()) { - std::cerr << "Error creating output file for JSON response" << std::endl; + std::cerr << "Error creating output file for JSON response: " << outputPath << std::endl; return; } diff --git a/tests/test_main.cpp b/tests/test_main.cpp new file mode 100644 index 0000000..0e616c9 --- /dev/null +++ b/tests/test_main.cpp @@ -0,0 +1,82 @@ +#define UNIT_TESTING + +#include +#include +#include +#include +#include +#include + +#include "../main.cpp" + +void TestFormatHTMLToString() +{ + std::string html = "
Value: <tag>'s
\n\nNext\t\tLine"; + std::string expected = "Value:\nNextLine"; + auto formatted = FormatHTMLToString(html); + assert(formatted == expected); +} + +void TestGetParamName() +{ + auto param = GetParamName("nums = [1, 2, 3]"); + assert(param.first == "nums"); + assert(param.second == "[1,2,3]"); +} + +void TestGetTestCases() +{ + std::string content = + "Example 1:\n" + "Input: nums = [1, 2, 3], k = 3\n" + "Output: 2\n" + "Example 2:\n" + "Input: nums = [1, 2], k = 1\n" + "Output: 1\n"; + + TestCaseResponse tests = GetTestCases(content); + assert(tests.testCases.size() == 2); + assert(tests.testCases[0] == "2"); + assert(tests.testCases[1] == "1"); + assert(tests.testCaseParams.size() == 4); + assert(tests.testCaseParams[0] == std::make_pair(std::string("nums"), std::string("[1,2,3]"))); + assert(tests.testCaseParams[1] == std::make_pair(std::string("k"), std::string("3"))); +} + +void TestCreateJSON() +{ + json response = {{"title", "Sample/Title"}, {"content", "desc"}, {"difficulty", "Easy"}}; + TestCaseResponse tests; + tests.testCases = {"42"}; + tests.testCaseParams = {{"nums", "[1,2,3]"}, {"k", "3"}}; + + std::filesystem::path tempRoot = std::filesystem::temp_directory_path() / "leetcode_tests"; + std::filesystem::remove_all(tempRoot); + + std::filesystem::path outputDir = tempRoot / "Questions"; + CreateJSON(&response, tests, outputDir.string()); + + std::filesystem::path outputFile = outputDir / "Sample_Title.txt"; + assert(std::filesystem::exists(outputFile)); + + std::ifstream input(outputFile); + std::stringstream buffer; + buffer << input.rdbuf(); + std::string content = buffer.str(); + assert(content.find("\"expectedResult\": \"42\"") != std::string::npos); + assert(content.find("\"nums\": \"[1,2,3]\"") != std::string::npos); + assert(content.find("\"k\": \"3\"") != std::string::npos); + + std::filesystem::remove_all(tempRoot); +} + +int main() +{ + TestFormatHTMLToString(); + TestGetParamName(); + TestGetTestCases(); + TestCreateJSON(); + + std::cout << "All tests passed!" << std::endl; + return 0; +}