test-spec 0.2

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.
File without changes
@@ -0,0 +1,11 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ setup.rb
6
+ lib/test-spec.rb
7
+ lib/test-spec/version.rb
8
+ lib/test-spec/test/spec.rb
9
+ lib/test-spec/test/spec/dox.rb
10
+ lib/test-spec/test/spec/rdox.rb
11
+ lib/test-spec/test/spec/should-output.rb
@@ -0,0 +1,206 @@
1
+ = test/spec, a BDD interface for Test::Unit
2
+
3
+ Copyright (C) 2006 Christian Neukirchen <mailto:chneukirchen@gmail.com>
4
+
5
+
6
+ == What is test/spec?
7
+
8
+ test/spec layers an RSpec-inspired interface on top of Test::Unit, so
9
+ you can mix TDD and BDD (Behavior-Driven Development).
10
+
11
+ test/spec is a clean-room implementation that maps most kinds of
12
+ Test::Unit assertions to a `should'-like syntax.
13
+
14
+ Consider this Test::Unit test case:
15
+
16
+ class TestFoo < Test::Unit::TestCase
17
+ def test_should_bar
18
+ assert_equal 5, 2 + 3
19
+ end
20
+ end
21
+
22
+ In test/spec, it looks like this:
23
+
24
+ require 'test/spec'
25
+
26
+ context "Foo" do
27
+ specify "should bar" do
28
+ (2 + 3).should.equal 5
29
+ end
30
+ end
31
+
32
+ test/spec does not include a mocking/stubbing-framework; use whichever
33
+ you like to. test/spec has been tested successfully with FlexMock and
34
+ Mocha.
35
+
36
+ test/spec has no dependencies outside Ruby 1.8.
37
+
38
+
39
+ == Mixing test/spec and test/unit
40
+
41
+ test/spec and Test::Unit contexts/test cases can be intermixed freely,
42
+ run in the same test and live in the same files. You can just add them
43
+ to your Rake::TestTask, too. test/spec allows you to leverage your
44
+ full existing Test::Unit infrastructure.
45
+
46
+ test/spec does not change Test::Unit with the exception of
47
+ monkey-patching Test::Unit::TestSuite to order the test cases before
48
+ running them. (This should not do any harm, but if you know a way
49
+ around it, please tell me.)
50
+
51
+ test/spec adds two global methods, Object#should and Kernel.context.
52
+
53
+ You can use <tt>assert_*</tt> freely in specify-blocks; Object#should
54
+ works in plain Test::Unit test cases, too, but they will not be counted.
55
+
56
+
57
+ == Wrapped assertions
58
+
59
+ +assert_equal+:: <tt>should.equal</tt>, <tt>should ==</tt>
60
+ +assert_not_equal+:: <tt>should.not.equal</tt>, <tt>should.not ==</tt>
61
+ +assert_same+:: <tt>should.be</tt>
62
+ +assert_not_same+:: <tt>should.not.be</tt>
63
+ +assert_nil+:: <tt>should.be.nil</tt>
64
+ +assert_not_nil+:: <tt>should.not.be.nil</tt>
65
+ +assert_in_delta+:: <tt>should.be.close</tt>
66
+ +assert_match+:: <tt>should.match</tt>, <tt>should =~</tt>
67
+ +assert_no_match+:: <tt>should.not.match</tt>, <tt>should.not =~</tt>
68
+
69
+ +assert_instance_of+:: <tt>should.be.an.instance_of</tt>
70
+ +assert_kind_of+:: <tt>should.be.a.kind_of</tt>
71
+ +assert_respond_to+:: <tt>should.respond_to</tt>
72
+ +assert_raise+:: <tt>should.raise</tt>
73
+ +assert_nothing_raised+:: <tt>should.not.raise</tt>
74
+ +assert_throws+:: <tt>should.throw</tt>
75
+ +assert_nothing_thrown+:: <tt>should.not.throw</tt>
76
+
77
+ +assert_block+:: <tt>should.satisfy</tt>
78
+
79
+ (+a+, +an+ and +be+ without arguments are optional and no-ops.)
80
+
81
+
82
+ == Additional assertions
83
+
84
+ These assertions are not included in Test::Unit, but have been added
85
+ to test/spec for convenience:
86
+
87
+ * <tt>should.not.satisfy</tt>
88
+ * <tt>should.include</tt>
89
+ * <tt>a.should.</tt>_predicate_ (works like <tt>assert
90
+ a.</tt>_predicate_<tt>?</tt>)
91
+ * <tt>a.should.be </tt>_operator_ (where _operator_ is one of <tt>></tt>, <tt>>=</tt>, <tt><</tt>, <tt><=</tt> or <tt>===</tt>)
92
+ * <tt>should.output</tt> (require test/spec/should-output)
93
+
94
+ If you write an useful general-purpose assertion, I'd like to hear of
95
+ it and may add it to the test/spec distribution.
96
+
97
+
98
+ == SpecDox and RDox
99
+
100
+ test/spec adds two additional test runners to Test::Unit, based on the
101
+ console runner but with a different output format.
102
+
103
+ SpecDox, run with <tt>--runner=specdox</tt> (or <tt>-rs</tt>) looks
104
+ like RSpec's output:
105
+
106
+ should.output
107
+ - works for print
108
+ - works for puts
109
+ - works with readline
110
+
111
+ RDox, run with <tt>--runner=rdox</tt> (or <tt>-rr</tt>) can be
112
+ included for RDoc documentation (e.g. see SPECS):
113
+
114
+ == should.output
115
+ * works for print
116
+ * works for puts
117
+ * works with readline
118
+
119
+ SpecDox and RDox work for Test::Unit too:
120
+
121
+ $ ruby -r test/spec test/testunit/test_testresult.rb -rs
122
+
123
+ Test::Unit::TC_TestResult
124
+ - fault notification
125
+ - passed?
126
+ - result changed notification
127
+
128
+ Finished in 0.106647 seconds.
129
+
130
+ 3 specifications (30 requirements), 0 failures
131
+
132
+
133
+ == specrb
134
+
135
+ Since version 0.2, test/spec features a standalone test runner called
136
+ specrb. specrb is like an extended version of testrb, Test::Unit's
137
+ test runner, but has additional options. It can be used for
138
+ plain Test::Unit suites, too.
139
+
140
+ $ specrb -a -s -n should.output
141
+
142
+ should.output
143
+ - works for print
144
+ - works for puts
145
+ - works with readline
146
+
147
+ Finished in 0.162571 seconds.
148
+
149
+ 3 specifications (6 requirements), 0 failures
150
+
151
+ Run <tt>specrb --help</tt> for the usage.
152
+
153
+
154
+ == History
155
+
156
+ * September 29th, 2006: First public release 0.1.
157
+
158
+ * October 18th, 2006: Second public release 0.2.
159
+ * Better, module-based implementation
160
+ * Official support for FlexMock and Mocha
161
+ * More robust Should#output
162
+ * Should#_operator_
163
+ * Nested contexts
164
+ * Standalone test/spec runner, specrb
165
+
166
+
167
+ == Contact
168
+
169
+ Please mail bugs, suggestions and patches to
170
+ <mailto:chneukirchen@gmail.com>.
171
+
172
+ Darcs repository ("darcs send" is welcome for patches):
173
+ http://chneukirchen.org/repos/testspec
174
+
175
+
176
+ == Thanks to
177
+
178
+ * Eero Saynatkari for writing <tt>should.output</tt>.
179
+ * Thomas Fuchs for script.aculo.us BDD testing which convinced me.
180
+ * Dave Astels for BDD.
181
+ * The RSpec team for API inspiration.
182
+ * Nathaniel Talbott for Test::Unit.
183
+
184
+
185
+ == Copying
186
+
187
+ Copyright (C) 2006 Christian Neukirchen <http://purl.org/net/chneukirchen>
188
+
189
+ test/spec is licensed under the same terms as Ruby itself.
190
+
191
+ Please mail bugs, feature requests or patches to the mail addresses
192
+ found above or use IRC[irc://freenode.net/#ruby-lang] to contact the
193
+ developer.
194
+
195
+
196
+ == Links
197
+
198
+ Behavior-Driven Development:: <http://behaviour-driven.org/>
199
+ RSpec:: <http://rspec.rubyforge.org/>
200
+ script.aculo.us testing:: <http://mir.aculo.us/articles/2006/08/29/bdd-style-javascript-testing>
201
+
202
+ FlexMock:: <http://onestepback.org/software/flexmock/>
203
+ Mocha:: <http://mocha.rubyforge.org/>
204
+
205
+ Christian Neukirchen:: <http://chneukirchen.org/>
206
+
@@ -0,0 +1,137 @@
1
+ # Rakefile for testspec. -*-ruby-*-
2
+ #
3
+ #
4
+ #
5
+ require 'rubygems'
6
+ require 'rake'
7
+ require 'rake/clean'
8
+ require 'rake/testtask'
9
+ require 'rake/packagetask'
10
+ require 'rake/gempackagetask'
11
+ require 'rake/rdoctask'
12
+ require 'rake/contrib/rubyforgepublisher'
13
+ require 'fileutils'
14
+ require 'hoe'
15
+ include FileUtils
16
+ require File.join(File.dirname(__FILE__), 'lib', 'test-spec', 'version')
17
+
18
+ AUTHOR = "Christian Neukirchen" # can also be an array of Authors
19
+ EMAIL = "chneukirchen@gmail.com"
20
+ DESCRIPTION = "Behaviour Driven Development with Test::Unit"
21
+ GEM_NAME = "test-spec" # what ppl will type to install your gem
22
+ RUBYFORGE_PROJECT = "test-spec" # The unix name for your project
23
+ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
24
+ RELEASE_TYPES = %w( gem ) # can use: gem, tar, zip
25
+
26
+
27
+ NAME = "test-spec"
28
+ REV = nil # UNCOMMENT IF REQUIRED: File.read(".svn/entries")[/committed-rev="(d+)"/, 1] rescue nil
29
+ VERS = ENV['VERSION'] || (TestSpec::VERSION::STRING + (REV ? ".#{REV}" : ""))
30
+ CLEAN.include ['**/.*.sw?', '*.gem', '.config']
31
+ RDOC_OPTS = ['--quiet', '--title', "test_spec documentation",
32
+ "--opname", "index.html",
33
+ "--line-numbers",
34
+ "--main", "README",
35
+ "--inline-source"]
36
+
37
+ # Generate all the Rake tasks
38
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
39
+ hoe = Hoe.new(GEM_NAME, VERS) do |p|
40
+ p.author = AUTHOR
41
+ p.description = DESCRIPTION
42
+ p.email = EMAIL
43
+ p.summary = DESCRIPTION
44
+ p.url = HOMEPATH
45
+ p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
46
+ p.test_globs = ["test/**/*_test.rb"]
47
+ p.clean_globs = CLEAN #An array of file patterns to delete on clean.
48
+ p.extra_deps = ['flexmock','>= 0.4.3'],['mocha','>= 0.3.2']
49
+ # == Optional
50
+ #p.changes - A description of the release's latest changes.
51
+ #p.spec_extras - A hash of extra values to set in the gemspec.
52
+ end
53
+
54
+
55
+ desc "Run all the tests"
56
+ task :default => [:test]
57
+
58
+ desc "Do predistribution stuff"
59
+ task :predist => [:chmod, :changelog, :rdoc]
60
+
61
+
62
+ desc "Run all the tests"
63
+ task :test => :chmod do
64
+ ruby "bin/specrb -Ilib:test -w #{ENV['TEST'] || '-a'} #{ENV['TESTOPTS']}"
65
+ end
66
+
67
+ desc "Make an archive as .tar.gz"
68
+ task :dist => :test do
69
+ system "export DARCS_REPO=#{File.expand_path "."}; " +
70
+ "darcs dist -d testspec#{get_darcs_tree_version}"
71
+ end
72
+
73
+ desc "Make binaries executable"
74
+ task :chmod do
75
+ Dir["bin/*"].each { |binary| File.chmod(0775, binary) }
76
+ end
77
+
78
+ desc "Generate a ChangeLog"
79
+ task :changelog do
80
+ system "darcs changes --repo=#{ENV["DARCS_REPO"] || "."} >ChangeLog"
81
+ end
82
+
83
+ desc "Generate RDoc documentation"
84
+ Rake::RDocTask.new(:rdoc) do |rdoc|
85
+ rdoc.options << '--line-numbers' << '--inline-source'
86
+ rdoc.rdoc_dir = "rdoc"
87
+ rdoc.rdoc_files.include 'README'
88
+ rdoc.rdoc_files.include 'ROADMAP'
89
+ rdoc.rdoc_files.include 'SPECS'
90
+ rdoc.rdoc_files.include('lib/**/*.rb')
91
+ end
92
+ task :rdoc => "SPECS"
93
+
94
+ desc "Generate RDox"
95
+ task "SPECS" do
96
+ ruby "bin/specrb -Ilib:test -a --rdox >SPECS"
97
+ end
98
+
99
+ begin
100
+ require 'rcov/rcovtask'
101
+
102
+ Rcov::RcovTask.new do |t|
103
+ t.test_files = FileList['test/spec_*.rb'] + ['--', '-rs'] # evil
104
+ t.verbose = true # uncomment to see the executed command
105
+ t.rcov_opts = ["--text-report", "--include-file", "^lib\\|^test"]
106
+ end
107
+ rescue LoadError
108
+ end
109
+
110
+
111
+ # Helper to retrieve the "revision number" of the darcs tree.
112
+ def get_darcs_tree_version
113
+ return "" unless File.directory? "_darcs"
114
+
115
+ changes = `darcs changes`
116
+ count = 0
117
+ tag = "0.0"
118
+
119
+ changes.each("\n\n") { |change|
120
+ head, title, desc = change.split("\n", 3)
121
+
122
+ if title =~ /^ \*/
123
+ # Normal change.
124
+ count += 1
125
+ elsif title =~ /tagged (.*)/
126
+ # Tag. We look for these.
127
+ tag = $1
128
+ break
129
+ else
130
+ warn "Unparsable change: #{change}"
131
+ end
132
+ }
133
+
134
+ "-" + tag + "." + count.to_s
135
+ end
136
+
137
+
@@ -0,0 +1,2 @@
1
+ Dir[File.join(File.dirname(__FILE__), 'test-spec/**/*.rb')].sort.each { |lib| require lib }
2
+ require 'rubygems'
@@ -0,0 +1,368 @@
1
+ #
2
+ # test/spec -- a BDD interface for Test::Unit
3
+ #
4
+ # Copyright (C) 2006 Christian Neukirchen <mailto:chneukirchen@gmail.com>
5
+ #
6
+ # This work is licensed under the same terms as Ruby itself.
7
+ #
8
+
9
+ require 'test/unit'
10
+
11
+ class Test::Unit::AutoRunner # :nodoc:
12
+ RUNNERS[:specdox] = lambda {
13
+ require 'test/spec/dox'
14
+ Test::Unit::UI::SpecDox::TestRunner
15
+ }
16
+
17
+ RUNNERS[:rdox] = lambda {
18
+ require 'test/spec/rdox'
19
+ Test::Unit::UI::RDox::TestRunner
20
+ }
21
+ end
22
+
23
+ module Test # :nodoc:
24
+ end
25
+
26
+ module Test::Spec
27
+ VERSION = "0.1"
28
+
29
+ CONTEXTS = {}
30
+
31
+ class DefinitionError < StandardError
32
+ end
33
+
34
+ class Should
35
+ include Test::Unit::Assertions
36
+
37
+ def initialize(object)
38
+ @object = object
39
+ end
40
+
41
+ $TEST_SPEC_TESTCASE = nil
42
+ def add_assertion
43
+ $TEST_SPEC_TESTCASE && $TEST_SPEC_TESTCASE.__send__(:add_assertion)
44
+ end
45
+
46
+
47
+ def an
48
+ self
49
+ end
50
+
51
+ def a
52
+ self
53
+ end
54
+
55
+ def not
56
+ ShouldNot.new(@object)
57
+ end
58
+
59
+
60
+ def satisfy(&block)
61
+ assert_block("satisfy block failed.") {
62
+ yield @object
63
+ }
64
+ end
65
+
66
+ def equal(value)
67
+ assert_equal value, @object
68
+ end
69
+ alias == equal
70
+
71
+ def close(value, delta)
72
+ assert_in_delta value, @object, delta
73
+ end
74
+ alias be_close close
75
+
76
+ def be(*value)
77
+ case value.size
78
+ when 0
79
+ self
80
+ when 1
81
+ assert_same value.first, @object
82
+ else
83
+ raise ArgumentError, "should.be needs zero or one argument"
84
+ end
85
+ end
86
+
87
+ def match(value)
88
+ assert_match value, @object
89
+ end
90
+ alias =~ match
91
+
92
+ def instance_of(klass)
93
+ assert_instance_of klass, @object
94
+ end
95
+ alias be_an_instance_of instance_of
96
+
97
+ def kind_of(klass)
98
+ assert_kind_of klass, @object
99
+ end
100
+ alias be_a_kind_of kind_of
101
+
102
+ def respond_to(method)
103
+ assert_respond_to @object, method
104
+ end
105
+
106
+ def _raise(*args)
107
+ args = [RuntimeError] if args.empty?
108
+ assert_raise(*args, &@object)
109
+ end
110
+
111
+ def throw(*args)
112
+ assert_throws(*args, &@object)
113
+ end
114
+
115
+ def nil
116
+ assert_nil @object
117
+ end
118
+ alias be_nil nil
119
+
120
+
121
+ def include(value)
122
+ msg = build_message(nil, "<?> expected to include ?, but it didn't.",
123
+ @object, value)
124
+ assert_block(msg) { @object.include?(value) }
125
+ end
126
+
127
+ def >(value)
128
+ assert_operator @object, :>, value
129
+ end
130
+
131
+ def >=(value)
132
+ assert_operator @object, :>=, value
133
+ end
134
+
135
+ def <(value)
136
+ assert_operator @object, :<, value
137
+ end
138
+
139
+ def <=(value)
140
+ assert_operator @object, :<=, value
141
+ end
142
+
143
+ def ===(value)
144
+ assert_operator @object, :===, value
145
+ end
146
+
147
+ def method_missing(name, *args)
148
+ # This will make raise call Kernel.raise, and self.raise call _raise.
149
+ return _raise(*args) if name == :raise
150
+
151
+ if @object.respond_to?("#{name}?")
152
+ assert @object.__send__("#{name}?", *args),
153
+ "#{name}? expected to be true."
154
+ else
155
+ super
156
+ end
157
+ end
158
+ end
159
+
160
+ class ShouldNot
161
+ include Test::Unit::Assertions
162
+
163
+ def initialize(object)
164
+ @object = object
165
+ end
166
+
167
+ def equal(value)
168
+ assert_not_equal value, @object
169
+ end
170
+ alias == equal
171
+
172
+ def be(*value)
173
+ case value.size
174
+ when 0
175
+ self
176
+ when 1
177
+ assert_not_same value.first, @object
178
+ else
179
+ Kernel.raise ArgumentError, "should.be needs zero or one argument"
180
+ end
181
+ end
182
+
183
+ def match(value)
184
+ # Icky Regexp check
185
+ assert_no_match value, @object
186
+ end
187
+ alias =~ match
188
+
189
+ def _raise(*args)
190
+ assert_nothing_raised(*args, &@object)
191
+ end
192
+
193
+ def throw
194
+ assert_nothing_thrown(&@object)
195
+ end
196
+
197
+ def nil
198
+ assert_not_nil @object
199
+ end
200
+ alias be_nil nil
201
+
202
+
203
+ def not
204
+ Should.new(@object)
205
+ end
206
+
207
+
208
+ def method_missing(name, *args)
209
+ # This will make raise call Kernel.raise, and self.raise call _raise.
210
+ return _raise(*args) if name == :raise
211
+
212
+ if @object.respond_to?("#{name}?")
213
+ assert_block("#{name}? expected to be false.") {
214
+ not @object.__send__("#{name}?", *args)
215
+ }
216
+ else
217
+ super
218
+ end
219
+ end
220
+
221
+ end
222
+ end
223
+
224
+ class Test::Spec::TestCase
225
+ attr_reader :testcase
226
+ attr_reader :name
227
+ attr_reader :position
228
+
229
+ module InstanceMethods
230
+ def setup # :nodoc:
231
+ $TEST_SPEC_TESTCASE = self
232
+ super
233
+ self.class.setups.each { |s| instance_eval(&s) }
234
+ end
235
+
236
+ def teardown # :nodoc:
237
+ super
238
+ self.class.teardowns.each { |t| instance_eval(&t) }
239
+ end
240
+
241
+ def initialize(name)
242
+ super name
243
+
244
+ # Don't let the default_test clutter up the results and don't
245
+ # flunk if no tests given, either.
246
+ throw :invalid_test if name == :default_test
247
+ end
248
+
249
+ def position
250
+ self.class.position
251
+ end
252
+
253
+ def context(*args)
254
+ raise Test::Spec::DefinitionError,
255
+ "context definition is not allowed inside a specify-block"
256
+ end
257
+ end
258
+
259
+ module ClassMethods
260
+ attr_accessor :count
261
+ attr_accessor :name
262
+ attr_accessor :position
263
+ attr_accessor :parent
264
+
265
+ attr_accessor :setups
266
+ attr_accessor :teardowns
267
+
268
+ def context(name, &block)
269
+ (Test::Spec::CONTEXTS[self.name + "\t" + name] ||=
270
+ Test::Spec::TestCase.new(name, self)).add(&block)
271
+ end
272
+
273
+ def specify(specname, &block)
274
+ raise ArgumentError, "specify needs a block" if block.nil?
275
+
276
+ self.count += 1 # Let them run in order of definition
277
+
278
+ # TODO Changed by Jean-Michel
279
+ # define_method("test_%03d: %s" % [count, specname], &block)
280
+ define_method("test_spec {%s} %03d [%s]" % [name, count, specname], &block)
281
+ end
282
+
283
+ def setup(&block)
284
+ setups << block
285
+ end
286
+
287
+ def teardown(&block)
288
+ teardowns << block
289
+ end
290
+
291
+ def init(name, position, parent)
292
+ self.position = position
293
+ self.parent = parent
294
+
295
+ if parent
296
+ self.name = parent.name + "\t" + name
297
+ else
298
+ self.name = name
299
+ end
300
+
301
+ self.count = 0
302
+ self.setups = []
303
+ self.teardowns = []
304
+ end
305
+ end
306
+
307
+ @@POSITION = 0
308
+
309
+ def initialize(name, parent=nil)
310
+ @testcase = Class.new(Test::Unit::TestCase) {
311
+ include InstanceMethods
312
+ extend ClassMethods
313
+ }
314
+
315
+ @@POSITION = @@POSITION + 1
316
+ @testcase.init(name, @@POSITION, parent)
317
+ end
318
+
319
+ def add(&block)
320
+ raise ArgumentError, "context needs a block" if block.nil?
321
+
322
+ @testcase.class_eval(&block)
323
+ self
324
+ end
325
+ end
326
+
327
+
328
+ # Monkey-patch test/unit to run tests in an optionally specified order.
329
+ module Test::Unit # :nodoc:
330
+ class TestSuite # :nodoc:
331
+ undef run
332
+ def run(result, &progress_block)
333
+ sort!
334
+ yield(STARTED, name)
335
+ @tests.each do |test|
336
+ test.run(result, &progress_block)
337
+ end
338
+ yield(FINISHED, name)
339
+ end
340
+
341
+ def sort!
342
+ @tests = @tests.sort_by { |test|
343
+ test.respond_to?(:position) ? test.position : 0
344
+ }
345
+ end
346
+
347
+ def position
348
+ @tests.first.respond_to?(:position) ? @tests.first.position : 0
349
+ end
350
+ end
351
+ end
352
+
353
+
354
+ # Global helpers
355
+
356
+ class Object
357
+ def should
358
+ Test::Spec::Should.new(self)
359
+ end
360
+ end
361
+
362
+ module Kernel
363
+ def context(name, &block)
364
+ (Test::Spec::CONTEXTS[name] ||= Test::Spec::TestCase.new(name)).add(&block)
365
+ end
366
+
367
+ private :context
368
+ end