Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .cmake-format.yaml
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @Coding-Cuddles/kata-maintainers
6 changes: 6 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
30 changes: 9 additions & 21 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,22 @@ jobs:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v3
- uses: actions/checkout@v7

- 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 }}

env:
GTEST_COLOR: "1"

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

- name: Build
run: make build

- name: Run main
run: make run
- uses: actions/checkout@v7

- name: Test
run: make test
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
build
cmake-build-*
.cache
.ccls-cache
compile_commands.json
43 changes: 32 additions & 11 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,26 +1,47 @@
cmake_minimum_required(VERSION 3.19)
cmake_minimum_required(VERSION 3.24)
project(bootstrap-cpp-kata CXX)
enable_testing()

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES})
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_COLOR_DIAGNOSTICS ON)

list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)

include(FetchGTest)
fetch_gtest()

include(GoogleTest)

find_package(GTest REQUIRED)
enable_testing()

add_executable(main main.cpp)
add_custom_target(
run
COMMAND $<TARGET_FILE:main>
DEPENDS main
COMMENT "Running the example executable"
)

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}
COMMENT "Copying compile commands to the source directory"
)
endif()
46 changes: 30 additions & 16 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,37 +1,51 @@
all: build test
COLOR_CYAN := \033[36m
COLOR_RESET := \033[0m

export CXX := clang++
export GTEST_COLOR := 1
CLICOLOR ?= 1
GTEST_COLOR ?= 1
export CLICOLOR GTEST_COLOR

BUILDDIR ?= build
SRCS := $(shell git ls-files *.cpp *.h)
BUILDCONFIG ?= Debug
SRCS := $(shell git ls-files '*.cpp' '*.h' '*.hpp')

.DEFAULT_GOAL := help

.PHONY: all
all: test ## Build and run tests

.PHONY: help
help: ## Show this help message
@awk 'BEGIN {FS = ":.*##"; printf "Usage: make [options] $(COLOR_CYAN)[target] ...$(COLOR_RESET)\n\n"} \
/^[a-zA-Z_-]+:.*##/ {printf " $(COLOR_CYAN)%-20s$(COLOR_RESET) %s\n", $$1, $$2}' \
$(MAKEFILE_LIST)

.PHONY: build
build:
cmake -B ${BUILDDIR} -G Ninja .
cmake --build ${BUILDDIR}
build: ## Configure and build
cmake -S . -B ${BUILDDIR} -DCMAKE_BUILD_TYPE=${BUILDCONFIG}
cmake --build ${BUILDDIR} --config ${BUILDCONFIG}

.PHONY: run
run:
cd ${BUILDDIR} && ./main
run: build ## Build and run the example executable
cmake --build ${BUILDDIR} --config ${BUILDCONFIG} --target run

.PHONY: test
test:
ctest --output-on-failure --test-dir ${BUILDDIR}
test: build ## Build and run tests
ctest --test-dir ${BUILDDIR} --build-config ${BUILDCONFIG} --output-on-failure

.PHONY: format
format:
format: ## Format C++ sources in place
clang-format -i -style=file $(SRCS)

.PHONY: format-check
format-check:
format-check: ## Fail if C++ sources require formatting
clang-format -style=file --dry-run -Werror $(SRCS) \
|| (echo "Some files require formatting. Run 'make format' to fix." && exit 1)

.PHONY: clean
clean:
rm -rf ${BUILDDIR}
clean: ## Remove generated build artifacts
rm -rf ${BUILDDIR} compile_commands.json

ifndef VERBOSE
ifneq ($(VERBOSE),1)
.SILENT:
endif
110 changes: 97 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Roman numerals kata in C++

[![CI](https://github.com/Coding-Cuddles/roman-numerals-cpp-kata/actions/workflows/main.yml/badge.svg)](https://github.com/Coding-Cuddles/roman-numerals-cpp-kata/actions/workflows/main.yml)
[![C++17](https://img.shields.io/badge/C%2B%2B-17-blue.svg)](https://en.cppreference.com/w/cpp/17)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![Replit](https://img.shields.io/badge/Try%20with%20Replit-black?logo=replit)](https://replit.com/new/github/Coding-Cuddles/roman-numerals-cpp-kata)

## Overview
Expand Down Expand Up @@ -62,33 +64,115 @@ their corresponding Arabic digits.
* If you do know an algorithm, evaluate if it can be implemented using strict
TDD principles.

This is a bootstrap repository for clean code katas in C++17 using GTest.
This is a C++17 kata using GoogleTest. Setup is complete when CTest reports
`100% tests passed`.

## Usage
## Prerequisites

You can import this project into [Replit](https://replit.com), and it will
handle all dependencies automatically.
Required:

### Prerequisites
- [Git](https://git-scm.com/downloads)
- A compiler with C++17 support. Choose one:
- [GCC](https://gcc.gnu.org/) 10+ on Linux
- [LLVM Clang](https://llvm.org/) 14+ on Linux
- [Apple Clang](https://developer.apple.com/xcode/) 17+ on macOS
- [MSVC](https://visualstudio.microsoft.com/) 2022 on Windows
- [CMake 3.24 or later](https://cmake.org)

* [CMake 3.19+](https://cmake.org)
* [Ninja](https://ninja-build.org)
* [GTest](https://github.com/google/googletest)
Optional:

### Build
- [GNU Make](https://www.gnu.org/software/make/), for shorter commands. Every
required task also has direct CMake and CTest commands. Make may be
unavailable on Windows.

You do not need to install GoogleTest separately. CMake finds an installed
copy or downloads the pinned release when needed.

## Set up the kata

The tracked Replit configuration is retained. The local setup below is the
validated development path.

1. Clone the repository:

```console
git clone https://github.com/Coding-Cuddles/roman-numerals-cpp-kata.git
```

2. Enter the repository directory:

```console
cd roman-numerals-cpp-kata
```

3. Build and run the tests. Use Make when it is installed:

```console
make test
```

Otherwise, use CMake and CTest directly:

```console
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build --config Debug
ctest --test-dir build --build-config Debug --output-on-failure
```

The first run may download and build GoogleTest. CTest should report
`100% tests passed`. If a command reports a missing compiler or CMake, install
that prerequisite and run the setup commands again. Setup is complete when
CTest reports `100% tests passed`.

## Work on the kata

Add one test at a time to `test_roman_numerals.cpp`, then implement enough code
in `roman_numerals.h` to make the test pass. Keep the existing exercises and
constraints above as the target behavior.

After each change, use Make when it is installed:

```console
make build
make test
```

### Run main
Otherwise, use CMake and CTest directly:

```console
cmake --build build --config Debug
ctest --test-dir build --build-config Debug --output-on-failure
```

Continue when CTest reports `100% tests passed`.

## Run the example

Use Make when it is installed:

```console
make run
```

### Run tests
Otherwise, use the CMake run target:

```console
make test
cmake --build build --config Debug --target run
```

The executable prints `Hello World!`.

## Make command reference

Make is optional. Run `make` or `make help` to list these commands in the
terminal.

| Command | Result |
| ------------------- | ----------------------------------------- |
| `make all` | Build and run the test suite |
| `make help` | List public Make targets |
| `make build` | Configure and build without running tests |
| `make run` | Build and run the example executable |
| `make test` | Build and run the test suite |
| `make format` | Format tracked C++ and header files |
| `make format-check` | Check formatting without changing files |
| `make clean` | Remove generated build artifacts |
31 changes: 31 additions & 0 deletions cmake/FetchGTest.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
include(FetchContent)

# Find an installed GoogleTest package or fetch and verify the pinned release
function(fetch_gtest)
string(
CONCAT
gtest_url
"https://github.com/google/googletest/releases/download/"
"v1.17.0/googletest-1.17.0.tar.gz"
)
set(
gtest_sha256
65fab701d9829d38cb77c14acdc431d2108bfdbf8979e40eb8ae567edf10b27c
)

FetchContent_Declare(
googletest
URL ${gtest_url}
URL_HASH SHA256=${gtest_sha256}
DOWNLOAD_EXTRACT_TIMESTAMP
FALSE
FIND_PACKAGE_ARGS
NAMES
GTest
)

# Prevent overriding parent project's compiler/linker settings on Windows
# cmake-lint: disable=C0103
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
endfunction()