Skip to content

Commit ccb048d

Browse files
committed
Befores and Afters
1 parent d6caf7b commit ccb048d

File tree

4 files changed

+114
-11
lines changed

4 files changed

+114
-11
lines changed

examples/sample/example_spec.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#include <cmath>
2+
#include <cstdlib>
13
#include <list>
24
#include "cppspec.hpp"
35

@@ -109,6 +111,47 @@ describe bool_spec("Some Tests", $ {
109111
// });
110112
});
111113

114+
describe abs_spec("abs", $ {
115+
// you can use the `explain` keyword to
116+
// group behavior and nest descriptions
117+
explain("argument is zero", _ {
118+
it("return zero", _ {
119+
expect(abs(0)).to_equal(0);
120+
});
121+
});
122+
123+
before_all([]{ std::srand(std::time(0)); });
124+
125+
int n = 0;
126+
before_each([&]{ n = std::rand(); });
127+
128+
// you can also use `context` instead of
129+
// `explain`, just like in RSpec
130+
context("argument is positive", _ {
131+
it("return positive", _ {
132+
expect(abs(n)).to_equal(n, "abs(" + std::to_string(n) + ") didn't equal " + std::to_string(n));
133+
});
134+
});
135+
136+
explain("argument is negative", _ {
137+
it("return positive", _ {
138+
expect(abs(-n)).to_equal(n);
139+
});
140+
});
141+
});
142+
143+
144+
145+
146+
147+
148+
149+
150+
151+
152+
153+
154+
112155
/* Here is the description of strcmp */
113156
// describe strcmp_spec("int strcmp ( const char * str1, const char * str2 )", _ {
114157
// it( "returns 0 only when strings are equal", _ {
@@ -157,6 +200,7 @@ describe list_spec("A list spec", $ {
157200
int main(){
158201
bool r = true;
159202
r &= bool_spec.run();
203+
r &= abs_spec.run();
160204
r &= vector_spec.run();
161205
r &= another_vector_spec.run();
162206
// #undef expect

include/class_description.hpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ bool ClassDescription<T>::context(T subject,
8686
std::function<void(ClassDescription&)> body) {
8787
ClassContext<T> context(subject, body);
8888
context.set_parent(this);
89+
context.before_eaches = this->before_eaches;
90+
context.after_eaches = this->after_eaches;
8991
return context.run();
9092
}
9193

@@ -99,6 +101,8 @@ template <class T>
99101
bool ClassDescription<T>::context(std::function<void(ClassDescription&)> body) {
100102
ClassContext<T> context(body);
101103
context.set_parent(this);
104+
context.before_eaches = this->before_eaches;
105+
context.after_eaches = this->after_eaches;
102106
return context.run();
103107
}
104108

@@ -108,6 +112,8 @@ bool Description::context(T subject,
108112
ClassContext<T> context(body);
109113
context.set_subject(subject);
110114
context.set_parent(this);
115+
context.before_eaches = this->before_eaches;
116+
context.after_eaches = this->after_eaches;
111117
return context.run();
112118
}
113119

@@ -122,6 +128,8 @@ bool Description::context(std::initializer_list<U> init_list,
122128
std::function<void(ClassDescription<T>&)> body) {
123129
ClassContext<T> context(T(init_list), body);
124130
context.set_parent(this);
131+
context.before_eaches = this->before_eaches;
132+
context.after_eaches = this->after_eaches;
125133
return context.run();
126134
}
127135

@@ -151,7 +159,10 @@ bool ClassDescription<T>::it(std::string name,
151159
std::function<void(ItCd<T>&)> body) {
152160
ItCd<T> it(name, body);
153161
it.set_parent(this);
154-
return it.run();
162+
bool result = it.run();
163+
exec_after_eaches();
164+
exec_before_eaches();
165+
return result;
155166
}
156167

157168
/**
@@ -179,7 +190,10 @@ template <class T>
179190
bool ClassDescription<T>::it(std::function<void(ItCd<T>&)> body) {
180191
ItCd<T> it(body);
181192
it.set_parent(this);
182-
return it.run();
193+
bool result = it.run();
194+
exec_after_eaches();
195+
exec_before_eaches();
196+
return result;
183197
}
184198

185199
template <class T>

include/cppspec.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
#define explain context
1111
#define expect self.template expect
1212
#define is_expected self.is_expected
13+
#define before_all self.before_all
14+
#define before_each self.before_each
15+
#define after_all self.after_all
16+
#define after_each self.after_each
1317

1418
typedef Description describe;
1519

include/description.hpp

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
#define DESCRIPTION_H
33

44
#include <string>
5-
#include <vector>
5+
#include <queue>
66
#include <map>
77
#include <functional>
88
#include <iostream>
99
#include <memory>
10+
#include "util.hpp"
1011
#include "runnable.hpp"
1112
#include "it.hpp"
1213

@@ -15,14 +16,14 @@ class ClassDescription;
1516

1617
class Description : public Runnable {
1718
typedef std::function<void(Description &)> block_t;
19+
typedef std::function<void()> rule_block_t;
1820
block_t body;
1921

2022
protected:
2123
std::string descr = "";
22-
// std::vector<block_t> before_all;
23-
// std::vector<block_t> after_all;
24-
// std::vector<block_t> before_each;
25-
// std::vector<block_t> after_each;
24+
std::deque<rule_block_t> after_alls;
25+
std::deque<rule_block_t> before_eaches;
26+
std::deque<rule_block_t> after_eaches;
2627

2728
explicit Description(std::string descr) : descr(descr){};
2829

@@ -47,8 +48,6 @@ class Description : public Runnable {
4748
bool context(std::initializer_list<U> init_list,
4849
std::function<void(ClassDescription<T> &)> body);
4950

50-
void before(std::string descr, block_t body);
51-
5251
template <class T>
5352
ClassDescription<T> subject(T subject);
5453

@@ -58,6 +57,13 @@ class Description : public Runnable {
5857
template <class T>
5958
ClassDescription<std::vector<T>> subject(std::initializer_list<T> init_list);
6059

60+
void before_each(rule_block_t block);
61+
void before_all(rule_block_t block);
62+
void after_each(rule_block_t block);
63+
void after_all(rule_block_t block);
64+
void exec_before_eaches();
65+
void exec_after_eaches();
66+
6167
bool run();
6268
};
6369

@@ -67,19 +73,27 @@ bool Description::context(std::string name,
6773
std::function<void(Description &)> body) {
6874
Context context(name, body);
6975
context.set_parent(this);
76+
context.before_eaches = this->before_eaches;
77+
context.after_eaches = this->after_eaches;
7078
return context.run();
7179
}
7280

7381
bool Description::it(std::string name, std::function<void(ItD &)> body) {
7482
ItD it(name, body);
7583
it.set_parent(this);
76-
return it.run();
84+
bool result = it.run();
85+
exec_after_eaches();
86+
exec_before_eaches();
87+
return result;
7788
}
7889

7990
bool Description::it(std::function<void(ItD &)> body) {
8091
ItD it(body);
8192
it.set_parent(this);
82-
return it.run();
93+
bool result = it.run();
94+
exec_after_eaches();
95+
exec_before_eaches();
96+
return result;
8397
}
8498

8599
template <class U>
@@ -104,9 +118,36 @@ ClassDescription<std::vector<U>> Description::subject(
104118
return cd;
105119
}
106120

121+
void Description::before_each(rule_block_t b) {
122+
before_eaches.push_back(b);
123+
124+
// Due to how lambdas and their contexts are passed around, we need to prime
125+
// the environment by executing the before_each, so that when an 'it'
126+
// declaration's lambda captures that env, it has the correct values for the
127+
// variables. Truthfully, 'before_each' is a misnomer, as they are not getting
128+
// executed directly before the lambda's execution as one might expect, but
129+
// instead before the *next* lambda is declared.
130+
b();
131+
}
132+
133+
void Description::before_all(rule_block_t b) { b(); }
134+
135+
void Description::after_each(rule_block_t b) { after_eaches.push_back(b); }
136+
137+
void Description::after_all(rule_block_t b) { after_alls.push_back(b); }
138+
139+
void Description::exec_before_eaches() {
140+
for (rule_block_t b : before_eaches) b();
141+
}
142+
143+
void Description::exec_after_eaches() {
144+
for (rule_block_t b : after_eaches) b();
145+
}
146+
107147
bool Description::run() {
108148
std::cout << padding() << descr << std::endl;
109149
body(*this);
150+
for (auto a : after_alls) a();
110151
std::cout << std::endl;
111152
return this->get_status();
112153
}

0 commit comments

Comments
 (0)