pork 0.1.0 → 0.9.0
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 +4 -4
- data/.gitignore +1 -0
- data/CHANGES.md +9 -0
- data/README.md +580 -2
- data/lib/pork.rb +132 -94
- data/lib/pork/auto.rb +4 -0
- data/lib/pork/version.rb +1 -1
- data/pork.gemspec +12 -9
- data/task/gemgem.rb +0 -4
- data/test/test_bacon.rb +112 -106
- data/test/test_nested.rb +30 -12
- data/test/test_readme.rb +14 -0
- metadata +11 -6
- data/lib/pork/task.rb +0 -2
- data/pkg/pork-0.1.0.gem +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0720abd3578e820759c2cec35d565a41e41d6f79
|
4
|
+
data.tar.gz: 3abb0dc9d216004aa1fa11590fef142671111168
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6387d2c2049e7bbab044bcfba005616e3a236b9f58f2303c06fbd6b47613ee277c8219f098b49671e5011f94c3dab80aa449ffa8effb139da8885a1fc138355f
|
7
|
+
data.tar.gz: e4e2189fc58eede08bdcf3d65580ef1728474728fce82db3dae57f5ab013b6611b4385b5b16700ab54feba4b97e9cd1ed18470ea05ad633622f78222bdbc09a4
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
/pkg/
|
data/CHANGES.md
ADDED
data/README.md
CHANGED
@@ -10,13 +10,140 @@ by Lin Jen-Shin ([godfat](http://godfat.org))
|
|
10
10
|
|
11
11
|
## DESCRIPTION:
|
12
12
|
|
13
|
-
|
13
|
+
Pork -- Simple and clean and modular testing library.
|
14
|
+
|
15
|
+
[Bacon][] reimplemented around 250 lines of code.
|
14
16
|
|
15
17
|
[Bacon]: https://github.com/chneukirchen/bacon
|
16
18
|
|
19
|
+
## DESIGN:
|
20
|
+
|
21
|
+
* Consistency over convenience.
|
22
|
+
* Avoid polluting anything by default to make integration easier.
|
23
|
+
* The less codes the better.
|
24
|
+
|
17
25
|
## WHY?
|
18
26
|
|
19
|
-
[Bacon][] has some issues which can't be easily worked around.
|
27
|
+
[Bacon][] has some issues which can't be easily worked around. For example,
|
28
|
+
the context of the running test is not consistent in nested describe block.
|
29
|
+
|
30
|
+
This won't work in Bacon:
|
31
|
+
|
32
|
+
``` ruby
|
33
|
+
require 'bacon'
|
34
|
+
Bacon.summary_on_exit
|
35
|
+
|
36
|
+
# This would include to all context,
|
37
|
+
# so that we don't have to include in all describe block.
|
38
|
+
Bacon::Context.include Module.new{
|
39
|
+
def in_module
|
40
|
+
object_id
|
41
|
+
end
|
42
|
+
}
|
43
|
+
|
44
|
+
describe 'A' do
|
45
|
+
def in_describe
|
46
|
+
object_id
|
47
|
+
end
|
48
|
+
|
49
|
+
describe 'B' do
|
50
|
+
should 'have the same context' do
|
51
|
+
in_module.should == in_describe # FAIL!
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
```
|
56
|
+
|
57
|
+
But this works in Pork:
|
58
|
+
|
59
|
+
``` ruby
|
60
|
+
require 'pork/auto'
|
61
|
+
|
62
|
+
describe 'A' do
|
63
|
+
include Module.new{
|
64
|
+
def in_module
|
65
|
+
object_id
|
66
|
+
end
|
67
|
+
}
|
68
|
+
|
69
|
+
def in_describe
|
70
|
+
object_id
|
71
|
+
end
|
72
|
+
|
73
|
+
describe 'B' do
|
74
|
+
would 'have the same context' do
|
75
|
+
in_module.should == in_describe
|
76
|
+
end
|
77
|
+
|
78
|
+
def in_nested_describe
|
79
|
+
object_id
|
80
|
+
end
|
81
|
+
|
82
|
+
would 'respond_to? in_nested_describe' do
|
83
|
+
should.respond_to?(:in_nested_describe)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Pork is completely tree structured, nested methods can't be accessed
|
88
|
+
# from outside of the scope.
|
89
|
+
would 'not respond_to? in_nested_describe' do
|
90
|
+
should.not.respond_to?(:in_nested_describe)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe 'C' do
|
95
|
+
# Also, we're not forced to include something in all describe blocks.
|
96
|
+
# If we want, we could do this instead: `Pork::Executor.include(Module.new)`
|
97
|
+
# That would be the same as including in `Bacon::Context`
|
98
|
+
would 'not respond_to? in_module nor in_describe' do
|
99
|
+
should.not.respond_to?(:in_module)
|
100
|
+
should.not.respond_to?(:in_describe)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
```
|
104
|
+
|
105
|
+
Also, Bacon won't clear instance variables as well.
|
106
|
+
|
107
|
+
``` ruby
|
108
|
+
require 'bacon'
|
109
|
+
Bacon.summary_on_exit
|
110
|
+
|
111
|
+
describe 'instance variables in tests' do
|
112
|
+
before do
|
113
|
+
@a ||= 0
|
114
|
+
@a += 1
|
115
|
+
end
|
116
|
+
|
117
|
+
should 'always be 1' do
|
118
|
+
@a.should == 1
|
119
|
+
end
|
120
|
+
|
121
|
+
should 'always be 1' do
|
122
|
+
@a.should == 1 # FAIL!
|
123
|
+
end
|
124
|
+
end
|
125
|
+
```
|
126
|
+
|
127
|
+
Every tests would be a whole new instance for Pork as expected:
|
128
|
+
|
129
|
+
``` ruby
|
130
|
+
require 'pork/auto'
|
131
|
+
|
132
|
+
describe 'instance variables in tests' do
|
133
|
+
before do
|
134
|
+
@a ||= 0
|
135
|
+
@a += 1
|
136
|
+
end
|
137
|
+
|
138
|
+
would 'always be 1' do
|
139
|
+
@a.should == 1
|
140
|
+
end
|
141
|
+
|
142
|
+
would 'always be 1' do
|
143
|
+
@a.should == 1
|
144
|
+
end
|
145
|
+
end
|
146
|
+
```
|
20
147
|
|
21
148
|
## REQUIREMENTS:
|
22
149
|
|
@@ -28,6 +155,457 @@ by Lin Jen-Shin ([godfat](http://godfat.org))
|
|
28
155
|
|
29
156
|
## SYNOPSIS:
|
30
157
|
|
158
|
+
A simple example:
|
159
|
+
|
160
|
+
``` ruby
|
161
|
+
require 'pork/auto'
|
162
|
+
|
163
|
+
describe Array do
|
164
|
+
before do
|
165
|
+
@array = []
|
166
|
+
end
|
167
|
+
|
168
|
+
after do
|
169
|
+
@array.clear
|
170
|
+
end
|
171
|
+
|
172
|
+
would 'be empty' do
|
173
|
+
@array.should.empty?
|
174
|
+
@array.should.not.include? 1
|
175
|
+
end
|
176
|
+
|
177
|
+
would 'have zero size' do
|
178
|
+
# We prefer `eq` here over `==` to avoid warnings from Ruby
|
179
|
+
@array.size.should.eq 0
|
180
|
+
end
|
181
|
+
|
182
|
+
would 'raise IndexError for fetching from non-existing index' do
|
183
|
+
should.raise(IndexError){ @array.fetch(0) }.message.
|
184
|
+
should.match(/\d+/)
|
185
|
+
|
186
|
+
# Alternatively:
|
187
|
+
lambda{ @array.fetch(0) }.should.raise(IndexError).message.
|
188
|
+
should.match(/\d+/)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
```
|
192
|
+
|
193
|
+
Copy and paste for modularity:
|
194
|
+
|
195
|
+
``` ruby
|
196
|
+
require 'pork/auto'
|
197
|
+
|
198
|
+
copy 'empty test' do |error|
|
199
|
+
after do
|
200
|
+
@data.clear
|
201
|
+
end
|
202
|
+
|
203
|
+
would 'be empty' do
|
204
|
+
@data.should.empty?
|
205
|
+
@data.should.not.include? 1
|
206
|
+
end
|
207
|
+
|
208
|
+
would 'have zero size' do
|
209
|
+
# We prefer `eq` here over `==` to avoid warnings from Ruby
|
210
|
+
@data.size.should.eq 0
|
211
|
+
end
|
212
|
+
|
213
|
+
would "raise #{error} for fetching from non-existing index" do
|
214
|
+
should.raise(error){ @data.fetch(0) }.message.
|
215
|
+
should.match(/\d+/)
|
216
|
+
|
217
|
+
# Alternatively:
|
218
|
+
lambda{ @data.fetch(0) }.should.raise(error).message.
|
219
|
+
should.match(/\d+/)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
describe Array do
|
224
|
+
before do
|
225
|
+
@data = []
|
226
|
+
end
|
227
|
+
|
228
|
+
paste 'empty test', IndexError
|
229
|
+
end
|
230
|
+
|
231
|
+
describe Hash do
|
232
|
+
before do
|
233
|
+
@data = {}
|
234
|
+
end
|
235
|
+
|
236
|
+
paste 'empty test', KeyError
|
237
|
+
end
|
238
|
+
```
|
239
|
+
|
240
|
+
Context sensitive paste:
|
241
|
+
|
242
|
+
``` ruby
|
243
|
+
require 'pork/auto'
|
244
|
+
|
245
|
+
copy 'empty test' do |error|
|
246
|
+
paste :setup_data # it would search from the pasted context
|
247
|
+
|
248
|
+
would "raise #{error} for fetching from non-existing index" do
|
249
|
+
should.raise(error){ @data.fetch(0) }.message.
|
250
|
+
should.match(/\d+/)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
describe Array do
|
255
|
+
copy :setup_data do
|
256
|
+
before do
|
257
|
+
@data = []
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
paste 'empty test', IndexError
|
262
|
+
end
|
263
|
+
|
264
|
+
describe Hash do
|
265
|
+
copy :setup_data do
|
266
|
+
before do
|
267
|
+
@data = {}
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
paste 'empty test', KeyError
|
272
|
+
end
|
273
|
+
```
|
274
|
+
|
275
|
+
## The API
|
276
|
+
|
277
|
+
### Pork::API.describe
|
278
|
+
|
279
|
+
So this creates a test suite which should be containing various test cases
|
280
|
+
(`Pork::API.would`). The argument represents the description of the test
|
281
|
+
suite, which accepts anything could be converted to a string. The _default_
|
282
|
+
description is `:default` (which would be converted to `'default: '`)
|
283
|
+
|
284
|
+
Each `describe` block would create a new subclass of `Pork::Executor` for
|
285
|
+
isolating test suites. Each nested `describe` block would be a subclass of
|
286
|
+
its parent `Pork::Executor`.
|
287
|
+
|
288
|
+
``` ruby
|
289
|
+
require 'pork/auto'
|
290
|
+
|
291
|
+
describe do
|
292
|
+
would 'be default: for the default description' do
|
293
|
+
self.class.desc.should.eq 'default: '
|
294
|
+
end
|
295
|
+
end
|
296
|
+
```
|
297
|
+
|
298
|
+
### Pork::API.would
|
299
|
+
|
300
|
+
Essentially runs a test case. It could also be called in the top-level
|
301
|
+
without being contained in a `describe` block. The argument represents the
|
302
|
+
description of the test case, which accepts anything could be converted to
|
303
|
+
a string. The _default_ description is also `:default`.
|
304
|
+
|
305
|
+
Each `would` block would be run inside a new instance of the describing
|
306
|
+
`Pork::Executor` to isolate instance variables.
|
307
|
+
|
308
|
+
``` ruby
|
309
|
+
require 'pork/auto'
|
310
|
+
|
311
|
+
would do
|
312
|
+
desc.should.eq :default
|
313
|
+
end
|
314
|
+
```
|
315
|
+
|
316
|
+
### Pork::API.before
|
317
|
+
|
318
|
+
Each `before` block would be called before each `would` block (test case).
|
319
|
+
You would probably want to setup stuffs inside `before` blocks.
|
320
|
+
|
321
|
+
Each nested `describe` would also run parents' `before` blocks as well.
|
322
|
+
|
323
|
+
``` ruby
|
324
|
+
require 'pork/auto'
|
325
|
+
|
326
|
+
describe do
|
327
|
+
before do
|
328
|
+
@a = 0
|
329
|
+
end
|
330
|
+
|
331
|
+
describe do
|
332
|
+
before do
|
333
|
+
@a.should.eq 0
|
334
|
+
@a += 1
|
335
|
+
end
|
336
|
+
|
337
|
+
would do
|
338
|
+
@a.should.eq 1
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
```
|
343
|
+
|
344
|
+
### Pork::API.after
|
345
|
+
|
346
|
+
Each `after` block would be called after each `would` block (test case).
|
347
|
+
You would probably want to cleanup stuffs inside `after` blocks.
|
348
|
+
|
349
|
+
Each nested `describe` would also run parents' `after` block as well.
|
350
|
+
|
351
|
+
``` ruby
|
352
|
+
require 'pork/auto'
|
353
|
+
|
354
|
+
describe do
|
355
|
+
after do
|
356
|
+
@a.should.eq 1
|
357
|
+
@a += 1
|
358
|
+
end
|
359
|
+
|
360
|
+
describe do
|
361
|
+
after do
|
362
|
+
@a.should.eq 2
|
363
|
+
end
|
364
|
+
|
365
|
+
would do
|
366
|
+
@a = 1
|
367
|
+
@a.should.eq 1
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
371
|
+
```
|
372
|
+
|
373
|
+
### Pork::API.copy and Pork::API.paste
|
374
|
+
|
375
|
+
It could be a bit confusing at first, but just think of `copy` as a way to
|
376
|
+
store the block with a name (default is `:default`), and whenever we `paste`,
|
377
|
+
the stored block would be called at the context where we paste.
|
378
|
+
|
379
|
+
The name could be anything, strings, symbols, numbers, classes, anything.
|
380
|
+
|
381
|
+
The block passed to `copy` could have parameters. The second through the last
|
382
|
+
arguments passed to `paste` would be passing to the block saved in copy.
|
383
|
+
|
384
|
+
``` ruby
|
385
|
+
require 'pork/auto'
|
386
|
+
|
387
|
+
copy :default do |a=0, b=1|
|
388
|
+
before do
|
389
|
+
@a, @b = a, b
|
390
|
+
end
|
391
|
+
|
392
|
+
def f
|
393
|
+
@a + @b
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
describe do
|
398
|
+
paste :default, 1, 0
|
399
|
+
|
400
|
+
would do
|
401
|
+
f.should.eq 1
|
402
|
+
end
|
403
|
+
end
|
404
|
+
```
|
405
|
+
|
406
|
+
### Pork::Executor#skip
|
407
|
+
|
408
|
+
At times we might want to skip some tests while leave the codes there without
|
409
|
+
removing them or commenting them out. This is where `skip` would be helpful.
|
410
|
+
|
411
|
+
``` ruby
|
412
|
+
require 'pork/auto'
|
413
|
+
|
414
|
+
describe do
|
415
|
+
would do
|
416
|
+
skip
|
417
|
+
end
|
418
|
+
end
|
419
|
+
```
|
420
|
+
|
421
|
+
### Pork::Executor#ok
|
422
|
+
|
423
|
+
Because Pork would complain if a test case does not have any assertions,
|
424
|
+
sometimes we might want to tell Pork that it's ok because we've already
|
425
|
+
made some assertions without using Pork's assertions. Then we'll want `ok`.
|
426
|
+
|
427
|
+
The reason why complaining about missing assertions is useful is because
|
428
|
+
sometimes we might expect some assertions would be made in a certain flow.
|
429
|
+
If the flow is not correctly called, we could miss assertions. So it's good
|
430
|
+
to explicitly claim that we don't care about assertions rather than letting
|
431
|
+
them slip through implicitly.
|
432
|
+
|
433
|
+
``` ruby
|
434
|
+
require 'pork/auto'
|
435
|
+
|
436
|
+
describe do
|
437
|
+
would do
|
438
|
+
'verify with mocks, and pork has no idea about that'.to_s
|
439
|
+
ok
|
440
|
+
end
|
441
|
+
end
|
442
|
+
```
|
443
|
+
|
444
|
+
### Pork::Executor#flunk
|
445
|
+
|
446
|
+
If we're writing program carefully, there are a few cases where a condition
|
447
|
+
would never meet. We could `raise "IMPOSSIBLE"` or we could simply call
|
448
|
+
`flunk`.
|
449
|
+
|
450
|
+
``` ruby
|
451
|
+
require 'pork/auto'
|
452
|
+
|
453
|
+
describe do
|
454
|
+
would do
|
455
|
+
should.raise(Pork::Error){ flunk }
|
456
|
+
end
|
457
|
+
end
|
458
|
+
```
|
459
|
+
|
460
|
+
### Pork::Should#satisfy
|
461
|
+
|
462
|
+
If we want to have custom verifier, that is it.
|
463
|
+
|
464
|
+
``` ruby
|
465
|
+
require 'pork/auto'
|
466
|
+
|
467
|
+
describe do
|
468
|
+
divided_by_2 = lambda{ |n| n % 2 == 0 }
|
469
|
+
|
470
|
+
would do
|
471
|
+
2.should.satisfy(÷d_by_2)
|
472
|
+
end
|
473
|
+
end
|
474
|
+
```
|
475
|
+
|
476
|
+
### Pork::Should#not
|
477
|
+
|
478
|
+
An easy way to negate the expectation.
|
479
|
+
|
480
|
+
``` ruby
|
481
|
+
require 'pork/auto'
|
482
|
+
|
483
|
+
would{ 1.should.not.eq 2 }
|
484
|
+
```
|
485
|
+
|
486
|
+
### Pork::Should#eq
|
487
|
+
|
488
|
+
To avoid warnings from Ruby, using `eq` instead of `==`. It's fine if you
|
489
|
+
still prefer using `==` if you don't care about warnings.
|
490
|
+
|
491
|
+
``` ruby
|
492
|
+
require 'pork/auto'
|
493
|
+
|
494
|
+
would{ 1.should.eq 1 }
|
495
|
+
```
|
496
|
+
|
497
|
+
### Pork::Should#lt
|
498
|
+
|
499
|
+
To avoid warnings from Ruby, using `lt` instead of `<`. It's fine if you
|
500
|
+
still prefer using `<` if you don't care about warnings.
|
501
|
+
|
502
|
+
``` ruby
|
503
|
+
require 'pork/auto'
|
504
|
+
|
505
|
+
would{ 1.should.lt 2 }
|
506
|
+
```
|
507
|
+
|
508
|
+
### Pork::Should#gt
|
509
|
+
|
510
|
+
To avoid warnings from Ruby, using `gt` instead of `>`. It's fine if you
|
511
|
+
still prefer using `>` if you don't care about warnings.
|
512
|
+
|
513
|
+
``` ruby
|
514
|
+
require 'pork/auto'
|
515
|
+
|
516
|
+
would{ 1.should.gt 0 }
|
517
|
+
```
|
518
|
+
|
519
|
+
### Pork::Should#lte
|
520
|
+
|
521
|
+
To avoid warnings from Ruby, using `lte` instead of `<=`. It's fine if you
|
522
|
+
still prefer using `<=` if you don't care about warnings.
|
523
|
+
|
524
|
+
``` ruby
|
525
|
+
require 'pork/auto'
|
526
|
+
|
527
|
+
would{ 1.should.lte 1 }
|
528
|
+
```
|
529
|
+
|
530
|
+
### Pork::Should#gte
|
531
|
+
|
532
|
+
To avoid warnings from Ruby, using `gte` instead of `>=`. It's fine if you
|
533
|
+
still prefer using `>=` if you don't care about warnings.
|
534
|
+
|
535
|
+
``` ruby
|
536
|
+
require 'pork/auto'
|
537
|
+
|
538
|
+
would{ 1.should.gte 1 }
|
539
|
+
```
|
540
|
+
|
541
|
+
### Pork::Should#raise
|
542
|
+
|
543
|
+
Expect for exceptions! There are two ways to call it. Either you could use
|
544
|
+
lambda to wrap the questioning expression, or you could simply pass a block
|
545
|
+
as the questioning expression.
|
546
|
+
|
547
|
+
``` ruby
|
548
|
+
require 'pork/auto'
|
549
|
+
|
550
|
+
describe 'Pork::Should#raise' do
|
551
|
+
would 'check with a block' do
|
552
|
+
e = should.raise(RuntimeError){ raise "nnf" }
|
553
|
+
e.should.message.include?("nnf")
|
554
|
+
end
|
555
|
+
|
556
|
+
would 'check with a lambda' do
|
557
|
+
e = lambda{ raise "nnf" }.should.raise(RuntimeError)
|
558
|
+
e.should.message.include?("nnf")
|
559
|
+
end
|
560
|
+
end
|
561
|
+
```
|
562
|
+
|
563
|
+
### Pork::Should#throw
|
564
|
+
|
565
|
+
Expect for something to be thrown. There are two ways to call it. Either
|
566
|
+
you could use lambda to wrap the questioning expression, or you could
|
567
|
+
simply pass a block as the questioning expression.
|
568
|
+
|
569
|
+
``` ruby
|
570
|
+
require 'pork/auto'
|
571
|
+
|
572
|
+
describe 'Pork::Should#throw' do
|
573
|
+
would 'check with a block' do
|
574
|
+
e = should.throw(:nnf){ throw :nnf, 0 }
|
575
|
+
e.should.eq [:nnf, 0]
|
576
|
+
end
|
577
|
+
|
578
|
+
would 'check with a lambda' do
|
579
|
+
e = lambda{ throw :nnf, 1 }.should.throw(:nnf)
|
580
|
+
e.should.eq [:nnf, 1]
|
581
|
+
end
|
582
|
+
end
|
583
|
+
```
|
584
|
+
|
585
|
+
### Pork.report
|
586
|
+
|
587
|
+
Report the summary from the tests. Usually you would want to call this at
|
588
|
+
program exit, therefore most of the time you would want `Pork.report_at_exit`
|
589
|
+
instead, unless you want to report the summary without exiting.
|
590
|
+
|
591
|
+
Note that you would probably want to run `Pork.stats.start` at the beginning
|
592
|
+
of your tests as well if you want to handle `Pork.report` manually.
|
593
|
+
|
594
|
+
### Pork.report_at_exit
|
595
|
+
|
596
|
+
Basically simply call `Pork.stats.start` and setup `Pork.report` at exit,
|
597
|
+
and exit with 0 if no error occurs or N for N errors and failures.
|
598
|
+
|
599
|
+
If you also plan to pollute the top-level namespace so that you could simply
|
600
|
+
call `describe` on top-level instead of calling it `Pork::API.describe`,
|
601
|
+
you would probably want to simply `require 'pork/auto'` which is essentially:
|
602
|
+
|
603
|
+
``` ruby
|
604
|
+
require 'pork'
|
605
|
+
extend Pork::API
|
606
|
+
Pork.report_at_exit
|
607
|
+
```
|
608
|
+
|
31
609
|
## CONTRIBUTORS:
|
32
610
|
|
33
611
|
* Lin Jen-Shin (@godfat)
|