├── .clang-format ├── .github └── workflows │ ├── ci.yml │ ├── clang-format.yml │ ├── gh-pages.yml │ └── include-guards.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE_1_0.txt ├── README.md ├── example ├── basic_assertions.cpp ├── boolean_operators.cpp ├── container_spec.cpp ├── custom_matchers_test.cpp ├── exceptions_tests.cpp ├── expression_error_handling.cpp ├── main.cpp ├── map_tests.cpp ├── operator_tests.cpp ├── sequence_container_tests.cpp ├── string_line_tests.cpp ├── string_tests.cpp ├── stringize_tests.cpp └── tests.h ├── include └── snowhouse │ ├── assert.h │ ├── assertionexception.h │ ├── constraints │ ├── constraints.h │ ├── containsconstraint.h │ ├── endswithconstraint.h │ ├── equalsconstraint.h │ ├── equalscontainerconstraint.h │ ├── equalswithdeltaconstraint.h │ ├── expressions │ │ ├── andexpression.h │ │ ├── expression.h │ │ ├── expression_fwd.h │ │ ├── notexpression.h │ │ └── orexpression.h │ ├── fulfillsconstraint.h │ ├── haslengthconstraint.h │ ├── isemptyconstraint.h │ ├── isgreaterthanconstraint.h │ ├── isgreaterthanorequaltoconstraint.h │ ├── islessthanconstraint.h │ ├── islessthanorequaltoconstraint.h │ └── startswithconstraint.h │ ├── exceptions.h │ ├── fluent │ ├── constraintadapter.h │ ├── constraintlist.h │ ├── expressionbuilder.h │ ├── fluent.h │ └── operators │ │ ├── andoperator.h │ │ ├── collections │ │ ├── alloperator.h │ │ ├── atleastoperator.h │ │ ├── atmostoperator.h │ │ ├── collectionconstraintevaluator.h │ │ ├── collectionoperator.h │ │ ├── exactlyoperator.h │ │ └── noneoperator.h │ │ ├── constraintoperator.h │ │ ├── invalidexpressionexception.h │ │ ├── notoperator.h │ │ └── oroperator.h │ ├── macros.h │ ├── snowhouse.h │ ├── stringize.h │ └── stringizers.h └── util ├── build-in-container.sh ├── build.sh └── format.sh /.clang-format: -------------------------------------------------------------------------------- 1 | # This .clang-format file is tested with clang-format 9.0.0 2 | # 3 | # Please use 4 | # clang-format -style=file -i 5 | # before committing your changes. 6 | --- 7 | Language: Cpp 8 | Standard: Cpp11 9 | 10 | ColumnLimit: 0 11 | IndentWidth: 2 12 | UseTab: Never 13 | AccessModifierOffset: -2 14 | NamespaceIndentation: All 15 | FixNamespaceComments: false 16 | IndentCaseLabels: false 17 | ContinuationIndentWidth: 4 18 | ConstructorInitializerIndentWidth: 4 19 | IndentWrappedFunctionNames: false 20 | 21 | AlwaysBreakTemplateDeclarations: true 22 | SpaceAfterTemplateKeyword: false 23 | 24 | DerivePointerAlignment: false 25 | PointerAlignment: Left 26 | 27 | BreakBeforeBraces: Custom 28 | BraceWrapping: 29 | AfterNamespace: true 30 | AfterStruct: true 31 | AfterClass: true 32 | AfterFunction: true 33 | AfterControlStatement: true 34 | AfterEnum: true 35 | AfterUnion: true 36 | BeforeCatch: true 37 | BeforeElse: true 38 | IndentBraces: false 39 | 40 | AllowShortBlocksOnASingleLine: true 41 | AllowShortCaseLabelsOnASingleLine: false 42 | AllowShortIfStatementsOnASingleLine: false 43 | AllowShortLoopsOnASingleLine: false 44 | AllowShortFunctionsOnASingleLine: None 45 | 46 | AlignAfterOpenBracket: DontAlign 47 | AlignConsecutiveAssignments: false 48 | AlignConsecutiveDeclarations: false 49 | 50 | SpacesInParentheses: false 51 | SpaceInEmptyParentheses: false 52 | SpacesInSquareBrackets: false 53 | SpacesInAngles: false 54 | SpaceAfterCStyleCast: false 55 | SpacesInCStyleCastParentheses: false 56 | SpaceBeforeAssignmentOperators: true 57 | SpaceBeforeParens: ControlStatements 58 | SpacesBeforeTrailingComments: 1 59 | SpacesInContainerLiterals: false 60 | 61 | KeepEmptyLinesAtTheStartOfBlocks: false 62 | MaxEmptyLinesToKeep: 1 63 | 64 | SortIncludes: false 65 | IncludeCategories: 66 | - Regex: 'snowhouse/' 67 | Priority: 2 68 | - Regex: '^<' 69 | Priority: 1 70 | - Regex: '.*' 71 | Priority: 3 72 | # XXX: There is no need to sort includes alphabetically, 73 | # but standard library includes should come before snowhouse 74 | # includes should come before local includes. 75 | 76 | # AlignEscapedNewlinesLeft: false 77 | # XXX: There should be no alignment at all, but this is not available 78 | 79 | AlwaysBreakAfterReturnType: None 80 | 81 | ReflowComments: false 82 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | linux-build-test-minimum-compiler-version: 7 | runs-on: ubuntu-latest 8 | container: 9 | image: docker://banditcpp/build-environments:debian-stretch-compilers 10 | strategy: 11 | matrix: 12 | cxx-standard: ["11"] 13 | compiler-env: ["CC=gcc-6 CXX=g++-6", "CC=clang-3.9 CXX=clang++-3.9"] 14 | steps: 15 | - name: Clone and checkout commit 16 | uses: actions/checkout@v3 17 | - name: Build C++${{ matrix.cxx-standard }} version with ${{ matrix.compiler-env }} and run tests 18 | run: 19 | ${{ matrix.compiler-env }} util/build.sh ${{ matrix.cxx-standard }} 20 | 21 | linux-build-test-recent-gcc: 22 | runs-on: ubuntu-latest 23 | container: 24 | image: docker://banditcpp/build-environments:gcc-13 25 | strategy: 26 | matrix: 27 | cxx-standard: ["11", "14", "17", "20", "23"] 28 | steps: 29 | - name: Clone and checkout commit 30 | uses: actions/checkout@v3 31 | - name: Build C++${{ matrix.cxx-standard }} version with recent gcc and run tests 32 | run: 33 | ${{ matrix.compiler-env }} util/build.sh ${{ matrix.cxx-standard }} 34 | 35 | linux-build-test-recent-clang: 36 | runs-on: ubuntu-latest 37 | container: 38 | image: docker://banditcpp/build-environments:clang-16 39 | strategy: 40 | matrix: 41 | cxx-standard: ["11", "14", "17", "20", "23"] 42 | steps: 43 | - name: Clone and checkout commit 44 | uses: actions/checkout@v3 45 | - name: Build C++${{ matrix.cxx-standard }} version with recent clang and run tests 46 | run: 47 | ${{ matrix.compiler-env }} util/build.sh ${{ matrix.cxx-standard }} 48 | 49 | windows-2022-build-test: 50 | runs-on: windows-2022 51 | strategy: 52 | matrix: 53 | cxx-standard: ["11", "14", "17", "20", "23"] 54 | steps: 55 | - name: Clone and checkout commit 56 | uses: actions/checkout@v3 57 | - name: Let CMake generate build configuration 58 | run: cmake -G "Visual Studio 17 2022" -DSNOWHOUSE_RUN_TESTS=0 -DSNOWHOUSE_BUILD_TESTS=1 -DSNOWHOUSE_CXX_STANDARD=C++${{ matrix.cxx-standard }} . 59 | - name: Build tests with MSVC and C++${{ matrix.cxx-standard }} 60 | run: cmake --build . 61 | - name: Run tests 62 | run: bin\Debug\snowhouse-tests.exe 63 | -------------------------------------------------------------------------------- /.github/workflows/clang-format.yml: -------------------------------------------------------------------------------- 1 | name: Test coding style 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/checkout@v3 11 | - uses: DoozyX/clang-format-lint-action@v0.16.2 12 | with: 13 | source: '.' 14 | extensions: 'h,cpp' 15 | -------------------------------------------------------------------------------- /.github/workflows/gh-pages.yml: -------------------------------------------------------------------------------- 1 | # Sample workflow for building and deploying a Jekyll site to GitHub Pages 2 | name: Deploy Jekyll with GitHub Pages dependencies preinstalled 3 | 4 | on: 5 | # Runs on pushes targeting the default branch 6 | push: 7 | branches: ["main"] 8 | 9 | # Allows you to run this workflow manually from the Actions tab 10 | workflow_dispatch: 11 | 12 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 13 | permissions: 14 | contents: read 15 | pages: write 16 | id-token: write 17 | 18 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 19 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 20 | concurrency: 21 | group: "pages" 22 | cancel-in-progress: false 23 | 24 | jobs: 25 | # Build job 26 | build: 27 | runs-on: ubuntu-latest 28 | steps: 29 | - name: Checkout 30 | uses: actions/checkout@v3 31 | - name: Setup Pages 32 | uses: actions/configure-pages@v3 33 | - name: Build with Jekyll 34 | uses: actions/jekyll-build-pages@v1 35 | with: 36 | source: ./ 37 | destination: ./_site 38 | - name: Upload artifact 39 | uses: actions/upload-pages-artifact@v2 40 | 41 | # Deployment job 42 | deploy: 43 | environment: 44 | name: github-pages 45 | url: ${{ steps.deployment.outputs.page_url }} 46 | runs-on: ubuntu-latest 47 | needs: build 48 | steps: 49 | - name: Deploy to GitHub Pages 50 | id: deployment 51 | uses: actions/deploy-pages@v2 52 | -------------------------------------------------------------------------------- /.github/workflows/include-guards.yml: -------------------------------------------------------------------------------- 1 | name: check-include-guards 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | include-guards: 7 | name: Check include guards 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout 11 | uses: actions/checkout@v3 12 | - name: Check include guard of snowhouse.h 13 | uses: sbeyer/include-guards-check-action@v1.0.0 14 | with: 15 | path: include 16 | pattern: '{file}' 17 | only: 'snowhouse/snowhouse\.h' 18 | - name: Check include guards of remaining files 19 | uses: sbeyer/include-guards-check-action@v1.0.0 20 | with: 21 | path: include 22 | pattern: '{first_dir}_{file}' 23 | ignore: 'snowhouse/snowhouse\.h' 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #cmake files 2 | CMakeCache.txt 3 | CMakeFiles/ 4 | Makefile 5 | bin/ 6 | cmake_install.cmake 7 | compile_commands.json 8 | *.todo 9 | /builds 10 | /.cache 11 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | 3 | project(snowhouse) 4 | 5 | option(SNOWHOUSE_BUILD_TESTS "Build the Snowhouse tests" OFF) 6 | option(SNOWHOUSE_RUN_TESTS "Run the Snowhouse tests" OFF) 7 | option(SNOWHOUSE_DEVELOP "Build tests with options useful for developing" OFF) 8 | set(SNOWHOUSE_CXX_STANDARD "C++11" CACHE STRING "The C++ standard the examples are compiled with") 9 | set_property(CACHE SNOWHOUSE_CXX_STANDARD PROPERTY STRINGS "C++11" "C++14" "C++17") 10 | 11 | add_library(snowhouse INTERFACE) 12 | target_include_directories(snowhouse INTERFACE include) 13 | 14 | if(SNOWHOUSE_CXX_STANDARD STREQUAL "C++11") 15 | set(CMAKE_CXX_STANDARD 11) 16 | elseif(SNOWHOUSE_CXX_STANDARD STREQUAL "C++14") 17 | set(CMAKE_CXX_STANDARD 14) 18 | elseif(SNOWHOUSE_CXX_STANDARD STREQUAL "C++17") 19 | set(CMAKE_CXX_STANDARD 17) 20 | elseif(SNOWHOUSE_CXX_STANDARD STREQUAL "C++20") 21 | set(CMAKE_CXX_STANDARD 20) 22 | elseif(SNOWHOUSE_CXX_STANDARD STREQUAL "C++23") 23 | set(CMAKE_CXX_STANDARD 23) 24 | else() 25 | message(WARNING "C++ standard \"${SNOWHOUSE_CXX_STANDARD}\" not known, falling back to default") 26 | endif() 27 | 28 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ./bin) 29 | 30 | if (MSVC) 31 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /MP ") 32 | else() 33 | # Assume GCC-style arguments 34 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} \ 35 | -Wall -Wextra -pedantic -Wdeprecated -Wdeprecated-declarations -Wnon-virtual-dtor \ 36 | -Wshadow -Wfloat-equal -Wundef -Wendif-labels -Wno-error=unknown-pragmas") 37 | 38 | if (SNOWHOUSE_DEVELOP) 39 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} \ 40 | -Werror -fsanitize=address,undefined") 41 | endif() 42 | endif() 43 | 44 | message(STATUS "C++ compiler flags: ${CMAKE_CXX_FLAGS}") 45 | 46 | if (SNOWHOUSE_BUILD_TESTS) 47 | FILE(GLOB SnowhouseSpecSourceFiles example/*.cpp) 48 | add_executable(snowhouse-tests ${SnowhouseSpecSourceFiles}) 49 | target_link_libraries(snowhouse-tests PRIVATE snowhouse) 50 | endif() 51 | 52 | if (SNOWHOUSE_BUILD_TESTS AND SNOWHOUSE_RUN_TESTS) 53 | add_custom_command(TARGET snowhouse-tests 54 | POST_BUILD 55 | COMMAND snowhouse-tests 56 | WORKING_DIRECTORY ./bin) 57 | elseif (SNOWHOUSE_RUN_TESTS) 58 | message(WARNING "Unable to run snowhouse tests - set:\n option(SNOWHOUSE_BUILD_TESTS, \"Build the Snowhouse tests\" ON)\nand clear your CMakeCache.txt") 59 | endif() 60 | -------------------------------------------------------------------------------- /LICENSE_1_0.txt: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | snowhouse 2 | ========= 3 | [![GitHub Actions CI](https://github.com/banditcpp/snowhouse/workflows/CI/badge.svg)](https://github.com/banditcpp/snowhouse/actions?query=workflow%3ACI+branch%3Amain) 4 | [![Codacy quality grade](https://app.codacy.com/project/badge/Grade/204e42185a3a4c92b55321ec01a79567)](https://app.codacy.com/gh/banditcpp/snowhouse/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) 5 | 6 | An assertion library for C++ 7 | 8 | Snowhouse is a stand-alone assertion framework for C++. 9 | It is a header-only library. 10 | 11 | Snowhouse requires a C++11-compatible compiler since version 5.0.0. 12 | Feel free to use Snowhouse with major version 4 if you want to use it 13 | in a pre-C++11 setting. 14 | Major version 4 is still maintained in the `maint-v4` branch (bug fixes, etc.). 15 | 16 | For inclusion in your projects, you have several options: 17 | 18 | a) You can copy the code and just use it as the license allows. 19 | 20 | b) You can use the `headers-only` branch as a submodule: 21 | 22 | ```sh 23 | git submodule add -b headers-only https://github.com/banditcpp/snowhouse snowhouse 24 | git submodule update --init --recursive 25 | ``` 26 | 27 | c) If you use CMake >= 3.1 in your project, 28 | you can use Snowhouse with the provided library target. 29 | Assuming you have cloned the `main` branch into a `snowhouse` subdirectory, 30 | your `CMakeLists.txt` might contain lines like the following: 31 | 32 | ```cmake 33 | add_subdirectory(snowhouse) 34 | add_executable(app main.cpp) 35 | target_link_libraries(app snowhouse) 36 | ``` 37 | 38 | ## Usage 39 | 40 | ```C++ 41 | #include 42 | 43 | using namespace snowhouse; 44 | 45 | int main() 46 | { 47 | std::cout << "Testing that 23 is 23" << std::endl; 48 | AssertThat(23, Is().EqualTo(23)); 49 | 50 | try 51 | { 52 | AssertThat(12, Is().LessThan(11).And().GreaterThan(99)); 53 | } 54 | catch (const AssertionException& ex) 55 | { 56 | std::cout << "Apparently this failed:" << std::endl; 57 | std::cout << ex.what() << std::endl; 58 | } 59 | 60 | return 0; 61 | } 62 | ``` 63 | 64 | ### Assertions 65 | 66 | Snowhouse uses a constraint-based assertion model that is heavily inspired by the 67 | model used in [NUnit](http://nunit.org/). An assertion in Snowhouse is written 68 | using the following format: 69 | 70 | ```cpp 71 | AssertThat(actual_value, ); 72 | ``` 73 | 74 | where `` is an expression that `actual_value` is 75 | evaluated against when the test is executed. 76 | 77 | Constraint expressions come in two basic forms: composite and fluent expressions. 78 | 79 | #### Composite Expressions 80 | 81 | With composite expressions, you can create compact, powerful expressions that 82 | combine a set of predefined constraints with ones that you provide yourself. 83 | 84 | Example: 85 | 86 | ```cpp 87 | AssertThat(length, IsGreaterThan(4) && !Equals(10)); 88 | ``` 89 | 90 | Composite expressions can be any combination of constraints and the 91 | standard logical C++ operators. 92 | 93 | You can also add your own constraints to be used within composite expressions. 94 | 95 | #### Fluent Expressions 96 | 97 | With fluent expressions, you can create assertions that better convey the intent 98 | of a test without exposing implementation-specific details. 99 | Fluent expressions aim to help you create tests that are not just by developers 100 | for developers, but rather can be read and understood by domain experts. 101 | 102 | Fluent expressions also have the ability to make assertions on the elements in a 103 | container in a way you cannot achieve with composite expressions. 104 | 105 | Example: 106 | 107 | ```cpp 108 | AssertThat(length, Is().GreaterThan(4).And().Not().EqualTo(10)); 109 | ``` 110 | 111 | ### Basic Constraints 112 | 113 | #### Equality Constraint 114 | 115 | Used to verify equality between actual and expected. 116 | 117 | ```cpp 118 | AssertThat(x, Equals(12)); 119 | AssertThat(x, Is().EqualTo(12)); 120 | ``` 121 | 122 | #### EqualityWithDelta Constraint 123 | 124 | Used to verify equality between actual and expected, 125 | allowing the two to differ by a delta. 126 | 127 | ```cpp 128 | AssertThat(2.49, EqualsWithDelta(2.5, 0.1)); 129 | AssertThat(2.49, Is().EqualToWithDelta(2.5, 0.1)); 130 | ``` 131 | 132 | #### GreaterThan Constraint 133 | 134 | Used to verify that actual is greater than a value. 135 | 136 | ```cpp 137 | AssertThat(x, IsGreaterThan(4)); 138 | AssertThat(x, Is().GreaterThan(4)); 139 | ``` 140 | 141 | #### LessThan Constraint 142 | 143 | Used to verify that actual is less than a value. 144 | 145 | ```cpp 146 | AssertThat(x, IsLessThan(3)); 147 | AssertThat(x, Is().LessThan(3)); 148 | ``` 149 | 150 | #### GreaterThanOrEqualTo Constraint 151 | 152 | Used to verify that actual is greater than or equal to a value. 153 | 154 | ```cpp 155 | AssertThat(x, IsGreaterThanOrEqualTo(5)); 156 | AssertThat(x, Is().GreaterThanOrEqualTo(5)); 157 | ``` 158 | 159 | #### LessThanOrEqualTo Constraint 160 | 161 | Used to verify that actual is less than or equal to a value. 162 | 163 | ```cpp 164 | AssertThat(x, IsLessThanOrEqualTo(6)); 165 | AssertThat(x, Is().LessThanOrEqualTo(6)); 166 | ``` 167 | 168 | ### Pointer Constraints 169 | 170 | Used to check for `nullptr` equality. 171 | 172 | ```cpp 173 | AssertThat(x, IsNull()); 174 | AssertThat(x, Is().Null()); 175 | ``` 176 | 177 | ### String Constraints 178 | 179 | String assertions in Snowhouse are used to verify the values of 180 | STL strings (`std::string`). 181 | 182 | #### Equality Constraints 183 | 184 | Used to verify that actual is equal to an expected value. 185 | 186 | ```cpp 187 | AssertThat(actual_str, Equals("foo")); 188 | AssertThat(actual_str, Is().EqualTo("foo")); 189 | ``` 190 | 191 | #### Contains Constraint 192 | 193 | Used to verify that a string contains a substring. 194 | 195 | ```cpp 196 | AssertThat(actual_str, Contains("foo")); 197 | AssertThat(actual_str, Is().Containing("foo")); 198 | ``` 199 | 200 | #### EndsWith Constraint 201 | 202 | Used to verify that a string ends with an expected substring. 203 | 204 | ```cpp 205 | AssertThat(actual_str, EndsWith("foo")); 206 | AssertThat(actual_str, Is().EndingWith("foo")); 207 | ``` 208 | 209 | #### StartsWith Constraint 210 | 211 | Used to verify that a string starts with an expected substring. 212 | 213 | ```cpp 214 | AssertThat(actual_str, StartsWith("foo")); 215 | AssertThat(actual_str, Is().StartingWith("foo")); 216 | ``` 217 | 218 | #### HasLength Constraint 219 | 220 | Used to verify that a string is of the expected length. 221 | 222 | ```cpp 223 | AssertThat(actual_str, HasLength(5)); 224 | AssertThat(actual_str, Is().OfLength(5)); 225 | ``` 226 | 227 | ### Constraints on Multiline Strings 228 | 229 | If you have a string that contains multiple lines, you can use the collection 230 | constraints to make assertions on the content of that string. 231 | This may be handy if you have a string that, for instance, represents the 232 | resulting content of a file or a network transmission. 233 | 234 | Snowhouse can handle both Windows (CR+LF) and Unix (LF) line endings. 235 | 236 | ```cpp 237 | std::string lines = "First line\r\nSecond line\r\nThird line"; 238 | AssertThat(lines, Has().Exactly(1).StartingWith("Second")); 239 | ``` 240 | 241 | ### Container Constraints 242 | 243 | The following constraints can be applied to containers in the standard template library. 244 | 245 | #### Contains Constraint 246 | 247 | Used to verify that a container contains an expected value. 248 | 249 | ```cpp 250 | AssertThat(container, Contains(12)); 251 | AssertThat(container, Is().Containing(12)); 252 | ``` 253 | 254 | #### HasLength Constraint 255 | 256 | Used to verify that a container has the expected length. 257 | 258 | ```cpp 259 | AssertThat(container, HasLength(3)); 260 | AssertThat(container, Is().OfLength(3)); 261 | ``` 262 | 263 | #### IsEmpty Constraint 264 | 265 | Used to verify that a container is empty. 266 | 267 | ```cpp 268 | AssertThat(container, IsEmpty()); 269 | AssertThat(container, Is().Empty()); 270 | ``` 271 | 272 | #### All 273 | 274 | Used to verify that all elements of a STL sequence container matches an expectation. 275 | 276 | ```cpp 277 | AssertThat(container, Has().All().LessThan(5).Or().EqualTo(66)); 278 | ``` 279 | 280 | #### AtLeast 281 | 282 | Used to verify that at least a specified amount of elements in a STL sequence 283 | container matches an expectation. 284 | 285 | ```cpp 286 | AssertThat(container, Has().AtLeast(3).StartingWith("foo")); 287 | ``` 288 | 289 | #### AtMost 290 | 291 | Used to verify that at most a specified amount of elements in a STL sequence 292 | container matches an expectation. 293 | 294 | ```cpp 295 | AssertThat(container, Has().AtMost(2).Not().Containing("failed")); 296 | ``` 297 | 298 | #### Exactly 299 | 300 | Used to verify that a STL sequence container has exactly a specified amount 301 | of elements that matches an expectation. 302 | 303 | ```cpp 304 | AssertThat(container, Has().Exactly(3).GreaterThan(10).And().LessThan(20)); 305 | ``` 306 | 307 | #### EqualsContainer 308 | 309 | Used to verify that two STL sequence containers are equal. 310 | 311 | ```cpp 312 | AssertThat(container1, EqualsContainer(container2)); 313 | AssertThat(container1, Is().EqualToContainer(container2)); 314 | ``` 315 | 316 | ##### Predicate functions 317 | 318 | You can supply a predicate function or a functor to `EqualsContainer` to 319 | customize how to compare the elements in the two containers. 320 | 321 | With a predicate function: 322 | 323 | ```cpp 324 | static bool are_my_types_equal(const my_type& lhs, const my_type& rhs) 325 | { 326 | return lhs.my_val_ == rhs.my_val_; 327 | } 328 | 329 | AssertThat(container1, EqualsContainer(container2, are_my_types_equal)); 330 | ``` 331 | 332 | With a functor as predicate: 333 | 334 | ```cpp 335 | struct within_delta 336 | { 337 | within_delta(int delta) : delta_(delta) {} 338 | 339 | bool operator()(const my_type& lhs, const my_type& rhs) const 340 | { 341 | return abs(lhs.my_val_ - rhs.my_val_) <= delta_; 342 | } 343 | 344 | private: 345 | int delta_; 346 | }; 347 | 348 | AssertThat(container1, Is().EqualToContainer(container1, within_delta(1)); 349 | ``` 350 | 351 | ### Exceptions 352 | 353 | Exception constraints can be used to verify that your code throws the correct exceptions. 354 | 355 | #### AssertThrows 356 | 357 | `AssertThrows` succeeds if the exception thrown by the call is of the supplied 358 | type (or one of its subtypes). 359 | 360 | ```cpp 361 | AssertThrows(std::logic_error, myObject.a_method(42)); 362 | ``` 363 | 364 | #### Making Assertions on the Thrown Exceptions 365 | 366 | If `AssertThrows` succeeds, it will store the thrown exception so that you can 367 | make more detailed assertions on it. 368 | 369 | ```cpp 370 | AssertThrows(std::logic_error, myObject.a_method(42)); 371 | AssertThat(LastException().what(), Is().Containing("logic failure")); 372 | ``` 373 | 374 | The `LastException<>` is available in the scope of the call to `AssertThrows`. 375 | An exception is not available between specs in order to avoid the result of 376 | one spec contaminating another. 377 | 378 | ### Custom Constraints 379 | 380 | You can add your own constraints to Snowhouse to create more expressive specifications. 381 | 382 | #### Fulfills Constraints 383 | 384 | By defining the following matcher 385 | 386 | ```cpp 387 | struct IsEvenNumber 388 | { 389 | bool Matches(const int actual) const 390 | { 391 | return (actual % 2) == 0; 392 | } 393 | 394 | friend std::ostream& operator<<(std::ostream& stm, const IsEvenNumber& ); 395 | }; 396 | 397 | std::ostream& operator<<(std::ostream& stm, const IsEvenNumber& ) 398 | { 399 | stm << "An even number"; 400 | return stm; 401 | } 402 | ``` 403 | 404 | You can create the following constraints in Snowhouse: 405 | 406 | ```cpp 407 | AssertThat(42, Fulfills(IsEvenNumber())); 408 | AssertThat(42, Is().Fulfilling(IsEvenNumber())); 409 | ``` 410 | 411 | Your custom matcher should implement a method called `Matches()` that takes 412 | a parameter of the type you expect and returns true if the passed parameter 413 | fulfills the constraint. 414 | 415 | To get more expressive failure messages, you should also implement the 416 | streaming operator as in the example above. 417 | 418 | ## Getting better output for your types 419 | 420 | Whenever Snowhouse prints an error message for a type, it will use the 421 | stream operator for that type, otherwise it will print "[unsupported type]" 422 | as a placeholder. 423 | 424 | ```cpp 425 | struct MyType { int x; char c; }; 426 | 427 | AssertThat(myType, Fulfills(MyConstraint()); 428 | ``` 429 | 430 | Will output the following if the constraint fails: 431 | 432 | ``` 433 | Expected: To fulfill my constraint 434 | Actual: [unsupported type] 435 | ``` 436 | 437 | If we add a stream operator: 438 | 439 | ```cpp 440 | std::ostream& operator<<(std::ostream& stream, const MyType& a) 441 | { 442 | stream << a.c << a.x; 443 | return stream; 444 | } 445 | ``` 446 | 447 | the output will be a bit more readable: 448 | 449 | ``` 450 | Expected: To fulfill my constraint 451 | Actual: f23 452 | ``` 453 | 454 | If it is necessary to print an object in a different manner than the 455 | usual output stream operator provides, for example, to output more detailed 456 | information, we can use a specialization of the `Stringizer` class template: 457 | 458 | ```cpp 459 | namespace snowhouse 460 | { 461 | template<> 462 | struct Stringizer 463 | { 464 | static std::string ToString(const MyType& a) 465 | { 466 | std::stringstream stream; 467 | stream << "MyType(x = " << a.x << ", c = " << int(a.c) << "('" << a.c << "'))"; 468 | return stream.str(); 469 | } 470 | }; 471 | } 472 | ``` 473 | 474 | with output: 475 | 476 | ``` 477 | Expected: To fulfill my constraint 478 | Actual: MyType(x = 23, c = 102('f')) 479 | ``` 480 | 481 | ## Configurable Failure Handlers 482 | 483 | You can provide Snowhouse with custom failure handlers, for example to 484 | call `std::terminate` instead of throwing an exception. 485 | See `DefaultFailureHandler` for an example of a failure handler. 486 | You can derive your own macros with custom failure handlers using 487 | `SNOWHOUSE_ASSERT_THAT` and `SNOWHOUSE_ASSERT_THROWS`. 488 | See the definitions of `AssertThat` and `AssertThrows` for examples of these. 489 | Define `SNOWHOUSE_NO_MACROS` to disable the unprefixed macros `AssertThat` 490 | and `AssertThrows`. 491 | 492 | ### Example Use Cases 493 | 494 | #### Assert Program State 495 | 496 | Log an error immediately as we may crash if we try to continue. 497 | Do not attempt to unwind the stack as we may be inside a destructor 498 | or `nothrow` function. 499 | We may want to call `std::terminate`, or attempt to muddle along 500 | with the rest of the program. 501 | 502 | #### Assert Program State in Safe Builds 503 | 504 | As above, but only in debug builds. 505 | 506 | #### Test Assert 507 | 508 | Assert that a test behaved as expected. 509 | Throw an exception and let our testing framework deal with the test failure. 510 | 511 | ## Versioning 512 | 513 | Snowhouse uses [Semantic Versioning 2.0.0](http://semver.org/spec/v2.0.0.html) since 514 | version 3.0.0. 515 | 516 | The macros `SNOWHOUSE_MAJOR`, `SNOWHOUSE_MINOR` and `SNOWHOUSE_PATCH` are defined 517 | accordingly and `SNOWHOUSE_VERSION` contains the version string. 518 | Note that in prior versions `SNOWHOUSE_VERSION` was the only defined macro. 519 | 520 | Compatibility-breaking changes since version 3.0.0: 521 | 522 | * Since version 4.0.0, the display of booleans and strings has changed. 523 | Booleans are now displayed as `true` or `false`. 524 | Strings are put into quotation marks for improved readability. 525 | 526 | * Since version 5.0.0, the support for C++ versions prior to C++11 are dropped. 527 | The definition of the macro `SNOWHOUSE_HAS_NULLPTR` is removed. 528 | Our exceptions are now derived from the `std::exception` hierarchy, 529 | thus their method names changed. 530 | 531 | ## Contributing 532 | 533 | The development of Snowhouse takes place on [GitHub](//github.com/banditcpp/snowhouse). 534 | 535 | Snowhouse is licensed under the Boost Software License. 536 | See LICENSE_1_0.txt for further information. 537 | 538 | By making available code for inclusion into Snowhouse (e.g., by opening a 539 | pull request on GitHub), you guarantee that the code is licensed under the 540 | same license as Snowhouse. 541 | 542 | Please make sure to be consistent with the project's coding style. 543 | The `.clang-format` file allows easy checking and implementation of the 544 | coding style. 545 | 546 | C++ code should comply to C++11. 547 | Please use `__cplusplus` guards if you want to use language features of 548 | a certain C++ version. 549 | 550 | ## Responsibilities 551 | 552 | Snowhouse was originally developed as part of the [Igloo](//github.com/joakimkarlsson/igloo) 553 | testing framework by [Joakim Karlsson](//github.com/joakimkarlsson). 554 | It has been extracted to be usable in other contexts, for example, 555 | [Bandit](//github.com/banditcpp/bandit). 556 | 557 | Snowhouse is maintained by [Stephan Beyer](//github.com/sbeyer) since 558 | [October 2016](//twitter.com/JHKarlsson/status/789332548799332352). 559 | -------------------------------------------------------------------------------- /example/basic_assertions.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "tests.h" 4 | 5 | using namespace snowhouse; 6 | 7 | static void throwRuntimeError() 8 | { 9 | throw std::runtime_error("This is expected"); 10 | } 11 | 12 | struct IgnoreErrors 13 | { 14 | template 15 | static void Handle(const ExpectedType&, const ActualType&, const char*, int) 16 | { 17 | } 18 | 19 | static void Handle(const std::string&) 20 | { 21 | } 22 | }; 23 | 24 | void BasicAssertions() 25 | { 26 | describe("Basic assertions"); 27 | 28 | it("handles integer equality"); 29 | { 30 | AssertThat(5, Is().EqualTo(5)); 31 | } 32 | 33 | it("detects integer inequality"); 34 | { 35 | AssertTestFails(AssertThat(5, Is().EqualTo(4)), "equal to 4"); 36 | } 37 | 38 | it("detects if Not() fails"); 39 | { 40 | AssertTestFails(AssertThat(5, Is().Not().EqualTo(5)), "Expected: not equal to 5\nActual: 5\n"); 41 | } 42 | 43 | it("handles strings"); 44 | { 45 | AssertThat(std::string("joakim"), Is().EqualTo(std::string("joakim"))); 46 | } 47 | 48 | it("handles strings without explicit template specialization"); 49 | { 50 | AssertThat("kim", Is().EqualTo("kim")); 51 | } 52 | 53 | it("handles GreaterThan()"); 54 | { 55 | AssertThat(5, Is().GreaterThan(4)); 56 | } 57 | 58 | it("detects when GreaterThan() fails"); 59 | { 60 | AssertTestFails(AssertThat(5, Is().GreaterThan(5)), 61 | "Expected: greater than 5\nActual: 5\n"); 62 | } 63 | 64 | it("handles LessThan()"); 65 | { 66 | AssertThat(5, Is().LessThan(6)); 67 | } 68 | 69 | it("detects when LessThan() fails"); 70 | { 71 | AssertTestFails(AssertThat(6, Is().LessThan(5)), 72 | "Expected: less than 5\nActual: 6\n"); 73 | } 74 | 75 | it("throws explicit failure message"); 76 | { 77 | AssertTestFails(Assert::Failure("foo"), "foo"); 78 | } 79 | 80 | it("contains location information"); 81 | { 82 | int line = -1; 83 | std::string file; 84 | 85 | try 86 | { 87 | Assert::That(5, Equals(2), "filename", 32); 88 | } 89 | catch (const AssertionException& e) 90 | { 91 | line = e.line(); 92 | file = e.file(); 93 | } 94 | 95 | AssertThat(line, Equals(32)); 96 | AssertThat(file, Equals("filename")); 97 | } 98 | 99 | it("ensures exception is thrown"); 100 | { 101 | AssertThrows(std::runtime_error, throwRuntimeError()); 102 | } 103 | 104 | it("ignores the error"); 105 | { 106 | ConfigurableAssert::That(1, Equals(2)); 107 | } 108 | 109 | describe("Assertion expression templates"); 110 | 111 | it("handles integer equality"); 112 | { 113 | AssertThat(5, Equals(5)); 114 | } 115 | 116 | it("detects integer inequality"); 117 | { 118 | AssertTestFails(AssertThat(5, Equals(4)), "equal to 4"); 119 | } 120 | 121 | it("detects if !Equals() fails"); 122 | { 123 | AssertTestFails(AssertThat(5, !Equals(5)), 124 | "Expected: not equal to 5\nActual: 5\n"); 125 | } 126 | 127 | it("handles strings"); 128 | { 129 | AssertThat(std::string("joakim"), Equals(std::string("joakim"))); 130 | } 131 | 132 | it("handles strings without explicit template specialization"); 133 | { 134 | AssertThat("kim", Equals("kim")); 135 | } 136 | 137 | it("handles IsGreaterThan()"); 138 | { 139 | AssertThat(5, IsGreaterThan(4)); 140 | } 141 | 142 | it("handles IsGreaterThanOrEqualTo()"); 143 | { 144 | AssertThat(4, IsGreaterThanOrEqualTo(4)); 145 | AssertThat(5, IsGreaterThanOrEqualTo(4)); 146 | } 147 | 148 | it("detects when IsGreaterThan() fails"); 149 | { 150 | AssertTestFails(AssertThat(5, IsGreaterThan(5)), 151 | "Expected: greater than 5\nActual: 5\n"); 152 | } 153 | 154 | it("detects when IsGreaterThanOrEqualTo() fails"); 155 | { 156 | AssertTestFails(AssertThat(4, IsGreaterThanOrEqualTo(5)), 157 | "Expected: greater than or equal to 5\nActual: 4\n"); 158 | } 159 | 160 | it("handles IsLessThan()"); 161 | { 162 | AssertThat(5, IsLessThan(6)); 163 | } 164 | 165 | it("handles IsLessThanOrEqualTo()"); 166 | { 167 | AssertThat(5, IsLessThanOrEqualTo(6)); 168 | AssertThat(6, IsLessThanOrEqualTo(6)); 169 | } 170 | 171 | it("detects when IsLessThan() fails"); 172 | { 173 | AssertTestFails(AssertThat(6, IsLessThan(5)), 174 | "Expected: less than 5\nActual: 6\n"); 175 | } 176 | 177 | it("detects when IsLessThanOrEqualTo() fails"); 178 | { 179 | AssertTestFails(AssertThat(6, IsLessThanOrEqualTo(5)), 180 | "Expected: less than or equal to 5\nActual: 6\n"); 181 | } 182 | 183 | it("handles IsNull()"); 184 | { 185 | AssertThat(nullptr, IsNull()); 186 | } 187 | 188 | it("handles Is().Null()"); 189 | { 190 | AssertThat(nullptr, Is().Null()); 191 | } 192 | 193 | it("handles !IsNull()"); 194 | { 195 | int anInt = 0; 196 | AssertThat(&anInt, !IsNull()); 197 | } 198 | 199 | it("detects when IsNull() fails (real address)"); 200 | { 201 | int anInt = 0; 202 | std::ostringstream message; 203 | message << "Expected: equal to nullptr\nActual: " << &anInt << "\n"; 204 | AssertTestFails(AssertThat(&anInt, IsNull()), message.str()); 205 | } 206 | 207 | it("detects when Is().Null() fails"); 208 | { 209 | int anInt = 0; 210 | std::ostringstream message; 211 | message << "Expected: equal to nullptr\nActual: " << &anInt << "\n"; 212 | AssertTestFails(AssertThat(&anInt, Is().Null()), message.str()); 213 | } 214 | 215 | it("detects when !IsNull() fails (nullptr)"); 216 | { 217 | std::ostringstream message; 218 | message << "Expected: not equal to nullptr\nActual: nullptr\n"; 219 | 220 | AssertTestFails(AssertThat(nullptr, !IsNull()), message.str()); 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /example/boolean_operators.cpp: -------------------------------------------------------------------------------- 1 | #include "tests.h" 2 | 3 | using namespace snowhouse; 4 | 5 | void BooleanOperators() 6 | { 7 | describe("Boolean operators"); 8 | 9 | it("handles IsFalse()"); 10 | { 11 | AssertThat(false, IsFalse()); 12 | } 13 | 14 | it("handles failing IsFalse()"); 15 | { 16 | AssertTestFails(AssertThat(true, IsFalse()), "Expected: false"); 17 | } 18 | 19 | it("handles IsTrue()"); 20 | { 21 | AssertThat(true, IsTrue()); 22 | } 23 | 24 | it("handles failing IsTrue()"); 25 | { 26 | AssertTestFails(AssertThat(false, IsTrue()), "Expected: true"); 27 | } 28 | 29 | it("handles Is().True()"); 30 | { 31 | AssertThat(true, Is().True()); 32 | AssertTestFails(AssertThat(false, Is().True()), "Expected: true"); 33 | } 34 | 35 | it("handles Is().False()"); 36 | { 37 | AssertThat(false, Is().False()); 38 | AssertTestFails(AssertThat(true, Is().False()), "Expected: false"); 39 | } 40 | 41 | it("treats assert without constraint as boolean constrains"); 42 | { 43 | Assert::That(true); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /example/container_spec.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2013. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include 7 | 8 | #include "tests.h" 9 | 10 | using namespace snowhouse; 11 | 12 | struct my_type 13 | { 14 | explicit my_type(int my_val) 15 | : my_val_(my_val) 16 | { 17 | } 18 | 19 | friend bool operator==(const my_type&, const my_type&); 20 | friend bool operator!=(const my_type&, const my_type&); 21 | friend std::ostream& operator<<(std::ostream&, const my_type&); 22 | 23 | int my_val_; 24 | }; 25 | 26 | bool operator==(const my_type& lhs, const my_type& rhs) 27 | { 28 | return lhs.my_val_ == rhs.my_val_; 29 | } 30 | 31 | bool operator!=(const my_type& lhs, const my_type& rhs) 32 | { 33 | return !(lhs == rhs); 34 | } 35 | 36 | std::ostream& operator<<(std::ostream& stream, const my_type& item) 37 | { 38 | stream << "(my_type: my_val_=" << item.my_val_ << " )"; 39 | return stream; 40 | } 41 | 42 | static bool are_my_types_equal(const my_type& lhs, const my_type& rhs) 43 | { 44 | return lhs.my_val_ == rhs.my_val_; 45 | } 46 | 47 | void ContainerConstraints() 48 | { 49 | describe("Container constraints"); 50 | 51 | it("is able to compare containers of custom types"); 52 | { 53 | const my_type e[] = {my_type(1), my_type(3)}; 54 | const std::list expected(e, e + sizeof(e) / sizeof(e[0])); 55 | std::list my_container_; 56 | my_container_.push_back(my_type(1)); 57 | my_container_.push_back(my_type(3)); 58 | 59 | AssertThat(my_container_, EqualsContainer(expected)); 60 | } 61 | 62 | it("handles failing comparisons"); 63 | { 64 | const my_type e[] = {my_type(1), my_type(2)}; 65 | const std::list expected(e, e + sizeof(e) / sizeof(e[0])); 66 | std::list my_container_; 67 | my_container_.push_back(my_type(1)); 68 | my_container_.push_back(my_type(3)); 69 | 70 | AssertTestFails(AssertThat(my_container_, EqualsContainer(expected)), 71 | "Expected: [ (my_type: my_val_=1 ), (my_type: my_val_=2 ) ]"); 72 | } 73 | 74 | it("handles comparison with a predicate function"); 75 | { 76 | const my_type e[] = {my_type(1), my_type(3)}; 77 | const std::list expected(e, e + sizeof(e) / sizeof(e[0])); 78 | std::list my_container_; 79 | my_container_.push_back(my_type(1)); 80 | my_container_.push_back(my_type(3)); 81 | 82 | AssertThat(my_container_, EqualsContainer(expected, are_my_types_equal)); 83 | AssertThat(my_container_, Is().EqualToContainer(expected, are_my_types_equal)); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /example/custom_matchers_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2013. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include "tests.h" 7 | 8 | using namespace snowhouse; 9 | 10 | struct IsEvenNumberNoStreamOperator 11 | { 12 | bool Matches(const int actual) const 13 | { 14 | return (actual % 2) == 0; 15 | } 16 | }; 17 | 18 | struct IsEvenNumberWithStreamOperator 19 | { 20 | bool Matches(const int actual) const 21 | { 22 | return (actual % 2) == 0; 23 | } 24 | 25 | friend std::ostream& operator<<(std::ostream& stm, 26 | const IsEvenNumberWithStreamOperator&); 27 | }; 28 | 29 | std::ostream& operator<<(std::ostream& stm, 30 | const IsEvenNumberWithStreamOperator&) 31 | { 32 | stm << "An even number"; 33 | return stm; 34 | } 35 | 36 | void CustomMatchers() 37 | { 38 | describe("Custom matchers"); 39 | 40 | it("handles custom matcher"); 41 | { 42 | AssertThat(2, Fulfills(IsEvenNumberNoStreamOperator())); 43 | } 44 | 45 | it("handles custom matcher with fluent"); 46 | { 47 | AssertThat(2, Is().Fulfilling(IsEvenNumberNoStreamOperator())); 48 | } 49 | 50 | it("outputs correct message when fails"); 51 | { 52 | AssertTestFails(AssertThat(3, Fulfills(IsEvenNumberNoStreamOperator())), 53 | "Expected: [unsupported type]\nActual: 3"); 54 | } 55 | 56 | it("outputs correct message when custom stream operator is defined"); 57 | { 58 | AssertTestFails(AssertThat(3, Fulfills(IsEvenNumberWithStreamOperator())), 59 | "Expected: An even number\nActual: 3"); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /example/exceptions_tests.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2013. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include 7 | 8 | #include "tests.h" 9 | 10 | using namespace snowhouse; 11 | 12 | struct ClassWithExceptions 13 | { 14 | int LogicError() 15 | { 16 | throw std::logic_error("not logical!"); 17 | } 18 | 19 | double RangeError() 20 | { 21 | throw std::range_error("range error!"); 22 | } 23 | 24 | void NoError() 25 | { 26 | } 27 | }; 28 | 29 | struct ExpectedException : public std::exception 30 | { 31 | const char* what() const noexcept override 32 | { 33 | return "Description of the exception we expected"; 34 | } 35 | }; 36 | 37 | void ExceptionTests() 38 | { 39 | ClassWithExceptions objectUnderTest; 40 | 41 | describe("Exceptions"); 42 | 43 | it("detects exceptions"); 44 | { 45 | AssertThrows(std::exception, objectUnderTest.LogicError()); 46 | } 47 | 48 | it("asserts on LastException()"); 49 | { 50 | AssertThrows(std::logic_error, objectUnderTest.LogicError()); 51 | AssertThat(LastException().what(), Contains("not logical!")); 52 | } 53 | 54 | it("detects when wrong exception is thrown"); 55 | { 56 | AssertTestFails(AssertThrows(std::logic_error, objectUnderTest.RangeError()), "Wrong exception"); 57 | } 58 | 59 | it("prints expected exception type when wrong exception is thrown"); 60 | { 61 | AssertTestFails(AssertThrows(std::logic_error, objectUnderTest.RangeError()), "Expected std::logic_error"); 62 | } 63 | 64 | it("has several exception assertions in same spec"); 65 | { 66 | AssertThrows(std::logic_error, objectUnderTest.LogicError()); 67 | AssertThat(LastException().what(), Contains("not logical!")); 68 | 69 | AssertThrows(std::range_error, objectUnderTest.RangeError()); 70 | AssertThat(LastException().what(), Contains("range error!")); 71 | } 72 | 73 | it("has several exception assertion for the same exception in same spec"); 74 | { 75 | AssertThrows(std::logic_error, objectUnderTest.LogicError()); 76 | AssertThat(LastException().what(), Contains("not logical!")); 77 | 78 | AssertThrows(std::logic_error, objectUnderTest.LogicError()); 79 | AssertThat(LastException().what(), Contains("not logical!")); 80 | } 81 | 82 | it("detects when no exception is thrown"); 83 | { 84 | AssertTestFails(AssertThrows(std::logic_error, objectUnderTest.NoError()), "No exception"); 85 | } 86 | 87 | it("prints expected exception when no exception is thrown"); 88 | { 89 | AssertTestFails(AssertThrows(std::logic_error, objectUnderTest.NoError()), "Expected std::logic_error"); 90 | } 91 | 92 | it("destroys exceptions when out-of-scope"); 93 | { 94 | { 95 | AssertThrows(std::logic_error, objectUnderTest.LogicError()); 96 | } 97 | AssertThrows(AssertionException, LastException()); 98 | AssertThat(LastException().what(), Contains("No exception was stored")); 99 | } 100 | 101 | it("prints description of unwanted exception"); 102 | { 103 | AssertTestFails(AssertThrows(ExpectedException, objectUnderTest.LogicError()), "Expected ExpectedException. Wrong exception was thrown. Description of unwanted exception: not logical!"); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /example/expression_error_handling.cpp: -------------------------------------------------------------------------------- 1 | #include "tests.h" 2 | 3 | using namespace snowhouse; 4 | 5 | void ExpressionErrorHandling() 6 | { 7 | describe("Expression error handling"); 8 | 9 | std::vector collection; 10 | collection.push_back(1); 11 | collection.push_back(2); 12 | collection.push_back(3); 13 | 14 | it("reports an invalid All() properly"); 15 | { 16 | AssertTestFails(AssertThat(collection, Has().All()), 17 | "The expression after \"all\" operator does not yield any result"); 18 | } 19 | 20 | it("reports an invalid AtLeast() properly"); 21 | { 22 | AssertTestFails(AssertThat(collection, Has().AtLeast(2)), 23 | "The expression after \"at least 2\" operator does not yield any result"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /example/main.cpp: -------------------------------------------------------------------------------- 1 | #include "tests.h" 2 | 3 | using namespace snowhouse; 4 | 5 | void BooleanOperators(); 6 | void BasicAssertions(); 7 | void ContainerConstraints(); 8 | void CustomMatchers(); 9 | void ExceptionTests(); 10 | void ExpressionErrorHandling(); 11 | void MapTests(); 12 | void OperatorTests(); 13 | void SequenceContainerTests(); 14 | void StringLineTests(); 15 | void StringTests(); 16 | void StringizeTests(); 17 | 18 | int main() 19 | { 20 | std::cout << "Spec for Snowhouse " SNOWHOUSE_VERSION << std::endl; 21 | 22 | try 23 | { 24 | BasicAssertions(); 25 | BooleanOperators(); 26 | ContainerConstraints(); 27 | CustomMatchers(); 28 | ExceptionTests(); 29 | ExpressionErrorHandling(); 30 | MapTests(); 31 | OperatorTests(); 32 | SequenceContainerTests(); 33 | StringLineTests(); 34 | StringTests(); 35 | StringizeTests(); 36 | } 37 | catch (const AssertionException& e) 38 | { 39 | std::cout << "Tests failed!" << std::endl; 40 | std::cout << e.what() << std::endl; 41 | return 1; 42 | } 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /example/map_tests.cpp: -------------------------------------------------------------------------------- 1 | #include "tests.h" 2 | 3 | using namespace snowhouse; 4 | 5 | void MapTests() 6 | { 7 | describe("Containing (std::map)"); 8 | 9 | std::map ages; 10 | ages["joakim"] = 38; 11 | ages["maria"] = 36; 12 | ages["hanna"] = 6; 13 | ages["moa"] = 4; 14 | 15 | it("determines if key exists"); 16 | { 17 | AssertThat(ages, Is().Containing("joakim")); 18 | } 19 | 20 | it("gives a proper message when fails"); 21 | { 22 | AssertTestFails(AssertThat(ages, Is().Not().Containing("hanna")), 23 | "Expected: not contains \"hanna\""); 24 | } 25 | 26 | it("determines if key exists"); 27 | { 28 | AssertThat(ages, Contains("joakim")); 29 | } 30 | 31 | it("gives a proper message when Contains() fails"); 32 | { 33 | AssertTestFails(AssertThat(ages, !Contains("hanna")), 34 | "Expected: not contains \"hanna\""); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /example/operator_tests.cpp: -------------------------------------------------------------------------------- 1 | #include "tests.h" 2 | 3 | using namespace snowhouse; 4 | 5 | void OperatorTests() 6 | { 7 | describe("Operators"); 8 | 9 | it("handles &&"); 10 | { 11 | AssertThat(5, IsLessThan(6) && IsGreaterThan(4)); 12 | } 13 | 14 | it("handles And()"); 15 | { 16 | AssertThat(5, Is().LessThan(6).And().GreaterThan(4)); 17 | } 18 | 19 | it("handles failing &&"); 20 | { 21 | AssertTestFails(AssertThat(5, IsLessThan(7) && IsGreaterThan(5)), 22 | "less than 7 and greater than 5"); 23 | } 24 | 25 | it("handles failing And()"); 26 | { 27 | AssertTestFails(AssertThat(5, Is().LessThan(7).And().GreaterThan(5)), 28 | "less than 7 and greater than 5"); 29 | } 30 | 31 | it("handles Or()"); 32 | { 33 | AssertThat(12, Is().LessThan(7).Or().GreaterThan(5)); 34 | } 35 | 36 | it("handles ||"); 37 | { 38 | AssertThat(12, IsLessThan(7) || IsGreaterThan(5)); 39 | } 40 | 41 | it("handles failing Or()"); 42 | { 43 | AssertTestFails(AssertThat(67, Is().LessThan(12).Or().GreaterThan(99)), 44 | "less than 12 or greater than 99"); 45 | } 46 | 47 | it("handles failing ||"); 48 | { 49 | AssertTestFails(AssertThat(67, IsLessThan(12) || IsGreaterThan(99)), 50 | "less than 12 or greater than 99"); 51 | } 52 | 53 | it("handles Not()"); 54 | { 55 | AssertThat(5, Is().Not().EqualTo(4)); 56 | } 57 | 58 | it("handles !"); 59 | { 60 | AssertThat(5, !Equals(4)); 61 | } 62 | 63 | it("handles failing Not()"); 64 | { 65 | AssertTestFails(AssertThat(12, Is().Not().EqualTo(12)), "not equal to 12"); 66 | } 67 | 68 | it("handles failing !"); 69 | { 70 | AssertTestFails(AssertThat(12, !Equals(12)), "not equal to 12"); 71 | } 72 | 73 | it("handles Not() for strings"); 74 | { 75 | AssertThat("joakim", Is().Not().EqualTo("harry")); 76 | } 77 | 78 | it("handles failing ! for strings"); 79 | { 80 | AssertThat("joakim", !Equals("harry")); 81 | } 82 | 83 | it("handles both left and right associative operators"); 84 | { 85 | AssertThat(5, Is().GreaterThan(4).And().Not().LessThan(3)); 86 | } 87 | 88 | it("handles both left and right associative operators expression templates"); 89 | { 90 | AssertThat(5, IsGreaterThan(4) && !IsLessThan(3)); 91 | } 92 | 93 | it("yields error on malformed expression"); 94 | { 95 | AssertTestFails(AssertThat(4, Is().Not()), 96 | "The expression contains a \"not\" operator without any operand"); 97 | } 98 | 99 | it("handles failing EqualsWithDelta() when larger than delta"); 100 | { 101 | AssertTestFails(AssertThat(3.9, EqualsWithDelta(3, 0.5)), 102 | "Expected: equal to 3 (+/- 0.5)"); 103 | } 104 | 105 | it("handles failing EqualsWithDelta() when less than delta"); 106 | { 107 | AssertTestFails(AssertThat(2.49, EqualsWithDelta(3, 0.5)), 108 | "Expected: equal to 3 (+/- 0.5)"); 109 | } 110 | 111 | it("handles EqualsWithDelta()"); 112 | { 113 | AssertThat(2, EqualsWithDelta(1.9, 0.1)); 114 | } 115 | 116 | it("handles failing Is().EqualToWithDelta() when larger than delta"); 117 | { 118 | AssertTestFails(AssertThat(3.9, Is().EqualToWithDelta(3, 0.5)), 119 | "Expected: equal to 3 (+/- 0.5)"); 120 | } 121 | 122 | it("handles failing Is().EqualToWithDelta() when less than delta"); 123 | { 124 | AssertTestFails(AssertThat(2.49, Is().EqualToWithDelta(3, 0.5)), 125 | "Expected: equal to 3 (+/- 0.5)"); 126 | } 127 | 128 | it("handles Is().EqualToWithDelta()"); 129 | { 130 | AssertThat(2, Is().EqualToWithDelta(1.9, 0.1)); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /example/sequence_container_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "tests.h" 8 | 9 | using namespace snowhouse; 10 | 11 | static const char* ExpectedActual = "\nActual: [ 1, 2, 3, 5, 8 ]"; 12 | 13 | template 14 | static void insert_numbers(T& container) 15 | { 16 | container.push_back(1); 17 | container.push_back(2); 18 | container.push_back(3); 19 | container.push_back(5); 20 | container.push_back(8); 21 | } 22 | 23 | template<> 24 | void insert_numbers(std::multiset& container) 25 | { 26 | container.insert(1); 27 | container.insert(2); 28 | container.insert(3); 29 | container.insert(5); 30 | container.insert(8); 31 | } 32 | 33 | template<> 34 | void insert_numbers(std::set& container) 35 | { 36 | container.insert(1); 37 | container.insert(2); 38 | container.insert(3); 39 | container.insert(5); 40 | container.insert(8); 41 | } 42 | 43 | template<> 44 | void insert_numbers(std::array& container) 45 | { 46 | container[0] = 1; 47 | container[1] = 2; 48 | container[2] = 3; 49 | container[3] = 5; 50 | container[4] = 8; 51 | } 52 | 53 | template<> 54 | void insert_numbers(std::forward_list& container) 55 | { 56 | container.push_front(8); 57 | container.push_front(5); 58 | container.push_front(3); 59 | container.push_front(2); 60 | container.push_front(1); 61 | } 62 | 63 | template 64 | static void TestHasAll(const T& container) 65 | { 66 | it("handles All()"); 67 | { 68 | AssertThat(container, Has().All().GreaterThan(1).Or().LessThan(4)); 69 | } 70 | 71 | it("handles failing All()"); 72 | { 73 | AssertTestFails(AssertThat(container, Has().All().GreaterThan(4)), std::string("Expected: all greater than 4") + ExpectedActual); 74 | } 75 | 76 | it("handles invalid expression after All()"); 77 | { 78 | AssertTestFails(AssertThat(container, Has().All().Not()), "The expression contains a \"not\" operator without any operand"); 79 | } 80 | 81 | it("handles no expression after All()"); 82 | { 83 | AssertTestFails(AssertThat(container, Has().All()), "The expression after \"all\" operator does not yield any result"); 84 | } 85 | } 86 | 87 | template<> 88 | void TestHasAll(const std::forward_list&) 89 | { 90 | // The constraint is size-based but there is no size() method available 91 | } 92 | 93 | template 94 | static void TestLength(const T& container) 95 | { 96 | it("handles HasLength()"); 97 | { 98 | AssertThat(container, HasLength(5)); 99 | } 100 | 101 | it("handles failing HasLength()"); 102 | { 103 | AssertTestFails(AssertThat(container, HasLength(7)), std::string("of length 7") + ExpectedActual); 104 | } 105 | 106 | it("handles Is().OfLength()"); 107 | { 108 | AssertThat(container, Is().OfLength(5)); 109 | } 110 | 111 | it("handles failing Is().OfLength()"); 112 | { 113 | AssertTestFails(AssertThat(container, Is().OfLength(7)), std::string("of length 7") + ExpectedActual); 114 | } 115 | } 116 | 117 | template<> 118 | void TestLength(const std::forward_list&) 119 | { 120 | // There is no size() method available 121 | } 122 | 123 | template 124 | static void TestEmpty(const T& container, const TEmpty& is_empty) 125 | { 126 | it("handles IsEmpty()"); 127 | { 128 | AssertThat(is_empty, IsEmpty()); 129 | } 130 | 131 | it("handles failing IsEmpty()"); 132 | { 133 | AssertTestFails(AssertThat(container, IsEmpty()), "empty"); 134 | } 135 | 136 | it("handles Is().Empty()"); 137 | { 138 | AssertThat(is_empty, Is().Empty()); 139 | } 140 | 141 | it("handles failing Is().Empty()"); 142 | { 143 | AssertTestFails(AssertThat(container, Is().Empty()), "empty"); 144 | } 145 | } 146 | 147 | template 148 | void TestEmpty(const T& container) 149 | { 150 | T is_empty; 151 | TestEmpty(container, is_empty); 152 | } 153 | 154 | template<> 155 | void TestEmpty(const std::array& container) 156 | { 157 | std::array is_empty; 158 | TestEmpty(container, is_empty); 159 | } 160 | 161 | template 162 | static void SequenceContainerActual() 163 | { 164 | T container; 165 | insert_numbers(container); 166 | 167 | TestHasAll(container); 168 | 169 | it("handles AtLeast()"); 170 | { 171 | AssertThat(container, Has().AtLeast(1).LessThan(5)); 172 | } 173 | 174 | it("handles failing AtLeast()"); 175 | { 176 | AssertTestFails(AssertThat(container, Has().AtLeast(2).LessThan(2)), std::string("Expected: at least 2 less than 2") + ExpectedActual); 177 | } 178 | 179 | it("handles Exactly()"); 180 | { 181 | AssertThat(container, Has().Exactly(1).EqualTo(3)); 182 | } 183 | 184 | it("handles failing Exactly()"); 185 | { 186 | AssertTestFails(AssertThat(container, Has().Exactly(2).EqualTo(3)), std::string("Expected: exactly 2 equal to 3") + ExpectedActual); 187 | } 188 | 189 | it("handles AtMost()"); 190 | { 191 | AssertThat(container, Has().AtMost(1).EqualTo(5)); 192 | } 193 | 194 | it("handles failing AtMost()"); 195 | { 196 | AssertTestFails(AssertThat(container, Has().AtMost(1).EqualTo(3).Or().EqualTo(5)), std::string("Expected: at most 1 equal to 3 or equal to 5") + ExpectedActual); 197 | } 198 | 199 | it("handles None()"); 200 | { 201 | AssertThat(container, Has().None().EqualTo(666)); 202 | } 203 | 204 | it("handles failing None()"); 205 | { 206 | AssertTestFails(AssertThat(container, Has().None().EqualTo(5)), std::string("Expected: none equal to 5") + ExpectedActual); 207 | } 208 | 209 | it("handles Contains()"); 210 | { 211 | AssertThat(container, Contains(3)); 212 | } 213 | 214 | it("detects failing Contains()"); 215 | { 216 | AssertTestFails(AssertThat(container, Contains(99)), std::string("contains 99") + ExpectedActual); 217 | } 218 | 219 | it("handles Is().Containing()"); 220 | { 221 | AssertThat(container, Is().Containing(3)); 222 | } 223 | 224 | it("detects failing Is().Containing()"); 225 | { 226 | AssertTestFails(AssertThat(container, Is().Containing(99)), std::string("contains 99") + ExpectedActual); 227 | } 228 | 229 | TestLength(container); 230 | 231 | TestEmpty(container); 232 | 233 | it("handles EqualsContainer()"); 234 | { 235 | std::list expected; 236 | expected.assign(container.begin(), container.end()); 237 | 238 | AssertThat(container, EqualsContainer(expected)); 239 | } 240 | 241 | it("handles failing EqualsContainer()"); 242 | { 243 | const int e[] = {4, 2, 4}; 244 | std::list expected(e, e + sizeof(e) / sizeof(e[0])); 245 | 246 | AssertTestFails(AssertThat(container, EqualsContainer(expected)), "Expected: [ 4, 2, 4 ]"); 247 | } 248 | 249 | it("handles Is().EqualToContainer()"); 250 | { 251 | std::list expected; 252 | expected.assign(container.begin(), container.end()); 253 | 254 | AssertThat(container, Is().EqualToContainer(expected)); 255 | } 256 | 257 | it("handles failing Is().EqualToContainer()"); 258 | { 259 | const int e[] = {4, 2, 4}; 260 | std::list expected(e, e + sizeof(e) / sizeof(e[0])); 261 | 262 | AssertTestFails(AssertThat(container, Is().EqualToContainer(expected)), "Expected: [ 4, 2, 4 ]"); 263 | } 264 | } 265 | 266 | void SequenceContainerTests() 267 | { 268 | describe("Sequence containers (std::vector)"); 269 | SequenceContainerActual>(); 270 | 271 | describe("Sequence containers (std::list)"); 272 | SequenceContainerActual>(); 273 | 274 | describe("Sequence containers (std::deque)"); 275 | SequenceContainerActual>(); 276 | 277 | describe("Sequence containers (std::set)"); 278 | SequenceContainerActual>(); 279 | 280 | describe("Sequence containers (std::multiset)"); 281 | SequenceContainerActual>(); 282 | 283 | describe("Sequence containers (std::array)"); 284 | SequenceContainerActual>(); 285 | 286 | describe("Sequence containers (std::forward_list)"); 287 | SequenceContainerActual>(); 288 | } 289 | -------------------------------------------------------------------------------- /example/string_line_tests.cpp: -------------------------------------------------------------------------------- 1 | #include "tests.h" 2 | 3 | using namespace snowhouse; 4 | 5 | void StringLineTests() 6 | { 7 | describe("String lines"); 8 | 9 | it("asserts that at least one line in a stream matches"); 10 | { 11 | AssertThat("First line\n", Has().AtLeast(1).EqualTo("First line")); 12 | } 13 | 14 | it("detects when assertion fails"); 15 | { 16 | AssertTestFails(AssertThat("First line\n", Has().AtLeast(1).EqualTo("Second line")), "Expected: at least 1 equal to \"Second line\""); 17 | } 18 | 19 | it("handles line missing newline"); 20 | { 21 | AssertThat("First line", Has().AtLeast(1).EqualTo("First line")); 22 | } 23 | 24 | it("handles several lines"); 25 | { 26 | std::string lines = "First line\nSecond line"; 27 | AssertThat(lines, Has().Exactly(2).EndingWith("line")); 28 | } 29 | 30 | it("handles Windows line endings"); 31 | { 32 | std::string lines = "First line\r\nSecond line\r\nThird line"; 33 | AssertThat(lines, Has().Exactly(3).EndingWith("line")); 34 | } 35 | 36 | it("matches beginning of lines with Windows line endings"); 37 | { 38 | std::string lines = "First line\nSecond line\r\nThird line"; 39 | AssertThat(lines, Has().Exactly(1).StartingWith("Second")); 40 | } 41 | 42 | it("handles empty lines when using Windows line endings"); 43 | { 44 | std::string lines = "\r\nSecond line\r\n\r\n"; 45 | AssertThat(lines, Has().Exactly(2).OfLength(0)); 46 | } 47 | 48 | it("handles last line missing newline for Windows line endings"); 49 | { 50 | std::string lines = "First line\r\nSecond line"; 51 | AssertThat(lines, Has().Exactly(2).EndingWith("line")); 52 | } 53 | 54 | it("handles all empty lines"); 55 | { 56 | AssertThat("\n\n\n\n\n\n", Has().Exactly(6).OfLength(0)); 57 | } 58 | 59 | it("handles all empty lines with Windows line endings"); 60 | { 61 | AssertThat("\r\n\r\n\r\n", Has().Exactly(3).OfLength(0)); 62 | } 63 | 64 | describe("StringLineParser"); 65 | 66 | it("parses an empty string"); 67 | { 68 | std::vector res; 69 | 70 | StringLineParser::Parse("", res); 71 | 72 | AssertThat(res, HasLength(0)); 73 | } 74 | 75 | it("parses a single line"); 76 | { 77 | std::vector res; 78 | 79 | StringLineParser::Parse("Simple line", res); 80 | 81 | AssertThat(res, HasLength(1)); 82 | AssertThat(res, Has().Exactly(1).EqualTo("Simple line")); 83 | } 84 | 85 | it("parses two lines"); 86 | { 87 | std::vector res; 88 | 89 | StringLineParser::Parse("One line\nTwo lines", res); 90 | 91 | AssertThat(res, HasLength(2)); 92 | AssertThat(res, Has().Exactly(1).EqualTo("One line")); 93 | AssertThat(res, Has().Exactly(1).EqualTo("Two lines")); 94 | } 95 | 96 | it("parses three lines"); 97 | { 98 | std::vector res; 99 | 100 | StringLineParser::Parse("One line\nTwo lines\nThree lines", res); 101 | 102 | AssertThat(res, HasLength(3)); 103 | AssertThat(res, Has().Exactly(1).EqualTo("One line")); 104 | AssertThat(res, Has().Exactly(1).EqualTo("Two lines")); 105 | AssertThat(res, Has().Exactly(1).EqualTo("Three lines")); 106 | } 107 | 108 | it("handles string ending with newline"); 109 | { 110 | std::vector res; 111 | StringLineParser::Parse("One line\n", res); 112 | AssertThat(res, HasLength(1)); 113 | AssertThat(res, Has().Exactly(1).EqualTo("One line")); 114 | } 115 | 116 | it("handles single line with Windows line ending"); 117 | { 118 | std::vector res; 119 | StringLineParser::Parse("One line\r\n", res); 120 | AssertThat(res, HasLength(1)); 121 | AssertThat(res, Has().Exactly(1).EqualTo("One line")); 122 | } 123 | 124 | it("handles two lines with Windows line endings"); 125 | { 126 | std::vector res; 127 | StringLineParser::Parse("One line\r\nTwo lines", res); 128 | AssertThat(res, HasLength(2)); 129 | AssertThat(res, Has().Exactly(1).EqualTo("One line")); 130 | AssertThat(res, Has().Exactly(1).EqualTo("Two lines")); 131 | } 132 | 133 | it("handles empty line with newline"); 134 | { 135 | std::vector res; 136 | StringLineParser::Parse("\n", res); 137 | AssertThat(res, Is().OfLength(1).And().Exactly(1).OfLength(0)); 138 | } 139 | 140 | it("handles two empty lines"); 141 | { 142 | std::vector res; 143 | StringLineParser::Parse("\n\n", res); 144 | AssertThat(res, HasLength(2)); 145 | AssertThat(res, Has().Exactly(2).OfLength(0)); 146 | } 147 | 148 | it("handles two empty lines with Windows line endings"); 149 | { 150 | std::vector res; 151 | StringLineParser::Parse("\r\n\r\n", res); 152 | AssertThat(res, HasLength(2)); 153 | AssertThat(res, Has().Exactly(2).OfLength(0)); 154 | } 155 | 156 | it("handles carriage return only"); 157 | { 158 | std::vector res; 159 | StringLineParser::Parse("One line\rTwo lines", res); 160 | AssertThat(res, HasLength(2)); 161 | AssertThat(res, Has().Exactly(1).EqualTo("One line")); 162 | AssertThat(res, Has().Exactly(1).EqualTo("Two lines")); 163 | } 164 | 165 | it("handles carriage return only at end of string"); 166 | { 167 | std::vector res; 168 | StringLineParser::Parse("One line\r\nTwo lines\r", res); 169 | AssertThat(res, HasLength(2)); 170 | AssertThat(res, Has().Exactly(1).EqualTo("One line")); 171 | AssertThat(res, Has().Exactly(1).EqualTo("Two lines")); 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /example/string_tests.cpp: -------------------------------------------------------------------------------- 1 | #include "tests.h" 2 | 3 | using namespace snowhouse; 4 | 5 | void StringTests() 6 | { 7 | describe("Strings"); 8 | 9 | it("handles string Contains()"); 10 | { 11 | AssertThat("abcdef", Contains("bcde")); 12 | } 13 | 14 | it("handles match at beginning of string"); 15 | { 16 | AssertThat("abcdef", Contains("a")); 17 | } 18 | 19 | it("detects failing Contains()"); 20 | { 21 | AssertTestFails(AssertThat("abcdef", Contains("hello")), "contains \"hello\""); 22 | } 23 | 24 | it("handles string StartsWith()"); 25 | { 26 | AssertThat("abcdef", StartsWith("abc")); 27 | } 28 | 29 | it("handles string EndsWith()"); 30 | { 31 | AssertThat("abcdef", EndsWith("def")); 32 | } 33 | 34 | it("handles operators for strings"); 35 | { 36 | AssertThat("abcdef", StartsWith("ab") && EndsWith("ef")); 37 | } 38 | 39 | it("handles strings with multiple operators"); 40 | { 41 | AssertThat("abcdef", StartsWith("ab") && !EndsWith("qwqw")); 42 | } 43 | 44 | it("handles HasLength()"); 45 | { 46 | AssertThat("12345", HasLength(5)); 47 | } 48 | 49 | it("handles failing HasLength()"); 50 | { 51 | AssertTestFails(AssertThat("1234", HasLength(5)), "of length 5"); 52 | } 53 | 54 | it("handles IsEmpty()"); 55 | { 56 | AssertThat("", IsEmpty()); 57 | } 58 | 59 | it("handles failing IsEmpty()"); 60 | { 61 | AssertTestFails(AssertThat("not empty", IsEmpty()), "empty"); 62 | } 63 | 64 | it("handles weird long expressions"); 65 | { 66 | AssertThat("12345", HasLength(5) && StartsWith("123") && !EndsWith("zyxxy")); 67 | } 68 | 69 | it("handles std::string"); 70 | { 71 | AssertThat("12345", Contains(std::string("23"))); 72 | } 73 | 74 | it("handles simple char"); 75 | { 76 | AssertThat("12345", StartsWith('1')); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /example/stringize_tests.cpp: -------------------------------------------------------------------------------- 1 | #include "tests.h" 2 | 3 | using namespace snowhouse; 4 | 5 | namespace 6 | { 7 | // No overload for operator<<(std::ostream&) or specialization of snowhouse::Stringizer 8 | struct WithoutStreamOperator 9 | { 10 | explicit WithoutStreamOperator(int id) 11 | : m_id(id) 12 | { 13 | } 14 | 15 | bool operator==(const WithoutStreamOperator& rhs) const 16 | { 17 | return m_id == rhs.m_id; 18 | } 19 | 20 | int m_id; 21 | }; 22 | 23 | // Has operator<<(std::ostream&) 24 | struct WithStreamOperator : public WithoutStreamOperator 25 | { 26 | explicit WithStreamOperator(int id) 27 | : WithoutStreamOperator(id) 28 | { 29 | } 30 | }; 31 | 32 | std::ostream& operator<<(std::ostream& stream, const WithStreamOperator& a) 33 | { 34 | stream << a.m_id; 35 | return stream; 36 | } 37 | 38 | // Has no operator<<(std::ostream&), but a specialization of snowhouse::Stringizer 39 | struct WithoutStreamOperatorButWithStringizer : public WithoutStreamOperator 40 | { 41 | explicit WithoutStreamOperatorButWithStringizer(int id) 42 | : WithoutStreamOperator(id) 43 | { 44 | } 45 | }; 46 | } 47 | 48 | namespace snowhouse 49 | { 50 | template<> 51 | struct Stringizer 52 | { 53 | static std::string ToString(const WithoutStreamOperatorButWithStringizer& value) 54 | { 55 | return snowhouse::Stringize(value.m_id); 56 | } 57 | }; 58 | } 59 | 60 | void StringizeTests() 61 | { 62 | describe("Stringize"); 63 | 64 | it("handles types with stream operators"); 65 | { 66 | WithStreamOperator a(12); 67 | WithStreamOperator b(13); 68 | AssertTestFails(AssertThat(a, Is().EqualTo(b)), "Expected: equal to 13\nActual: 12"); 69 | } 70 | 71 | it("handles types without stream operators"); 72 | { 73 | WithoutStreamOperator a(12); 74 | WithoutStreamOperator b(13); 75 | AssertTestFails(AssertThat(a, Is().EqualTo(b)), "Expected: equal to [unsupported type]\nActual: [unsupported type]"); 76 | } 77 | 78 | it("handles types with traits"); 79 | { 80 | WithoutStreamOperatorButWithStringizer a(12); 81 | WithoutStreamOperatorButWithStringizer b(13); 82 | AssertTestFails(AssertThat(a, Is().EqualTo(b)), "Expected: equal to 13\nActual: 12"); 83 | } 84 | 85 | it("provides bools as true or false"); 86 | { 87 | AssertTestFails(AssertThat(false, Is().True()), "Expected: true\nActual: false"); 88 | } 89 | 90 | it("provides strings in quotation marks"); 91 | { 92 | AssertTestFails(AssertThat("wrong", Is().EqualTo("right")), "Expected: equal to \"right\"\nActual: \"wrong\""); 93 | } 94 | 95 | describe("Stringize expression templates"); 96 | 97 | it("handles types with stream operators"); 98 | { 99 | WithStreamOperator a(12); 100 | WithStreamOperator b(13); 101 | AssertTestFails(AssertThat(a, Equals(b)), "Expected: equal to 13\nActual: 12"); 102 | } 103 | 104 | it("handles types without stream operators"); 105 | { 106 | WithoutStreamOperator a(12); 107 | WithoutStreamOperator b(13); 108 | AssertTestFails(AssertThat(a, Equals(b)), "Expected: equal to [unsupported type]\nActual: [unsupported type]"); 109 | } 110 | 111 | it("handles types with traits"); 112 | { 113 | WithoutStreamOperatorButWithStringizer a(12); 114 | WithoutStreamOperatorButWithStringizer b(13); 115 | AssertTestFails(AssertThat(a, Equals(b)), "Expected: equal to 13\nActual: 12"); 116 | } 117 | 118 | it("provides bools as true or false"); 119 | { 120 | AssertTestFails(AssertThat(true, IsFalse()), "Expected: false\nActual: true"); 121 | } 122 | 123 | it("provides strings in quotation marks"); 124 | { 125 | AssertTestFails(AssertThat("wrong", Equals("right")), "Expected: equal to \"right\"\nActual: \"wrong\""); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /example/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef SNOWHOUSE_EXAMPLES_TEST_H 2 | #define SNOWHOUSE_EXAMPLES_TEST_H 3 | 4 | #include 5 | 6 | // clang-format off 7 | #define AssertTestFails(assertion, expected_error_text) \ 8 | std::string SNOWHOUSE_INTERNAL_expected_error = "Test did not fail"; \ 9 | try \ 10 | { \ 11 | assertion; \ 12 | } \ 13 | catch (const AssertionException& exception_from_snowhouse_assertion) \ 14 | { \ 15 | SNOWHOUSE_INTERNAL_expected_error = exception_from_snowhouse_assertion.what(); \ 16 | } \ 17 | AssertThat(SNOWHOUSE_INTERNAL_expected_error, Is().Containing(expected_error_text)); 18 | // clang-format on 19 | 20 | inline void describe(const char* title) 21 | { 22 | std::cout << std::endl 23 | << title << ":" << std::endl; 24 | } 25 | 26 | inline void it(const char* title) 27 | { 28 | std::cout << " - " << title << std::endl; 29 | } 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /include/snowhouse/assert.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_ASSERT_H 7 | #define SNOWHOUSE_ASSERT_H 8 | 9 | #include "assertionexception.h" 10 | #include "fluent/expressionbuilder.h" 11 | 12 | // clang-format off 13 | #define SNOWHOUSE_ASSERT_THAT(P1, P2, FAILURE_HANDLER) \ 14 | ::snowhouse::ConfigurableAssert::That((P1), (P2), __FILE__, __LINE__) 15 | 16 | #ifndef SNOWHOUSE_NO_MACROS 17 | # define AssertThat(P1, P2) \ 18 | SNOWHOUSE_ASSERT_THAT((P1), (P2), ::snowhouse::DefaultFailureHandler) 19 | #endif 20 | // clang-format on 21 | 22 | namespace snowhouse 23 | { 24 | struct DefaultFailureHandler 25 | { 26 | template 27 | static void Handle(const ExpectedType& expected, const ActualType& actual, const char* file_name, int line_number) 28 | { 29 | std::ostringstream str; 30 | 31 | str << "Expected: " << snowhouse::Stringize(expected) << std::endl; 32 | str << "Actual: " << snowhouse::Stringize(actual) << std::endl; 33 | 34 | throw AssertionException(str.str(), file_name, line_number); 35 | } 36 | 37 | static void Handle(const std::string& message) 38 | { 39 | throw AssertionException(message); 40 | } 41 | }; 42 | 43 | template 44 | struct ConfigurableAssert 45 | { 46 | template 47 | static void That(const ActualType& actual, ExpressionBuilder expression, const char* file_name = "", int line_number = 0) 48 | { 49 | try 50 | { 51 | ResultStack result; 52 | OperatorStack operators; 53 | expression.Evaluate(result, operators, actual); 54 | 55 | while (!operators.empty()) 56 | { 57 | ConstraintOperator* op = operators.top(); 58 | op->PerformOperation(result); 59 | operators.pop(); 60 | } 61 | 62 | if (result.empty()) 63 | { 64 | throw InvalidExpressionException("The expression did not yield any result"); 65 | } 66 | 67 | if (!result.top()) 68 | { 69 | FailureHandler::Handle(expression, actual, file_name, line_number); 70 | } 71 | } 72 | catch (const InvalidExpressionException& e) 73 | { 74 | FailureHandler::Handle("Malformed expression: \"" + snowhouse::Stringize(expression) + "\"\n" + e.what()); 75 | } 76 | } 77 | 78 | template 79 | static void That(const char* actual, ExpressionBuilder expression, const char* file_name = "", int line_number = 0) 80 | { 81 | return That(std::string(actual), expression, file_name, line_number); 82 | } 83 | 84 | template 85 | static void That(const ActualType& actual, const ExpressionType& expression, const char* file_name = "", int line_number = 0) 86 | { 87 | if (!expression(actual)) 88 | { 89 | FailureHandler::Handle(expression, actual, file_name, line_number); 90 | } 91 | } 92 | 93 | template 94 | static void That(const char* actual, const ExpressionType& expression, const char* file_name = "", int line_number = 0) 95 | { 96 | return That(std::string(actual), expression, file_name, line_number); 97 | } 98 | 99 | static void That(bool actual) 100 | { 101 | if (!actual) 102 | { 103 | FailureHandler::Handle("Expected: true\nActual: false"); 104 | } 105 | } 106 | 107 | static void Failure(const std::string& message) 108 | { 109 | FailureHandler::Handle(message); 110 | } 111 | }; 112 | 113 | using Assert = ConfigurableAssert; 114 | } 115 | 116 | #endif 117 | -------------------------------------------------------------------------------- /include/snowhouse/assertionexception.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_ASSERTIONEXCEPTION_H 7 | #define SNOWHOUSE_ASSERTIONEXCEPTION_H 8 | 9 | #include 10 | #include 11 | 12 | #include "macros.h" 13 | 14 | namespace snowhouse 15 | { 16 | struct AssertionException : public std::runtime_error 17 | { 18 | explicit AssertionException(const std::string& message, const std::string& filename, unsigned int line_number) 19 | : std::runtime_error(message), m_file(filename), m_line(line_number) 20 | { 21 | } 22 | 23 | explicit AssertionException(const std::string& message) 24 | : AssertionException(message, "", 0) 25 | { 26 | } 27 | 28 | std::string file() const 29 | { 30 | return m_file; 31 | } 32 | 33 | unsigned int line() const 34 | { 35 | return m_line; 36 | } 37 | 38 | private: 39 | std::string m_file; 40 | unsigned int m_line; 41 | }; 42 | } 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /include/snowhouse/constraints/constraints.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_CONSTRAINTS_H 7 | #define SNOWHOUSE_CONSTRAINTS_H 8 | 9 | #include "containsconstraint.h" 10 | #include "endswithconstraint.h" 11 | #include "equalsconstraint.h" 12 | #include "haslengthconstraint.h" 13 | #include "isemptyconstraint.h" 14 | #include "isgreaterthanconstraint.h" 15 | #include "isgreaterthanorequaltoconstraint.h" 16 | #include "islessthanconstraint.h" 17 | #include "islessthanorequaltoconstraint.h" 18 | #include "startswithconstraint.h" 19 | #include "fulfillsconstraint.h" 20 | #include "equalswithdeltaconstraint.h" 21 | #include "equalscontainerconstraint.h" 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /include/snowhouse/constraints/containsconstraint.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_CONTAINSCONSTRAINT_H 7 | #define SNOWHOUSE_CONTAINSCONSTRAINT_H 8 | 9 | #include 10 | #include 11 | 12 | #include "expressions/expression.h" 13 | 14 | namespace snowhouse 15 | { 16 | template 17 | struct find_in_container_traits 18 | { 19 | template 20 | static bool find(const ContainerType& container, const ExpectedType& expected) 21 | { 22 | return std::find(container.begin(), container.end(), expected) != container.end(); 23 | } 24 | }; 25 | 26 | template 27 | struct find_in_container_traits> 28 | { 29 | template 30 | static bool find(const std::map& container, const ExpectedType& expected) 31 | { 32 | return container.find(expected) != container.end(); 33 | } 34 | }; 35 | 36 | template 37 | struct ContainsConstraint : Expression> 38 | { 39 | ContainsConstraint(const ExpectedType& expected) 40 | : m_expected(expected) 41 | { 42 | } 43 | 44 | template 45 | bool operator()(const ActualType& actual) const 46 | { 47 | return find_in_container_traits::find(actual, m_expected); 48 | } 49 | 50 | bool operator()(const std::string& actual) const 51 | { 52 | return actual.find(m_expected) != std::string::npos; 53 | } 54 | 55 | ExpectedType m_expected; 56 | }; 57 | 58 | template 59 | inline ContainsConstraint Contains(const ExpectedType& expected) 60 | { 61 | return ContainsConstraint(expected); 62 | } 63 | 64 | inline ContainsConstraint Contains(const char* expected) 65 | { 66 | return ContainsConstraint(expected); 67 | } 68 | 69 | template 70 | struct Stringizer> 71 | { 72 | static std::string ToString(const ContainsConstraint& constraint) 73 | { 74 | std::ostringstream builder; 75 | builder << "contains " << snowhouse::Stringize(constraint.m_expected); 76 | 77 | return builder.str(); 78 | } 79 | }; 80 | } 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /include/snowhouse/constraints/endswithconstraint.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_ENDSWITHCONSTRAINT_H 7 | #define SNOWHOUSE_ENDSWITHCONSTRAINT_H 8 | 9 | #include "expressions/expression.h" 10 | 11 | namespace snowhouse 12 | { 13 | template 14 | struct EndsWithConstraint : Expression> 15 | { 16 | EndsWithConstraint(const ExpectedType& expected) 17 | : m_expected(expected) 18 | { 19 | } 20 | 21 | bool operator()(const std::string& actual) const 22 | { 23 | size_t expectedPos = actual.length() - m_expected.length(); 24 | return actual.find(m_expected) == expectedPos; 25 | } 26 | 27 | ExpectedType m_expected; 28 | }; 29 | 30 | template 31 | inline EndsWithConstraint EndsWith(const ExpectedType& expected) 32 | { 33 | return EndsWithConstraint(expected); 34 | } 35 | 36 | inline EndsWithConstraint EndsWith(const char* expected) 37 | { 38 | return EndsWithConstraint(expected); 39 | } 40 | 41 | template 42 | struct Stringizer> 43 | { 44 | static std::string ToString(const EndsWithConstraint& constraint) 45 | { 46 | std::ostringstream builder; 47 | builder << "ends with " << snowhouse::Stringize(constraint.m_expected); 48 | 49 | return builder.str(); 50 | } 51 | }; 52 | } 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /include/snowhouse/constraints/equalsconstraint.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_EQUALSCONSTRAINT_H 7 | #define SNOWHOUSE_EQUALSCONSTRAINT_H 8 | 9 | #include "expressions/expression.h" 10 | 11 | namespace snowhouse 12 | { 13 | template 14 | struct EqualsConstraint : Expression> 15 | { 16 | EqualsConstraint(const ExpectedType& expected) 17 | : m_expected(expected) 18 | { 19 | } 20 | 21 | template 22 | bool operator()(const ActualType& actual) const 23 | { 24 | return (m_expected == actual); 25 | } 26 | 27 | ExpectedType m_expected; 28 | }; 29 | 30 | template 31 | inline EqualsConstraint Equals(const ExpectedType& expected) 32 | { 33 | return EqualsConstraint(expected); 34 | } 35 | 36 | inline EqualsConstraint Equals(const char* expected) 37 | { 38 | return EqualsConstraint(expected); 39 | } 40 | 41 | inline EqualsConstraint IsFalse() 42 | { 43 | return EqualsConstraint(false); 44 | } 45 | 46 | inline EqualsConstraint IsTrue() 47 | { 48 | return EqualsConstraint(true); 49 | } 50 | 51 | inline EqualsConstraint IsNull() 52 | { 53 | return EqualsConstraint(nullptr); 54 | } 55 | 56 | template<> 57 | struct Stringizer> 58 | { 59 | static std::string ToString(const EqualsConstraint& constraint) 60 | { 61 | return constraint.m_expected ? "true" : "false"; 62 | } 63 | }; 64 | 65 | template 66 | struct Stringizer> 67 | { 68 | static std::string ToString(const EqualsConstraint& constraint) 69 | { 70 | std::ostringstream builder; 71 | builder << "equal to " << snowhouse::Stringize(constraint.m_expected); 72 | 73 | return builder.str(); 74 | } 75 | }; 76 | } 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /include/snowhouse/constraints/equalscontainerconstraint.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_EQUALSCONTAINERCONSTRAINT_H 7 | #define SNOWHOUSE_EQUALSCONTAINERCONSTRAINT_H 8 | 9 | #include "expressions/expression.h" 10 | 11 | namespace snowhouse 12 | { 13 | namespace constraint_internal 14 | { 15 | template 16 | inline bool default_comparer(const T& lhs, const T& rhs) 17 | { 18 | return lhs == rhs; 19 | } 20 | } 21 | 22 | template 23 | struct EqualsContainerConstraint : Expression> 24 | { 25 | EqualsContainerConstraint(const ExpectedType& expected, const BinaryPredicate predicate) 26 | : m_expected(expected), m_predicate(predicate) 27 | { 28 | } 29 | 30 | template 31 | bool operator()(const ActualType& actual) const 32 | { 33 | typename ActualType::const_iterator actual_it; 34 | typename ExpectedType::const_iterator expected_it; 35 | 36 | for (actual_it = actual.begin(), expected_it = m_expected.begin(); actual_it != actual.end() && expected_it != m_expected.end(); ++actual_it, ++expected_it) 37 | { 38 | if (!m_predicate(*actual_it, *expected_it)) 39 | { 40 | return false; 41 | } 42 | } 43 | 44 | return actual_it == actual.end() && expected_it == m_expected.end(); 45 | } 46 | 47 | const ExpectedType m_expected; 48 | const BinaryPredicate m_predicate; 49 | }; 50 | 51 | template 52 | inline EqualsContainerConstraint EqualsContainer(const ExpectedType& expected) 53 | { 54 | return EqualsContainerConstraint(expected, constraint_internal::default_comparer); 55 | } 56 | 57 | template 58 | inline EqualsContainerConstraint EqualsContainer(const ExpectedType& expected, const BinaryPredicate predicate) 59 | { 60 | return EqualsContainerConstraint(expected, predicate); 61 | } 62 | 63 | template 64 | struct Stringizer> 65 | { 66 | static std::string ToString(const EqualsContainerConstraint& constraint) 67 | { 68 | std::ostringstream builder; 69 | builder << snowhouse::Stringize(constraint.m_expected); 70 | return builder.str(); 71 | } 72 | }; 73 | } 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /include/snowhouse/constraints/equalswithdeltaconstraint.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_EQUALSWITHDELTACONSTRAINT_H 7 | #define SNOWHOUSE_EQUALSWITHDELTACONSTRAINT_H 8 | 9 | #include "expressions/expression.h" 10 | 11 | namespace snowhouse 12 | { 13 | template 14 | struct EqualsWithDeltaConstraint : Expression> 15 | { 16 | EqualsWithDeltaConstraint(const ExpectedType& expected, const DeltaType& delta) 17 | : m_expected(expected), m_delta(delta) 18 | { 19 | } 20 | 21 | template 22 | bool operator()(const ActualType& actual) const 23 | { 24 | return ((m_expected <= (actual + m_delta)) && (m_expected >= (actual - m_delta))); 25 | } 26 | 27 | ExpectedType m_expected; 28 | DeltaType m_delta; 29 | }; 30 | 31 | template 32 | inline EqualsWithDeltaConstraint EqualsWithDelta(const ExpectedType& expected, const DeltaType& delta) 33 | { 34 | return EqualsWithDeltaConstraint(expected, delta); 35 | } 36 | 37 | template 38 | struct Stringizer> 39 | { 40 | static std::string ToString(const EqualsWithDeltaConstraint& constraint) 41 | { 42 | std::ostringstream builder; 43 | builder << "equal to " << snowhouse::Stringize(constraint.m_expected) << " (+/- " << snowhouse::Stringize(constraint.m_delta) << ")"; 44 | 45 | return builder.str(); 46 | } 47 | }; 48 | } 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /include/snowhouse/constraints/expressions/andexpression.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_ANDEXPRESSION_H 7 | #define SNOWHOUSE_ANDEXPRESSION_H 8 | 9 | #include "../../stringize.h" 10 | #include "expression_fwd.h" 11 | 12 | namespace snowhouse 13 | { 14 | template 15 | struct AndExpression : Expression> 16 | { 17 | AndExpression(const LeftExpression& left, const RightExpression& right) 18 | : m_left(left), m_right(right) 19 | { 20 | } 21 | 22 | template 23 | bool operator()(const ActualType& actual) const 24 | { 25 | return (m_left(actual) && m_right(actual)); 26 | } 27 | 28 | LeftExpression m_left; 29 | RightExpression m_right; 30 | }; 31 | 32 | template 33 | struct Stringizer> 34 | { 35 | static std::string ToString(const AndExpression& expression) 36 | { 37 | std::ostringstream builder; 38 | builder << Stringize(expression.m_left) << " and " << Stringize(expression.m_right); 39 | 40 | return builder.str(); 41 | } 42 | }; 43 | } 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /include/snowhouse/constraints/expressions/expression.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_EXPRESSION_H 7 | #define SNOWHOUSE_EXPRESSION_H 8 | 9 | #include "notexpression.h" 10 | #include "andexpression.h" 11 | #include "orexpression.h" 12 | 13 | namespace snowhouse 14 | { 15 | template 16 | struct Expression 17 | { 18 | NotExpression operator!() const 19 | { 20 | return NotExpression(static_cast(*this)); 21 | } 22 | 23 | template 24 | AndExpression operator&&(const Right& right) const 25 | { 26 | return AndExpression(static_cast(*this), right); 27 | } 28 | 29 | template 30 | OrExpression operator||(const Right& right) const 31 | { 32 | return OrExpression(static_cast(*this), right); 33 | } 34 | }; 35 | } 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /include/snowhouse/constraints/expressions/expression_fwd.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_EXPRESSION_FWD_H 7 | #define SNOWHOUSE_EXPRESSION_FWD_H 8 | 9 | namespace snowhouse 10 | { 11 | template 12 | struct Expression; 13 | } 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /include/snowhouse/constraints/expressions/notexpression.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_NOTEXPRESSION_H 7 | #define SNOWHOUSE_NOTEXPRESSION_H 8 | 9 | #include "../../stringize.h" 10 | #include "expression_fwd.h" 11 | 12 | namespace snowhouse 13 | { 14 | template 15 | struct NotExpression : Expression> 16 | { 17 | explicit NotExpression(const ExpressionType& expression) 18 | : m_expression(expression) 19 | { 20 | } 21 | 22 | template 23 | bool operator()(const ActualType& actual) const 24 | { 25 | return !m_expression(actual); 26 | } 27 | 28 | ExpressionType m_expression; 29 | }; 30 | 31 | template 32 | struct Stringizer> 33 | { 34 | static std::string ToString(const NotExpression& expression) 35 | { 36 | std::ostringstream builder; 37 | builder << "not " << snowhouse::Stringize(expression.m_expression); 38 | 39 | return builder.str(); 40 | } 41 | }; 42 | } 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /include/snowhouse/constraints/expressions/orexpression.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_OREXPRESSION_H 7 | #define SNOWHOUSE_OREXPRESSION_H 8 | 9 | #include "../../stringize.h" 10 | #include "expression_fwd.h" 11 | 12 | namespace snowhouse 13 | { 14 | template 15 | struct OrExpression : Expression> 16 | { 17 | OrExpression(const LeftExpression& left, const RightExpression& right) 18 | : m_left(left), m_right(right) 19 | { 20 | } 21 | 22 | template 23 | bool operator()(const ActualType& actual) const 24 | { 25 | return (m_left(actual) || m_right(actual)); 26 | } 27 | 28 | LeftExpression m_left; 29 | RightExpression m_right; 30 | }; 31 | 32 | template 33 | struct Stringizer> 34 | { 35 | static std::string ToString(const OrExpression& expression) 36 | { 37 | std::ostringstream builder; 38 | builder << snowhouse::Stringize(expression.m_left) << " or " << snowhouse::Stringize(expression.m_right); 39 | 40 | return builder.str(); 41 | } 42 | }; 43 | } 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /include/snowhouse/constraints/fulfillsconstraint.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_FULFILLSCONSTRAINT_H 7 | #define SNOWHOUSE_FULFILLSCONSTRAINT_H 8 | 9 | #include "expressions/expression.h" 10 | 11 | namespace snowhouse 12 | { 13 | template 14 | struct FulfillsConstraint : Expression> 15 | { 16 | FulfillsConstraint(const MatcherType& matcher) 17 | : m_matcher(matcher) 18 | { 19 | } 20 | 21 | template 22 | bool operator()(const ActualType& actual) const 23 | { 24 | return m_matcher.Matches(actual); 25 | } 26 | 27 | MatcherType m_matcher; 28 | }; 29 | 30 | template 31 | inline FulfillsConstraint Fulfills(const MatcherType& matcher) 32 | { 33 | return FulfillsConstraint(matcher); 34 | } 35 | 36 | template 37 | struct Stringizer> 38 | { 39 | static std::string ToString(const FulfillsConstraint& constraint) 40 | { 41 | std::ostringstream builder; 42 | builder << snowhouse::Stringize(constraint.m_matcher); 43 | 44 | return builder.str(); 45 | } 46 | }; 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /include/snowhouse/constraints/haslengthconstraint.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_HASLENGTHCONSTRAINT_H 7 | #define SNOWHOUSE_HASLENGTHCONSTRAINT_H 8 | 9 | #include "expressions/expression.h" 10 | 11 | namespace snowhouse 12 | { 13 | template 14 | struct HasLengthConstraint : Expression> 15 | { 16 | HasLengthConstraint(const ExpectedType& expected) 17 | : m_expected(expected) 18 | { 19 | } 20 | 21 | template 22 | bool operator()(const ActualType& actual) const 23 | { 24 | using SizeType = typename ActualType::size_type; 25 | SizeType expectedSize = static_cast(m_expected); 26 | return (actual.size() == expectedSize); 27 | } 28 | 29 | ExpectedType m_expected; 30 | }; 31 | 32 | template 33 | inline HasLengthConstraint HasLength(const ExpectedType& expected) 34 | { 35 | return HasLengthConstraint(expected); 36 | } 37 | 38 | inline HasLengthConstraint HasLength(const char* expected) 39 | { 40 | return HasLengthConstraint(expected); 41 | } 42 | 43 | template 44 | struct Stringizer> 45 | { 46 | static std::string ToString(const HasLengthConstraint& constraint) 47 | { 48 | std::ostringstream builder; 49 | builder << "of length " << snowhouse::Stringize(constraint.m_expected); 50 | 51 | return builder.str(); 52 | } 53 | }; 54 | } 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /include/snowhouse/constraints/isemptyconstraint.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Stephan Beyer 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #ifndef SNOWHOUSE_ISEMPTYCONSTRAINT_H 6 | #define SNOWHOUSE_ISEMPTYCONSTRAINT_H 7 | 8 | #include "expressions/expression.h" 9 | 10 | namespace snowhouse 11 | { 12 | struct IsEmptyConstraint : Expression 13 | { 14 | // The ignored default argument is a workaround to make this class 15 | // compatible to ConstraintAdapterType 16 | IsEmptyConstraint(int = 0) 17 | { 18 | } 19 | 20 | template 21 | bool operator()(const ActualType& actual) const 22 | { 23 | return actual.empty(); 24 | } 25 | }; 26 | 27 | inline IsEmptyConstraint IsEmpty() 28 | { 29 | return IsEmptyConstraint(); 30 | } 31 | 32 | template<> 33 | struct Stringizer 34 | { 35 | static std::string ToString(const IsEmptyConstraint&) 36 | { 37 | return "empty"; 38 | } 39 | }; 40 | } 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /include/snowhouse/constraints/isgreaterthanconstraint.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_ISGREATERTHANCONSTRAINT_H 7 | #define SNOWHOUSE_ISGREATERTHANCONSTRAINT_H 8 | 9 | #include "expressions/expression.h" 10 | 11 | namespace snowhouse 12 | { 13 | template 14 | struct IsGreaterThanConstraint : Expression> 15 | { 16 | IsGreaterThanConstraint(const ExpectedType& expected) 17 | : m_expected(expected) 18 | { 19 | } 20 | 21 | template 22 | bool operator()(const ActualType& actual) const 23 | { 24 | return (actual > m_expected); 25 | } 26 | 27 | ExpectedType m_expected; 28 | }; 29 | 30 | template 31 | inline IsGreaterThanConstraint IsGreaterThan(const ExpectedType& expected) 32 | { 33 | return IsGreaterThanConstraint(expected); 34 | } 35 | 36 | inline IsGreaterThanConstraint IsGreaterThan(const char* expected) 37 | { 38 | return IsGreaterThanConstraint(expected); 39 | } 40 | 41 | template 42 | struct Stringizer> 43 | { 44 | static std::string ToString(const IsGreaterThanConstraint& constraint) 45 | { 46 | std::ostringstream builder; 47 | builder << "greater than " << snowhouse::Stringize(constraint.m_expected); 48 | 49 | return builder.str(); 50 | } 51 | }; 52 | } 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /include/snowhouse/constraints/isgreaterthanorequaltoconstraint.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_ISGREATERTHANOREQUALTOCONSTRAINT_H 7 | #define SNOWHOUSE_ISGREATERTHANOREQUALTOCONSTRAINT_H 8 | 9 | #include "expressions/expression.h" 10 | 11 | namespace snowhouse 12 | { 13 | template 14 | struct IsGreaterThanOrEqualToConstraint : Expression> 15 | { 16 | IsGreaterThanOrEqualToConstraint(const ExpectedType& expected) 17 | : m_expected(expected) 18 | { 19 | } 20 | 21 | template 22 | bool operator()(const ActualType& actual) const 23 | { 24 | return (actual >= m_expected); 25 | } 26 | 27 | ExpectedType m_expected; 28 | }; 29 | 30 | template 31 | inline IsGreaterThanOrEqualToConstraint IsGreaterThanOrEqualTo(const ExpectedType& expected) 32 | { 33 | return IsGreaterThanOrEqualToConstraint(expected); 34 | } 35 | 36 | inline IsGreaterThanOrEqualToConstraint IsGreaterThanOrEqualTo(const char* expected) 37 | { 38 | return IsGreaterThanOrEqualToConstraint(expected); 39 | } 40 | 41 | template 42 | struct Stringizer> 43 | { 44 | static std::string ToString(const IsGreaterThanOrEqualToConstraint& constraint) 45 | { 46 | std::ostringstream builder; 47 | builder << "greater than or equal to " << snowhouse::Stringize(constraint.m_expected); 48 | 49 | return builder.str(); 50 | } 51 | }; 52 | } 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /include/snowhouse/constraints/islessthanconstraint.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_ISLESSTHANCONSTRAINT_H 7 | #define SNOWHOUSE_ISLESSTHANCONSTRAINT_H 8 | 9 | #include "expressions/expression.h" 10 | 11 | namespace snowhouse 12 | { 13 | template 14 | struct IsLessThanConstraint : Expression> 15 | { 16 | IsLessThanConstraint(const ExpectedType& expected) 17 | : m_expected(expected) 18 | { 19 | } 20 | 21 | template 22 | bool operator()(const ActualType& actual) const 23 | { 24 | return (actual < m_expected); 25 | } 26 | 27 | ExpectedType m_expected; 28 | }; 29 | 30 | template 31 | inline IsLessThanConstraint IsLessThan(const ExpectedType& expected) 32 | { 33 | return IsLessThanConstraint(expected); 34 | } 35 | 36 | inline IsLessThanConstraint IsLessThan(const char* expected) 37 | { 38 | return IsLessThanConstraint(expected); 39 | } 40 | 41 | template 42 | struct Stringizer> 43 | { 44 | static std::string ToString(const IsLessThanConstraint& constraint) 45 | { 46 | std::ostringstream builder; 47 | builder << "less than " << snowhouse::Stringize(constraint.m_expected); 48 | 49 | return builder.str(); 50 | } 51 | }; 52 | } 53 | #endif 54 | -------------------------------------------------------------------------------- /include/snowhouse/constraints/islessthanorequaltoconstraint.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_ISLESSTHANOREQUALTOCONSTRAINT_H 7 | #define SNOWHOUSE_ISLESSTHANOREQUALTOCONSTRAINT_H 8 | 9 | #include "expressions/expression.h" 10 | 11 | namespace snowhouse 12 | { 13 | template 14 | struct IsLessThanOrEqualToConstraint : Expression> 15 | { 16 | IsLessThanOrEqualToConstraint(const ExpectedType& expected) 17 | : m_expected(expected) 18 | { 19 | } 20 | 21 | template 22 | bool operator()(const ActualType& actual) const 23 | { 24 | return (actual <= m_expected); 25 | } 26 | 27 | ExpectedType m_expected; 28 | }; 29 | 30 | template 31 | inline IsLessThanOrEqualToConstraint IsLessThanOrEqualTo(const ExpectedType& expected) 32 | { 33 | return IsLessThanOrEqualToConstraint(expected); 34 | } 35 | 36 | inline IsLessThanOrEqualToConstraint IsLessThanOrEqualTo(const char* expected) 37 | { 38 | return IsLessThanOrEqualToConstraint(expected); 39 | } 40 | 41 | template 42 | struct Stringizer> 43 | { 44 | static std::string ToString(const IsLessThanOrEqualToConstraint& constraint) 45 | { 46 | std::ostringstream builder; 47 | builder << "less than or equal to " << snowhouse::Stringize(constraint.m_expected); 48 | 49 | return builder.str(); 50 | } 51 | }; 52 | } 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /include/snowhouse/constraints/startswithconstraint.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_STARTSWITHCONSTRAINT_H 7 | #define SNOWHOUSE_STARTSWITHCONSTRAINT_H 8 | 9 | #include "expressions/expression.h" 10 | 11 | namespace snowhouse 12 | { 13 | template 14 | struct StartsWithConstraint : Expression> 15 | { 16 | StartsWithConstraint(const ExpectedType& expected) 17 | : m_expected(expected) 18 | { 19 | } 20 | 21 | bool operator()(const std::string& actual) const 22 | { 23 | return actual.find(m_expected) == 0; 24 | } 25 | 26 | ExpectedType m_expected; 27 | }; 28 | 29 | template 30 | inline StartsWithConstraint StartsWith(const ExpectedType& expected) 31 | { 32 | return StartsWithConstraint(expected); 33 | } 34 | 35 | inline StartsWithConstraint StartsWith(const char* expected) 36 | { 37 | return StartsWithConstraint(expected); 38 | } 39 | 40 | template 41 | struct Stringizer> 42 | { 43 | static std::string ToString(const StartsWithConstraint& constraint) 44 | { 45 | std::ostringstream builder; 46 | builder << "starts with " << snowhouse::Stringize(constraint.m_expected); 47 | 48 | return builder.str(); 49 | } 50 | }; 51 | } 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /include/snowhouse/exceptions.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_EXCEPTIONS_H 7 | #define SNOWHOUSE_EXCEPTIONS_H 8 | 9 | #include "assert.h" 10 | 11 | namespace snowhouse 12 | { 13 | template 14 | struct ExceptionStorage 15 | { 16 | static void last_exception(ExceptionType*** e, bool clear = false) 17 | { 18 | static ExceptionType* last = nullptr; 19 | if (clear && last) 20 | { 21 | delete last; 22 | return; 23 | } 24 | 25 | *e = &last; 26 | silly_warning_about_unused_arg(e); 27 | } 28 | 29 | static ExceptionType*** silly_warning_about_unused_arg(ExceptionType*** e) 30 | { 31 | return e; 32 | } 33 | 34 | static void store(const ExceptionType& e) 35 | { 36 | ExceptionType** last = nullptr; 37 | last_exception(&last); 38 | if (*last) 39 | { 40 | delete *last; 41 | *last = nullptr; 42 | } 43 | 44 | *last = new ExceptionType(e); 45 | } 46 | 47 | void compiler_thinks_i_am_unused() 48 | { 49 | } 50 | 51 | ~ExceptionStorage() 52 | { 53 | ExceptionType** e = nullptr; 54 | last_exception(&e); 55 | if (*e) 56 | { 57 | delete *e; 58 | *e = nullptr; 59 | } 60 | } 61 | }; 62 | 63 | template 64 | inline ExceptionType& LastException() 65 | { 66 | ExceptionType** e = nullptr; 67 | ExceptionStorage::last_exception(&e); 68 | if (*e == nullptr) 69 | { 70 | Assert::Failure("No exception was stored"); 71 | } 72 | 73 | return **e; 74 | } 75 | } 76 | 77 | // clang-format off 78 | #define SNOWHOUSE_CONCAT2(a, b) a##b 79 | #define SNOWHOUSE_CONCAT(a, b) SNOWHOUSE_CONCAT2(a, b) 80 | #define SNOWHOUSE_LINESUFFIX(a) SNOWHOUSE_CONCAT(a, __LINE__) 81 | #define SNOWHOUSE_TEMPVAR(a) SNOWHOUSE_CONCAT(SNOWHOUSE_, SNOWHOUSE_LINESUFFIX(a ## _)) 82 | 83 | #define SNOWHOUSE_ASSERT_THROWS(EXCEPTION_TYPE, METHOD, FAILURE_HANDLER_TYPE) \ 84 | ::snowhouse::ExceptionStorage SNOWHOUSE_TEMPVAR(storage); \ 85 | SNOWHOUSE_TEMPVAR(storage).compiler_thinks_i_am_unused(); \ 86 | bool SNOWHOUSE_TEMPVAR(wrong_exception) = false; \ 87 | bool SNOWHOUSE_TEMPVAR(no_exception) = false; \ 88 | bool SNOWHOUSE_TEMPVAR(more_info) = true; \ 89 | std::string SNOWHOUSE_TEMPVAR(info_string); \ 90 | try \ 91 | { \ 92 | METHOD; \ 93 | SNOWHOUSE_TEMPVAR(no_exception) = true; \ 94 | } \ 95 | catch (const EXCEPTION_TYPE& SNOWHOUSE_TEMPVAR(catched_exception)) \ 96 | { \ 97 | ::snowhouse::ExceptionStorage::store(SNOWHOUSE_TEMPVAR(catched_exception)); \ 98 | } \ 99 | catch (...) \ 100 | { \ 101 | SNOWHOUSE_TEMPVAR(wrong_exception) = true; \ 102 | if (auto eptr = std::current_exception()) { \ 103 | try { \ 104 | std::rethrow_exception(eptr); \ 105 | } catch (const std::exception& e) { \ 106 | SNOWHOUSE_TEMPVAR(more_info) = true; \ 107 | SNOWHOUSE_TEMPVAR(info_string) = e.what(); \ 108 | } catch (...) {} \ 109 | } \ 110 | } \ 111 | if (SNOWHOUSE_TEMPVAR(no_exception)) \ 112 | { \ 113 | ::std::ostringstream SNOWHOUSE_TEMPVAR(stm); \ 114 | SNOWHOUSE_TEMPVAR(stm) << "Expected " #EXCEPTION_TYPE ". No exception was thrown."; \ 115 | ::snowhouse::ConfigurableAssert::Failure(SNOWHOUSE_TEMPVAR(stm).str()); \ 116 | } \ 117 | if (SNOWHOUSE_TEMPVAR(wrong_exception)) \ 118 | { \ 119 | ::std::ostringstream SNOWHOUSE_TEMPVAR(stm); \ 120 | SNOWHOUSE_TEMPVAR(stm) << "Expected " #EXCEPTION_TYPE ". Wrong exception was thrown."; \ 121 | if (SNOWHOUSE_TEMPVAR(more_info)) { \ 122 | SNOWHOUSE_TEMPVAR(stm) << " Description of unwanted exception: " << SNOWHOUSE_TEMPVAR(info_string); \ 123 | } \ 124 | ::snowhouse::ConfigurableAssert::Failure(SNOWHOUSE_TEMPVAR(stm).str()); \ 125 | } \ 126 | do {} while (false) 127 | 128 | #ifndef SNOWHOUSE_NO_MACROS 129 | # define AssertThrows(EXCEPTION_TYPE, METHOD) \ 130 | SNOWHOUSE_ASSERT_THROWS(EXCEPTION_TYPE, (METHOD), ::snowhouse::DefaultFailureHandler) 131 | #endif 132 | // clang-format on 133 | 134 | #endif 135 | -------------------------------------------------------------------------------- /include/snowhouse/fluent/constraintadapter.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_CONSTRAINTADAPTER_H 7 | #define SNOWHOUSE_CONSTRAINTADAPTER_H 8 | 9 | #include "../stringize.h" 10 | #include "constraintlist.h" 11 | 12 | namespace snowhouse 13 | { 14 | template 15 | struct ConstraintAdapter 16 | { 17 | explicit ConstraintAdapter(const ConstraintType& constraint) 18 | : m_constraint(constraint) 19 | { 20 | } 21 | 22 | template 23 | void Evaluate(ConstraintListType& list, ResultStack& result, OperatorStack& operators, const ActualType& actual) 24 | { 25 | result.push(m_constraint(actual)); 26 | EvaluateConstraintList(list.m_tail, result, operators, actual); 27 | } 28 | 29 | ConstraintType m_constraint; 30 | }; 31 | 32 | template 33 | struct Stringizer> 34 | { 35 | static std::string ToString(const ConstraintAdapter& constraintAdapter) 36 | { 37 | return snowhouse::Stringize(constraintAdapter.m_constraint); 38 | } 39 | }; 40 | } 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /include/snowhouse/fluent/constraintlist.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_CONSTRAINTLIST_H 7 | #define SNOWHOUSE_CONSTRAINTLIST_H 8 | 9 | #include 10 | 11 | namespace snowhouse 12 | { 13 | struct ConstraintOperator; 14 | using ResultStack = std::stack; 15 | using OperatorStack = std::stack; 16 | 17 | template 18 | struct ConstraintList 19 | { 20 | using HeadType = HT; 21 | using TailType = TT; 22 | 23 | ConstraintList(const HeadType& head, const TailType& tail) 24 | : m_head(head), m_tail(tail) 25 | { 26 | } 27 | 28 | HeadType m_head; 29 | TailType m_tail; 30 | }; 31 | 32 | struct Nil 33 | { 34 | Nil() 35 | { 36 | } 37 | 38 | Nil(const Nil&) 39 | { 40 | } 41 | }; 42 | 43 | // ---- These structs defines the resulting types of list concatenation operations 44 | template 45 | struct type_concat 46 | { 47 | using t = ConstraintList::t>; 48 | }; 49 | 50 | template 51 | struct type_concat 52 | { 53 | using t = L2; 54 | }; 55 | 56 | template 57 | inline L3 tr_concat(const Nil&, const Nil&) 58 | { 59 | return Nil(); 60 | } 61 | 62 | // ---- These structs define the concatenation operations. 63 | 64 | template 65 | struct ListConcat 66 | { 67 | static ResultList Concatenate(const LeftList& left, const RightList& right) 68 | { 69 | return ResultList(left.m_head, ListConcat::t>::Concatenate(left.m_tail, right)); 70 | } 71 | }; 72 | 73 | // Concatenating an empty list with a second list yields the second list 74 | template 75 | struct ListConcat 76 | { 77 | static ResultList Concatenate(const Nil&, const RightList& right) 78 | { 79 | return right; 80 | } 81 | }; 82 | 83 | // Concatenating two empty lists yields an empty list 84 | template 85 | struct ListConcat 86 | { 87 | static ResultList Concatenate(const Nil&, const Nil&) 88 | { 89 | return Nil(); 90 | } 91 | }; 92 | 93 | // ---- The concatenation operation 94 | 95 | template 96 | inline typename type_concat::t Concatenate(const L1& list1, const L2& list2) 97 | { 98 | return ListConcat::t>::Concatenate(list1, list2); 99 | } 100 | } 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /include/snowhouse/fluent/expressionbuilder.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_EXPRESSIONBUILDER_H 7 | #define SNOWHOUSE_EXPRESSIONBUILDER_H 8 | 9 | #include "../constraints/constraints.h" 10 | #include "constraintadapter.h" 11 | #include "operators/andoperator.h" 12 | #include "operators/notoperator.h" 13 | #include "operators/oroperator.h" 14 | #include "operators/collections/alloperator.h" 15 | #include "operators/collections/noneoperator.h" 16 | #include "operators/collections/atleastoperator.h" 17 | #include "operators/collections/exactlyoperator.h" 18 | #include "operators/collections/atmostoperator.h" 19 | 20 | namespace snowhouse 21 | { 22 | // ---- Evaluation of list of constraints 23 | 24 | template 25 | inline void EvaluateConstraintList(ConstraintListType& constraint_list, ResultStack& result, OperatorStack& operators, const ActualType& actual) 26 | { 27 | constraint_list.m_head.Evaluate(constraint_list, result, operators, actual); 28 | } 29 | 30 | template 31 | inline void EvaluateConstraintList(Nil&, ResultStack&, OperatorStack&, const ActualType&) 32 | { 33 | } 34 | 35 | template 36 | struct ExpressionBuilder 37 | { 38 | explicit ExpressionBuilder(const ConstraintListType& list) 39 | : m_constraint_list(list) 40 | { 41 | } 42 | 43 | template 44 | ExpressionBuilder>, Nil>>::t> 45 | EqualTo(const ExpectedType& expected) 46 | { 47 | using ConstraintAdapterType = ConstraintAdapter>; 48 | using BuilderType = ExpressionBuilder>::t>; 49 | 50 | ConstraintAdapterType constraint(expected); 51 | ConstraintList node(constraint, Nil()); 52 | 53 | return BuilderType(Concatenate(m_constraint_list, node)); 54 | } 55 | 56 | template 57 | ExpressionBuilder>, Nil>>::t> 58 | EqualToWithDelta(const ExpectedType& expected, const DeltaType& delta) 59 | { 60 | using ConstraintAdapterType = ConstraintAdapter>; 61 | using BuilderType = ExpressionBuilder>::t>; 62 | 63 | ConstraintAdapterType constraint(EqualsWithDeltaConstraint(expected, delta)); 64 | ConstraintList node(constraint, Nil()); 65 | 66 | return BuilderType(Concatenate(m_constraint_list, node)); 67 | } 68 | 69 | template 70 | ExpressionBuilder>, Nil>>::t> 71 | Fulfilling(const MatcherType& matcher) 72 | { 73 | using ConstraintAdapterType = ConstraintAdapter>; 74 | using BuilderType = ExpressionBuilder>::t>; 75 | 76 | ConstraintAdapterType constraint(matcher); 77 | ConstraintList node(constraint, Nil()); 78 | 79 | return BuilderType(Concatenate(m_constraint_list, node)); 80 | } 81 | 82 | ExpressionBuilder>, Nil>>::t> 83 | False() 84 | { 85 | return EqualTo(false); 86 | } 87 | 88 | ExpressionBuilder>, Nil>>::t> 89 | True() 90 | { 91 | return EqualTo(true); 92 | } 93 | 94 | ExpressionBuilder>, Nil>>::t> 95 | Null() 96 | { 97 | return EqualTo(nullptr); 98 | } 99 | 100 | ExpressionBuilder>, Nil>>::t> 101 | EqualTo(const char* expected) 102 | { 103 | return EqualTo(std::string(expected)); 104 | } 105 | 106 | template 107 | ExpressionBuilder>, Nil>>::t> 108 | GreaterThan(const ExpectedType& expected) 109 | { 110 | using ConstraintAdapterType = ConstraintAdapter>; 111 | 112 | using BuilderType = ExpressionBuilder>::t>; 113 | ConstraintAdapterType constraint(expected); 114 | ConstraintList node(constraint, Nil()); 115 | return BuilderType(Concatenate(m_constraint_list, node)); 116 | } 117 | 118 | template 119 | ExpressionBuilder>, Nil>>::t> 120 | GreaterThanOrEqualTo(const ExpectedType& expected) 121 | { 122 | using ConstraintAdapterType = ConstraintAdapter>; 123 | 124 | using BuilderType = ExpressionBuilder>::t>; 125 | ConstraintAdapterType constraint(expected); 126 | ConstraintList node(constraint, Nil()); 127 | return BuilderType(Concatenate(m_constraint_list, node)); 128 | } 129 | 130 | template 131 | ExpressionBuilder>, Nil>>::t> 132 | LessThan(const ExpectedType& expected) 133 | { 134 | using ConstraintAdapterType = ConstraintAdapter>; 135 | 136 | using BuilderType = ExpressionBuilder>::t>; 137 | ConstraintAdapterType constraint(expected); 138 | ConstraintList node(constraint, Nil()); 139 | return BuilderType(Concatenate(m_constraint_list, node)); 140 | } 141 | 142 | template 143 | ExpressionBuilder>, Nil>>::t> 144 | LessThanOrEqualTo(const ExpectedType& expected) 145 | { 146 | using ConstraintAdapterType = ConstraintAdapter>; 147 | 148 | using BuilderType = ExpressionBuilder>::t>; 149 | ConstraintAdapterType constraint(expected); 150 | ConstraintList node(constraint, Nil()); 151 | return BuilderType(Concatenate(m_constraint_list, node)); 152 | } 153 | 154 | template 155 | ExpressionBuilder>, Nil>>::t> 156 | Containing(const ExpectedType& expected) 157 | { 158 | using ConstraintAdapterType = ConstraintAdapter>; 159 | 160 | using BuilderType = ExpressionBuilder>::t>; 161 | ConstraintAdapterType constraint(expected); 162 | ConstraintList node(constraint, Nil()); 163 | return BuilderType(Concatenate(m_constraint_list, node)); 164 | } 165 | 166 | ExpressionBuilder>, Nil>>::t> 167 | Containing(const char* expected) 168 | { 169 | return Containing(std::string(expected)); 170 | } 171 | 172 | template 173 | ExpressionBuilder>, Nil>>::t> 174 | EndingWith(const ExpectedType& expected) 175 | { 176 | using ConstraintAdapterType = ConstraintAdapter>; 177 | using BuilderType = ExpressionBuilder>::t>; 178 | 179 | ConstraintAdapterType constraint(expected); 180 | ConstraintList node(constraint, Nil()); 181 | return BuilderType(Concatenate(m_constraint_list, node)); 182 | } 183 | 184 | ExpressionBuilder>, Nil>>::t> 185 | EndingWith(const char* expected) 186 | { 187 | return EndingWith(std::string(expected)); 188 | } 189 | 190 | template 191 | ExpressionBuilder>, Nil>>::t> 192 | StartingWith(const ExpectedType& expected) 193 | { 194 | using ConstraintAdapterType = ConstraintAdapter>; 195 | 196 | using BuilderType = ExpressionBuilder>::t>; 197 | ConstraintAdapterType constraint(expected); 198 | ConstraintList node(constraint, Nil()); 199 | return BuilderType(Concatenate(m_constraint_list, node)); 200 | } 201 | 202 | ExpressionBuilder>, Nil>>::t> 203 | StartingWith(const char* expected) 204 | { 205 | return StartingWith(std::string(expected)); 206 | } 207 | 208 | template 209 | ExpressionBuilder>, Nil>>::t> 210 | OfLength(const ExpectedType& expected) 211 | { 212 | using ConstraintAdapterType = ConstraintAdapter>; 213 | 214 | using BuilderType = ExpressionBuilder>::t>; 215 | ConstraintAdapterType constraint(expected); 216 | ConstraintList node(constraint, Nil()); 217 | return BuilderType(Concatenate(m_constraint_list, node)); 218 | } 219 | 220 | ExpressionBuilder, Nil>>::t> 221 | Empty() 222 | { 223 | using ConstraintAdapterType = ConstraintAdapter; 224 | 225 | using BuilderType = ExpressionBuilder>::t>; 226 | ConstraintAdapterType constraint(0); 227 | ConstraintList node(constraint, Nil()); 228 | return BuilderType(Concatenate(m_constraint_list, node)); 229 | } 230 | 231 | template 232 | ExpressionBuilder>, Nil>>::t> 233 | EqualToContainer(const ExpectedType& expected) 234 | { 235 | using DefaultBinaryPredicateType = bool (*)(const typename ExpectedType::value_type&, const typename ExpectedType::value_type&); 236 | using ConstraintAdapterType = ConstraintAdapter>; 237 | 238 | using BuilderType = ExpressionBuilder>::t>; 239 | ConstraintAdapterType constraint(EqualsContainerConstraint(expected, constraint_internal::default_comparer)); 240 | ConstraintList node(constraint, Nil()); 241 | return BuilderType(Concatenate(m_constraint_list, node)); 242 | } 243 | 244 | template 245 | ExpressionBuilder>, Nil>>::t> 246 | EqualToContainer(const ExpectedType& expected, const BinaryPredicate predicate) 247 | { 248 | using ConstraintAdapterType = ConstraintAdapter>; 249 | 250 | using BuilderType = ExpressionBuilder>::t>; 251 | ConstraintAdapterType constraint(EqualsContainerConstraint(expected, predicate)); 252 | ConstraintList node(constraint, Nil()); 253 | return BuilderType(Concatenate(m_constraint_list, node)); 254 | } 255 | 256 | using AndOperatorNode = ConstraintList; 257 | using OrOperatorNode = ConstraintList; 258 | using NotOperatorNode = ConstraintList; 259 | using AllOperatorNode = ConstraintList; 260 | using AtLeastOperatorNode = ConstraintList; 261 | using ExactlyOperatorNode = ConstraintList; 262 | using AtMostOperatorNode = ConstraintList; 263 | using NoneOperatorNode = ConstraintList; 264 | 265 | ExpressionBuilder::t> All() 266 | { 267 | using BuilderType = ExpressionBuilder::t>; 268 | AllOperator op; 269 | AllOperatorNode node(op, Nil()); 270 | return BuilderType(Concatenate(m_constraint_list, node)); 271 | } 272 | 273 | ExpressionBuilder::t> AtLeast(unsigned int expected) 274 | { 275 | using BuilderType = ExpressionBuilder::t>; 276 | AtLeastOperator op(expected); 277 | AtLeastOperatorNode node(op, Nil()); 278 | return BuilderType(Concatenate(m_constraint_list, node)); 279 | } 280 | 281 | ExpressionBuilder::t> Exactly(unsigned int expected) 282 | { 283 | using BuilderType = ExpressionBuilder::t>; 284 | ExactlyOperator op(expected); 285 | ExactlyOperatorNode node(op, Nil()); 286 | return BuilderType(Concatenate(m_constraint_list, node)); 287 | } 288 | 289 | ExpressionBuilder::t> AtMost(unsigned int expected) 290 | { 291 | using BuilderType = ExpressionBuilder::t>; 292 | AtMostOperator op(expected); 293 | AtMostOperatorNode node(op, Nil()); 294 | return BuilderType(Concatenate(m_constraint_list, node)); 295 | } 296 | 297 | ExpressionBuilder::t> None() 298 | { 299 | using BuilderType = ExpressionBuilder::t>; 300 | NoneOperator op; 301 | NoneOperatorNode node(op, Nil()); 302 | return BuilderType(Concatenate(m_constraint_list, node)); 303 | } 304 | 305 | ExpressionBuilder::t> And() 306 | { 307 | using BuilderType = ExpressionBuilder::t>; 308 | AndOperator op; 309 | AndOperatorNode node(op, Nil()); 310 | return BuilderType(Concatenate(m_constraint_list, node)); 311 | } 312 | 313 | ExpressionBuilder::t> Or() 314 | { 315 | using BuilderType = ExpressionBuilder::t>; 316 | OrOperator op; 317 | OrOperatorNode node(op, Nil()); 318 | return BuilderType(Concatenate(m_constraint_list, node)); 319 | } 320 | 321 | ExpressionBuilder::t> Not() 322 | { 323 | using BuilderType = ExpressionBuilder::t>; 324 | NotOperator op; 325 | NotOperatorNode node(op, Nil()); 326 | return BuilderType(Concatenate(m_constraint_list, node)); 327 | } 328 | 329 | template 330 | void Evaluate(ResultStack& result, OperatorStack& operators, const ActualType& actual) 331 | { 332 | EvaluateConstraintList(m_constraint_list, result, operators, actual); 333 | } 334 | 335 | ConstraintListType m_constraint_list; 336 | }; 337 | 338 | template 339 | inline void StringizeConstraintList(const T& list, std::ostringstream& stm) 340 | { 341 | if (stm.tellp() > 0) 342 | stm << " "; 343 | 344 | stm << snowhouse::Stringize(list.m_head); 345 | StringizeConstraintList(list.m_tail, stm); 346 | } 347 | 348 | inline void StringizeConstraintList(const Nil&, std::ostringstream&) 349 | { 350 | } 351 | 352 | template 353 | struct Stringizer> 354 | { 355 | static std::string ToString(const ExpressionBuilder& builder) 356 | { 357 | std::ostringstream stm; 358 | StringizeConstraintList(builder.m_constraint_list, stm); 359 | 360 | return stm.str(); 361 | } 362 | }; 363 | } 364 | 365 | #endif 366 | -------------------------------------------------------------------------------- /include/snowhouse/fluent/fluent.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_FLUENT_H 7 | #define SNOWHOUSE_FLUENT_H 8 | 9 | #include "expressionbuilder.h" 10 | 11 | namespace snowhouse 12 | { 13 | inline ExpressionBuilder Is() 14 | { 15 | return ExpressionBuilder(Nil()); 16 | } 17 | 18 | inline ExpressionBuilder Has() 19 | { 20 | return ExpressionBuilder(Nil()); 21 | } 22 | } 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /include/snowhouse/fluent/operators/andoperator.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_ANDOPERATOR_H 7 | #define SNOWHOUSE_ANDOPERATOR_H 8 | 9 | #include "constraintoperator.h" 10 | 11 | namespace snowhouse 12 | { 13 | struct AndOperator : public ConstraintOperator 14 | { 15 | template 16 | void Evaluate(ConstraintListType& list, ResultStack& result, OperatorStack& operators, const ActualType& actual) 17 | { 18 | EvaluateOperatorsWithLessOrEqualPrecedence(*this, operators, result); 19 | 20 | operators.push(this); 21 | 22 | EvaluateConstraintList(list.m_tail, result, operators, actual); 23 | } 24 | 25 | void PerformOperation(ResultStack& result) override 26 | { 27 | if (result.size() < 2) 28 | { 29 | throw InvalidExpressionException("The expression contains an \"and\" operator with too few operands"); 30 | } 31 | 32 | bool right = result.top(); 33 | result.pop(); 34 | bool left = result.top(); 35 | result.pop(); 36 | 37 | result.push(left && right); 38 | } 39 | 40 | int Precedence() const override 41 | { 42 | return 3; 43 | } 44 | }; 45 | 46 | template<> 47 | struct Stringizer 48 | { 49 | static std::string ToString(const AndOperator&) 50 | { 51 | return "and"; 52 | } 53 | }; 54 | } 55 | #endif 56 | -------------------------------------------------------------------------------- /include/snowhouse/fluent/operators/collections/alloperator.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_ALLOPERATOR_H 7 | #define SNOWHOUSE_ALLOPERATOR_H 8 | 9 | #include "collectionoperator.h" 10 | #include "collectionconstraintevaluator.h" 11 | 12 | namespace snowhouse 13 | { 14 | struct AllOperator : public CollectionOperator 15 | { 16 | template 17 | void Evaluate(ConstraintListType& list, ResultStack& result, OperatorStack& operators, const ActualType& actual) 18 | { 19 | unsigned int passed_elements = CollectionConstraintEvaluator::Evaluate(*this, list, result, operators, actual); 20 | 21 | result.push(passed_elements == actual.size()); 22 | } 23 | }; 24 | 25 | template<> 26 | struct Stringizer 27 | { 28 | static std::string ToString(const AllOperator&) 29 | { 30 | return "all"; 31 | } 32 | }; 33 | } 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /include/snowhouse/fluent/operators/collections/atleastoperator.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_ATLEASTOPERATOR_H 7 | #define SNOWHOUSE_ATLEASTOPERATOR_H 8 | 9 | #include "collectionoperator.h" 10 | #include "collectionconstraintevaluator.h" 11 | 12 | namespace snowhouse 13 | { 14 | struct AtLeastOperator : public CollectionOperator 15 | { 16 | explicit AtLeastOperator(unsigned int expected) 17 | : m_expected(expected) 18 | { 19 | } 20 | 21 | template 22 | void Evaluate(ConstraintListType& list, ResultStack& result, OperatorStack& operators, const ActualType& actual) 23 | { 24 | unsigned int passed_elements = CollectionConstraintEvaluator::Evaluate(*this, list, result, operators, actual); 25 | 26 | result.push(passed_elements >= m_expected); 27 | } 28 | 29 | unsigned int m_expected; 30 | }; 31 | 32 | template<> 33 | struct Stringizer 34 | { 35 | static std::string ToString(const AtLeastOperator& op) 36 | { 37 | std::ostringstream stm; 38 | stm << "at least " << op.m_expected; 39 | return stm.str(); 40 | } 41 | }; 42 | } 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /include/snowhouse/fluent/operators/collections/atmostoperator.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_ATMOSTOPERATOR_H 7 | #define SNOWHOUSE_ATMOSTOPERATOR_H 8 | 9 | #include "collectionoperator.h" 10 | #include "collectionconstraintevaluator.h" 11 | 12 | namespace snowhouse 13 | { 14 | struct AtMostOperator : public CollectionOperator 15 | { 16 | explicit AtMostOperator(unsigned int expected) 17 | : m_expected(expected) 18 | { 19 | } 20 | 21 | template 22 | void Evaluate(ConstraintListType& list, ResultStack& result, OperatorStack& operators, const ActualType& actual) 23 | { 24 | unsigned int passed_elements = CollectionConstraintEvaluator::Evaluate(*this, list, result, operators, actual); 25 | 26 | result.push(passed_elements <= m_expected); 27 | } 28 | 29 | unsigned int m_expected; 30 | }; 31 | 32 | template<> 33 | struct Stringizer 34 | { 35 | static std::string ToString(const AtMostOperator& op) 36 | { 37 | std::ostringstream stm; 38 | stm << "at most " << op.m_expected; 39 | return stm.str(); 40 | } 41 | }; 42 | } 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /include/snowhouse/fluent/operators/collections/collectionconstraintevaluator.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_COLLECTIONCONSTRAINTEVALUATOR_H 7 | #define SNOWHOUSE_COLLECTIONCONSTRAINTEVALUATOR_H 8 | 9 | #include 10 | 11 | #include "../constraintoperator.h" 12 | 13 | namespace snowhouse 14 | { 15 | template 16 | struct CollectionConstraintEvaluator 17 | { 18 | static unsigned int Evaluate(const ConstraintOperator& op, 19 | ConstraintListType& expression, ResultStack& result, 20 | OperatorStack& operators, const ActualType& actual) 21 | { 22 | ConstraintOperator::EvaluateOperatorsWithLessOrEqualPrecedence(op, 23 | operators, result); 24 | 25 | unsigned int passed_elements = 0; 26 | for (const auto& member : actual) 27 | { 28 | if (ConstraintOperator::EvaluateElementAgainstRestOfExpression(expression, member)) 29 | { 30 | ++passed_elements; 31 | } 32 | } 33 | 34 | return passed_elements; 35 | } 36 | }; 37 | 38 | struct StringLineParser 39 | { 40 | static void Parse(const std::string& str, std::vector& res) 41 | { 42 | size_t start = 0; 43 | size_t newline = FindNewline(str, start); 44 | 45 | while (newline != std::string::npos) 46 | { 47 | StoreLine(str, start, newline, res); 48 | start = MoveToNextLine(str, newline); 49 | newline = FindNewline(str, start); 50 | } 51 | 52 | if (start < str.size()) 53 | { 54 | StoreLine(str, start, std::string::npos, res); 55 | } 56 | } 57 | 58 | private: 59 | static size_t FindNewline(const std::string& str, size_t start) 60 | { 61 | return str.find_first_of("\r\n", start); 62 | } 63 | 64 | static void StoreLine(const std::string& str, size_t start, size_t end, 65 | std::vector& res) 66 | { 67 | std::string line = str.substr(start, end - start); 68 | res.push_back(line); 69 | } 70 | 71 | static size_t MoveToNextLine(const std::string& str, size_t newline) 72 | { 73 | if (str.find("\r\n", newline) == newline) 74 | { 75 | return newline + 2; 76 | } 77 | 78 | if (str.find('\n', newline) == newline) 79 | { 80 | return newline + 1; 81 | } 82 | 83 | if (str.find('\r', newline) == newline) 84 | { 85 | return newline + 1; 86 | } 87 | 88 | std::ostringstream stm; 89 | stm << "This string seems to contain an invalid line ending at position " 90 | << newline << ":" << std::endl 91 | << str << std::endl; 92 | throw InvalidExpressionException(stm.str()); 93 | } 94 | }; 95 | 96 | template 97 | struct CollectionConstraintEvaluator 98 | { 99 | static unsigned int Evaluate(const ConstraintOperator& op, 100 | ConstraintListType& expression, ResultStack& result, 101 | OperatorStack& operators, const std::string& actual) 102 | { 103 | std::vector lines; 104 | StringLineParser::Parse(actual, lines); 105 | return CollectionConstraintEvaluator>::Evaluate(op, expression, result, operators, lines); 106 | } 107 | }; 108 | } 109 | 110 | #endif 111 | -------------------------------------------------------------------------------- /include/snowhouse/fluent/operators/collections/collectionoperator.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_COLLECTIONOPERATOR_H 7 | #define SNOWHOUSE_COLLECTIONOPERATOR_H 8 | 9 | #include "../constraintoperator.h" 10 | 11 | namespace snowhouse 12 | { 13 | struct CollectionOperator : public ConstraintOperator 14 | { 15 | void PerformOperation(ResultStack&) override 16 | { 17 | } 18 | 19 | int Precedence() const override 20 | { 21 | return 1; 22 | } 23 | }; 24 | } 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /include/snowhouse/fluent/operators/collections/exactlyoperator.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_EXACTLYOPERATOR_H 7 | #define SNOWHOUSE_EXACTLYOPERATOR_H 8 | 9 | #include "collectionoperator.h" 10 | #include "collectionconstraintevaluator.h" 11 | 12 | namespace snowhouse 13 | { 14 | struct ExactlyOperator : public CollectionOperator 15 | { 16 | explicit ExactlyOperator(unsigned int expected) 17 | : m_expected(expected) 18 | { 19 | } 20 | 21 | template 22 | void Evaluate(ConstraintListType& list, ResultStack& result, OperatorStack& operators, const ActualType& actual) 23 | { 24 | unsigned int passed_elements = CollectionConstraintEvaluator::Evaluate(*this, list, result, operators, actual); 25 | 26 | result.push(passed_elements == m_expected); 27 | } 28 | 29 | unsigned int m_expected; 30 | }; 31 | 32 | template<> 33 | struct Stringizer 34 | { 35 | static std::string ToString(const ExactlyOperator& op) 36 | { 37 | std::ostringstream stm; 38 | stm << "exactly " << op.m_expected; 39 | return stm.str(); 40 | } 41 | }; 42 | } 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /include/snowhouse/fluent/operators/collections/noneoperator.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_NONEOPERATOR_H 7 | #define SNOWHOUSE_NONEOPERATOR_H 8 | 9 | #include "collectionoperator.h" 10 | #include "collectionconstraintevaluator.h" 11 | 12 | namespace snowhouse 13 | { 14 | struct NoneOperator : public CollectionOperator 15 | { 16 | template 17 | void Evaluate(ConstraintListType& list, ResultStack& result, OperatorStack& operators, const ActualType& actual) 18 | { 19 | unsigned int passed_elements = CollectionConstraintEvaluator::Evaluate(*this, list, result, operators, actual); 20 | result.push(passed_elements == 0); 21 | } 22 | }; 23 | 24 | template<> 25 | struct Stringizer 26 | { 27 | static std::string ToString(const NoneOperator&) 28 | { 29 | return "none"; 30 | } 31 | }; 32 | } 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /include/snowhouse/fluent/operators/constraintoperator.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_CONSTRAINTOPERATOR_H 7 | #define SNOWHOUSE_CONSTRAINTOPERATOR_H 8 | 9 | #include "../../stringize.h" 10 | #include "../constraintlist.h" 11 | #include "invalidexpressionexception.h" 12 | 13 | namespace snowhouse 14 | { 15 | struct ConstraintOperator 16 | { 17 | ConstraintOperator() = default; 18 | explicit ConstraintOperator(const ConstraintOperator&) = default; 19 | ConstraintOperator& operator=(const ConstraintOperator&) = default; 20 | virtual ~ConstraintOperator() noexcept = default; 21 | virtual void PerformOperation(ResultStack& result) = 0; 22 | virtual int Precedence() const = 0; 23 | 24 | template 25 | static bool EvaluateElementAgainstRestOfExpression(ConstraintListType& list, const ActualType& actual) 26 | { 27 | ResultStack innerResult; 28 | OperatorStack innerOperators; 29 | 30 | EvaluateConstraintList(list.m_tail, innerResult, innerOperators, actual); 31 | EvaluateAllOperatorsOnStack(innerOperators, innerResult); 32 | 33 | if (innerResult.empty()) 34 | { 35 | throw InvalidExpressionException("The expression after \"" + snowhouse::Stringize(list.m_head) + "\" operator does not yield any result"); 36 | } 37 | 38 | return innerResult.top(); 39 | } 40 | 41 | static void EvaluateOperatorsWithLessOrEqualPrecedence(const ConstraintOperator& op, OperatorStack& operators, ResultStack& result) 42 | { 43 | while (!operators.empty()) 44 | { 45 | ConstraintOperator* op_from_stack = operators.top(); 46 | 47 | if (op_from_stack->Precedence() > op.Precedence()) 48 | { 49 | break; 50 | } 51 | 52 | op_from_stack->PerformOperation(result); 53 | operators.pop(); 54 | } 55 | } 56 | 57 | static void EvaluateAllOperatorsOnStack(OperatorStack& operators, ResultStack& result) 58 | { 59 | while (!operators.empty()) 60 | { 61 | ConstraintOperator* op = operators.top(); 62 | op->PerformOperation(result); 63 | operators.pop(); 64 | } 65 | } 66 | }; 67 | } 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /include/snowhouse/fluent/operators/invalidexpressionexception.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_INVALIDEXPRESSIONEXCEPTION_H 7 | #define SNOWHOUSE_INVALIDEXPRESSIONEXCEPTION_H 8 | 9 | #include 10 | #include 11 | 12 | namespace snowhouse 13 | { 14 | struct InvalidExpressionException : public std::runtime_error 15 | { 16 | using std::runtime_error::runtime_error; 17 | }; 18 | } 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /include/snowhouse/fluent/operators/notoperator.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_NOTOPERATOR_H 7 | #define SNOWHOUSE_NOTOPERATOR_H 8 | 9 | #include "constraintoperator.h" 10 | 11 | namespace snowhouse 12 | { 13 | struct NotOperator : public ConstraintOperator 14 | { 15 | template 16 | void Evaluate(ConstraintListType& list, ResultStack& result, OperatorStack& operators, const ActualType& actual) 17 | { 18 | EvaluateOperatorsWithLessOrEqualPrecedence(*this, operators, result); 19 | 20 | operators.push(this); 21 | 22 | EvaluateConstraintList(list.m_tail, result, operators, actual); 23 | } 24 | 25 | void PerformOperation(ResultStack& result) override 26 | { 27 | if (result.empty()) 28 | { 29 | throw InvalidExpressionException("The expression contains a \"not\" operator without any operand"); 30 | } 31 | 32 | bool right = result.top(); 33 | result.pop(); 34 | 35 | result.push(!right); 36 | } 37 | 38 | int Precedence() const override 39 | { 40 | return 2; 41 | } 42 | }; 43 | 44 | template<> 45 | struct Stringizer 46 | { 47 | static std::string ToString(const NotOperator&) 48 | { 49 | return "not"; 50 | } 51 | }; 52 | } 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /include/snowhouse/fluent/operators/oroperator.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_OROPERATOR_H 7 | #define SNOWHOUSE_OROPERATOR_H 8 | 9 | #include "constraintoperator.h" 10 | 11 | namespace snowhouse 12 | { 13 | struct OrOperator : public ConstraintOperator 14 | { 15 | template 16 | void Evaluate(ConstraintListType& list, ResultStack& result, OperatorStack& operators, const ActualType& actual) 17 | { 18 | EvaluateOperatorsWithLessOrEqualPrecedence(*this, operators, result); 19 | 20 | operators.push(this); 21 | 22 | EvaluateConstraintList(list.m_tail, result, operators, actual); 23 | } 24 | 25 | void PerformOperation(ResultStack& result) override 26 | { 27 | if (result.size() < 2) 28 | { 29 | throw InvalidExpressionException("The expression contains an \"or\" operator with too few operands"); 30 | } 31 | 32 | bool right = result.top(); 33 | result.pop(); 34 | bool left = result.top(); 35 | result.pop(); 36 | 37 | result.push(left || right); 38 | } 39 | 40 | int Precedence() const override 41 | { 42 | return 4; 43 | } 44 | }; 45 | 46 | template<> 47 | struct Stringizer 48 | { 49 | static std::string ToString(const OrOperator&) 50 | { 51 | return "or"; 52 | } 53 | }; 54 | } 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /include/snowhouse/macros.h: -------------------------------------------------------------------------------- 1 | #ifndef SNOWHOUSE_MACROS_H 2 | #define SNOWHOUSE_MACROS_H 3 | // clang-format off 4 | 5 | #define SNOWHOUSE_MAJOR 5 6 | #define SNOWHOUSE_MINOR 0 7 | #define SNOWHOUSE_PATCH 0 8 | 9 | #define SNOWHOUSE_TOSTRING(x) #x 10 | #define SNOWHOUSE_MACROTOSTRING(x) SNOWHOUSE_TOSTRING(x) 11 | #define SNOWHOUSE_VERSION \ 12 | SNOWHOUSE_MACROTOSTRING(SNOWHOUSE_MAJOR) "." \ 13 | SNOWHOUSE_MACROTOSTRING(SNOWHOUSE_MINOR) "." \ 14 | SNOWHOUSE_MACROTOSTRING(SNOWHOUSE_PATCH) 15 | #endif 16 | -------------------------------------------------------------------------------- /include/snowhouse/snowhouse.h: -------------------------------------------------------------------------------- 1 | #ifndef SNOWHOUSE_H 2 | #define SNOWHOUSE_H 3 | 4 | #include "fluent/fluent.h" 5 | #include "stringizers.h" 6 | #include "assert.h" 7 | #include "exceptions.h" 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /include/snowhouse/stringize.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_STRINGIZE_H 7 | #define SNOWHOUSE_STRINGIZE_H 8 | 9 | #include 10 | #include 11 | 12 | #include "macros.h" 13 | 14 | namespace snowhouse 15 | { 16 | namespace typing 17 | { 18 | // This type soaks up any implicit conversions and makes the following operator<< 19 | // less preferred than any other such operator found via ADL. 20 | struct any 21 | { 22 | // Conversion constructor for any type. 23 | template 24 | any(T const&); 25 | }; 26 | 27 | // A tag type returned by operator<< for the any struct in this namespace 28 | // when T does not support <<. 29 | struct tag 30 | { 31 | }; 32 | 33 | // Fallback operator<< for types T that don't support <<. 34 | tag operator<<(std::ostream&, any const&); 35 | 36 | // Two overloads to distinguish whether T supports a certain operator expression. 37 | // The first overload returns a reference to a two-element character array and is chosen if 38 | // T does not support the expression, such as <<, whereas the second overload returns a char 39 | // directly and is chosen if T supports the expression. So using sizeof(check()) 40 | // returns 2 for the first overload and 1 for the second overload. 41 | using yes = char; 42 | using no = char (&)[2]; 43 | 44 | no check(tag); 45 | 46 | template 47 | yes check(T const&); 48 | 49 | template 50 | struct is_output_streamable 51 | { 52 | static const T& x; 53 | static const bool value = sizeof(check(std::cout << x)) == sizeof(yes); 54 | }; 55 | 56 | template<> 57 | struct is_output_streamable 58 | { 59 | static const bool value = false; 60 | }; 61 | } 62 | 63 | namespace detail 64 | { 65 | template 66 | struct DefaultStringizer 67 | { 68 | static std::string ToString(const T& value) 69 | { 70 | std::ostringstream buf; 71 | buf << value; 72 | return buf.str(); 73 | } 74 | }; 75 | 76 | template<> 77 | struct DefaultStringizer 78 | { 79 | static std::string ToString(bool value) 80 | { 81 | return value ? "true" : "false"; 82 | } 83 | }; 84 | 85 | template<> 86 | struct DefaultStringizer 87 | { 88 | static std::string ToString(const std::string& value) 89 | { 90 | return "\"" + value + "\""; 91 | } 92 | }; 93 | 94 | template 95 | struct DefaultStringizer 96 | { 97 | static std::string ToString(const T&) 98 | { 99 | return "[unsupported type]"; 100 | } 101 | }; 102 | } 103 | 104 | template 105 | struct Stringizer; 106 | 107 | template 108 | std::string Stringize(const T& value) 109 | { 110 | return Stringizer::ToString(value); 111 | } 112 | 113 | // NOTE: Specialize snowhouse::Stringizer to customize assertion messages 114 | template 115 | struct Stringizer 116 | { 117 | static std::string ToString(const T& value) 118 | { 119 | return detail::DefaultStringizer::value>::ToString(value); 120 | } 121 | }; 122 | 123 | // We need this because nullptr_t has ambiguous overloads of operator<< in the standard library. 124 | template<> 125 | struct Stringizer 126 | { 127 | static std::string ToString(std::nullptr_t) 128 | { 129 | return "nullptr"; 130 | } 131 | }; 132 | } 133 | 134 | #endif 135 | -------------------------------------------------------------------------------- /include/snowhouse/stringizers.h: -------------------------------------------------------------------------------- 1 | // Copyright Joakim Karlsson & Kim Gräsman 2010-2012. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef SNOWHOUSE_STRINGIZERS_H 7 | #define SNOWHOUSE_STRINGIZERS_H 8 | 9 | #include "stringize.h" 10 | 11 | namespace snowhouse 12 | { 13 | namespace detail 14 | { 15 | template 16 | struct SequentialContainerStringizer 17 | { 18 | static std::string 19 | ToString(const Container& cont) 20 | { 21 | std::ostringstream stm; 22 | using Iterator = typename Container::const_iterator; 23 | 24 | stm << "[ "; 25 | for (Iterator it = cont.begin(); it != cont.end();) 26 | { 27 | stm << snowhouse::Stringize(*it); 28 | 29 | if (++it != cont.end()) 30 | { 31 | stm << ", "; 32 | } 33 | } 34 | stm << " ]"; 35 | return stm.str(); 36 | } 37 | }; 38 | } 39 | 40 | namespace typing 41 | { 42 | template 43 | struct is_const_iterable 44 | { 45 | template 46 | static yes compile_time_check_const_iterator(typename CLASS::const_iterator*); 47 | 48 | template 49 | static no compile_time_check_const_iterator(...); 50 | 51 | static const bool value = sizeof(compile_time_check_const_iterator(nullptr)) == sizeof(yes); 52 | }; 53 | 54 | template::value> 55 | struct is_container 56 | { 57 | using Iterator = typename T::const_iterator; 58 | 59 | struct FallbackBeginEnd 60 | { 61 | Iterator begin() const; 62 | Iterator end() const; 63 | }; 64 | 65 | using fallback_method = Iterator (FallbackBeginEnd::*)() const; 66 | 67 | template 68 | struct is_of_type; 69 | 70 | template 71 | static no compile_time_check_begin(is_of_type*); 72 | 73 | template 74 | static no compile_time_check_end(is_of_type*); 75 | 76 | template 77 | static yes compile_time_check_begin(...); 78 | 79 | template 80 | static yes compile_time_check_end(...); 81 | 82 | struct FallbackContainer : T, FallbackBeginEnd 83 | { 84 | }; 85 | 86 | static const bool has_begin = sizeof(compile_time_check_begin(0)) == sizeof(yes); 87 | static const bool has_end = sizeof(compile_time_check_end(0)) == sizeof(yes); 88 | 89 | static const bool value = has_begin && has_end; 90 | }; 91 | 92 | template 93 | struct is_container 94 | { 95 | static const bool value = false; 96 | }; 97 | 98 | template<> 99 | struct is_container 100 | { 101 | static const bool value = false; 102 | }; 103 | 104 | template 105 | struct enable_if 106 | { 107 | }; 108 | 109 | template 110 | struct enable_if 111 | { 112 | using type = TRUE_TYPE; 113 | }; 114 | } 115 | 116 | template 117 | struct Stringizer::value>::type> 119 | : detail::SequentialContainerStringizer 120 | { 121 | }; 122 | } 123 | 124 | #endif 125 | -------------------------------------------------------------------------------- /util/build-in-container.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if test "$#" -ne 2; then 4 | cat >&2 < 6 | 7 | C++ standard versions are 11, 14, 17, etc. 8 | 9 | Our docker images are, for example, 10 | - banditcpp/build-environments:gcc-13 11 | - banditcpp/build-environments:clang-16 12 | EOF 13 | exit 2 14 | fi 15 | 16 | # run the image 17 | SRCDIR=/usr/src/snowhouse 18 | docker run \ 19 | -v "$PWD":"$SRCDIR" \ 20 | -e "SRCDIR=$SRCDIR" \ 21 | -e "CC=$CC" \ 22 | -e "CXX=$CXX" \ 23 | "$2" "$SRCDIR"/util/build.sh "$1" "$2" 24 | -------------------------------------------------------------------------------- /util/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | test -n "$SRCDIR" || SRCDIR="$(pwd)" 4 | test -n "$CC" || CC=cc 5 | test -n "$CXX" || CXX=c++ 6 | 7 | cxxstandard="$1" 8 | case "$cxxstandard" in 9 | 11|14|17|20|23) 10 | ;; 11 | *) 12 | echo "Usage: $0 (11|14|17|20|23) [image name]" >&2 13 | exit 1 14 | esac 15 | 16 | image="$2" 17 | test -n "$image" || image=default 18 | 19 | buildpath="builds/$(basename "$image" | sed 's/^.*://')/$(basename "$CXX")/std$cxxstandard" 20 | 21 | echo "Build settings:" 22 | echo " * source directory: $SRCDIR" 23 | echo " * C compiler: $CC" 24 | echo " * C++ compiler: $CXX" 25 | echo " * C++ standard: C++$cxxstandard" 26 | echo " * image: $image" 27 | echo " * build path: $buildpath" 28 | 29 | mkdir -p "$SRCDIR/$buildpath" 30 | cd "$SRCDIR/$buildpath" || exit 31 | cmake -DSNOWHOUSE_BUILD_TESTS=1 -DSNOWHOUSE_DEVELOP=1 -DSNOWHOUSE_RUN_TESTS=1 -D"SNOWHOUSE_CXX_STANDARD=C++$cxxstandard" "$SRCDIR" || exit 32 | cmake --build . || exit 33 | -------------------------------------------------------------------------------- /util/format.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Reformat all tracked files (run this from snowhouse git root directory, 3 | # not from util!) 4 | 5 | DEFAULT_FORMAT_TOOL=clang-format-16 6 | test -n "$FORMATTER" || FORMATTER="$(command -v "$DEFAULT_FORMAT_TOOL")" 7 | 8 | if test -z "$FORMATTER" 9 | then 10 | echo "Error: No '$DEFAULT_FORMAT_TOOL' executable found in PATH" >&2 11 | echo "You can define your clang-format path by setting the FORMATTER variable" >&2 12 | exit 2 13 | fi 14 | 15 | git ls-files '*.cpp' '*.h' | xargs "$FORMATTER" -i 16 | --------------------------------------------------------------------------------