bacon 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.
Files changed (8) hide show
  1. data/COPYING +18 -0
  2. data/RDOX +35 -0
  3. data/README +227 -0
  4. data/Rakefile +133 -0
  5. data/bin/bacon +110 -0
  6. data/lib/bacon.rb +298 -0
  7. data/test/spec_bacon.rb +310 -0
  8. metadata +53 -0
data/COPYING ADDED
@@ -0,0 +1,18 @@
1
+ Copyright (c) 2007, 2008 Christian Neukirchen <purl.org/net/chneukirchen>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to
5
+ deal in the Software without restriction, including without limitation the
6
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
+ sell copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16
+ THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/RDOX ADDED
@@ -0,0 +1,35 @@
1
+ Bacon
2
+ - should have should.satisfy
3
+ - should have should.equal
4
+ - should have should.raise
5
+ - should have should.raise with a block
6
+ - should have a should.raise should return the exception
7
+ - should have should.be.an.instance_of
8
+ - should have should.be.nil
9
+ - should have should.include
10
+ - should have should.be.a.kind_of
11
+ - should have should.match
12
+ - should have should.not.raise
13
+ - should have should.throw
14
+ - should have should.not.satisfy
15
+ - should have should.not.equal
16
+ - should have should.not.match
17
+ - should have should.be.identical_to/same_as
18
+ - should have should.respond_to
19
+ - should have should.be.close
20
+ - should support multiple negation
21
+ - should have should.<predicate>
22
+ - should have should <operator> (>, >=, <, <=, ===)
23
+ - should allow for custom shoulds
24
+ - should have should.flunk
25
+
26
+ before/after
27
+ - should run in the right order
28
+
29
+ shared/behaves_like
30
+ - gets called where it is included
31
+ - raises NameError when the context is not found
32
+ - gets called where it is included
33
+ - can access data
34
+
35
+ 28 specifications (288 requirements), 0 failures, 0 errors
data/README ADDED
@@ -0,0 +1,227 @@
1
+ = Bacon -- small RSpec clone.
2
+
3
+ "Truth will sooner come out from error than from confusion."
4
+ ---Francis Bacon
5
+
6
+ Bacon is a small RSpec clone weighing less than 300 LoC but
7
+ nevertheless providing all essential features.
8
+
9
+ == Whirl-wind tour
10
+
11
+ require 'bacon'
12
+
13
+ describe 'A new array' do
14
+ before do
15
+ @ary = Array.new
16
+ end
17
+
18
+ it 'should be empty' do
19
+ @ary.should.be.empty
20
+ @ary.should.not.include 1
21
+ end
22
+
23
+ it 'should have zero size' do
24
+ @ary.size.should.equal 0
25
+ @ary.size.should.be.close 0.1, 0.5
26
+ end
27
+
28
+ it 'should raise on trying fetch any index' do
29
+ lambda { @ary.fetch 0 }.
30
+ should.raise(IndexError).
31
+ message.should.match(/out of array/)
32
+
33
+ # Alternatively:
34
+ should.raise(IndexError) { @ary.fetch 0 }
35
+ end
36
+
37
+ it 'should have an object identity' do
38
+ @ary.should.not.be.same_as Array.new
39
+ end
40
+
41
+ # Custom assertions are trivial to do, they are lambdas returning a
42
+ # boolean vale:
43
+ palindrome = lambda { |obj| obj == obj.reverse }
44
+ it 'should be a palindrome' do
45
+ @ary.should.be.a palindrome
46
+ end
47
+
48
+ it 'should have super powers' do
49
+ should.flunk "no super powers found"
50
+ end
51
+ end
52
+
53
+ Now run it:
54
+
55
+ $ bacon whirlwind.rb
56
+ A new array
57
+ - should be empty
58
+ - should have zero size
59
+ - should raise on trying fetch any index
60
+ - should have an object identity
61
+ - should be a palindrome
62
+ - should have super powers [FAILED]
63
+
64
+ Bacon::Error: no super powers found
65
+ ./whirlwind.rb:39: A new array - should have super powers
66
+ ./whirlwind.rb:38
67
+ ./whirlwind.rb:3
68
+
69
+ 6 specifications (9 requirements), 1 failures, 0 errors
70
+
71
+ If you want shorter output, use the Test::Unit format:
72
+
73
+ $ bacon -q whirlwind.rb
74
+ .....F
75
+ Bacon::Error: no super powers found
76
+ ./whirlwind.rb:39: A new array - should have super powers
77
+ ./whirlwind.rb:38
78
+ ./whirlwind.rb:3
79
+
80
+ 6 tests, 9 assertions, 1 failures, 0 errors
81
+
82
+ It also supports TAP:
83
+
84
+ $ bacon -p whirlwind.rb
85
+ ok 1 - should be empty
86
+ ok 2 - should have zero size
87
+ ok 3 - should raise on trying fetch any index
88
+ ok 4 - should have an object identity
89
+ ok 5 - should be a palindrome
90
+ not ok 6 - should have super powers: FAILED
91
+ # Bacon::Error: no super powers found
92
+ # ./whirlwind.rb:39: A new array - should have super powers
93
+ # ./whirlwind.rb:38
94
+ # ./whirlwind.rb:3
95
+ 1..6
96
+ # 6 tests, 9 assertions, 1 failures, 0 errors
97
+
98
+ $ bacon -p whirlwind.rb | taptap -q
99
+ Tests took 0.00 seconds.
100
+ FAILED tests 6
101
+ 6) should have super powers: FAILED
102
+
103
+ Failed 1/6 tests, 83.33% okay.
104
+
105
+ (taptap is available from http://chneukirchen.org/repos/taptap/)
106
+
107
+
108
+ == Implemented assertions
109
+
110
+ * should.<predicate> and should.be.<predicate>
111
+ * should.equal
112
+ * should.match
113
+ * should.be.identical_to / should.be.same_as
114
+ * should.raise(*exceptions) { }
115
+ * should.change { }
116
+ * should.throw(symbol) { }
117
+ * should.satisfy { |object| }
118
+
119
+
120
+ == Added core predicates
121
+
122
+ * Object#true?
123
+ * Object#false?
124
+ * Proc#change?
125
+ * Proc#raise?
126
+ * Proc#throw?
127
+ * Numeric#close?
128
+
129
+
130
+ == before/after
131
+
132
+ before and after need to be defined before the first specification in
133
+ a context and are run before and after each specification.
134
+
135
+
136
+ == Shared contexts
137
+
138
+ You can define shared contexts in Bacon like this:
139
+
140
+ shared "an empty container" do
141
+ it "should have size zero" do
142
+ end
143
+
144
+ it "should be empty" do
145
+ end
146
+ end
147
+
148
+ context "A new array" do
149
+ behaves_like "an empty container"
150
+ end
151
+
152
+ These contexts are not executed on their own, but can be included with
153
+ behaves_like in other contexts. You can use shared contexts to
154
+ structure suites with many recurring specifications.
155
+
156
+
157
+ == Matchers
158
+
159
+ Custom matchers are simply lambdas returning a boolean value, for
160
+ example:
161
+
162
+ def shorter_than(max_size)
163
+ lambda { |obj| obj.size < max_size }
164
+ end
165
+
166
+ [1,2,3].should.be shorter_than(5)
167
+
168
+ You can use modules and extend to group matchers for use in multiple
169
+ contexts.
170
+
171
+
172
+ == bacon standalone runner
173
+
174
+ -s, --specdox do AgileDox-like output (default)
175
+ -q, --quiet do Test::Unit-like non-verbose output
176
+ -p, --tap do TAP (Test Anything Protocol) output
177
+ -o, --output FORMAT do FORMAT (SpecDox/TestUnit/Tap) output
178
+ -a, --automatic gather tests from ./test/, include ./lib/
179
+ -n, --name NAME runs tests matching regexp NAME
180
+ -t, --testcase TESTCASE runs tests in TestCases matching regexp TESTCASE
181
+
182
+ If you don't want to use the standalone runner, run
183
+ Bacon.summary_on_exit to install an exit handler showing the summary.
184
+
185
+
186
+ == Object#should
187
+
188
+ You can use Object#should outside of contexts, where the result of
189
+ assertion will be returned as a boolean. This is nice for
190
+ demonstrations, quick checks and doctest tests.
191
+
192
+ >> require 'bacon'
193
+ >> (1 + 1).should.equal 2
194
+ => true
195
+ >> (6*9).should.equal 42
196
+ => false
197
+
198
+
199
+ == Thanks to
200
+
201
+ * Michael Fellinger, for fixing Bacon for 1.9 and various improvements.
202
+
203
+
204
+ == Contact
205
+
206
+ Please mail bugs, suggestions and patches to
207
+ <mailto:chneukirchen@gmail.com>.
208
+
209
+ Darcs repository ("darcs send" is welcome for patches):
210
+ http://chneukirchen.org/repos/bacon
211
+
212
+
213
+ == Copying
214
+
215
+ Copyright (C) 2007, 2008 Christian Neukirchen <purl.org/net/chneukirchen>
216
+
217
+ Bacon is freely distributable under the terms of an MIT-style license.
218
+ See COPYING or http://www.opensource.org/licenses/mit-license.php.
219
+
220
+
221
+ == Links
222
+
223
+ Behavior-Driven Development:: <http://behaviour-driven.org/>
224
+ RSpec:: <http://rspec.rubyforge.org/>
225
+ test/spec:: <http://test-spec.rubyforge.org/>
226
+
227
+ Christian Neukirchen:: <http://chneukirchen.org/>
@@ -0,0 +1,133 @@
1
+ # Rakefile for Bacon. -*-ruby-*-
2
+ require 'rake/rdoctask'
3
+ require 'rake/testtask'
4
+
5
+
6
+ desc "Run all the tests"
7
+ task :default => [:test]
8
+
9
+ desc "Do predistribution stuff"
10
+ task :predist => [:chmod, :changelog, :rdoc]
11
+
12
+
13
+ desc "Make an archive as .tar.gz"
14
+ task :dist => :test do
15
+ sh "export DARCS_REPO=#{File.expand_path "."}; " +
16
+ "darcs dist -d bacon-#{get_darcs_tree_version}"
17
+ end
18
+
19
+ # Helper to retrieve the "revision number" of the darcs tree.
20
+ def get_darcs_tree_version
21
+ unless File.directory? "_darcs"
22
+ $: << "lib"
23
+ require 'bacon'
24
+ return Bacon::VERSION
25
+ end
26
+
27
+ changes = `darcs changes`
28
+ count = 0
29
+ tag = "0.0"
30
+
31
+ changes.each("\n\n") { |change|
32
+ head, title, desc = change.split("\n", 3)
33
+
34
+ if title =~ /^ \*/
35
+ # Normal change.
36
+ count += 1
37
+ elsif title =~ /tagged (.*)/
38
+ # Tag. We look for these.
39
+ tag = $1
40
+ break
41
+ else
42
+ warn "Unparsable change: #{change}"
43
+ end
44
+ }
45
+
46
+ tag + "." + count.to_s
47
+ end
48
+
49
+ def manifest
50
+ `darcs query manifest 2>/dev/null`.split("\n").map { |f| f.gsub(/\A\.\//, '') }
51
+ end
52
+
53
+
54
+ desc "Make binaries executable"
55
+ task :chmod do
56
+ Dir["bin/*"].each { |binary| File.chmod(0775, binary) }
57
+ end
58
+
59
+ desc "Generate a ChangeLog"
60
+ task :changelog do
61
+ sh "darcs changes --repo=#{ENV["DARCS_REPO"] || "."} >ChangeLog"
62
+ end
63
+
64
+
65
+ desc "Generate RDox"
66
+ task "RDOX" do
67
+ sh "bin/bacon -Ilib --automatic --specdox >RDOX"
68
+ end
69
+
70
+ desc "Run all the fast tests"
71
+ task :test do
72
+ ruby "bin/bacon -Ilib --automatic --quiet"
73
+ end
74
+
75
+
76
+ begin
77
+ $" << "sources" if defined? FromSrc
78
+ require 'rubygems'
79
+
80
+ require 'rake'
81
+ require 'rake/clean'
82
+ require 'rake/packagetask'
83
+ require 'rake/gempackagetask'
84
+ require 'fileutils'
85
+ rescue LoadError
86
+ # Too bad.
87
+ else
88
+ spec = Gem::Specification.new do |s|
89
+ s.name = "bacon"
90
+ s.version = get_darcs_tree_version
91
+ s.platform = Gem::Platform::RUBY
92
+ s.summary = "a small RSpec clone"
93
+
94
+ s.description = <<-EOF
95
+ Bacon is a small RSpec clone weighing less than 300 LoC but
96
+ nevertheless providing all essential features.
97
+
98
+ http://chneukirchen.org/repos/bacon
99
+ EOF
100
+
101
+ s.files = manifest + %w(RDOX)
102
+ s.bindir = 'bin'
103
+ s.executables << 'bacon'
104
+ s.require_path = 'lib'
105
+ s.has_rdoc = true
106
+ s.extra_rdoc_files = ['README', 'RDOX']
107
+ s.test_files = []
108
+
109
+ s.author = 'Christian Neukirchen'
110
+ s.email = 'chneukirchen@gmail.com'
111
+ s.homepage = 'http://chneukirchen.org/repos/bacon'
112
+ end
113
+
114
+ Rake::GemPackageTask.new(spec) do |p|
115
+ p.gem_spec = spec
116
+ p.need_tar = false
117
+ p.need_zip = false
118
+ end
119
+ end
120
+
121
+ desc "Generate RDoc documentation"
122
+ Rake::RDocTask.new(:rdoc) do |rdoc|
123
+ rdoc.options << '--line-numbers' << '--inline-source' <<
124
+ '--main' << 'README' <<
125
+ '--title' << 'Bacon Documentation' <<
126
+ '--charset' << 'utf-8'
127
+ rdoc.rdoc_dir = "doc"
128
+ rdoc.rdoc_files.include 'README'
129
+ rdoc.rdoc_files.include 'COPYING'
130
+ rdoc.rdoc_files.include 'RDOX'
131
+ rdoc.rdoc_files.include('lib/bacon.rb')
132
+ end
133
+ task :rdoc => ["RDOX"]
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- ruby -*-
3
+
4
+ require 'optparse'
5
+ module Bacon; end
6
+
7
+ automatic = false
8
+ output = 'SpecDoxOutput'
9
+
10
+ opts = OptionParser.new("", 24, ' ') { |opts|
11
+ opts.banner = "Usage: bacon [options] [files | -a] [-- untouched arguments]"
12
+
13
+ opts.separator ""
14
+ opts.separator "Ruby options:"
15
+
16
+ lineno = 1
17
+ opts.on("-e", "--eval LINE", "evaluate a LINE of code") { |line|
18
+ eval line, TOPLEVEL_BINDING, "-e", lineno
19
+ lineno += 1
20
+ }
21
+
22
+ opts.on("-d", "--debug", "set debugging flags (set $DEBUG to true)") {
23
+ $DEBUG = true
24
+ }
25
+ opts.on("-w", "--warn", "turn warnings on for your script") {
26
+ $-w = true
27
+ }
28
+
29
+ opts.on("-I", "--include PATH",
30
+ "specify $LOAD_PATH (may be used more than once)") { |path|
31
+ $LOAD_PATH.unshift(*path.split(":"))
32
+ }
33
+
34
+ opts.on("-r", "--require LIBRARY",
35
+ "require the library, before executing your script") { |library|
36
+ require library
37
+ }
38
+
39
+ opts.separator ""
40
+ opts.separator "bacon options:"
41
+
42
+ opts.on("-s", "--specdox", "do AgileDox-like output (default)") {
43
+ output = 'SpecDoxOutput'
44
+ }
45
+ opts.on("-q", "--quiet", "do Test::Unit-like non-verbose output") {
46
+ output = 'TestUnitOutput'
47
+ }
48
+ opts.on("-p", "--tap", "do TAP (Test Anything Protocol) output") {
49
+ output = 'TapOutput'
50
+ }
51
+
52
+ opts.on("-o", "--output FORMAT",
53
+ "do FORMAT (SpecDox/TestUnit/Tap) output") { |format|
54
+ output = format + "Output"
55
+ }
56
+
57
+ opts.on("-a", "--automatic", "gather tests from ./test/, include ./lib/") {
58
+ $LOAD_PATH.unshift "lib" if File.directory? "lib"
59
+ automatic = true
60
+ }
61
+
62
+ opts.on('-n', '--name NAME', String,
63
+ "runs tests matching regexp NAME") { |n|
64
+ Bacon.const_set :RestrictName, Regexp.new(n)
65
+ }
66
+
67
+ opts.on('-t', '--testcase TESTCASE', String,
68
+ "runs tests in TestCases matching regexp TESTCASE") { |t|
69
+ Bacon.const_set :RestrictContext, Regexp.new(t)
70
+ }
71
+
72
+ opts.separator ""
73
+ opts.separator "Common options:"
74
+
75
+ opts.on_tail("-h", "--help", "Show this message") do
76
+ puts opts
77
+ exit
78
+ end
79
+
80
+ opts.on_tail("--version", "Show version") do
81
+ require 'bacon'
82
+ puts "bacon #{Bacon::VERSION}"
83
+ exit
84
+ end
85
+
86
+ opts.parse! ARGV
87
+ }
88
+
89
+ files = ARGV
90
+
91
+ if automatic
92
+ files.concat Dir["test/test_*.rb"]
93
+ files.concat Dir["test/spec_*.rb"]
94
+ files.concat Dir["spec/spec_*.rb"]
95
+ end
96
+
97
+ if files.empty?
98
+ puts opts.banner
99
+ exit 1
100
+ end
101
+
102
+ require 'bacon'
103
+
104
+ Bacon.extend Bacon.const_get(output) rescue abort "No such formatter: #{output}"
105
+ Bacon.summary_on_exit
106
+
107
+ files.each { |file|
108
+ load file
109
+ }
110
+
@@ -0,0 +1,298 @@
1
+ # Bacon -- small RSpec clone.
2
+ #
3
+ # "Truth will sooner come out from error than from confusion." ---Francis Bacon
4
+
5
+ # Copyright (C) 2007, 2008 Christian Neukirchen <purl.org/net/chneukirchen>
6
+ #
7
+ # Bacon is freely distributable under the terms of an MIT-style license.
8
+ # See COPYING or http://www.opensource.org/licenses/mit-license.php.
9
+
10
+ module Bacon
11
+ VERSION = "0.9"
12
+
13
+ Counter = Hash.new(0)
14
+ ErrorLog = ""
15
+ Shared = Hash.new { |_, name|
16
+ raise NameError, "no such context: #{name.inspect}"
17
+ }
18
+
19
+ RestrictName = // unless defined? RestrictName
20
+ RestrictContext = // unless defined? RestrictContext
21
+
22
+ def self.summary_on_exit
23
+ return if Counter[:installed_summary] > 0
24
+ at_exit {
25
+ handle_summary
26
+ if $!
27
+ raise $!
28
+ elsif Counter[:errors] + Counter[:failed] > 0
29
+ exit 1
30
+ end
31
+ }
32
+ Counter[:installed_summary] += 1
33
+ end
34
+
35
+ module SpecDoxOutput
36
+ def handle_specification(name)
37
+ puts name
38
+ yield
39
+ puts
40
+ end
41
+
42
+ def handle_requirement(description)
43
+ print "- #{description}"
44
+ error = yield
45
+ puts error.empty? ? "" : " [#{error}]"
46
+ end
47
+
48
+ def handle_summary
49
+ print ErrorLog
50
+ puts "%d specifications (%d requirements), %d failures, %d errors" %
51
+ Counter.values_at(:specifications, :requirements, :failed, :errors)
52
+ end
53
+ end
54
+
55
+ module TestUnitOutput
56
+ def handle_specification(name) yield end
57
+
58
+ def handle_requirement(description)
59
+ error = yield
60
+ if error.empty?
61
+ print "."
62
+ else
63
+ print error[0..0]
64
+ end
65
+ end
66
+
67
+ def handle_summary
68
+ puts "", ErrorLog
69
+ puts "%d tests, %d assertions, %d failures, %d errors" %
70
+ Counter.values_at(:specifications, :requirements, :failed, :errors)
71
+ end
72
+ end
73
+
74
+ module TapOutput
75
+ def handle_specification(name) yield end
76
+
77
+ def handle_requirement(description)
78
+ ErrorLog.replace ""
79
+ error = yield
80
+ if error.empty?
81
+ printf "ok %-3d - %s\n" % [Counter[:specifications], description]
82
+ else
83
+ printf "not ok %d - %s: %s\n" %
84
+ [Counter[:specifications], description, error]
85
+ puts ErrorLog.strip.gsub(/^/, '# ')
86
+ end
87
+ end
88
+
89
+ def handle_summary
90
+ puts "1..#{Counter[:specifications]}"
91
+ puts "# %d tests, %d assertions, %d failures, %d errors" %
92
+ Counter.values_at(:specifications, :requirements, :failed, :errors)
93
+ end
94
+ end
95
+
96
+ extend SpecDoxOutput # default
97
+
98
+ class Error < RuntimeError
99
+ attr_accessor :count_as
100
+
101
+ def initialize(count_as, message)
102
+ @count_as = count_as
103
+ super message
104
+ end
105
+ end
106
+
107
+ class Context
108
+ def initialize(name, &block)
109
+ @name = name
110
+ @before, @after = [], []
111
+
112
+ return unless name =~ RestrictContext
113
+ Bacon.handle_specification(name) { instance_eval(&block) }
114
+ end
115
+
116
+ def before(&block); @before << block; end
117
+ def after(&block); @after << block; end
118
+
119
+ def behaves_like(*names)
120
+ names.each { |name| instance_eval(&Shared[name]) }
121
+ end
122
+
123
+ def it(description, &block)
124
+ return unless description =~ RestrictName
125
+ Counter[:specifications] += 1
126
+ run_requirement description, block
127
+ end
128
+
129
+ def run_requirement(description, spec)
130
+ Bacon.handle_requirement description do
131
+ begin
132
+ Counter[:depth] += 1
133
+ @before.each { |block| instance_eval(&block) }
134
+ instance_eval(&spec)
135
+ @after.each { |block| instance_eval(&block) }
136
+ rescue Object => e
137
+ ErrorLog << "#{e.class}: #{e.message}\n"
138
+ e.backtrace.find_all { |line| line !~ /bin\/bacon|\/bacon\.rb:\d+/ }.
139
+ each_with_index { |line, i|
140
+ ErrorLog << "\t#{line}#{i==0 ? ": #@name - #{description}" : ""}\n"
141
+ }
142
+ ErrorLog << "\n"
143
+
144
+ if e.kind_of? Error
145
+ Counter[e.count_as] += 1
146
+ e.count_as.to_s.upcase
147
+ else
148
+ Counter[:errors] += 1
149
+ "ERROR: #{e.class}"
150
+ end
151
+ else
152
+ ""
153
+ ensure
154
+ Counter[:depth] -= 1
155
+ end
156
+ end
157
+ end
158
+
159
+ def raise?(*args, &block); block.raise?(*args); end
160
+ def throw?(*args, &block); block.throw?(*args); end
161
+ def change?(*args, &block); block.change?(*args); end
162
+ end
163
+ end
164
+
165
+
166
+ class Object
167
+ def true?; false; end
168
+ def false?; false; end
169
+ end
170
+
171
+ class TrueClass
172
+ def true?; true; end
173
+ end
174
+
175
+ class FalseClass
176
+ def false?; true; end
177
+ end
178
+
179
+ class Proc
180
+ def raise?(*exceptions)
181
+ exceptions << RuntimeError if exceptions.empty?
182
+ call
183
+
184
+ # Only to work in 1.9.0, rescue with splat doesn't work there right now
185
+ rescue Object => e
186
+ case e
187
+ when *exceptions
188
+ e
189
+ else
190
+ raise e
191
+ end
192
+ else
193
+ false
194
+ end
195
+
196
+ def throw?(sym)
197
+ catch(sym) {
198
+ call
199
+ return false
200
+ }
201
+ return true
202
+ end
203
+
204
+ def change?
205
+ pre_result = yield
206
+ called = call
207
+ post_result = yield
208
+ pre_result != post_result
209
+ end
210
+ end
211
+
212
+ class Numeric
213
+ def close?(to, delta)
214
+ (to.to_f - self).abs <= delta.to_f rescue false
215
+ end
216
+ end
217
+
218
+
219
+ class Object
220
+ def should(*args, &block) Should.new(self).be(*args, &block) end
221
+ end
222
+
223
+ module Kernel
224
+ private
225
+
226
+ def describe(name, &block) Bacon::Context.new(name, &block) end
227
+ def shared(name, &block) Bacon::Shared[name] = block end
228
+ end
229
+
230
+
231
+ class Should
232
+ # Kills ==, ===, =~, eql?, equal?, frozen?, instance_of?, is_a?,
233
+ # kind_of?, nil?, respond_to?, tainted?
234
+ instance_methods.each { |method|
235
+ undef_method method if method =~ /\?|^\W+$/
236
+ }
237
+
238
+ def initialize(object)
239
+ @object = object
240
+ @negated = false
241
+ end
242
+
243
+ def not(*args, &block)
244
+ @negated = !@negated
245
+
246
+ if args.empty?
247
+ self
248
+ else
249
+ be(*args, &block)
250
+ end
251
+ end
252
+
253
+ def be(*args, &block)
254
+ if args.empty?
255
+ self
256
+ else
257
+ block = args.shift unless block_given?
258
+ satisfy(*args, &block)
259
+ end
260
+ end
261
+
262
+ alias a be
263
+ alias an be
264
+
265
+ def satisfy(*args, &block)
266
+ if args.size == 1 && String === args.first
267
+ description = args.shift
268
+ else
269
+ description = ""
270
+ end
271
+
272
+ r = yield(@object, *args)
273
+ if Bacon::Counter[:depth] > 0
274
+ raise Bacon::Error.new(:failed, description) unless @negated ^ r
275
+ Bacon::Counter[:requirements] += 1
276
+ end
277
+ @negated ^ r ? r : false
278
+ end
279
+
280
+ def method_missing(name, *args, &block)
281
+ name = "#{name}?" if name.to_s =~ /\w[^?]\z/
282
+
283
+ desc = @negated ? "not " : ""
284
+ desc << @object.inspect << "." << name.to_s
285
+ desc << "(" << args.map{|x|x.inspect}.join(", ") << ") failed"
286
+
287
+ satisfy(desc) { |x| x.__send__(name, *args, &block) }
288
+ end
289
+
290
+ def equal(value) self == value end
291
+ def match(value) self =~ value end
292
+ def identical_to(value) self.equal? value end
293
+ alias same_as identical_to
294
+
295
+ def flunk(reason="Flunked")
296
+ raise Bacon::Error.new(:failed, reason)
297
+ end
298
+ end
@@ -0,0 +1,310 @@
1
+ $: << File.dirname(__FILE__) + '/../lib/'
2
+ require 'bacon'
3
+
4
+ # Hooray for meta-testing.
5
+ module MetaTests
6
+ def succeed
7
+ lambda { |block|
8
+ block.should.not.raise Bacon::Error
9
+ true
10
+ }
11
+ end
12
+
13
+ def fail
14
+ lambda { |block|
15
+ block.should.raise Bacon::Error
16
+ true
17
+ }
18
+ end
19
+
20
+ def equal_string(x)
21
+ lambda { |s|
22
+ x == s.to_s
23
+ }
24
+ end
25
+ end
26
+
27
+ describe "Bacon" do
28
+ extend MetaTests
29
+
30
+ it "should have should.satisfy" do
31
+ lambda { should.satisfy { 1 == 1 } }.should succeed
32
+ lambda { should.satisfy { 1 } }.should succeed
33
+
34
+ lambda { should.satisfy { 1 == 2 } }.should fail
35
+ lambda { should.satisfy { false } }.should fail
36
+ lambda { should.satisfy { false } }.should fail
37
+
38
+ lambda { 1.should.satisfy { |n| n % 2 == 0 } }.should fail
39
+ lambda { 2.should.satisfy { |n| n % 2 == 0 } }.should succeed
40
+ end
41
+
42
+ it "should have should.equal" do
43
+ lambda { "string1".should == "string1" }.should succeed
44
+ lambda { "string1".should == "string2" }.should fail
45
+ lambda { "1".should == 1 }.should fail
46
+
47
+ lambda { "string1".should.equal "string1" }.should succeed
48
+ lambda { "string1".should.equal "string2" }.should fail
49
+ lambda { "1".should.equal 1 }.should fail
50
+ end
51
+
52
+ it "should have should.raise" do
53
+ lambda { lambda { raise "Error" }.should.raise }.should succeed
54
+ lambda { lambda { raise "Error" }.should.raise RuntimeError }.should succeed
55
+ lambda { lambda { raise "Error" }.should.not.raise }.should fail
56
+ lambda { lambda { raise "Error" }.should.not.raise(RuntimeError) }.should fail
57
+
58
+ lambda { lambda { 1 + 1 }.should.raise }.should fail
59
+ lambda {
60
+ lambda { raise "Error" }.should.raise(Interrupt)
61
+ }.should.raise
62
+ end
63
+
64
+ it "should have should.raise with a block" do
65
+ lambda { should.raise { raise "Error" } }.should succeed
66
+ lambda { should.raise(RuntimeError) { raise "Error" } }.should succeed
67
+ lambda { should.not.raise { raise "Error" } }.should fail
68
+ lambda { should.not.raise(RuntimeError) { raise "Error" } }.should fail
69
+
70
+ lambda { should.raise { 1 + 1 } }.should fail
71
+ lambda {
72
+ should.raise(Interrupt) { raise "Error" }
73
+ }.should.raise
74
+ end
75
+
76
+ it "should have a should.raise should return the exception" do
77
+ ex = lambda { raise "foo!" }.should.raise
78
+ ex.should.be.kind_of RuntimeError
79
+ ex.message.should =~ /foo/
80
+ end
81
+
82
+ it "should have should.be.an.instance_of" do
83
+ lambda { "string".should.be.instance_of String }.should succeed
84
+ lambda { "string".should.be.instance_of Hash }.should fail
85
+
86
+ lambda { "string".should.be.an.instance_of String }.should succeed
87
+ lambda { "string".should.be.an.instance_of Hash }.should fail
88
+ end
89
+
90
+ it "should have should.be.nil" do
91
+ lambda { nil.should.be.nil }.should succeed
92
+ lambda { nil.should.not.be.nil }.should fail
93
+ lambda { "foo".should.be.nil }.should fail
94
+ lambda { "foo".should.not.be.nil }.should succeed
95
+ end
96
+
97
+ it "should have should.include" do
98
+ lambda { [1,2,3].should.include 2 }.should succeed
99
+ lambda { [1,2,3].should.include 4 }.should fail
100
+
101
+ lambda { {1=>2, 3=>4}.should.include 1 }.should succeed
102
+ lambda { {1=>2, 3=>4}.should.include 2 }.should fail
103
+ end
104
+
105
+ it "should have should.be.a.kind_of" do
106
+ lambda { Array.should.be.kind_of Module }.should succeed
107
+ lambda { "string".should.be.kind_of Object }.should succeed
108
+ lambda { 1.should.be.kind_of Comparable }.should succeed
109
+
110
+ lambda { Array.should.be.a.kind_of Module }.should succeed
111
+
112
+ lambda { "string".should.be.a.kind_of Class }.should fail
113
+ end
114
+
115
+ it "should have should.match" do
116
+ lambda { "string".should.match(/strin./) }.should succeed
117
+ lambda { "string".should =~ /strin./ }.should succeed
118
+
119
+ lambda { "string".should.match(/slin./) }.should fail
120
+ lambda { "string".should =~ /slin./ }.should fail
121
+ end
122
+
123
+ it "should have should.not.raise" do
124
+ lambda { lambda { 1 + 1 }.should.not.raise }.should succeed
125
+ lambda { lambda { 1 + 1 }.should.not.raise(Interrupt) }.should succeed
126
+
127
+ lambda {
128
+ lambda {
129
+ lambda {
130
+ Kernel.raise ZeroDivisionError.new("ArgumentError")
131
+ }.should.not.raise(RuntimeError, Comparable)
132
+ }.should.raise ZeroDivisionError
133
+ }.should succeed
134
+
135
+ lambda { lambda { raise "Error" }.should.not.raise }.should fail
136
+ end
137
+
138
+ it "should have should.throw" do
139
+ lambda { lambda { throw :foo }.should.throw(:foo) }.should succeed
140
+ lambda { lambda { :foo }.should.throw(:foo) }.should fail
141
+
142
+ should.throw(:foo) { throw :foo }
143
+ end
144
+
145
+ it "should have should.not.satisfy" do
146
+ lambda { should.not.satisfy { 1 == 2 } }.should succeed
147
+ lambda { should.not.satisfy { 1 == 1 } }.should fail
148
+ end
149
+
150
+ it "should have should.not.equal" do
151
+ lambda { "string1".should.not == "string2" }.should succeed
152
+ lambda { "string1".should.not == "string1" }.should fail
153
+ end
154
+
155
+ it "should have should.not.match" do
156
+ lambda { "string".should.not.match(/sling/) }.should succeed
157
+ lambda { "string".should.not.match(/string/) }.should fail
158
+ # lambda { "string".should.not.match("strin") }.should fail
159
+
160
+ lambda { "string".should.not =~ /sling/ }.should succeed
161
+ lambda { "string".should.not =~ /string/ }.should fail
162
+ # lambda { "string".should.not =~ "strin" }.should fail
163
+ end
164
+
165
+ it "should have should.be.identical_to/same_as" do
166
+ lambda { s = "string"; s.should.be.identical_to s }.should succeed
167
+ lambda { "string".should.be.identical_to "string" }.should fail
168
+
169
+ lambda { s = "string"; s.should.be.same_as s }.should succeed
170
+ lambda { "string".should.be.same_as "string" }.should fail
171
+ end
172
+
173
+ it "should have should.respond_to" do
174
+ lambda { "foo".should.respond_to :to_s }.should succeed
175
+ lambda { 5.should.respond_to :to_str }.should fail
176
+ lambda { :foo.should.respond_to :nx }.should fail
177
+ end
178
+
179
+ it "should have should.be.close" do
180
+ lambda { 1.4.should.be.close 1.4, 0 }.should succeed
181
+ lambda { 0.4.should.be.close 0.5, 0.1 }.should succeed
182
+
183
+ lambda { 0.4.should.be.close 0.5, 0.05 }.should fail
184
+ lambda { 0.4.should.be.close Object.new, 0.1 }.should fail
185
+ lambda { 0.4.should.be.close 0.5, -0.1 }.should fail
186
+ end
187
+
188
+ it "should support multiple negation" do
189
+ lambda { 1.should.equal 1 }.should succeed
190
+ lambda { 1.should.not.equal 1 }.should fail
191
+ lambda { 1.should.not.not.equal 1 }.should succeed
192
+ lambda { 1.should.not.not.not.equal 1 }.should fail
193
+
194
+ lambda { 1.should.equal 2 }.should fail
195
+ lambda { 1.should.not.equal 2 }.should succeed
196
+ lambda { 1.should.not.not.equal 2 }.should fail
197
+ lambda { 1.should.not.not.not.equal 2 }.should succeed
198
+ end
199
+
200
+ it "should have should.<predicate>" do
201
+ lambda { [].should.be.empty }.should succeed
202
+ lambda { [1,2,3].should.not.be.empty }.should succeed
203
+
204
+ lambda { [].should.not.be.empty }.should fail
205
+ lambda { [1,2,3].should.be.empty }.should fail
206
+
207
+ lambda { {1=>2, 3=>4}.should.has_key 1 }.should succeed
208
+ lambda { {1=>2, 3=>4}.should.not.has_key 2 }.should succeed
209
+
210
+ lambda { nil.should.bla }.should.raise(NoMethodError)
211
+ lambda { nil.should.not.bla }.should.raise(NoMethodError)
212
+ end
213
+
214
+ it "should have should <operator> (>, >=, <, <=, ===)" do
215
+ lambda { 2.should.be > 1 }.should succeed
216
+ lambda { 1.should.be > 2 }.should fail
217
+
218
+ lambda { 1.should.be < 2 }.should succeed
219
+ lambda { 2.should.be < 1 }.should fail
220
+
221
+ lambda { 2.should.be >= 1 }.should succeed
222
+ lambda { 2.should.be >= 2 }.should succeed
223
+ lambda { 2.should.be >= 2.1 }.should fail
224
+
225
+ lambda { 2.should.be <= 1 }.should fail
226
+ lambda { 2.should.be <= 2 }.should succeed
227
+ lambda { 2.should.be <= 2.1 }.should succeed
228
+
229
+ lambda { Array.should === [1,2,3] }.should succeed
230
+ lambda { Integer.should === [1,2,3] }.should fail
231
+
232
+ lambda { /foo/.should === "foobar" }.should succeed
233
+ lambda { "foobar".should === /foo/ }.should fail
234
+ end
235
+
236
+ it "should allow for custom shoulds" do
237
+ lambda { (1+1).should equal_string("2") }.should succeed
238
+ lambda { (1+2).should equal_string("2") }.should fail
239
+
240
+ lambda { (1+1).should.be equal_string("2") }.should succeed
241
+ lambda { (1+2).should.be equal_string("2") }.should fail
242
+
243
+ lambda { (1+1).should.not equal_string("2") }.should fail
244
+ lambda { (1+2).should.not equal_string("2") }.should succeed
245
+ lambda { (1+2).should.not.not equal_string("2") }.should fail
246
+
247
+ lambda { (1+1).should.not.be equal_string("2") }.should fail
248
+ lambda { (1+2).should.not.be equal_string("2") }.should succeed
249
+ end
250
+
251
+ it "should have should.flunk" do
252
+ lambda { should.flunk }.should fail
253
+ lambda { should.flunk "yikes" }.should fail
254
+ end
255
+ end
256
+
257
+ describe "before/after" do
258
+ before do
259
+ @a = 1
260
+ @b = 2
261
+ end
262
+
263
+ before do
264
+ @a = 2
265
+ end
266
+
267
+ after do
268
+ @a.should.equal 2
269
+ @a = 3
270
+ end
271
+
272
+ after do
273
+ @a.should.equal 3
274
+ end
275
+
276
+ it "should run in the right order" do
277
+ @a.should.equal 2
278
+ @b.should.equal 2
279
+ end
280
+ end
281
+
282
+ shared "a shared context" do
283
+ it "gets called where it is included" do
284
+ true.should.be.true
285
+ end
286
+ end
287
+
288
+ shared "another shared context" do
289
+ it "can access data" do
290
+ @magic.should.be.equal 42
291
+ end
292
+ end
293
+
294
+ describe "shared/behaves_like" do
295
+ behaves_like "a shared context"
296
+
297
+ ctx = self
298
+ it "raises NameError when the context is not found" do
299
+ lambda {
300
+ ctx.behaves_like "whoops"
301
+ }.should.raise NameError
302
+ end
303
+
304
+ behaves_like "a shared context"
305
+
306
+ before {
307
+ @magic = 42
308
+ }
309
+ behaves_like "another shared context"
310
+ end
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.4
3
+ specification_version: 1
4
+ name: bacon
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.9.0
7
+ date: 2008-01-07 00:00:00 +01:00
8
+ summary: a small RSpec clone
9
+ require_paths:
10
+ - lib
11
+ email: chneukirchen@gmail.com
12
+ homepage: http://chneukirchen.org/repos/bacon
13
+ rubyforge_project:
14
+ description: Bacon is a small RSpec clone weighing less than 300 LoC but nevertheless providing all essential features. http://chneukirchen.org/repos/bacon
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Christian Neukirchen
31
+ files:
32
+ - bin/bacon
33
+ - COPYING
34
+ - lib/bacon.rb
35
+ - Rakefile
36
+ - README
37
+ - test/spec_bacon.rb
38
+ - RDOX
39
+ test_files: []
40
+
41
+ rdoc_options: []
42
+
43
+ extra_rdoc_files:
44
+ - README
45
+ - RDOX
46
+ executables:
47
+ - bacon
48
+ extensions: []
49
+
50
+ requirements: []
51
+
52
+ dependencies: []
53
+