├── .github └── workflows │ └── cmake-multi-platform.yml ├── .gitignore ├── .gitmodules ├── .idea ├── .gitignore ├── cmake-project-template.iml ├── dictionaries │ └── kig.xml ├── externalDependencies.xml ├── inspectionProfiles │ └── Project_Default.xml ├── markdown-navigator.xml ├── markdown-navigator │ └── profiles_settings.xml ├── misc.xml ├── modules.xml ├── vcs.xml └── workspace.xml.example ├── CMakeLists.txt ├── LICENSE ├── README.md ├── bin └── .git-keep ├── build-and-run ├── doc ├── .git-keep ├── build-and-run.png └── cmake-clion.png ├── include └── .git-keep ├── lib └── .git-keep ├── src ├── CMakeLists.txt ├── division │ ├── CMakeLists.txt │ ├── division.cpp │ └── division.h ├── main.cpp └── main.h └── test ├── .git-keep ├── CMakeLists.txt ├── lib └── .git-keep ├── main.cpp └── src └── divider_tests.cpp /.github/workflows/cmake-multi-platform.yml: -------------------------------------------------------------------------------- 1 | # This starter workflow is for a CMake project running on multiple platforms. There is a different starter workflow if you just want a single platform. 2 | # See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-single-platform.yml 3 | name: CMake on multiple platforms 4 | 5 | on: 6 | push: 7 | branches: [ "master" ] 8 | pull_request: 9 | branches: [ "master" ] 10 | 11 | jobs: 12 | build: 13 | runs-on: ${{ matrix.os }} 14 | 15 | strategy: 16 | # Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. Consider changing this to true when your workflow is stable. 17 | fail-fast: false 18 | 19 | # Set up a matrix to run the following 3 configurations: 20 | # 1. 21 | # 2. 22 | # 3. 23 | # 24 | # To add more build types (Release, Debug, RelWithDebInfo, etc.) customize the build_type list. 25 | matrix: 26 | os: [ubuntu-latest, macos-latest] 27 | build_type: [Release] 28 | c_compiler: [gcc, clang] 29 | include: 30 | - os: macos-latest 31 | c_compiler: clang 32 | cpp_compiler: clang++ 33 | - os: ubuntu-latest 34 | c_compiler: gcc 35 | cpp_compiler: g++ 36 | - os: ubuntu-latest 37 | c_compiler: clang 38 | cpp_compiler: clang++ 39 | 40 | steps: 41 | - uses: actions/checkout@v3 42 | 43 | # - name: Set reusable strings 44 | # # Turn repeated input strings (such as the build output directory) into step outputs. These step outputs can be used throughout the workflow file. 45 | # id: strings 46 | # shell: bash 47 | # run: | 48 | # echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT" 49 | 50 | # - name: Configure CMake 51 | # # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. 52 | # # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type 53 | # run: > 54 | # cmake -B ${{ steps.strings.outputs.build-output-dir }} 55 | # -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} 56 | # -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} 57 | # -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} 58 | # -S ${{ github.workspace }} 59 | 60 | - name: Build and Test 61 | run: bash ./build-and-run 62 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | **/.DS_Store 3 | *.slo 4 | *.lo 5 | *.o 6 | *.obj 7 | 8 | # Precompiled Headers 9 | *.gch 10 | *.pch 11 | 12 | # Compiled Dynamic libraries 13 | *.so 14 | *.dylib 15 | *.dll 16 | 17 | # Fortran module files 18 | *.mod 19 | *.smod 20 | 21 | # Compiled Static libraries 22 | *.lai 23 | *.la 24 | *.a 25 | *.lib 26 | 27 | # Executables 28 | *.exe 29 | *.out 30 | *.app 31 | 32 | **/cmake-build-debug 33 | **/CMakeCache.txt 34 | **/cmake_install.cmake 35 | **/install_manifest.txt 36 | **/CMakeFiles/ 37 | **/CTestTestfile.cmake 38 | **/Makefile 39 | **/*.cbp 40 | **/CMakeScripts 41 | **/compile_commands.json 42 | 43 | include/divisible/* 44 | 45 | 46 | ## Local 47 | 48 | .idea/*.xml 49 | 50 | build/**/* 51 | 52 | include/* 53 | lib/* 54 | bin/* 55 | test/test_runner 56 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "googletest"] 2 | path = test/lib/googletest 3 | url = https://github.com/google/googletest.git 4 | branch = master 5 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Project exclude paths 2 | /. -------------------------------------------------------------------------------- /.idea/cmake-project-template.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/dictionaries/kig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gredeskoul 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/externalDependencies.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | -------------------------------------------------------------------------------- /.idea/markdown-navigator.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 36 | 37 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /.idea/markdown-navigator/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/workspace.xml.example: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 31 | 32 | 37 | 38 | 39 | 49 | 50 | 51 | 52 | 53 | 55 | 56 | 57 | 58 | 60 | 61 | 62 | 63 | 65 | 66 | 67 | 68 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 81 | 82 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | 3 | project(cmake-project-template) 4 | 5 | set(CMAKE_CXX_STANDARD 11) 6 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -O3") 7 | 8 | set(CMAKE_INSTALL_PREFIX ${PROJECT_SOURCE_DIR}) 9 | 10 | set(DIVISIBLE_INSTALL_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include) 11 | set(DIVISIBLE_INSTALL_BIN_DIR ${PROJECT_SOURCE_DIR}/bin) 12 | set(DIVISIBLE_INSTALL_LIB_DIR ${PROJECT_SOURCE_DIR}/lib) 13 | 14 | set(DIVISION_HEADERS_DIR ${PROJECT_SOURCE_DIR}/src/division) 15 | 16 | include_directories(${DIVISIBLE_INSTALL_INCLUDE_DIR}) 17 | include_directories(${DIVISION_HEADERS_DIR}) 18 | 19 | add_subdirectory(src) 20 | add_subdirectory(test) 21 | 22 | 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Konstantin Gredeskoul 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![CMake on multiple platforms](https://github.com/kigster/cmake-project-template/actions/workflows/cmake-multi-platform.yml/badge.svg)](https://github.com/kigster/cmake-project-template/actions/workflows/cmake-multi-platform.yml) 2 | [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fkigster%2Fcmake-project-template.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fkigster%2Fcmake-project-template?ref=badge_shield) 3 | 4 | --- 5 | 6 | Donate using Liberapay       7 | 8 | # CMake C++ Project Template with Google-Test Unit Testing Library 9 | 10 | > WTF is this? 11 | > 12 | > I was just starting with C++ and CMake and I was having a hard time building a workable template that had all the pieces I wanted. This project represents a culmination of work to distill down to bare minimum any C/C++ project that wants to have the option to be build via CMake, to install itself as executables, libraries (shared/static), and provides test binaries that can be used to execute unit tests. 13 | > 14 | > GoogleTest library is a git module, and is a pull by the "setup-and-run" script `./build-and-run` 15 | 16 | ### Division with a remainder library 17 | 18 | Thank you for your interest in this project! 19 | 20 | Are you just starting with `CMake` or C++? 21 | 22 | Do you need some easy-to-use starting point, but one that has the basic moving parts you are likely going to need on any medium sized project? 23 | 24 | Do you believe in test-driven development, or at the very least — write your tests *together* with the feature code? If so you'd want to start your project pre-integrated with a good testing framework. 25 | 26 | Divider is a minimal project that's kept deliberately very small. When you build it using CMake/make (see below) it generates: 27 | 28 | 1. A tiny **static library** `lib/libdivision.a`, 29 | 2. **A command line binary `bin/divider`**, which links with the library, 30 | 3. **An executable unit test** `bin/divider_tests` using [Google Test library](https://github.com/google/googletest). 31 | 4. **An optional BASH build script** `build-and-run` that you can use to quickly test if the project compiles, and runs. 32 | 33 | ## Usage 34 | 35 | ### Prerequisites 36 | 37 | You will need: 38 | 39 | * A modern C/C++ compiler 40 | * CMake 3.1+ installed (on a Mac, run `brew install cmake`) 41 | * If you prefer to code in a great IDE, I highly recommend [Jetbrains CLion](https://www.jetbrains.com/clion/). It is fully compatible with this project. 42 | 43 | ### Building The Project 44 | 45 | #### Git Clone 46 | 47 | First we need to check out the git repo: 48 | 49 | ```bash 50 | ❯ mkdir ~/workspace 51 | ❯ cd ~/workspace 52 | ❯ git clone \ 53 | https://github.com/kigster/cmake-project-template \ 54 | my-project 55 | ❯ cd my-project 56 | ❯ bash build-and-run 57 | ``` 58 | 59 | The output of this script is rather long and is shown [on this screenshot](doc/build-and-run.png). 60 | 61 | The script `build-and-run` is a short-cut — you shouldn't really be using this script to build your project, but see how to do it properly below. 62 | 63 | #### Project Structure 64 | 65 | There are three empty folders: `lib`, `bin`, and `include`. Those are populated by `make install`. 66 | 67 | The rest should be obvious: `src` is the sources, and `test` is where we put our unit tests. 68 | 69 | Now we can build this project, and below we show three separate ways to do so. 70 | 71 | #### Building Manually 72 | 73 | ```bash 74 | ❯ rm -rf build && mkdir build 75 | ❯ git submodule init && git submodule update 76 | ❯ cd build 77 | ❯ cmake .. 78 | ❯ make && make install 79 | ❯ cd .. 80 | ``` 81 | 82 | 83 | #### Running the tests 84 | 85 | ```bash 86 | ❯ bin/divider_tests 87 | [==========] Running 5 tests from 1 test case. 88 | [----------] Global test environment set-up. 89 | [----------] 5 tests from DividerTest 90 | [ RUN ] DividerTest.5_DivideBy_2 91 | [ OK ] DividerTest.5_DivideBy_2 (1 ms) 92 | [ RUN ] DividerTest.9_DivideBy_3 93 | [ OK ] DividerTest.9_DivideBy_3 (0 ms) 94 | [ RUN ] DividerTest.17_DivideBy_19 95 | [ OK ] DividerTest.17_DivideBy_19 (0 ms) 96 | [ RUN ] DividerTest.Long_DivideBy_Long 97 | [ OK ] DividerTest.Long_DivideBy_Long (0 ms) 98 | [ RUN ] DividerTest.DivisionByZero 99 | [ OK ] DividerTest.DivisionByZero (0 ms) 100 | [----------] 5 tests from DividerTest (1 ms total) 101 | 102 | [----------] Global test environment tear-down 103 | [==========] 5 tests from 1 test case ran. (1 ms total) 104 | [ PASSED ] 5 tests. 105 | ``` 106 | 107 | #### Running the CLI Executable 108 | 109 | Without arguments, it prints out its usage: 110 | 111 | ```bash 112 | ❯ bin/divider 113 | 114 | Divider © 2018 Monkey Claps Inc. 115 | 116 | Usage: 117 | divider 118 | 119 | Description: 120 | Computes the result of a fractional division, 121 | and reports both the result and the remainder. 122 | ``` 123 | 124 | But with arguments, it computes as expected the denominator: 125 | 126 | ```bash 127 | ❯ bin/divider 112443477 12309324 128 | 129 | Divider © 2018 Monkey Claps Inc. 130 | 131 | Division : 112443477 / 12309324 = 9 132 | Remainder: 112443477 % 12309324 = 1659561 133 | ``` 134 | 135 | ### Building in CLion 136 | 137 | > **NOTE**: Since JetBrains software [does not officially support git submodules](https://youtrack.jetbrains.com/issue/IDEA-64024), you must run `git submodule init && git submodule update` before starting CLion on a freshly checked-out repo. 138 | 139 | > **NOTE**: We recommend that you copy file `.idea/workspace.xml.example` into `.idea/workspace.xml` **before starting CLion**. It will provide a good starting point for your project's workspace. 140 | 141 | Assuming you've done the above two steps, you can start CLion, and open the project's top level folder. CLion should automatically detect the top level `CMakeLists.txt` file and provide you with the full set of build targets. 142 | 143 | Select menu option **Build ➜ Build Project**, and then **Build ➜ Install**. 144 | 145 | ![CLION](doc/cmake-clion.png) 146 | 147 | The above screenshot is an example of CLion with this project open. 148 | 149 | ### Using it as a C++ Library 150 | 151 | We build a static library that, given a simple fraction will return the integer result of the division, and the remainder. 152 | 153 | We can use it from C++ like so: 154 | 155 | ```cpp 156 | #include 157 | #include 158 | 159 | Fraction f = Fraction{25, 7}; 160 | DivisionResult r = Division(f).divide(); 161 | 162 | std::cout << "Result of the division is " << r.division; 163 | std::cout << "Remainder of the division is " << r.remainder; 164 | ``` 165 | 166 | ## File Locations 167 | 168 | * `src/*` — C++ code that ultimately compiles into a library 169 | * `test/lib` — C++ libraries used for tests (eg, Google Test) 170 | * `test/src` — C++ test suite 171 | * `bin/`, `lib`, `include` are all empty directories, until the `make install` install the project artifacts there. 172 | 173 | Tests: 174 | 175 | * A `test` folder with the automated tests and fixtures that mimics the directory structure of `src`. 176 | * For every C++ file in `src/A/B/.cpp` there is a corresponding test file `test/A/B/_test.cpp` 177 | * Tests compile into a single binary `test/bin/runner` that is run on a command line to run the tests. 178 | * `test/lib` folder with a git submodule in `test/lib/googletest`, and possibly other libraries. 179 | 180 | #### Contributing 181 | 182 | **Pull Requests are WELCOME!** Please submit any fixes or improvements, and I promise to review it as soon as I can at the project URL: 183 | 184 | * [Project Github Home](https://github.com/kigster/cmake-project-template) 185 | * [Submit Issues](https://github.com/kigster/cmake-project-template/issues) 186 | * [Pull Requests](https://github.com/kigster/cmake-project-template/pulls) 187 | 188 | ### License 189 | 190 | © 2017-2019 Konstantin Gredeskoul. 191 | 192 | Open sourced under MIT license, the terms of which can be read here — [MIT License](http://opensource.org/licenses/MIT). 193 | 194 | 195 | [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fkigster%2Fcmake-project-template.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fkigster%2Fcmake-project-template?ref=badge_large) 196 | 197 | ### Acknowledgements 198 | 199 | This project is a derivative of the [CMake Tutorial](https://cmake.org/cmake-tutorial/), and is aimed at saving time for starting new projects in C++ that use CMake and GoogleTest. 200 | -------------------------------------------------------------------------------- /bin/.git-keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kigster/cmake-project-template/602247571baf269a8290de3c25c296bba5ab0c19/bin/.git-keep -------------------------------------------------------------------------------- /build-and-run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # © 2018-2019 Konstantin Gredeskoul, All Rights Reserved. 4 | # MIT License 5 | # 6 | # WARNING: This BASH script is completely optional. You don't need it to build this project. 7 | # 8 | # If you choose to run this script to build the project, run: 9 | # 10 | # $ ./build-and-run 11 | # 12 | # It will clean, build and run the tests. 13 | # 14 | 15 | [[ -z $(which git) ]] && { 16 | echo "You need git installed. Please run 'xcode-select --install' first." 17 | exit 1 18 | } 19 | 20 | export BashMatic="${HOME}/.bashmatic" 21 | 22 | [[ -s ${BashMatic}/init.sh ]] || { 23 | rm -rf "${BashMatic}" 2>/dev/null 24 | git clone https://github.com/kigster/bashmatic "${BashMatic}" 2>&1 1>/dev/null 25 | } 26 | 27 | source "${BashMatic}/init.sh" 28 | 29 | export ProjectRoot=$(pwd) 30 | export BuildDir="${ProjectRoot}/build/run" 31 | export BashLibRoot="${ProjectRoot}/bin/lib-bash" 32 | export LibBashRepo="https://github.com/kigster/lib-bash" 33 | 34 | divider.header() { 35 | h1.purple "Fractional Division With Remainder: A CMake Project Template with Tests" 36 | local OIFC=${IFC} 37 | IFS="|" read -r -a gcc_info <<< "$(gcc --version 2>&1 | tr '\n' '|')" 38 | export IFC=${OIFC} 39 | h1 "${bldylw}GCC" "${gcc_info[1]}" "${gcc_info[2]}" "${gcc_info[3]}" "${gcc_info[4]}" 40 | h1 "${bldylw}GIT: ${bldblu}$(git --version)" 41 | h1 "${bldylw}CMAKE: ${bldblu}$(cmake --version | tr '\n' ' ')" 42 | } 43 | 44 | divider.setup() { 45 | hl.subtle "Creating Build Folder..." 46 | run "mkdir -p build/run" 47 | run "git submodule init && git submodule update" 48 | 49 | [[ -f .idea/workspace.xml ]] || cp .idea/workspace.xml.example .idea/workspace.xml 50 | } 51 | 52 | divider.clean() { 53 | hl.subtle "Cleaning output folders..." 54 | run 'rm -rf bin/d* include/d* lib/*' 55 | } 56 | 57 | divider.build() { 58 | run "cd build/run" 59 | run "cmake ../.. " 60 | run.set-next show-output-on 61 | run "make -j 12" 62 | run "make install | egrep -v 'gmock|gtest'" 63 | run "cd ${ProjectRoot}" 64 | } 65 | 66 | divider.tests() { 67 | if [[ -f bin/divider_tests ]]; then 68 | run.set-next show-output-on 69 | run "echo && bin/divider_tests" 70 | else 71 | printf "${bldred}Can't find installed executable ${bldylw}bin/divider_tests.${clr}\n" 72 | exit 2 73 | fi 74 | } 75 | 76 | divider.examples() { 77 | [[ ! -f bin/divider ]] && { 78 | error "You don't have the cmpiled binary yet". 79 | exit 3 80 | } 81 | 82 | run.set-all show-output-on 83 | 84 | hr 85 | run "bin/divider 11 7" 86 | hr 87 | run "bin/divider 1298798375 94759897" 88 | hr 89 | run "bin/divider 78 17" 90 | hr 91 | 92 | } 93 | 94 | main() { 95 | divider.header 96 | divider.setup 97 | divider.build 98 | divider.tests 99 | divider.examples 100 | } 101 | 102 | (( $_s_ )) || main 103 | -------------------------------------------------------------------------------- /doc/.git-keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kigster/cmake-project-template/602247571baf269a8290de3c25c296bba5ab0c19/doc/.git-keep -------------------------------------------------------------------------------- /doc/build-and-run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kigster/cmake-project-template/602247571baf269a8290de3c25c296bba5ab0c19/doc/build-and-run.png -------------------------------------------------------------------------------- /doc/cmake-clion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kigster/cmake-project-template/602247571baf269a8290de3c25c296bba5ab0c19/doc/cmake-clion.png -------------------------------------------------------------------------------- /include/.git-keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kigster/cmake-project-template/602247571baf269a8290de3c25c296bba5ab0c19/include/.git-keep -------------------------------------------------------------------------------- /lib/.git-keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kigster/cmake-project-template/602247571baf269a8290de3c25c296bba5ab0c19/lib/.git-keep -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | project(divider) 3 | 4 | add_subdirectory(division) 5 | set(SOURCE_FILES main.cpp) 6 | 7 | add_executable(divider ${SOURCE_FILES}) 8 | target_link_libraries(divider division) 9 | install(TARGETS divider DESTINATION ${DIVISIBLE_INSTALL_BIN_DIR}) 10 | -------------------------------------------------------------------------------- /src/division/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | project(division C CXX) 3 | 4 | set(SOURCE_FILES 5 | division.h 6 | division.cpp 7 | ) 8 | 9 | add_library(division SHARED STATIC ${SOURCE_FILES}) 10 | 11 | install(TARGETS division DESTINATION ${DIVISIBLE_INSTALL_LIB_DIR}) 12 | install(FILES division.h DESTINATION ${DIVISIBLE_INSTALL_INCLUDE_DIR}) 13 | -------------------------------------------------------------------------------- /src/division/division.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Konstantin Gredeskoul on 5/14/17. 3 | // 4 | 5 | #include "division.h" 6 | 7 | DivisionResult Division::divide() { 8 | if (fraction.denominator == 0L) throw DivisionByZero(); 9 | 10 | DivisionResult result = DivisionResult{ 11 | fraction.numerator / fraction.denominator, 12 | fraction.numerator % fraction.denominator 13 | }; 14 | 15 | return result; 16 | } 17 | -------------------------------------------------------------------------------- /src/division/division.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Konstantin Gredeskoul on 5/14/17. 3 | // 4 | 5 | #ifndef CMAKE_DIVISION_H 6 | #define CMAKE_DIVISION_H 7 | 8 | static const char *const DIVISION_BY_ZERO_MESSAGE = "Division by zero is illegal"; 9 | 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | class DivisionByZero : public exception { 16 | public: 17 | virtual const char *what() const throw() { 18 | return DIVISION_BY_ZERO_MESSAGE; 19 | } 20 | }; 21 | 22 | struct Fraction { 23 | long long numerator; 24 | long long denominator; 25 | }; 26 | 27 | struct DivisionResult { 28 | long long division; 29 | long long remainder; 30 | 31 | friend bool operator==(const DivisionResult &lhs, const DivisionResult &rhs) { 32 | return lhs.division == rhs.division ? lhs.remainder < rhs.remainder : lhs.division < rhs.division; 33 | } 34 | }; 35 | 36 | class Division { 37 | public: 38 | explicit Division(Fraction fraction) { 39 | this->fraction = fraction; 40 | } 41 | 42 | ~Division() { 43 | }; 44 | 45 | DivisionResult divide(); 46 | 47 | protected: 48 | Fraction fraction; 49 | DivisionResult result; 50 | }; 51 | 52 | #endif //CMAKE_DIVISION_H 53 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | static const char *const HEADER = "\nDivider © 2018 Monkey Claps Inc.\n\n"; 7 | static const char *const USAGE = "Usage:\n\tdivider \n\nDescription:\n\tComputes the result of a fractional division,\n\tand reports both the result and the remainder.\n"; 8 | 9 | int main(int argc, const char *argv[]) { 10 | Fraction f; 11 | 12 | cout << HEADER; 13 | 14 | // ensure the correct number of parameters are used. 15 | if (argc < 3) { 16 | cout << USAGE; 17 | return 1; 18 | } 19 | 20 | f.numerator = atoll(argv[1]); 21 | f.denominator = atoll(argv[2]); 22 | 23 | Division d = Division(f); 24 | try { 25 | DivisionResult r = d.divide(); 26 | 27 | cout << "Division : " << f.numerator << " / " << f.denominator << " = " << r.division << "\n"; 28 | cout << "Remainder: " << f.numerator << " % " << f.denominator << " = " << r.remainder << "\n"; 29 | } catch (DivisionByZero) { 30 | cout << "Can not divide by zero, Homer. Sober up!\n"; 31 | } 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /src/main.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Konstantin Gredeskoul on 10/7/18. 3 | // 4 | 5 | #ifndef PROJECT_MAIN_H 6 | #define PROJECT_MAIN_H 7 | 8 | static const char *const HEADER = "\nDivider © 2018 Monkey Claps Inc.\n\n"; 9 | static const char *const USAGE = "Usage:\n\tdivider \n\nDescription:\n\tComputes the result of a fractional division,\n\tand reports both the result and the remainder.\n"; 10 | 11 | 12 | #endif //PROJECT_MAIN_H 13 | -------------------------------------------------------------------------------- /test/.git-keep: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | project(divider_tests) 3 | 4 | add_subdirectory(lib/googletest) 5 | 6 | include_directories(${DIVISION_HEADERS_DIR}) 7 | include_directories(lib/googletest/googletest/include) 8 | 9 | set(SOURCE_FILES main.cpp src/divider_tests.cpp) 10 | 11 | add_executable(divider_tests ${SOURCE_FILES}) 12 | target_link_libraries(divider_tests division gtest) 13 | install(TARGETS divider_tests DESTINATION bin) 14 | 15 | -------------------------------------------------------------------------------- /test/lib/.git-keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kigster/cmake-project-template/602247571baf269a8290de3c25c296bba5ab0c19/test/lib/.git-keep -------------------------------------------------------------------------------- /test/main.cpp: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | 3 | int main(int argc, char *argv[]) { 4 | ::testing::InitGoogleTest(&argc, argv); 5 | return RUN_ALL_TESTS(); 6 | } 7 | -------------------------------------------------------------------------------- /test/src/divider_tests.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Konstantin Gredeskoul on 5/16/17. 3 | // 4 | #include 5 | #include "gtest/gtest.h" 6 | 7 | using namespace std; 8 | 9 | 10 | #define VI vector 11 | 12 | class DividerTest : public ::testing::Test { 13 | 14 | protected: 15 | VI numerators = {5, 9, 17, 933345453464353416L}; 16 | VI denominators = {2, 3, 19, 978737423423423499L}; 17 | VI divisions = {2, 3, 0, 0}; 18 | VI remainders = {1, 0, 17, 933345453464353416}; 19 | 20 | virtual void SetUp() { 21 | }; 22 | 23 | virtual void TearDown() { 24 | }; 25 | 26 | virtual void verify(int index) { 27 | Fraction f = Fraction{numerators.at(index), denominators.at(index)}; 28 | DivisionResult expected = DivisionResult{divisions.at(index), remainders.at(index)}; 29 | DivisionResult result = Division(f).divide(); 30 | EXPECT_EQ(result.division, expected.division); 31 | EXPECT_EQ(result.remainder, expected.remainder); 32 | } 33 | }; 34 | 35 | TEST_F(DividerTest, 5_DivideBy_2) { 36 | verify(0); 37 | } 38 | 39 | TEST_F(DividerTest, 9_DivideBy_3) { 40 | verify(1); 41 | } 42 | 43 | TEST_F(DividerTest, 17_DivideBy_19) { 44 | verify(2); 45 | } 46 | 47 | TEST_F(DividerTest, Long_DivideBy_Long) { 48 | verify(3); 49 | } 50 | 51 | TEST_F(DividerTest, DivisionByZero) { 52 | Division d = Division(Fraction{1, 0}); 53 | try { 54 | d.divide(); 55 | FAIL() << "Expected divide() method to throw DivisionByZeroException"; 56 | } catch (DivisionByZero const &err) { 57 | EXPECT_EQ(err.what(), DIVISION_BY_ZERO_MESSAGE); 58 | } 59 | catch (...) { 60 | FAIL() << "Expected DivisionByZeroException!"; 61 | } 62 | } 63 | 64 | --------------------------------------------------------------------------------