|
1 |
| -#C++Spec |
2 |
| -Have a taste of some RSpec in your C++. |
| 1 | +#C++Spec []() |
| 2 | +[](https://travis-ci.org/toroidal-code/cppspec) |
| 3 | +[](https://github.com/toroidal-code/cppspec/releases/latest) |
| 4 | +[]() |
| 5 | +[](http://cppspec.readthedocs.org/en/latest/?badge=latest) |
3 | 6 |
|
4 |
| -```cpp |
5 |
| -#include <cmath> |
6 |
| -#include <cstdlib> |
7 |
| -#include <list> |
8 |
| -#include "cppspec.hpp" |
| 7 | +C++Spec is a behavior-driven development library for C++ with an RSpec-inspired DSL. |
9 | 8 |
|
| 9 | +## Installation ## |
10 | 10 |
|
11 |
| -describe fabs_spec("fabs", $ { |
12 |
| - // you can use the `explain` keyword to |
13 |
| - // group behavior and nest descriptions |
14 |
| - explain("argument is zero", _ { |
15 |
| - it("return zero", _ { |
16 |
| - expect(fabs(0)).to_equal(0); |
17 |
| - }); |
18 |
| - }); |
| 11 | +C++Spec is available as a single collated header-file that can be placed in any include path in your project. After that, all features are available via `#include "cppspec.hpp"`. |
19 | 12 |
|
20 |
| - int n = 0; |
21 |
| - before_each([&]{ n = rand(); }); |
| 13 | +## Documentation ## |
22 | 14 |
|
23 |
| - // you can also use `context` instead of |
24 |
| - // `explain`, just like in RSpec |
25 |
| - context("argument is positive", _ { |
26 |
| - it("return positive", _ { |
27 |
| - expect(fabs(n)).to_equal(n, "fabs(" + std::to_string(n) + ") didn't equal " + std::to_string(n)); |
28 |
| - }); |
29 |
| - }); |
| 15 | +See [http://cppspec.readthedocs.org/]() for all documentation. |
30 | 16 |
|
31 |
| - explain("argument is negative", _ { |
32 |
| - it("return positive", _ { |
33 |
| - expect(fabs(-n)).to_equal(n); |
34 |
| - }); |
35 |
| - }); |
36 |
| -}); |
| 17 | +## Testing ## |
37 | 18 |
|
38 |
| -// describe_a allows you to create specs with implied subjects, |
39 |
| -// useful for testing specific classes and a mock instance |
40 |
| -describe_a <std::list<int>> int_list_spec({1,2,3}, $ { |
41 |
| - // the `is_expected` function is used for matching an implied subject |
42 |
| - it(_{ is_expected().to_include(3); }); |
43 |
| -}); |
| 19 | +## Requirements ## |
44 | 20 |
|
45 |
| -int main(void) { |
46 |
| - bool r = true; |
47 |
| - r &= fabs_spec.run(); |
48 |
| - r &= int_list_spec.run(); |
49 |
| - return r ? EXIT_SUCCESS : EXIT_FAILURE; |
50 |
| -} |
| 21 | +C++Spec requires a compiler with support for C++11 and polymorphic lambda expressions from C++14. This includes GCC >= 4.9, MSVCC >= 14.0, or clang >= 3.4. For other compilers check [this chart](http://en.cppreference.com/w/cpp/compiler_support). |
51 | 22 |
|
52 |
| -``` |
| 23 | +__Note:__ Only the tests require being compiled with C++14 support (`-std=c++14`). No other part of an existing project's build must be modified. |
53 | 24 |
|
54 |
| -## Why? |
55 |
| -Short answer: Because I got fed up with using assertions. |
| 25 | +## FAQ ## |
56 | 26 |
|
57 |
| -Long answer: |
58 |
| -
|
59 |
| -Because good BDD-testing on C and C++ is hard. |
60 |
| -
|
61 |
| -I come from a software-engineering background, and it's been driven through my head that |
62 |
| -testing is one of (if not _the_) the most important thing about writing stable software. |
63 |
| -So when I started doing C++ development seriously about three years ago, I was really |
64 |
| -surprised to see that there was no flexible RSpec-like testing framework for a language |
65 |
| -that is used daily by thousands (millions?). |
66 |
| -
|
67 |
| -I wanted a library that let me make comprehensive and readable BDD tests really, really easily, |
68 |
| -but nothing fit what I was looking for. |
69 |
| -
|
70 |
| -So I decided to try and make it myself. |
71 |
| -
|
72 |
| -## How? |
73 |
| -Unholy black magic. |
74 |
| -
|
75 |
| -## No, really. How? |
76 |
| -Lots of templates. Templates everywhere. _Literally_ everywhere. It's why this library is header-only. |
77 |
| -
|
78 |
| -A single 'describe' is actually a local variable that has a runtime-created execution tree. |
79 |
| -Calling `.run()` on the root recursively calls `.run()` on its' children. |
80 |
| -
|
81 |
| -A common expectation like `expect({1,2,3}).to_include({1,2});` is more like |
82 |
| -```cpp |
83 |
| -Expecatations::Expectation<std::vector<int>>({1,2,3}).to_include<std::vector<int>,std::vector<int>,int>({1,2}) |
84 |
| -``` |
85 |
| - |
86 |
| -Not fun. Cool. But definitely not fun. |
87 |
| - |
88 |
| -## Why should I use this instead of some other testing framework? |
89 |
| - |
90 |
| -So that your tests can look nice. Or because you want to use RSpec syntax for testing C or C++. Or because it's pretty simple to use, yet powerful thanks to the extensible matchers. There's a bunch of possible reasons. |
91 |
| - |
92 |
| -...Or maybe because you find it cool and you'd like to hack on it and contribute? (pretty please?) |
93 |
| - |
94 |
| -## It's Ugly! |
95 |
| -Yeah, I know. It's not the best. Let's see you make it any prettier (and if you do, send me a pull request :P ). |
96 |
| - |
97 |
| -In all honesty though, this was as close to RSpec or Jasmine syntax as I could get. I think I did |
98 |
| -a pretty darn good job, if I do say so myself. Even if the library itself seriously needs |
99 |
| -to be cleaned up. |
100 |
| - |
101 |
| -## It's Beautiful! |
102 |
| -Why, thank you! I certainly tried. |
103 |
| - |
104 |
| -## What the heck are `$` and `_`!? |
105 |
| -They're just syntax sugar for `[](auto &self)` and `[=](auto &self)` respectively, defined to avoid repetition and improve readability. `it([=](auto &self){ is_expected.to_equal(5); });` isn't exactly what I'm aiming for with syntax. |
106 |
| - |
107 |
| -We need that `self` parameter to pass a reference to the containing structure. For example, `describe` |
108 |
| -blocks get a `Description` object, while `it` blocks get an `It` object. |
109 |
| - |
110 |
| -Annoyingly, you can't have an automatic capture-list on a non-local lambda |
111 |
| -(which is what a top-level `describe`'s body is). This means that there needs |
112 |
| -to be a separate one-character shortcut. If they really bother you, or you just |
113 |
| -want to be verbose, you can stick `#undef $` and/or `#undef _` at the top of your file. |
114 |
| - |
115 |
| -## It's awesome and I totally want to use it, but how? |
116 |
| - |
117 |
| -If you look up there ^ at that code snippet, it'll give you a basic idea of how things work right now. |
118 |
| - |
119 |
| -You stick the library into your include folder, probably using something like `git submodule add https://github.com/toroidal-code/cppspec testing/include/cppspec`, and then import the main header, `cppspec.hpp`. |
120 |
| - |
121 |
| -I'm (We're?) working on an actual test runner, instead of the weird boolean and-ing that you can see in the example, but the explicit `run`-ing works for now, and will probably always be an option. |
122 |
| - |
123 |
| -There are really two ways to go about creating your tests: as a bunch of little individual executables, or as one giant monolithic one. CMake's CTest likes it when you have a bunch of individual test programs, but having a single runner file with a bunch of tests implemented in separate `something_spec.hpp` files might compile faster for you. |
124 |
| - |
125 |
| -## Attribution |
| 27 | +## Attribution ## |
126 | 28 | Heavily inspired by [RSpec](https://github.com/rspec) and [Jasmine](http://jasmine.github.io).
|
127 | 29 |
|
128 |
| -## Authors |
129 |
| -Copyright 2016 Katherine Whitlock |
| 30 | +## Authors ## |
| 31 | +Copyright © 2014-2016 Katherine Whitlock |
130 | 32 |
|
131 |
| -## License |
132 |
| -This code is licensed under the 3-clause BSD License. |
| 33 | +## License ## |
| 34 | +The project is licensed under the MIT License. |
0 commit comments