Skip to content

Commit 3da4237

Browse files
committed
Begin ReadTheDocs documentation
1 parent f45e4e2 commit 3da4237

File tree

2 files changed

+74
-120
lines changed

2 files changed

+74
-120
lines changed

README.md

Lines changed: 20 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1,132 +1,34 @@
1-
#C++Spec
2-
Have a taste of some RSpec in your C++.
1+
#C++Spec [![version](https://img.shields.io/badge/version-v0.0.0-blue.svg)]()
2+
[![Build Status](https://travis-ci.org/toroidal-code/cppspec.svg?branch=master)](https://travis-ci.org/toroidal-code/cppspec) 
3+
[![GitHub release](https://img.shields.io/github/release/toroidal-code/cppspec.svg)](https://github.com/toroidal-code/cppspec/releases/latest) 
4+
[![Github Releases](https://img.shields.io/github/downloads/toroidal-code/cppspec/latest/total.svg)]() 
5+
[![Documentation Status](https://readthedocs.org/projects/cppspec/badge/?version=latest)](http://cppspec.readthedocs.org/en/latest/?badge=latest)
36

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.
98

9+
## Installation ##
1010

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"`.
1912

20-
int n = 0;
21-
before_each([&]{ n = rand(); });
13+
## Documentation ##
2214

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.
3016

31-
explain("argument is negative", _ {
32-
it("return positive", _ {
33-
expect(fabs(-n)).to_equal(n);
34-
});
35-
});
36-
});
17+
## Testing ##
3718

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 ##
4420

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).
5122

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.
5324

54-
## Why?
55-
Short answer: Because I got fed up with using assertions.
25+
## FAQ ##
5626

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 ##
12628
Heavily inspired by [RSpec](https://github.com/rspec) and [Jasmine](http://jasmine.github.io).
12729

128-
## Authors
129-
Copyright 2016 Katherine Whitlock
30+
## Authors ##
31+
Copyright © 2014-2016 Katherine Whitlock
13032

131-
## License
132-
This code is licensed under the 3-clause BSD License.
33+
## License ##
34+
The project is licensed under the MIT License.

docs/syntax/describe.md

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,55 @@
1-
# Describe
21

3-
`describe` is the base structure in C++Spec.
2+
Every test suite begins with either `describe` or `describe_a`.
3+
4+
# describe #
5+
6+
Describes have the form of:
7+
8+
```c++
9+
describe example_spec("An example", $ { });
10+
```
11+
12+
Each `describe` is a global instance of the `Description` class, the name of the spec being
13+
the name of the global variable that the test is contained in.
14+
15+
__Important!__ Take note of the `$`. This is used whenever you write a `describe` or a `describe_a`.
16+
17+
In conventional C++, the above snippet would be written as:
18+
19+
```c++
20+
Description example_spec("An example", [](&self auto) { });
21+
```
22+
23+
The `Description` constructor takes two arguments: a string, and a lambda. For simplicity's sake,
24+
any lambdas passed to any C++Spec functions are referred to as "blocks", as the capture-list
25+
and arguments of the lambda are effectively never seen.
26+
27+
# describe_a #
28+
29+
A `describe_a` is more complex than `describe`.
30+
31+
Unlike `describe` which creates instances of `Description`, `describe_a` creates instances of
32+
`ClassDescription`. `ClassDescription` is a template class, where the template's type variable
33+
is used to specialize the description and create a subject available to all statements in the
34+
description.
35+
36+
```c++
37+
template <typename T>
38+
class ClassDescription : public Description { };
39+
```
40+
41+
Also unlike `describe`, there are two forms of `describe_a`: one where the subject is explicit,
42+
and another where it is implicit.
43+
44+
The explicit form:
45+
46+
```c++
47+
describe_a <TestClass> tc_spec(TestClass(arg1, arg2), $ { });
48+
```
49+
50+
The implicit form:
51+
52+
```c++
53+
describe_a <AnotherTestClass> atc_spec($ { });
54+
```
55+

0 commit comments

Comments
 (0)