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.
@@ -1,71 +1,57 @@
1
1
 
2
2
  require 'thread'
3
3
 
4
- module Pork
5
- class Stats < Struct.new(:tests, :assertions, :skips, :failures, :errors)
6
- def initialize
7
- @mutex = Mutex.new
8
- super(0, 0, 0, [], [])
9
- end
10
- def assertions= num; @mutex.synchronize{ super }; end
11
- def tests= num; @mutex.synchronize{ super }; end
12
- def skips= num; @mutex.synchronize{ super ; print('s')}; end
13
- def add_failure *e ; @mutex.synchronize{ failures << e; print('F')}; end
14
- def add_error *e ; @mutex.synchronize{ errors << e; print('E')}; end
15
- def numbers
16
- [tests, assertions, failures.size, errors.size, skips]
17
- end
18
- def start
19
- @start ||= Time.now
20
- end
21
- def report
22
- puts
23
- puts (failures + errors).map{ |(e, m)|
24
- "\n#{m}\n#{e.class}: #{e.message}\n #{backtrace(e)}"
25
- }
26
- printf("\nFinished in %f seconds.\n", Time.now - @start)
27
- printf("%d tests, %d assertions, %d failures, %d errors, %d skips\n",
28
- *numbers)
29
- end
30
- private
31
- def backtrace e
32
- if $VERBOSE
33
- e.backtrace
34
- else
35
- e.backtrace.reject{ |line| line =~ %r{/pork\.rb:\d+} }
36
- end.join("\n ")
37
- end
4
+ module Kernel
5
+ def should message=nil, &checker
6
+ Pork::Should.new(self, message, &checker)
38
7
  end
8
+ end
9
+
10
+ module Pork
11
+ Error = Class.new(Exception)
12
+ Failure = Class.new(Error)
13
+ Skip = Class.new(Error)
39
14
 
40
15
  def self.stats ; @stats ||= Stats.new; end
41
16
  def self.reset ; @stats = nil ; end
42
17
  def self.report; stats.report; reset ; end
18
+ def self.report_at_exit
19
+ Pork.stats.start
20
+ @report_at_exit ||= at_exit do
21
+ stats.report
22
+ exit stats.failures.size + stats.errors.size
23
+ end
24
+ end
43
25
 
44
26
  module API
45
27
  module_function
46
- def describe desc, &suite
47
- Pork.stats.start
48
- Pork::Executor.execute(self, desc, &suite)
49
- Pork.stats.tests += 1
50
- end
28
+ def before &block; Executor.before(&block); end
29
+ def after &block; Executor.after( &block); end
30
+ def describe desc=:default, &suite; Executor.describe(desc, &suite); end
31
+ def copy desc=:default, &suite; Executor.copy( desc, &suite); end
32
+ def paste desc=:default, *args ; Executor.paste( desc, *args ); end
33
+ def would desc=:default, &test ; Executor.would( desc, &test ); end
51
34
  end
52
35
 
53
- Error = Class.new(Exception)
54
- Failure = Class.new(Error)
55
- Skip = Class.new(Error)
56
-
57
- class Executor < Struct.new(:name)
58
- extend Pork::API
59
- def self.execute caller, desc, &suite
60
- parent = if caller.kind_of?(Class) then caller else self end
61
- Class.new(parent){
62
- @desc, @before, @after = "#{desc}:", [], []
63
- }.module_eval(&suite)
36
+ module Imp
37
+ attr_reader :stash, :desc
38
+ def before &block
39
+ if block_given? then @before << block else @before end
64
40
  end
65
-
66
- def self.would name, &test
41
+ def after &block
42
+ if block_given? then @after << block else @after end
43
+ end
44
+ def describe desc=:default, &suite
45
+ Class.new(self){ init("#{desc}: ") }.module_eval(&suite)
46
+ end
47
+ def copy desc=:default, &suite; stash[desc] = suite; end
48
+ def paste desc=:default, *args
49
+ stashes = [self, super_executor].compact.map(&:stash)
50
+ module_exec(*args, &stashes.find{ |s| s[desc] }[desc])
51
+ end
52
+ def would desc=:default, &test
67
53
  assertions = Pork.stats.assertions
68
- context = new(name)
54
+ context = new(desc)
69
55
  run_before(context)
70
56
  context.instance_eval(&test)
71
57
  if assertions == Pork.stats.assertions
@@ -74,55 +60,81 @@ module Pork
74
60
  rescue Error, StandardError => e
