tokyo 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +335 -0
- data/Rakefile +11 -0
- data/bin/tokyo +4 -0
- data/lib/tokyo/assert.rb +148 -0
- data/lib/tokyo/core_ext.rb +103 -0
- data/lib/tokyo/expectations/raise.rb +32 -0
- data/lib/tokyo/expectations/return.rb +32 -0
- data/lib/tokyo/expectations/throw.rb +24 -0
- data/lib/tokyo/expectations/with.rb +36 -0
- data/lib/tokyo/expectations.rb +103 -0
- data/lib/tokyo/pretty_print.rb +55 -0
- data/lib/tokyo/run.rb +126 -0
- data/lib/tokyo/unit.rb +185 -0
- data/lib/tokyo/util/assert_raise.rb +54 -0
- data/lib/tokyo/util/assert_throw.rb +40 -0
- data/lib/tokyo/util/refute_raise.rb +48 -0
- data/lib/tokyo/util/refute_throw.rb +34 -0
- data/lib/tokyo/util.rb +91 -0
- data/lib/tokyo.rb +121 -0
- data/test/assert_test.rb +98 -0
- data/test/context_inheritance_test.rb +52 -0
- data/test/hooks_test.rb +35 -0
- data/test/raise_test.rb +66 -0
- data/test/receive_and_raise_test.rb +83 -0
- data/test/receive_and_return_test.rb +46 -0
- data/test/receive_and_throw_test.rb +74 -0
- data/test/receive_test.rb +71 -0
- data/test/receive_with_test.rb +57 -0
- data/test/refute_raise_test.rb +90 -0
- data/test/refute_throw_test.rb +42 -0
- data/test/setup.rb +25 -0
- data/test/skip_test.rb +35 -0
- data/test/throw_test.rb +58 -0
- data/tokyo.gemspec +27 -0
- metadata +195 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 69ea25a5800b85ee00d0af3c0129aec353c1fa95
|
4
|
+
data.tar.gz: 9bf8e1ae90ce5094fa1c9bb3a15e736c151fe491
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b03505ddcac1cc3a69ed2eca8dee762d35872d0063dec027214894c06263be54de8a160b9f0c0d36cea1cda2aa51995060f814e0c763daa33eb94ce8f633fbf7
|
7
|
+
data.tar.gz: 8a2971ff0047dcd9ec8a28c62211bc0f39aa327fd11165faf53775e20bcde6b7945538c8667abde0b84debc6f87f12347373d0db400985ccbab79e7d34c62cfb
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Slee Woo
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,335 @@
|
|
1
|
+
[](https://travis-ci.org/sleewoo/tokyo)
|
2
|
+
|
3
|
+
## Tokyo - super-simple testing library for Ruby
|
4
|
+
|
5
|
+
Its base API consist of just 10 memorable methods:
|
6
|
+
|
7
|
+
- spec, context
|
8
|
+
- before, around, after
|
9
|
+
- test
|
10
|
+
- assert, refute
|
11
|
+
- skip, fail
|
12
|
+
|
13
|
+
|
14
|
+
Assertions uses native Ruby methods so no need to remember contrived ones.
|
15
|
+
|
16
|
+
Forget about repeatedly scanning documentation, just use methods Ruby already provides.
|
17
|
+
|
18
|
+
Want to check whether something is nil? Use `nil?` method:
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
assert(something).nil?
|
22
|
+
```
|
23
|
+
|
24
|
+
Want to check whether some array contains some value? Use `include?` method:
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
assert(some_array).include? some_value
|
28
|
+
```
|
29
|
+
|
30
|
+
Need to check equality? Nothing simpler:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
assert(something) == something_else
|
34
|
+
```
|
35
|
+
|
36
|
+
Perhaps match?
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
assert(something) =~ something_else
|
40
|
+
```
|
41
|
+
|
42
|
+
Or any?
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
assert(some_array).any? {|v| v > 0}
|
46
|
+
```
|
47
|
+
|
48
|
+
Whatever. Use Ruby rather than contrived APIs.
|
49
|
+
|
50
|
+
|
51
|
+
And when you need to cook your own assertions simply use `assert` method to define them:
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
# defining a custom assertion
|
55
|
+
assert :is_a_pizza do |something|
|
56
|
+
something =~ /Cheese/ && something =~ /Olives/
|
57
|
+
end
|
58
|
+
|
59
|
+
# using it inside tests
|
60
|
+
test 'food' do
|
61
|
+
assert(something).is_a_pizza
|
62
|
+
end
|
63
|
+
```
|
64
|
+
|
65
|
+
## Installation
|
66
|
+
|
67
|
+
Add this line to your application's Gemfile:
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
gem 'tokyo'
|
71
|
+
```
|
72
|
+
|
73
|
+
And then execute:
|
74
|
+
|
75
|
+
$ bundle
|
76
|
+
|
77
|
+
Or install it yourself as:
|
78
|
+
|
79
|
+
$ gem install tokyo
|
80
|
+
|
81
|
+
## Usage
|
82
|
+
|
83
|
+
Add `require 'tokyo'` to your `Rakefile`.
|
84
|
+
|
85
|
+
Then create a task and use `Tokyo.run`:
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
task :test do
|
89
|
+
Tokyo.run
|
90
|
+
end
|
91
|
+
```
|
92
|
+
|
93
|
+
By default it will load `*_spec.rb` and `*_test.rb` files from `./spec` and `./test` folders.
|
94
|
+
|
95
|
+
If you named your test files differently use `Tokyo.run` with your pattern:
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
# search for test_*.rb files in ./tests folder
|
99
|
+
task :test do
|
100
|
+
Tokyo.run 'tests/test_*.rb'
|
101
|
+
end
|
102
|
+
```
|
103
|
+
|
104
|
+
If you want to run tests directly just use `tokyo` in your terminal:
|
105
|
+
|
106
|
+
```bash
|
107
|
+
tokyo
|
108
|
+
```
|
109
|
+
|
110
|
+
This will load `*_spec.rb` and `*_test.rb` files from `./spec` and `./test` folders.<br>
|
111
|
+
If your tests have different naming conventions call `tokyo` command with a pattern.<br>
|
112
|
+
For ex. load `test_*.rb` files in `./tests` folder:
|
113
|
+
|
114
|
+
```bash
|
115
|
+
tokyo tests/test_*.rb
|
116
|
+
```
|
117
|
+
|
118
|
+
|
119
|
+
## Specs
|
120
|
+
|
121
|
+
Specs are defined by using `spec` method. It requires a single argument - the spec label.<br>
|
122
|
+
It can be whatever but `nil`(which is used for another purpose, as shown below).
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
# defining a spec
|
126
|
+
spec Apple do
|
127
|
+
|
128
|
+
# and tests inside it
|
129
|
+
test :color do
|
130
|
+
end
|
131
|
+
end
|
132
|
+
```
|
133
|
+
|
134
|
+
Nested contexts can be used for splitting logic:
|
135
|
+
|
136
|
+
```ruby
|
137
|
+
spec Greens do
|
138
|
+
|
139
|
+
context Fruits do
|
140
|
+
|
141
|
+
context Apple do
|
142
|
+
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
```
|
147
|
+
|
148
|
+
## Specs are modules
|
149
|
+
|
150
|
+
`spec` method returns a module. Specs including that module will inherit all tests:
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
FruitsTests = spec Fruits do
|
154
|
+
# some tests
|
155
|
+
end
|
156
|
+
|
157
|
+
spec Apple do
|
158
|
+
# inheriting tests from FruitsTests spec
|
159
|
+
include FruitsTests
|
160
|
+
|
161
|
+
# defining own specs
|
162
|
+
end
|
163
|
+
```
|
164
|
+
|
165
|
+
If you want a module that just holds tests without run them, use `nil` for label:
|
166
|
+
|
167
|
+
|
168
|
+
```ruby
|
169
|
+
FruitsTests = spec nil do
|
170
|
+
# tests defined here will run only on specs that includes FruitsTests
|
171
|
+
end
|
172
|
+
```
|
173
|
+
|
174
|
+
## Global setups
|
175
|
+
|
176
|
+
`spec` method can also be used for defining a superset of instructions that will be run by all specs.
|
177
|
+
|
178
|
+
For this to work `spec` method should be called without arguments.<br>
|
179
|
+
Then the given block will run equally on all consequent specs.<br>
|
180
|
+
Multiple global setups can be defined and they will run inside specs in the order they was defined.
|
181
|
+
|
182
|
+
```ruby
|
183
|
+
# supposedly in setup.rb
|
184
|
+
spec do
|
185
|
+
include SomeModule
|
186
|
+
end
|
187
|
+
|
188
|
+
# somewhere in test files
|
189
|
+
spec Fruits do
|
190
|
+
# this spec will include SomeModule implicitly
|
191
|
+
end
|
192
|
+
```
|
193
|
+
|
194
|
+
## Before, around, after
|
195
|
+
|
196
|
+
Run some code before every test:
|
197
|
+
|
198
|
+
```ruby
|
199
|
+
spec 'Fruits' do
|
200
|
+
before { @fruit = Fruit.new }
|
201
|
+
|
202
|
+
# tests here will have @fruit variable defined
|
203
|
+
end
|
204
|
+
```
|
205
|
+
|
206
|
+
When you need to run some code after every test simply use `after` method same way as `before`.
|
207
|
+
|
208
|
+
There is also an `around` method that will wrap each test into a block.<br>
|
209
|
+
The difference is you have to call test manually:
|
210
|
+
|
211
|
+
```ruby
|
212
|
+
spec 'Fruits' do
|
213
|
+
around do |test|
|
214
|
+
# initialization stuff
|
215
|
+
test.call
|
216
|
+
# teardown stuff
|
217
|
+
end
|
218
|
+
|
219
|
+
# tests here will run inside around block
|
220
|
+
end
|
221
|
+
```
|
222
|
+
|
223
|
+
There is no way to run code before/around/after specific tests.<br>
|
224
|
+
If you have tests that needs specific initialization/teardown logic put them into a separate `context`.
|
225
|
+
|
226
|
+
|
227
|
+
## Skipping tests and specs
|
228
|
+
|
229
|
+
When you need to skip a test simply use `skip` method with a reason provided as first argument:
|
230
|
+
|
231
|
+
```ruby
|
232
|
+
test 'something' do
|
233
|
+
# any code before skip will still run
|
234
|
+
skip 'will test this later'
|
235
|
+
# code here wont run
|
236
|
+
end
|
237
|
+
```
|
238
|
+
|
239
|
+
`skip` also works for entire specs:
|
240
|
+
|
241
|
+
```ruby
|
242
|
+
spec Fruits do
|
243
|
+
|
244
|
+
skip 'concentrating on Vegetables for now...'
|
245
|
+
|
246
|
+
# tests here wont run
|
247
|
+
end
|
248
|
+
```
|
249
|
+
|
250
|
+
## Explicit failures
|
251
|
+
|
252
|
+
When you need to throw a failure with a custom message use `fail` method:
|
253
|
+
|
254
|
+
```ruby
|
255
|
+
test 'something' do
|
256
|
+
@a > @b || fail("#a should be greater than #b")
|
257
|
+
# code here wont run
|
258
|
+
end
|
259
|
+
```
|
260
|
+
|
261
|
+
## `raise` helper
|
262
|
+
|
263
|
+
`raise` allows to check whether some code raises a specific or any exception.
|
264
|
+
|
265
|
+
Check the block raises whatever exception:
|
266
|
+
|
267
|
+
```ruby
|
268
|
+
assert {some code}.raise
|
269
|
+
```
|
270
|
+
|
271
|
+
Check the block raises a NameError exception:
|
272
|
+
|
273
|
+
```ruby
|
274
|
+
assert {some code}.raise NameError
|
275
|
+
```
|
276
|
+
|
277
|
+
Check the block raises a FruitError exception that match /apple/:
|
278
|
+
|
279
|
+
```ruby
|
280
|
+
assert {some code}.raise FruitError, /apple/
|
281
|
+
```
|
282
|
+
|
283
|
+
Use a block to check raised exception:
|
284
|
+
|
285
|
+
```ruby
|
286
|
+
assert {some code}.raise {|e| e.is_a? FruitError}
|
287
|
+
```
|
288
|
+
|
289
|
+
Also alternative syntax available:
|
290
|
+
|
291
|
+
```ruby
|
292
|
+
expect {some code}.to_raise ...
|
293
|
+
```
|
294
|
+
|
295
|
+
|
296
|
+
## `throw` helper
|
297
|
+
|
298
|
+
Check the block throws whatever symbol:
|
299
|
+
|
300
|
+
```ruby
|
301
|
+
assert {some code}.throw
|
302
|
+
```
|
303
|
+
|
304
|
+
Check the block throws `:ok` symbol:
|
305
|
+
|
306
|
+
```ruby
|
307
|
+
assert {some code}.throw :ok
|
308
|
+
```
|
309
|
+
|
310
|
+
Use a block to validate thrown symbol:
|
311
|
+
|
312
|
+
```ruby
|
313
|
+
assert {some code}.throw {|s| s == :ok}
|
314
|
+
```
|
315
|
+
|
316
|
+
Also alternative syntax available:
|
317
|
+
|
318
|
+
```ruby
|
319
|
+
expect {some code}.to_throw ...
|
320
|
+
```
|
321
|
+
|
322
|
+
## Development
|
323
|
+
|
324
|
+
Make sure `bundler` is installed then run `bundle install` to install all dependencies.
|
325
|
+
|
326
|
+
Make your changes and run `rake` to check all tests pass.
|
327
|
+
|
328
|
+
|
329
|
+
## Contributing
|
330
|
+
|
331
|
+
1. Fork it ( https://github.com/[my-github-username]/tokyo/fork )
|
332
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
333
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
334
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
335
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
|
5
|
+
root = File.expand_path('..', __FILE__)
|
6
|
+
Rake::TestTask.new do |t|
|
7
|
+
t.ruby_opts << '-r "%s/test/setup" -I "%s/lib"' % [root, root]
|
8
|
+
t.pattern = 'test/**/*_test.rb'
|
9
|
+
t.verbose = true
|
10
|
+
end
|
11
|
+
task default: :test
|
data/bin/tokyo
ADDED
data/lib/tokyo/assert.rb
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
module Tokyo
|
2
|
+
class Assert
|
3
|
+
|
4
|
+
def initialize object, action = :assert, caller = nil
|
5
|
+
@object = object
|
6
|
+
@caller = caller
|
7
|
+
@assert = action == :assert
|
8
|
+
@refute = action == :refute
|
9
|
+
@assert || @refute || Kernel.raise(ArgumentError, 'action should be either :assert or :refute')
|
10
|
+
end
|
11
|
+
|
12
|
+
instance_methods.each do |m|
|
13
|
+
# overriding all instance methods so received messages to be passed to tested object.
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
# assert(x).frozen?
|
17
|
+
# # `assert` returns a object that receives `frozen?` message and pass it to x
|
18
|
+
#
|
19
|
+
define_method m do |*a, &b|
|
20
|
+
__assert__(m, a, b)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# forward any missing method to tested object.
|
25
|
+
#
|
26
|
+
# @example
|
27
|
+
# assert(some_array).include? x
|
28
|
+
# # object returned by `assert` does not respond to `include?`
|
29
|
+
# # so `include?` is passed to `some_array`
|
30
|
+
#
|
31
|
+
def method_missing m, *a, &b
|
32
|
+
__assert__(m, a, b)
|
33
|
+
end
|
34
|
+
|
35
|
+
# ensure the given block raises as expected
|
36
|
+
#
|
37
|
+
# @note if block given it will have precedence over arguments
|
38
|
+
#
|
39
|
+
# @example assertion pass if block raises whatever
|
40
|
+
# assert {some code}.raise
|
41
|
+
#
|
42
|
+
# @example assertion pass if block raises NameError
|
43
|
+
# assert {some code}.raise NameError
|
44
|
+
#
|
45
|
+
# @example assertion pass if block raises NameError and error message matches /blah/
|
46
|
+
# assert {some code}.raise NameError, /blah/
|
47
|
+
#
|
48
|
+
# @example assertion pass if block raises whatever error that matches /blah/
|
49
|
+
# assert {some code}.raise nil, /blah/
|
50
|
+
#
|
51
|
+
# @example assertion pass if validation block returns a positive value
|
52
|
+
# assert {some code}.raise {|e| e.is_a?(NameError) && e.message =~ /blah/}
|
53
|
+
#
|
54
|
+
#
|
55
|
+
# @example assertion pass if nothing raised
|
56
|
+
# refute {some code}.raise
|
57
|
+
# # same
|
58
|
+
# fail_if {some code}.raise
|
59
|
+
#
|
60
|
+
# @example assertion fails only if block raises a NameError.
|
61
|
+
# it may raise whatever but NameError. if nothing raised assertion will fail.
|
62
|
+
#
|
63
|
+
# fail_if {some code}.raise NameError
|
64
|
+
#
|
65
|
+
# @example assertion pass if raised error does not match /blah/
|
66
|
+
# if nothing raised assertion will fail.
|
67
|
+
#
|
68
|
+
# fail_if {some code}.raise nil, /blah/
|
69
|
+
#
|
70
|
+
# @example assertion will pass if raised error is not a NameError
|
71
|
+
# and error message does not match /blah/
|
72
|
+
# if nothing raised assertion will fail as well.
|
73
|
+
#
|
74
|
+
# fail_if {some code}.raise NameError, /blah/
|
75
|
+
#
|
76
|
+
def raise type = nil, message = nil, &block
|
77
|
+
failure = Tokyo.__send__(
|
78
|
+
@assert ? :assert_raised_as_expected : :refute_raised_as_expected,
|
79
|
+
@object, type, message, block
|
80
|
+
)
|
81
|
+
Tokyo.fail(failure, caller[0]) if failure
|
82
|
+
end
|
83
|
+
alias to_raise raise
|
84
|
+
|
85
|
+
# ensure given block thrown as expected
|
86
|
+
#
|
87
|
+
# @note if block given it will have precedence over arguments
|
88
|
+
#
|
89
|
+
# @example assertion pass if any symbol thrown
|
90
|
+
# assert {some code}.throw
|
91
|
+
#
|
92
|
+
# @example assertion pass only if :x symbol thrown
|
93
|
+
# assert {some code}.throw(:x)
|
94
|
+
#
|
95
|
+
# @example assertion pass only if given block validates thrown symbol
|
96
|
+
# assert {some code}.throw {|sym| sym == :x}
|
97
|
+
#
|
98
|
+
def throw expected_symbol = nil, &block
|
99
|
+
failure = Tokyo.__send__(
|
100
|
+
@assert ? :assert_thrown_as_expected : :refute_thrown_as_expected,
|
101
|
+
@object, expected_symbol ? expected_symbol.to_sym : nil, block
|
102
|
+
)
|
103
|
+
Tokyo.fail(failure, caller[0]) if failure
|
104
|
+
end
|
105
|
+
alias to_throw throw
|
106
|
+
|
107
|
+
# ensure given mock will receive expected message by the end of test
|
108
|
+
#
|
109
|
+
# @example
|
110
|
+
# test :auth do
|
111
|
+
# user = mock(User.new)
|
112
|
+
# expect(user).to_receive(:password)
|
113
|
+
# user.authenticate
|
114
|
+
# # by the end of test user should receive :password message,
|
115
|
+
# # otherwise the test will fail
|
116
|
+
# end
|
117
|
+
#
|
118
|
+
# @param Symbol expected message
|
119
|
+
# @return [Expectation]
|
120
|
+
#
|
121
|
+
def receive expected_message
|
122
|
+
Kernel.throw(:__tokyo_status__, @object[:raised]) if @object[:raised]
|
123
|
+
@__expectation__ = Expectation.new(@object[:returned], expected_message.to_sym, @assert, caller[0])
|
124
|
+
end
|
125
|
+
alias to_receive receive
|
126
|
+
|
127
|
+
def __validate_expectations__
|
128
|
+
return unless @__expectation__
|
129
|
+
@__expectation__.validate
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
def __assert__ message, arguments, block
|
134
|
+
Tokyo.total_assertions << true
|
135
|
+
Kernel.throw(:__tokyo_status__, @object[:raised]) if @object[:raised]
|
136
|
+
result = __send_message__(@object[:returned], message, arguments, block)
|
137
|
+
return true if (@assert && result) || (@refute && !result)
|
138
|
+
Kernel.throw(:__tokyo_status__, AssertionFailure.new(@object[:returned], arguments, @caller))
|
139
|
+
end
|
140
|
+
|
141
|
+
def __send_message__ object, message, arguments, block
|
142
|
+
if assertion = Tokyo.assertions[message.to_sym]
|
143
|
+
return assertion.call(object, *arguments, &block)
|
144
|
+
end
|
145
|
+
object.__send__(message, *arguments, &block)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module Kernel
|
2
|
+
|
3
|
+
# when called with a no-nil no-false argument it defines, register and returns a spec.
|
4
|
+
# when called with a nil or false argument it defines and returns a spec but does not register it.
|
5
|
+
# when called without arguments it defines a global setup that will run on each new created spec/context.
|
6
|
+
#
|
7
|
+
# @note a Unit Module is a regular Ruby Module that when included will execute the Unit's block on base
|
8
|
+
#
|
9
|
+
# @example define regular specs
|
10
|
+
# spec :some_spec do
|
11
|
+
# # ...
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# @example define a spec that will run on its own and can also be included into another specs/contexts
|
15
|
+
# shared = spec :some_shared_spec do
|
16
|
+
# # ...
|
17
|
+
# end
|
18
|
+
# # `shared` is now a spec good for inclusion in another specs/contexts.
|
19
|
+
#
|
20
|
+
# @example define a spec that wont run on itself but can be included into another specs/contexts
|
21
|
+
# Shared = spec nil do
|
22
|
+
# # ...
|
23
|
+
# end
|
24
|
+
# # `Shared` is now a module good for inclusion in another specs/contexts
|
25
|
+
# # but because `nil` used as first argument it wont run as a spec itself
|
26
|
+
#
|
27
|
+
# @example define a global setup, i.e. a block that will run inside any new defined spec/context
|
28
|
+
# spec do
|
29
|
+
# include Rack::Test # now Rack::Test will be included in any spec/context
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
def spec label = (noargs=true; nil), &block
|
33
|
+
block || raise(ArgumentError, 'missing block')
|
34
|
+
|
35
|
+
if noargs
|
36
|
+
# no arguments given, defining a global setup and returning
|
37
|
+
Tokyo::GLOBAL_SETUPS.include?(block) || Tokyo::GLOBAL_SETUPS.push(block)
|
38
|
+
return
|
39
|
+
end
|
40
|
+
|
41
|
+
if label
|
42
|
+
# a no-nil no-false argument given, defining a regular spec
|
43
|
+
Tokyo.define_and_register_a_spec(label, block)
|
44
|
+
end
|
45
|
+
|
46
|
+
# defining a shared spec that wont run itself
|
47
|
+
# but can be included in another specs/contexts
|
48
|
+
Tokyo.define_unit_module(block)
|
49
|
+
end
|
50
|
+
|
51
|
+
# when used out of tests it defines a assertion helper.
|
52
|
+
# the block should return a no-false no-nil value for assertion to pass.
|
53
|
+
# the block will receive tested object as first argument
|
54
|
+
# and any arguments passed to assertion as consequent ones.
|
55
|
+
# it will also receive the passed block.
|
56
|
+
#
|
57
|
+
# @example checks whether two arrays has same keys, orderlessly
|
58
|
+
# assert :has_same_keys_as do |a, b|
|
59
|
+
# a.keys.sort == b.keys.sort
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
# spec :some_spec do
|
63
|
+
# test :some_test do
|
64
|
+
# a = [1, 2]
|
65
|
+
# b = [2, 1]
|
66
|
+
# assert(a).has_same_keys_as(b) # => true
|
67
|
+
# end
|
68
|
+
# end
|
69
|
+
#
|
70
|
+
# @example same assertion by multiple names
|
71
|
+
# assert :includes, :to_include do |a, b|
|
72
|
+
# a.keys.sort == b.keys.sort
|
73
|
+
# end
|
74
|
+
#
|
75
|
+
# spec :some_spec do
|
76
|
+
# test :some_test do
|
77
|
+
# a = [1, 2]
|
78
|
+
# assert(a).includes(1) # => true
|
79
|
+
# # same
|
80
|
+
# expect(a).to_include(1) # => true
|
81
|
+
# end
|
82
|
+
# end
|
83
|
+
#
|
84
|
+
# @param [Array] *labels
|
85
|
+
#
|
86
|
+
def assert *labels, &block
|
87
|
+
labels.any? || raise(ArgumentError, 'Wrong number of arguments, 0 for 1+')
|
88
|
+
block || raise(ArgumentError, 'missing block')
|
89
|
+
labels.each {|label| Tokyo.assertions[label.to_sym] = block}
|
90
|
+
end
|
91
|
+
|
92
|
+
# stop executing any code and report a failure
|
93
|
+
#
|
94
|
+
# @example
|
95
|
+
# x > y || fail('x should be greater than y')
|
96
|
+
#
|
97
|
+
# @param reason
|
98
|
+
#
|
99
|
+
def fail *reason
|
100
|
+
reason.empty? && raise(ArgumentError, 'Wrong number or arguments, 0 for 1+')
|
101
|
+
Tokyo.fail(reason.flatten, caller[0])
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Tokyo
|
2
|
+
class Expectation
|
3
|
+
|
4
|
+
# ensure received message raises as expected
|
5
|
+
#
|
6
|
+
# @note if block given it will have precedence over arguments
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# x = mock(X.new)
|
10
|
+
# expect(x).to_receive(:y).and_raise(NoMethodError)
|
11
|
+
# # call `x.y` for test to pass
|
12
|
+
#
|
13
|
+
def and_raise type = nil, message = nil, &block
|
14
|
+
@raise = block || [type, message]
|
15
|
+
end
|
16
|
+
|
17
|
+
def assert_message_raised_as_expected
|
18
|
+
return unless @raise
|
19
|
+
if @raise.is_a?(Proc)
|
20
|
+
received_messages.find {|log| @raise.call(log[:raised])} || Tokyo.fail([
|
21
|
+
'Looks like :%s message never raised as expected' % expected_message,
|
22
|
+
'See validation block'
|
23
|
+
], @caller)
|
24
|
+
else
|
25
|
+
received_messages.each do |log|
|
26
|
+
next unless f = Tokyo.assert_raised_as_expected(log, *@raise)
|
27
|
+
Tokyo.fail(f, log[:caller])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|