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
[](https://github.com/Coding-Cuddles/expense-report-refactoring-cpp-kata/actions/workflows/main.yml)
-[](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));