75
61
  case e
76
62
  when Skip
77
- Pork.stats.skips += 1
63
+ Pork.stats.incr_skips
78
64
  when Failure
79
- Pork.stats.add_failure(e, description_for("would #{name}"))
65
+ Pork.stats.add_failure(e, description_for("would #{desc}"))
80
66
  when Error, StandardError
81
- Pork.stats.add_error( e, description_for("would #{name}"))
67
+ Pork.stats.add_error( e, description_for("would #{desc}"))
82
68
  end
83
69
  else
84
70
  print '.'
85
71
  ensure
72
+ Pork.stats.incr_tests
86
73
  run_after(context)
87
74
  end
88
75
 
89
- def self.before &block
90
- if block_given? then @before << block else @before end
76
+ protected
77
+ def init desc=''
78
+ @desc, @before, @after, @stash = desc, [], [], {}
91
79
  end
92
- def self.after &block
93
- if block_given? then @after << block else @after end
94
- end
95
-
96
- def self.super_executor
97
- @super_executor ||= ancestors[1..-1].find{ |a| a < Executor }
80
+ def super_executor
81
+ @super_executor ||= ancestors[1..-1].find{ |a| a <= Executor }
98
82
  end
99
-
100
- def self.description_for name=''
101
- supername = if super_executor
102
- " #{super_executor.description_for}"
103
- else
104
- ' '
105
- end
106
- "#{@desc}#{supername}#{name}"
83
+ def description_for name=''
84
+ "#{desc}#{super_executor && super_executor.description_for}#{name}"
107
85
  end
108
-
109
- def self.run_before context
86
+ def run_before context
110
87
  super_executor.run_before(context) if super_executor
111
88
  before.each{ |b| context.instance_eval(&b) }
112
89
  end
113
-
114
- def self.run_after context
90
+ def run_after context
115
91
  super_executor.run_after(context) if super_executor
116
92
  after.each{ |b| context.instance_eval(&b) }
117
93
  end
94
+ end
95
+
96
+ class Executor < Struct.new(:desc)
97
+ extend Pork::Imp, Pork::API
98
+ init
99
+ def skip ; raise Skip.new("Skipping #{desc}"); end
100
+ def flunk reason='Flunked'; raise Error.new(reason) ; end
101
+ def ok ; Pork.stats.incr_assertions ; end
102
+ end
103
+
104
+ module InspectInlineError
105
+ def inspect_error object, msg, args, negate
106
+ a = args.map(&:inspect).join(', ')
107
+ "#{object.inspect}.#{msg}(#{a}) to return #{!negate}"
108
+ end
109
+ end
118
110
 
119
- def skip
120
- raise Skip.new("Skipping #{name}")
111
+ module InspectNewlineError
112
+ def inspect_error object, msg, args, negate
113
+ a = args.map(&:inspect).join(', ')
114
+ "\n#{object.inspect}.#{msg}(\n#{a}) to return #{!negate}"
115
+ end
116
+ end
117
+
118
+ module InspectDiffError
119
+ def inspect_error object, msg, args, negate
120
+ ::Kernel.require 'tempfile'
121
+ ::Tempfile.open('pork-expect') do |expect|
122
+ ::Tempfile.open('pork-was') do |was|
123
+ expect.puts(object.to_s)
124
+ expect.close
125
+ was.puts(args.map(&:to_s).join(",\n"))
126
+ was.close
127
+ name = "#{object.class}##{msg}(\n"
128
+ diff = ::Kernel.__send__(:`, "diff #{expect.path} #{was.path}")
129
+ "#{name}#{diff}) to return #{!negate}"
130
+ end
131
+ end
121
132
  end
122
133
  end
123
134
 
124
135
  class Should < BasicObject
125
136
  instance_methods.each{ |m| undef_method(m) unless m =~ /^__|^object_id$/ }
137
+ include ::Pork::InspectInlineError
126
138
 
127
139
  def initialize object, message, &checker
128
140
  @object = object
@@ -132,8 +144,7 @@ module Pork
132
144
  end
133
145
 
134
146
  def method_missing msg, *args, &block
135
- satisfy("#{@object.inspect}.#{msg}(#{args.join(', ')}) to" \
136
- " return #{!@negate}") do
147
+ satisfy(inspect_error(@object, msg, args, @negate)) do
137
148
  @object.public_send(msg, *args, &block)
138
149
  end
139
150
  end
@@ -143,7 +154,7 @@ module Pork
143
154
  if !!result == @negate
144
155
  ::Kernel.raise Failure.new("Expect #{desc}\n#{@message}".chomp)
145
156
  else
146
- ::Pork.stats.assertions += 1
157
+ ::Pork.stats.incr_assertions
147
158
  end
148
159
  result
149
160
  end
@@ -154,9 +165,11 @@ module Pork
154
165
  self
155
166
  end
156
167
 
157
- def eq rhs
158
- self == rhs
159
- end
168
+ def eq rhs; self == rhs; end
169
+ def lt rhs; self < rhs; end
170
+ def gt rhs; self > rhs; end
171
+ def lte rhs; self <= rhs; end
172
+ def gte rhs; self >= rhs; end
160
173
 
161
174
  def raise exception=::RuntimeError
162
175
  satisfy("#{__not__}raising #{exception}") do
@@ -173,18 +186,14 @@ module Pork
173
186
  def throw msg
174
187
  satisfy("#{__not__}throwing #{msg}") do
175
188
  flag = true
176
- ::Kernel.catch(msg) do
189
+ data = ::Kernel.catch(msg) do
177
190
  if ::Kernel.block_given? then yield else @object.call end
178
191
  flag = false
179
192
  end
180
- flag
193
+ flag && [msg, data]
181
194
  end
182
195
  end
183
196
 
184
- def flunk reason='Flunked'
185
- ::Kernel.raise Error.new(reason)
186
- end
187
-
188
197
  private
189
198
  def __not__
190
199
  if @negate == true
@@ -194,10 +203,39 @@ module Pork
194
203
  end
195
204
  end
196
205
  end
197
- end
198
206
 
199
- module Kernel
200
- def should message=nil, &checker
201
- Pork::Should.new(self, message, &checker)
207
+ class Stats < Struct.new(:tests, :assertions, :skips, :failures, :errors)
208
+ def initialize
209
+ @mutex = Mutex.new
210
+ super(0, 0, 0, [], [])
211
+ end
212
+ def incr_assertions; @mutex.synchronize{ self.assertions += 1 }; end
213
+ def incr_tests ; @mutex.synchronize{ self.tests += 1 }; end
214
+ def incr_skips ; @mutex.synchronize{ self.skips += 1; print('s')}; end
215
+ def add_failure *e ; @mutex.synchronize{ failures << e; print('F')}; end
216
+ def add_error *e ; @mutex.synchronize{ errors << e; print('E')}; end
217
+ def numbers
218
+ [tests, assertions, failures.size, errors.size, skips]
219
+ end
220
+ def start
221
+ @start ||= Time.now
222
+ end
223
+ def report
224
+ puts
225
+ puts (failures + errors).map{ |(e, m)|
226
+ "\n#{m}\n#{e.class}: #{e.message}\n #{backtrace(e)}"
227
+ }
228
+ printf("\nFinished in %f seconds.\n", Time.now - @start)
229
+ printf("%d tests, %d assertions, %d failures, %d errors, %d skips\n",
230
+ *numbers)
231
+ end
232
+ private
233
+ def backtrace e
234
+ if $VERBOSE
235
+ e.backtrace
236
+ else
237
+ e.backtrace.reject{ |line| line =~ %r{/pork\.rb:\d+} }
238
+ end.join("\n ")
239
+ end
202
240
  end
203
241
  end
@@ -0,0 +1,4 @@
1
+
2
+ require 'pork'
3
+ extend Pork::API
4
+ Pork.report_at_exit
@@ -1,4 +1,4 @@
1
1
 
2
2
  module Pork
3
- VERSION = '0.1.0'
3
+ VERSION = '0.9.0'
4
4
  end
@@ -1,36 +1,39 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: pork 0.1.0 ruby lib
2
+ # stub: pork 0.9.0 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "pork"
6
- s.version = "0.1.0"
6
+ s.version = "0.9.0"
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
9
9
  s.require_paths = ["lib"]
10
10
  s.authors = ["Lin Jen-Shin (godfat)"]
11
- s.date = "2014-07-09"
12
- s.description = "[Bacon][] reimplemented in an even more lightweight manner.\n\n[Bacon]: https://github.com/chneukirchen/bacon"
11
+ s.date = "2014-07-11"
12
+ s.description = "Pork -- Simple and clean and modular testing library.\n\n[Bacon][] reimplemented around 250 lines of code.\n\n[Bacon]: https://github.com/chneukirchen/bacon"
13
13
  s.email = ["godfat (XD) godfat.org"]
14
14
  s.files = [
15
+ ".gitignore",
15
16
  ".gitmodules",
16
17
  ".travis.yml",
18
+ "CHANGES.md",
17
19
  "LICENSE",
18
20
  "README.md",
19
21
  "Rakefile",
20
22
  "lib/pork.rb",
21
- "lib/pork/task.rb",
23
+ "lib/pork/auto.rb",
22
24
  "lib/pork/version.rb",
23
- "pkg/pork-0.1.0.gem",
24
25
  "pork.gemspec",
25
26
  "task/README.md",
26
27
  "task/gemgem.rb",
27
28
  "test/test_bacon.rb",
28
- "test/test_nested.rb"]
29
+ "test/test_nested.rb",
30
+ "test/test_readme.rb"]
29
31
  s.homepage = "https://github.com/godfat/pork"
30
32
  s.licenses = ["Apache License 2.0"]
31
33
  s.rubygems_version = "2.3.0"
32
- s.summary = "[Bacon][] reimplemented in an even more lightweight manner."
34
+ s.summary = "Pork -- Simple and clean and modular testing library."
33
35
  s.test_files = [
34
36
  "test/test_bacon.rb",
35
- "test/test_nested.rb"]
37
+ "test/test_nested.rb",
38
+ "test/test_readme.rb"]
36
39
  end
@@ -227,10 +227,6 @@ end # of gem namespace
227
227
  desc 'Run tests'
228
228
  task :test do
229
229
  next if Gemgem.test_files.empty?
230
-
231
- # require 'bacon'
232
- # Bacon.extend(Bacon::TestUnitOutput)
233
- # Bacon.summary_on_exit
234
230
  Gemgem.test_files.each{ |file| require "#{Gemgem.dir}/#{file[0..-4]}" }
235
231
  end
236
232
 
@@ -1,23 +1,21 @@
1
1
 
2
- require 'pork'
2
+ require 'pork/auto'
3
3
 
4
- # Hooray for meta-testing.
5
- module MetaTests
6
- def succeed block
7
- block.should.not.raise Pork::Error
8
- end
9
-
10
- def fail block
11
- block.should.raise Pork::Error
12
- end
4
+ describe Pork do
5
+ # Hooray for meta-testing.
6
+ include Module.new{
7
+ def succeed block
8
+ block.should.not.raise Pork::Error
9
+ end
13
10
 
14
- def equal_string x
15
- lambda{ |s| x == s.to_s }
16
- end
17
- end
11
+ def fail block
12
+ block.should.raise Pork::Error
13
+ end
18
14
 
19
- Pork::API.describe Pork do
20
- include MetaTests
15
+ def equal_string x
16
+ lambda{ |s| x == s.to_s }
17
+ end
18
+ }
21
19
 
22
20
  would "have should.satisfy" do
23
21
  succeed lambda { should.satisfy { 1 == 1 } }
@@ -221,13 +219,13 @@ Pork::API.describe Pork do
221
219
  succeed lambda { (1+2).should.not(&f) }
222
220
  end
223
221
 
224
- would "have should.flunk" do
225
- fail lambda { should.flunk }
226
- fail lambda { should.flunk "yikes" }
222
+ would "have flunk" do
223
+ fail lambda { flunk }
224
+ fail lambda { flunk "yikes" }
227
225
  end
228
226
  end
229
227
 
230
- Pork::API.describe "before/after" do
228
+ describe "before/after" do
231
229
  before do
232
230
  @a = 1
233
231
  @b = 2
@@ -287,89 +285,97 @@ Pork::API.describe "before/after" do
287
285
  end
288
286
  end
289
287
 
290
- # shared "a shared context" do
291
- # it "gets called where it is included" do
292
- # true.should.be.true
293
- # end
294
- # end
295
-
296
- # shared "another shared context" do
297
- # it "can access data" do
298
- # @magic.should.be.equal 42
299
- # end
300
- # end
301
-
302
- # describe "shared/behaves_like" do
303
- # behaves_like "a shared context"
304
-
305
- # ctx = self
306
- # it "raises NameError when the context is not found" do
307
- # lambda {
308
- # ctx.behaves_like "whoops"
309
- # }.should.raise NameError
310
- # end
311
-
312
- # behaves_like "a shared context"
313
-
314
- # before {
315
- # @magic = 42
316
- # }
317
- # behaves_like "another shared context"
318
- # end
319
-
320
- # describe "Methods" do
321
- # def the_meaning_of_life
322
- # 42
323
- # end
324
-
325
- # def the_towels
326
- # yield "DON'T PANIC"
327
- # end
328
-
329
- # it "should be accessible in a test" do
330
- # the_meaning_of_life.should == 42
331
- # end
332
-
333
- # describe "when in a sibling context" do
334
- # it "should be accessible in a test" do
335
- # the_meaning_of_life.should == 42
336
- # end
337
-
338
- # it "should pass the block" do
339
- # the_towels do |label|
340
- # label.should == "DON'T PANIC"
341
- # end.should == true
342
- # end
343
- # end
344
- # end
345
-
346
- # describe 'describe arguments' do
347
-
348
- # def check(ctx,name)
349
- # ctx.should.be.an.instance_of Bacon::Context
350
- # ctx.instance_variable_get('@name').should == name
351
- # end
352
-
353
- # it 'should work with string' do
354
- # check(describe('string') {},'string')
355
- # end
356
-
357
- # it 'should work with symbols' do
358
- # check(describe(:behaviour) {},'behaviour')
359
- # end
360
-
361
- # it 'should work with modules' do
362
- # check(describe(Bacon) {},'Bacon')
363
- # end
364
-
365
- # it 'should work with namespaced modules' do
366
- # check(describe(Bacon::Context) {},'Bacon::Context')
367
- # end
368
-
369
- # it 'should work with multiple arguments' do
370
- # check(describe(Bacon::Context, :empty) {},'Bacon::Context empty')
371
- # end
372
-
373
- # end
374
-
375
- Pork.report
288
+ copy "a shared context" do
289
+ would "get called where it is included" do
290
+ true.should.eq true
291
+ end
292
+ end
293
+
294
+ copy "another shared context" do
295
+ would "access data" do
296
+ @magic.should.eq 42
297
+ end
298
+ end
299
+
300
+ describe "shared/behaves_like" do
301
+ paste "a shared context"
302
+
303
+ ctx = self
304
+ would "raise NameError when the context is not found" do
305
+ lambda {
306
+ ctx.paste "whoops"
307
+ }.should.raise NameError
308
+ end
309
+
310
+ paste "a shared context"
311
+
312
+ before {
313
+ @magic = 42
314
+ }
315
+ paste "another shared context"
316
+ end
317
+
318
+ describe "Methods" do
319
+ def the_meaning_of_life
320
+ 42
321
+ end
322
+
323
+ def the_towels
324
+ yield "DON'T PANIC"
325
+ end
326
+
327
+ would "be accessible in a test" do
328
+ the_meaning_of_life.should.eq 42
329
+ end
330
+
331
+ describe "when in a sibling context" do
332
+ would "should be accessible in a test" do
333
+ the_meaning_of_life.should.eq 42
334
+ end
335
+
336
+ would "should pass the block" do
337
+ the_towels do |label|
338
+ label.should.eq "DON'T PANIC"
339
+ end.should.eq true
340
+ end
341
+ end
342
+ end
343
+
344
+ describe 'describe arguments' do
345
+ check = lambda do |ctx, desc, name=nil|
346
+ ctx.should.lt Pork::Executor
347
+ ctx.description_for(name).should.eq "#{desc}: #{name}"
348
+ end
349
+
350
+ would 'work with string' do
351
+ str = 'string'
352
+ Pork::API.describe(str) do
353
+ check[self, str]
354
+ would 'a' do check[self.class, str, 'a'] end
355
+ end
356
+ end
357
+
358
+ would 'work with symbols' do
359
+ str = 'behaviour'
360
+ Pork::API.describe(:behaviour) do
361
+ check[self, str]
362
+ would 'b' do check[self.class, str, 'b'] end
363
+ end
364
+ end
365
+
366
+ would 'work with modules' do
367
+ str = 'Pork'
368
+ Pork::API.describe(Pork) do
369
+ check[self, str]
370
+ would 'c' do check[self.class, str, 'c'] end
371
+ end
372
+ end
373
+
374
+ would 'work with namespaced modules' do
375
+ str = 'Pork::Executor'
376
+ Pork::API.describe(Pork::Executor) do
377
+ check[self, str]
378
+ would 'd' do check[self.class, str, 'd'] end
379
+ end
380
+ end
381
+ end