test-garden 0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. checksums.yaml +7 -0
  2. data/COPYING +22 -0
  3. data/README.md +64 -0
  4. data/Rakefile +65 -0
  5. data/lib/test-garden.rb +250 -0
  6. metadata +73 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5355162fcc4ae930d4cdc5ebf84ffa0bd241bae8
4
+ data.tar.gz: 1ec76a8eefcc3e54601c2bb02b0f55cdf7f08c36
5
+ SHA512:
6
+ metadata.gz: 88e3890465b22a04480b2fdfcb862bede60305a038a0c90bd9dc7097d87eabdfe65ff89dcbc63bd59d432c7b57a7a0e842332397ea200953a7067852bcaabe2a
7
+ data.tar.gz: c5eca2fdf237d5abb003ee7f99af9a686728ee291bced3892b8653c188adec99068a0c9f7f2b91acb85aa5f3609a0d10251b0651402907b07c05eb71f4b3edcc
data/COPYING ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013-2014, Joel VanderWerf, vjoel@users.sourceforge.net
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+ 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+
13
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,64 @@
1
+ TestGarden
2
+ ==========
3
+
4
+ A garden of forking tests.[1]
5
+
6
+ TestGarden is a testing framework for concisely sharing several stages of
7
+ setup code across tests. The shared code is executed once for each test
8
+ that needs it. Tests may be nested to any depth.
9
+
10
+ TestGarden generates summary output, reporting how many pass, fail, skip,
11
+ and error cases were detected for each group of tests. TestGarden assumes
12
+ assertion failure exceptions are generated by Wrong::Assert#assert.
13
+
14
+ Synopsis:
15
+
16
+ require 'test-garden'
17
+
18
+ test Thing do
19
+ thing = Thing.new; teardown {thing.cleanup()}
20
+ assert {thing.ok?}
21
+
22
+ test "assign foo" do
23
+ thing.foo = "baz" # does not affect foo in subsequent tests
24
+ assert {thing.foo == "baz"}
25
+ end
26
+
27
+ test "compare foo in two instances" do
28
+ thing2 = Thing.new; teardown {thing2.cleanup()}
29
+ assert {thing.foo == thing2.foo}
30
+ end
31
+ end
32
+
33
+ Run the test like so:
34
+
35
+ ruby test_thing.rb [-v | --verbose] [topic topic ...]
36
+
37
+ If no topics are given, the verbose output is:
38
+
39
+ T: Thing
40
+ T: Thing: assign foo
41
+ P: Thing: assign foo
42
+ T: Thing
43
+ T: Thing: compare foo in two instances
44
+ P: Thing: compare foo in two instances
45
+ 2 passed, 0 failed, 0 skipped, 0 errors in Thing
46
+
47
+ If a topic list is given, it is treated as a sequence of regular expressions.
48
+ Only tests whose topic path matches those regular expressions, one for one,
49
+ are executed. (Matching is case insensitive.) For example:
50
+
51
+ ruby testfilename.rb thing compare
52
+
53
+ This executes only the the last test. The verbose output is:
54
+
55
+ T: Thing
56
+ S: Thing: assign foo
57
+ T: Thing
58
+ T: Thing: compare foo in two instances
59
+ P: Thing: compare foo in two instances
60
+ 1 passed, 0 failed, 1 skipped, 0 errors in Thing
61
+
62
+ Note that the "assign foo" test was skipped, and counted as such.
63
+
64
+ [1] In reference to "The garden of forking paths", by J.L. Borges.
data/Rakefile ADDED
@@ -0,0 +1,65 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+
4
+ PRJ = "test-garden"
5
+
6
+ def version
7
+ @version ||= begin
8
+ require 'test-garden'
9
+ warn "TestGarden::VERSION not a string" unless
10
+ TestGarden::VERSION.kind_of? String
11
+ TestGarden::VERSION
12
+ end
13
+ end
14
+
15
+ def tag
16
+ @tag ||= "#{PRJ}-#{version}"
17
+ end
18
+
19
+ desc "Run tests"
20
+ Rake::TestTask.new :test do |t|
21
+ t.libs << "lib"
22
+ t.libs << "ext"
23
+ t.test_files = FileList["test/**/*.rb"]
24
+ end
25
+
26
+ desc "Commit, tag, and push repo; build and push gem"
27
+ task :release => "release:is_new_version" do
28
+ require 'tempfile'
29
+
30
+ sh "gem build #{PRJ}.gemspec"
31
+
32
+ file = Tempfile.new "template"
33
+ begin
34
+ file.puts "release #{version}"
35
+ file.close
36
+ sh "git commit --allow-empty -a -v -t #{file.path}"
37
+ ensure
38
+ file.close unless file.closed?
39
+ file.unlink
40
+ end
41
+
42
+ sh "git tag #{tag}"
43
+ sh "git push"
44
+ sh "git push --tags"
45
+
46
+ sh "gem push #{tag}.gem"
47
+ end
48
+
49
+ namespace :release do
50
+ desc "Diff to latest release"
51
+ task :diff do
52
+ latest = `git describe --abbrev=0 --tags --match '#{PRJ}-*'`.chomp
53
+ sh "git diff #{latest}"
54
+ end
55
+
56
+ desc "Log to latest release"
57
+ task :log do
58
+ latest = `git describe --abbrev=0 --tags --match '#{PRJ}-*'`.chomp
59
+ sh "git log #{latest}.."
60
+ end
61
+
62
+ task :is_new_version do
63
+ abort "#{tag} exists; update version!" unless `git tag -l #{tag}`.empty?
64
+ end
65
+ end
@@ -0,0 +1,250 @@
1
+ require 'wrong'
2
+ include Wrong::Assert
3
+
4
+ if Wrong.config[:color]
5
+ require "wrong/rainbow"
6
+ else
7
+ class String
8
+ def color(*); self; end
9
+ def bright; self; end
10
+ end
11
+ end
12
+
13
+ # Not directly instantiated by the user. See README and examples.
14
+ class TestGarden
15
+ # Array of nested topics in descending order from the main topic to the topic
16
+ # of the current test.
17
+ attr_reader :stack
18
+
19
+ # Hash of counters for pass, fail, skip, error cases.
20
+ attr_reader :status
21
+
22
+ # Array of regexes that restrict which topics are traversed.
23
+ attr_reader :pattern
24
+
25
+ # Stack of arrays of procs that will be called to tear down the current setup.
26
+ attr_reader :teardowns
27
+
28
+ VERSION = '0.4'
29
+
30
+ class IncompleteTest < StandardError; end
31
+
32
+ # Reads params from command line, or from given array of strings. If
33
+ # passing an array, you should call this method *before* all tests.
34
+ def self.params argv=ARGV
35
+ @params ||= {
36
+ :verbose => argv.delete("-v") || argv.delete("--verbose"),
37
+ :pattern => argv.map {|arg| /#{arg}/i}
38
+ }
39
+ end
40
+
41
+ # By default, share params for all TestGardens, but allow per-instance
42
+ # variation by modifying the params hash.
43
+ def params
44
+ @params ||= self.class.params.dup
45
+ end
46
+
47
+ def initialize
48
+ @pos = []
49
+ @next = nil
50
+ @did_one_test = false
51
+ @stack = []
52
+ @status = Hash.new(0)
53
+ @enabled = false
54
+ @pattern = params[:pattern]
55
+ @teardowns = []
56
+ @finishing = false
57
+ end
58
+
59
+ def enabled?
60
+ @enabled
61
+ end
62
+
63
+ def verbose?
64
+ params[:verbose]
65
+ end
66
+
67
+ def nest topic
68
+ topic = topic.to_s
69
+ @main_topic ||= topic
70
+
71
+ if @did_one_test
72
+ if not @next
73
+ @next = @pos.dup
74
+ end
75
+ @pos[-1] += 1 if @pos.length > 0
76
+ return
77
+ end
78
+
79
+ if @next
80
+ len = [@pos.length, @next.length].min
81
+ if @next[0...len] != @pos[0...len]
82
+ @pos[-1] += 1 if @pos.length > 0
83
+ return
84
+ end
85
+
86
+ if @next == @pos
87
+ @next = nil
88
+ end
89
+ end
90
+
91
+ begin
92
+ stack.push topic
93
+ @pos << 0
94
+ teardowns << []
95
+ old_enabled = @enabled
96
+ @enabled = pattern.zip(stack).all? {|pat,subj| !subj or pat === subj}
97
+ if enabled?
98
+ puts "T: #{stack.join(": ")}" if verbose?
99
+ @finishing = false
100
+ catch :break_test do
101
+ yield
102
+ @finishing = stack.dup
103
+ end
104
+ else
105
+ puts "S: #{stack.join(": ")}" if verbose?
106
+ status[:skip] += 1
107
+ end
108
+
109
+ ensure
110
+ if not @did_one_test
111
+ @did_one_test = true
112
+ else
113
+ @finishing = false
114
+ end
115
+
116
+ @enabled = old_enabled
117
+ @pos.pop
118
+ stack.pop
119
+ @pos[-1] += 1 if @pos.length > 0
120
+ end
121
+ end
122
+
123
+ def do_teardowns
124
+ teardowns.pop.reverse_each {|block| block.call}
125
+ end
126
+
127
+ def print_report
128
+ ps = "%3d passed" % status[:pass]
129
+ fs = "%3d failed" % status[:fail]
130
+ fs = fs.color(:yellow) if status[:fail] > 0
131
+ ss = "%3d skipped" % status[:skip]
132
+ es = "%3d errors" % status[:err]
133
+ es = es.color(:red) if status[:err] > 0
134
+ report = [ps,fs,ss,es].join(", ")
135
+
136
+ inc = status[:incomplete]
137
+ if inc > 0
138
+ is = "%3d incomplete" % inc
139
+ is = is.color(:white)
140
+ report << ", #{is}"
141
+ end
142
+
143
+ line = "#{report} in #{@main_topic}"
144
+ line = line.bright if verbose?
145
+ puts line
146
+ end
147
+
148
+ def handle_test_exceptions
149
+ yield
150
+
151
+ rescue Wrong::Assert::AssertionFailedError => ex
152
+ status[:fail] += 1
153
+ line = nil
154
+ ex.backtrace.reverse_each {|l| break if /wrong\/assert.rb/ =~ l; line = l}
155
+ msg = "F: #{stack.join(": ")}: failed assertion, at #{line}"
156
+ puts msg.color(:yellow), ex.message
157
+ throw :break_test
158
+
159
+ rescue IncompleteTest => ex
160
+ status[:incomplete] += 1
161
+ if verbose?
162
+ msg = "I: #{stack.join(": ")}"
163
+ msg = msg.color(:white)
164
+ puts msg
165
+ end
166
+ throw :break_test
167
+
168
+ rescue => ex
169
+ status[:err] += 1
170
+ bt = []
171
+ ex.backtrace.each {|l| break if /wrong\/assert.rb/ =~ l; bt << l}
172
+ bts = bt.join("\n from ")
173
+ msg = "E: #{stack.join(": ")}: #{ex} (#{ex.class}), at #{bts}"
174
+ puts msg.color(:red)
175
+ throw :break_test
176
+
177
+ else
178
+ if enabled?
179
+ if @finishing
180
+ status[:pass] += 1
181
+ puts "P: #{@finishing.join(": ")}" if verbose?
182
+ @finishing = false
183
+ end
184
+ else
185
+ raise
186
+ end
187
+ end
188
+
189
+ def main topic
190
+ begin
191
+ nest topic do
192
+ handle_test_exceptions do
193
+ yield
194
+ do_teardowns
195
+ end
196
+ end
197
+ @did_one_test = false
198
+ end while @next
199
+ ensure
200
+ print_report
201
+ end
202
+ end
203
+
204
+ # Begin a test block. The topic can be any object; its to_s method is applied
205
+ # to generate the output string. A class or string is typical.
206
+ #
207
+ # The block can include essentially any code, including more #test calls,
208
+ # method calls that call #test, assert{} and teardown{} calls, etc.
209
+ #
210
+ # If the block is omitted, then the test is assumed to be incomplete, perhaps
211
+ # a stub indicating future work. Incomplete tests are counted and reported.
212
+ def test topic
213
+ if @test
214
+ @test.nest topic do
215
+ @test.handle_test_exceptions do
216
+ if block_given?
217
+ yield
218
+ @test.do_teardowns
219
+ else
220
+ raise TestGarden::IncompleteTest
221
+ end
222
+ end
223
+ end
224
+
225
+ else
226
+ begin
227
+ @test = TestGarden.new
228
+ @test.main topic do
229
+ if block_given?
230
+ yield
231
+ else
232
+ raise TestGarden::IncompleteTest
233
+ end
234
+ end
235
+ ensure
236
+ @test = nil
237
+ end
238
+ end
239
+ end
240
+
241
+ # Alternative to putting the teardown code after all relevant tests.
242
+ # This can be used to keep related setup and teardown code together.
243
+ # Teardows are executed in the reverse of their creation order.
244
+ def teardown(&block)
245
+ if @test
246
+ @test.teardowns.last << block
247
+ else
248
+ raise "Cannot teardown: not in a test"
249
+ end
250
+ end
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: test-garden
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.4'
5
+ platform: ruby
6
+ authors:
7
+ - Joel VanderWerf
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-01-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: wrong
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.7'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.7'
27
+ description: |-
28
+ A testing framework for concisely sharing several stages of
29
+ setup code across tests.
30
+ email: vjoel@users.sourceforge.net
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files:
34
+ - README.md
35
+ - COPYING
36
+ files:
37
+ - COPYING
38
+ - README.md
39
+ - Rakefile
40
+ - lib/test-garden.rb
41
+ homepage: https://github.com/vjoel/test-garden
42
+ licenses:
43
+ - BSD
44
+ metadata: {}
45
+ post_install_message:
46
+ rdoc_options:
47
+ - "--quiet"
48
+ - "--line-numbers"
49
+ - "--inline-source"
50
+ - "--title"
51
+ - test-garden
52
+ - "--main"
53
+ - README.md
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubyforge_project:
68
+ rubygems_version: 2.2.1
69
+ signing_key:
70
+ specification_version: 4
71
+ summary: A garden of forking tests
72
+ test_files: []
73
+ has_rdoc: