From 9d4aa77181a17fdeeff5c50c59047a803ea7837e Mon Sep 17 00:00:00 2001 From: Yury Bayda Date: Thu, 29 May 2025 23:05:13 -0700 Subject: [PATCH] Update to latest changes from bootstrap --- .clang-format | 25 ++++--- .cmake-format.yaml | 7 ++ .cmakelintrc | 1 + .github/workflows/main.yml | 24 ++----- .gitignore | 1 + .idea/.gitignore | 5 ++ .idea/bootstrap-cpp-kata.iml | 2 + .idea/codeStyles/Project.xml | 103 +++++++++++++++++++++++++++ .idea/codeStyles/codeStyleConfig.xml | 5 ++ .idea/editor.xml | 102 ++++++++++++++++++++++++++ .idea/misc.xml | 7 ++ .idea/modules.xml | 8 +++ .idea/vcs.xml | 6 ++ .replit | 19 ----- .vscode/c_cpp_properties.json | 27 +++++++ .vscode/extensions.json | 6 ++ .vscode/launch.json | 28 ++++++++ .vscode/settings.json | 7 ++ .vscode/tasks.json | 33 +++++++++ CMakeLists.txt | 34 +++++---- Makefile | 9 +-- README.md | 102 ++++++++++++-------------- cmake/FetchGTest.cmake | 18 +++++ expense_report.h | 4 +- main.cpp | 8 --- replit.nix | 8 --- test_expense_report.cpp | 8 +-- 27 files changed, 462 insertions(+), 145 deletions(-) create mode 100644 .cmake-format.yaml create mode 100644 .cmakelintrc create mode 100644 .idea/.gitignore create mode 100644 .idea/bootstrap-cpp-kata.iml create mode 100644 .idea/codeStyles/Project.xml create mode 100644 .idea/codeStyles/codeStyleConfig.xml create mode 100644 .idea/editor.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml delete mode 100644 .replit create mode 100644 .vscode/c_cpp_properties.json create mode 100644 .vscode/extensions.json create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json create mode 100644 cmake/FetchGTest.cmake delete mode 100644 main.cpp delete mode 100644 replit.nix diff --git a/.clang-format b/.clang-format index 3db5891..b47e6dc 100644 --- a/.clang-format +++ b/.clang-format @@ -1,25 +1,28 @@ -# Requires clang version >= 3.8 +# Requires clang-format 14 or newer BasedOnStyle: LLVM -Standard: Cpp11 -# +Standard: c++17 + AccessModifierOffset: -4 -AlignConsecutiveAssignments: true -AlignEscapedNewlinesLeft: true -AlignOperands: true +AlignConsecutiveAssignments: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false +AlignConsecutiveDeclarations: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false +AlignOperands: Align AlignTrailingComments: true -AlignConsecutiveDeclarations: true AllowShortFunctionsOnASingleLine: Inline -AlwaysBreakAfterDefinitionReturnType: TopLevel -AlwaysBreakTemplateDeclarations: false BinPackArguments: false BreakBeforeBraces: Stroustrup ColumnLimit: 100 -ConstructorInitializerAllOnOneLineOrOnePerLine: true Cpp11BracedListStyle: true IndentCaseLabels: false IndentWidth: 4 KeepEmptyLinesAtTheStartOfBlocks: false +PackConstructorInitializers: NextLine PointerAlignment: Left -SortIncludes: false +SortIncludes: Never SpaceAfterCStyleCast: true # vim: ft=yaml diff --git a/.cmake-format.yaml b/.cmake-format.yaml new file mode 100644 index 0000000..8606e38 --- /dev/null +++ b/.cmake-format.yaml @@ -0,0 +1,7 @@ +format: + line_width: 100 + tab_size: 4 + use_tabchars: false + max_subgroups_hwrap: 3 + max_pargs_hwrap: 3 + dangle_parens: true diff --git a/.cmakelintrc b/.cmakelintrc new file mode 100644 index 0000000..187d482 --- /dev/null +++ b/.cmakelintrc @@ -0,0 +1 @@ +filter=-linelength,-readability/wonkeycase,-syntax diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d11a83c..255c5f4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -11,34 +11,22 @@ jobs: runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Check formatting run: make format-check test: - runs-on: ubuntu-latest + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + runs-on: ${{ matrix.os }} steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Install Ninja, GTest, and GMock - run: | - sudo apt-get update - sudo apt-get install \ - google-mock \ - googletest \ - libgmock-dev \ - libgtest-dev \ - ninja-build + - uses: actions/checkout@v4 - name: Build run: make build - - name: Run main - run: make run - - name: Test run: make test diff --git a/.gitignore b/.gitignore index 8de37ca..ae1801a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ build +cmake-build-* .cache .ccls-cache compile_commands.json diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..b58b603 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,5 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/bootstrap-cpp-kata.iml b/.idea/bootstrap-cpp-kata.iml new file mode 100644 index 0000000..f08604b --- /dev/null +++ b/.idea/bootstrap-cpp-kata.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..9db4553 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,103 @@ + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/editor.xml b/.idea/editor.xml new file mode 100644 index 0000000..e54e87a --- /dev/null +++ b/.idea/editor.xml @@ -0,0 +1,102 @@ + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..0b76fe5 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..cca38d5 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.replit b/.replit deleted file mode 100644 index 5dec4e6..0000000 --- a/.replit +++ /dev/null @@ -1,19 +0,0 @@ -compile = ["make", "build"] -run = ["make", "test"] -entrypoint = "main.cpp" -language = "c++" -hidden = ["LICENSE", "CMakeLists.txt", "Makefile", ".gitignore", ".clang-format", "compile_commands.json", ".ccls-cache", "build"] - -[nix] -channel = "stable-21_11" - -[languages] - -[languages.cpp] -pattern = "**/*.{cpp,h}" - -[languages.cpp.languageServer] -start = "clangd" - -[debugger] -support = false diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..9564b16 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,27 @@ +{ + "configurations": [ + { + "name": "Mac", + "includePath": [ + "${workspaceFolder}/**" + ], + "defines": [], + "cStandard": "c17", + "cppStandard": "c++17", + "intelliSenseMode": "macos-clang-arm64", + "configurationProvider": "ms-vscode.cmake-tools" + }, + { + "name": "Linux", + "includePath": [ + "${workspaceFolder}/**" + ], + "defines": [], + "cStandard": "c17", + "cppStandard": "c++17", + "intelliSenseMode": "linux-gcc-x64", + "configurationProvider": "ms-vscode.cmake-tools" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..91118cb --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,6 @@ +{ + "recommendations": [ + "ms-vscode.cpptools", + "ms-vscode.cmake-tools", + ] +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..c1421ff --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,28 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug Tests", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/test_something", + "args": [], + "cwd": "${workspaceFolder}", + "preLaunchTask": "Build", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + "osx": { + "MIMode": "lldb", + }, + "linux": { + "MIMode": "gdb", + "miDebuggerPath": "/usr/bin/gdb", + } + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..01f1256 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools", + "cmake.buildDirectory": "${workspaceFolder}/build", + "cmake.configureOnOpen": true, + "editor.formatOnSave": true, + "C_Cpp.formatting": "clangFormat" +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..9ed5ca3 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,33 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Build", + "type": "shell", + "command": "make build", + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "Run Tests", + "type": "shell", + "command": "make test", + "group": { + "kind": "test", + "isDefault": true + }, + "dependsOn": "Build" + }, + { + "label": "Format", + "type": "shell", + "command": "make format", + "presentation": { + "reveal": "silent" + }, + "problemMatcher": [] + } + ] +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fd44aa..7aab09a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,26 +1,36 @@ cmake_minimum_required(VERSION 3.19) -project(bootstrap-cpp-kata CXX) -enable_testing() +project(expense-report-refactoring-cpp-kata CXX) set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -find_package(GTest REQUIRED) +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) + +include(FetchGTest) +fetch_gtest() -add_executable(main main.cpp) +include(GoogleTest) + +enable_testing() file(GLOB tests test_*.cpp) foreach(test ${tests}) get_filename_component(name ${test} NAME_WE) add_executable(${name} ${test}) - add_test(${name} ${name}) - target_link_libraries(${name} PRIVATE GTest::gmock GTest::gmock_main) + target_link_libraries(${name} PRIVATE GTest::gmock_main) + + gtest_discover_tests(${name}) endforeach() -add_custom_target( - copy-compile-commands ALL - ${CMAKE_COMMAND} -E copy_if_different - ${CMAKE_BINARY_DIR}/compile_commands.json - ${CMAKE_CURRENT_LIST_DIR} -) +if(UNIX) + add_custom_target( + copy-compile-commands ALL + ${CMAKE_COMMAND} + -E + copy_if_different + ${CMAKE_BINARY_DIR}/compile_commands.json + ${CMAKE_CURRENT_LIST_DIR} + ) +endif() diff --git a/Makefile b/Makefile index f268d8c..1bd5a45 100644 --- a/Makefile +++ b/Makefile @@ -1,20 +1,13 @@ all: build test -export CXX := clang++ -export GTEST_COLOR := 1 - BUILDDIR ?= build SRCS := $(shell git ls-files *.cpp *.h) .PHONY: build build: - cmake -B ${BUILDDIR} -G Ninja . + cmake -B ${BUILDDIR} . cmake --build ${BUILDDIR} -.PHONY: run -run: - cd ${BUILDDIR} && ./main - .PHONY: test test: ctest --output-on-failure --test-dir ${BUILDDIR} diff --git a/README.md b/README.md index c45cfc0..a39ccba 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # Expense Report Refactoring C++ Kata [![CI](https://github.com/Coding-Cuddles/expense-report-refactoring-cpp-kata/actions/workflows/main.yml/badge.svg)](https://github.com/Coding-Cuddles/expense-report-refactoring-cpp-kata/actions/workflows/main.yml) -[![Replit](https://replit.com/badge?caption=Try%20with%20Replit&variant=small)](https://replit.com/new/github/Coding-Cuddles/expense-report-refactoring-cpp-kata) ## Overview @@ -35,73 +34,64 @@ implementing two additional scenarios: 1. Extend our system to handle two more types of expenses. - 1. **Transportation**. Surcharge: 5% of the expense amount. - 2. **Supplies**. Surcharge: No surcharge. + 1. **Transportation**. Surcharge: 5% of the expense amount. + 2. **Supplies**. Surcharge: No surcharge. 2. Add dynamic surcharge based on day of week. - * For dinners on weekends, the surcharge is 15% of the expense amount. - * For breakfasts on weekends, the surcharge is 10% of the expense amount. - * On weekdays, the surcharges remain the same as before (10% for dinner - and 5% for breakfast). - - You may need to add a `date` field to the `Expense` class to support this - requirement. The date should be the date when the expense occurred. - - > **Note** - > - > You can use the `std::tm` type in C++ to work with dates, and you - > can determine if a date is a weekend by using the following function: - > - > ```cpp - > #include - > #include - > #include - > #include - > - > bool is_weekend(const std::string& date_str) - > { - > std::tm date{}; - > std::istringstream ss(date_str); - > ss >> std::get_time(&date, "%Y-%m-%d"); - > std::mktime(&date); - > - > int day_of_week = date.tm_wday; - > // Check if it's Saturday (6) or Sunday (0) - > return day_of_week == 6 || day_of_week == 0; - > } - > - > int main() - > { - > std::string date_str = "2023-06-17"; // this is a Saturday - > std::cout << is_weekend(date_str) << std::endl; // this should print: 1 - > return 0; - > } - > ``` + - For dinners on weekends, the surcharge is 15% of the expense amount. + - For breakfasts on weekends, the surcharge is 10% of the expense amount. + - On weekdays, the surcharges remain the same as before (10% for dinner + and 5% for breakfast). + + You may need to add a `date` field to the `Expense` class to support this + requirement. The date should be the date when the expense occurred. + + > [!NOTE] + > + > You can use the `std::tm` type in C++ to work with dates, and you + > can determine if a date is a weekend by using the following function: + > + > ```cpp + > #include + > #include + > #include + > #include + > + > bool is_weekend(const std::string& date_str) + > { + > std::tm date{}; + > std::istringstream ss(date_str); + > ss >> std::get_time(&date, "%Y-%m-%d"); + > std::mktime(&date); + > + > int day_of_week = date.tm_wday; + > // Check if it's Saturday (6) or Sunday (0) + > return day_of_week == 6 || day_of_week == 0; + > } + > + > int main() + > { + > std::string date_str = "2023-06-17"; // this is a Saturday + > std::cout << is_weekend(date_str) << std::endl; // this should print: 1 + > return 0; + > } + > ``` + +## Prerequisites + +- A compatible C++ compiler that supports at least C++17 +- [CMake](https://cmake.org) +- [GoogleTest](https://github.com/google/googletest) ## Usage -You can import this project into [Replit](https://replit.com), and it will -handle all dependencies automatically. - -### Prerequisites - -* [CMake 3.19+](https://cmake.org) -* [Ninja](https://ninja-build.org) -* [GTest](https://github.com/google/googletest) - ### Build ```console make build ``` -### Run main - -```console -make run -``` - ### Run tests ```console diff --git a/cmake/FetchGTest.cmake b/cmake/FetchGTest.cmake new file mode 100644 index 0000000..f3778ae --- /dev/null +++ b/cmake/FetchGTest.cmake @@ -0,0 +1,18 @@ +include(FetchContent) + +function(fetch_gtest) + FetchContent_Declare( + googletest + URL https://github.com/google/googletest/releases/download/v1.16.0/googletest-1.16.0.tar.gz + URL_HASH MD5=9a75eb2ac97300cdb8b65b1a5833f411 + DOWNLOAD_EXTRACT_TIMESTAMP + FALSE + FIND_PACKAGE_ARGS + NAMES + GTest + ) + + # Prevent overriding parent project's compiler/linker settings on Windows + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + FetchContent_MakeAvailable(googletest) +endfunction() diff --git a/expense_report.h b/expense_report.h index 77f843c..1b4c977 100644 --- a/expense_report.h +++ b/expense_report.h @@ -6,6 +6,8 @@ class ReportPrinter { public: + virtual ~ReportPrinter() = default; + virtual void print(const std::string& text) = 0; }; @@ -26,7 +28,7 @@ class ExpenseReport { public: void add_expense(const Expense& expense) { expenses.push_back(expense); } - void print_report(ReportPrinter& printer) + void print_report(ReportPrinter& printer) const { printer.print("Expense Report"); printer.print("--------------"); diff --git a/main.cpp b/main.cpp deleted file mode 100644 index 85f8daa..0000000 --- a/main.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include - -int -main() -{ - std::cout << "Hello World!\n"; - return 0; -} diff --git a/replit.nix b/replit.nix deleted file mode 100644 index 5eb161e..0000000 --- a/replit.nix +++ /dev/null @@ -1,8 +0,0 @@ -{ pkgs }: { - deps = [ - pkgs.clang_12 - pkgs.cmake - pkgs.gtest - pkgs.ninja - ]; -} diff --git a/test_expense_report.cpp b/test_expense_report.cpp index fc1cd96..e148e65 100644 --- a/test_expense_report.cpp +++ b/test_expense_report.cpp @@ -28,7 +28,7 @@ class ExpenseReportTest : public ::testing::Test { std::unique_ptr printer; }; -TEST_F(ExpenseReportTest, print_empty) +TEST_F(ExpenseReportTest, PrintEmpty) { report->print_report(*printer); @@ -40,7 +40,7 @@ TEST_F(ExpenseReportTest, print_empty) EXPECT_EQ(printer->get_text(), expected_output); } -TEST_F(ExpenseReportTest, print_one_dinner) +TEST_F(ExpenseReportTest, PrintOneDinner) { report->add_expense(Expense(ExpenseType::DINNER, 3000)); report->print_report(*printer); @@ -54,7 +54,7 @@ TEST_F(ExpenseReportTest, print_one_dinner) EXPECT_EQ(printer->get_text(), expected_output); } -TEST_F(ExpenseReportTest, print_two_meals_and_dinner_over) +TEST_F(ExpenseReportTest, PrintTwoMealsAndDinnerOver) { report->add_expense(Expense(ExpenseType::DINNER, 6000)); report->add_expense(Expense(ExpenseType::BREAKFAST, 1000)); @@ -70,7 +70,7 @@ TEST_F(ExpenseReportTest, print_two_meals_and_dinner_over) EXPECT_EQ(printer->get_text(), expected_output); } -TEST_F(ExpenseReportTest, print_mix_and_dinner_over) +TEST_F(ExpenseReportTest, PrintMixAndDinnerOver) { report->add_expense(Expense(ExpenseType::DINNER, 5000)); report->add_expense(Expense(ExpenseType::BREAKFAST, 2000));