test-garden 0.4

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 (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: