tst 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +3 -3
- data/lib/tst.rb +45 -171
- data/lib/tst/reporters/plain.rb +3 -5
- data/test/plain_reporter.rb +31 -19
- data/test/test.rb +3 -21
- data/test/test2.rb +5 -0
- metadata +4 -2
data/README.md
CHANGED
@@ -184,7 +184,7 @@ Just looking in the 'lib' directories:
|
|
184
184
|
- test/unit: 6313
|
185
185
|
- rspec: 5460
|
186
186
|
- minitest: 1210
|
187
|
-
- tst:
|
187
|
+
- tst: 190
|
188
188
|
|
189
|
-
The core of tst's testing engine is really just
|
190
|
-
other
|
189
|
+
The core of tst's testing engine is really just 91 lines (see 'tst.rb'). The
|
190
|
+
other 99 is IO/reporting code.
|
data/lib/tst.rb
CHANGED
@@ -1,17 +1,12 @@
|
|
1
1
|
require 'tst/reporters'
|
2
2
|
|
3
|
-
# Tst
|
4
3
|
module Tst
|
5
|
-
VERSION = "0.0.
|
4
|
+
VERSION = "0.0.3"
|
6
5
|
|
7
|
-
# ### Failure ###
|
8
|
-
#
|
9
6
|
# An error class that carries data about test failures.
|
10
7
|
class Failure < StandardError
|
11
8
|
attr_reader :message, :expected, :actual
|
12
9
|
|
13
|
-
# Takes the `message`, `expected`, and `actual` parameters
|
14
|
-
# and stuffs them into instance variables.
|
15
10
|
def initialize(message, expected, actual)
|
16
11
|
@message = message
|
17
12
|
@expected = expected
|
@@ -20,48 +15,23 @@ module Tst
|
|
20
15
|
end
|
21
16
|
end
|
22
17
|
|
23
|
-
#
|
24
|
-
#
|
25
|
-
# Defines a few `assert` methods for use in tests.
|
26
|
-
#
|
27
|
-
# If you'd like to define your own assertion methods,
|
28
|
-
# open up the module and do so:
|
29
|
-
#
|
30
|
-
# module Tst::Assertions
|
31
|
-
# def assert_seven(actual)
|
32
|
-
# # return without raising to pass
|
33
|
-
# return if actual == 7
|
34
|
-
#
|
35
|
-
# # raise a Tst::Failure to fail
|
36
|
-
# raise Tst::Failure.new('Not 7', 7, actual)
|
37
|
-
# end
|
38
|
-
# end
|
39
|
-
#
|
40
|
-
# Because `Assertions` is included into `Test`, your
|
41
|
-
# new methods will be available in `tst` blocks.
|
18
|
+
# Assertions available in `tst` blocks.
|
42
19
|
module Assertions
|
43
|
-
|
44
|
-
#
|
45
|
-
# It fails if `value` is `false` or `nil`. Succeeds otherwise.
|
20
|
+
|
21
|
+
# Fails if `value` is `false` or `nil`. Succeeds otherwise.
|
46
22
|
def assert(value)
|
47
23
|
return if value
|
48
24
|
raise Failure.new("Failure: Truthiness", "not false or nil", value)
|
49
25
|
end
|
50
26
|
|
51
|
-
# *assert_equal*, the egalitarian.
|
52
|
-
#
|
53
27
|
# Fails unless it's arguments are equal (with `==`).
|
54
28
|
def assert_equal(expected, actual)
|
55
29
|
return if expected == actual
|
56
30
|
raise Failure.new("Equality Failure", expected, actual)
|
57
31
|
end
|
58
32
|
|
59
|
-
# *assert_raises*, the pessimist.
|
60
|
-
#
|
61
33
|
# Succeeds if it catches an error AND that error is
|
62
|
-
# a `kind_of?` the `expected` error.
|
63
|
-
#
|
64
|
-
# Fails otherwise.
|
34
|
+
# a `kind_of?` the `expected` error. Fails otherwise.
|
65
35
|
def assert_raises(expected=StandardError)
|
66
36
|
begin
|
67
37
|
yield
|
@@ -73,55 +43,25 @@ module Tst
|
|
73
43
|
end
|
74
44
|
end
|
75
45
|
|
76
|
-
# ### Test ###
|
77
|
-
#
|
78
|
-
# An instance of test is basically only responsible for providing
|
79
|
-
# a scope within which to run a block.
|
80
|
-
#
|
81
|
-
# It includes the Assertions module so that the assertions
|
82
|
-
# methods are available to you inside your tests.
|
83
|
-
class Test
|
84
|
-
include Assertions
|
85
|
-
|
86
|
-
attr_reader :name
|
87
|
-
|
88
|
-
def initialize(name, &block)
|
89
|
-
@name = name
|
90
|
-
@block = block
|
91
|
-
end
|
92
|
-
|
93
|
-
def run
|
94
|
-
instance_eval &@block
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
46
|
# Set up some constants to represent test outcomes.
|
99
47
|
SUCCEEDED = :success
|
100
48
|
FAILED = :failure
|
101
49
|
RAISED = :exception
|
102
50
|
|
103
|
-
#
|
104
|
-
#
|
105
|
-
# A tidy little place to store test result information.
|
106
|
-
# The values should be self-explanatory.
|
51
|
+
# A little value object containing test result data
|
107
52
|
Result = Struct.new(:name, :status, :elapsed, :exception)
|
108
53
|
|
109
|
-
|
110
|
-
# ### Results ###
|
111
|
-
#
|
112
54
|
# A collection class that keeps track of test results.
|
113
55
|
class Results
|
114
56
|
attr_reader :count, :elapsed, :results
|
115
57
|
|
116
|
-
# It starts out with everything zeroed out.
|
117
58
|
def initialize
|
118
59
|
@count = 0
|
119
60
|
@elapsed = 0
|
120
61
|
@results = []
|
121
62
|
end
|
122
63
|
|
123
|
-
# Collects
|
124
|
-
# to reflect the new `result`.
|
64
|
+
# Collects a test result.
|
125
65
|
def <<(result)
|
126
66
|
@count += 1
|
127
67
|
@elapsed += result.elapsed
|
@@ -134,38 +74,31 @@ module Tst
|
|
134
74
|
def exceptions; results.select { |r| r.status == RAISED } end
|
135
75
|
end
|
136
76
|
|
137
|
-
#
|
138
|
-
#
|
139
|
-
# Collects and runs your tests.
|
77
|
+
# Runs test files in a fresh scope. It's not perfectly isolated, since
|
78
|
+
# requires can still add to the global scope, but it's good enough.
|
140
79
|
class Runner
|
141
|
-
attr_reader :tests, :results, :reporter
|
142
80
|
|
143
|
-
#
|
144
|
-
|
145
|
-
#
|
146
|
-
# Look at 'lib/tst/reporters.rb' for more information on reporters.
|
147
|
-
def initialize(reporter=nil)
|
148
|
-
@tests = []
|
149
|
-
@results = Results.new
|
150
|
-
@reporter = reporter || Reporters::Plain.new
|
151
|
-
end
|
81
|
+
# Gets us access to the assertions in our `tst` blocks.
|
82
|
+
include Assertions
|
152
83
|
|
153
|
-
|
154
|
-
|
155
|
-
|
84
|
+
def initialize(file, reporter, results)
|
85
|
+
@__reporter = reporter
|
86
|
+
@__results = results
|
87
|
+
__run_tests(file)
|
156
88
|
end
|
157
89
|
|
158
|
-
# Runs
|
159
|
-
|
160
|
-
|
161
|
-
tests.each { |test| run_test(test) }
|
162
|
-
reporter.summarize(results)
|
90
|
+
# Runs the tests by `instance-eval`-ing the test file.
|
91
|
+
def __run_tests(file)
|
92
|
+
instance_eval(File.read(file), File.expand_path(file), 1)
|
163
93
|
end
|
164
94
|
|
165
|
-
# The
|
166
|
-
|
95
|
+
# The `tst` methods itself.
|
96
|
+
# Takes a `name` and a block.
|
97
|
+
# Runs the block.
|
98
|
+
# Records the result.
|
99
|
+
def tst(name, &block)
|
167
100
|
start = Time.now
|
168
|
-
|
101
|
+
block.call
|
169
102
|
status = SUCCEEDED
|
170
103
|
rescue Failure => exception
|
171
104
|
status = FAILED
|
@@ -173,95 +106,36 @@ module Tst
|
|
173
106
|
status = RAISED
|
174
107
|
ensure
|
175
108
|
elapsed = Time.now - start
|
176
|
-
|
109
|
+
__record(name, status, elapsed, exception)
|
177
110
|
end
|
178
111
|
|
179
|
-
|
180
|
-
# `failure`, or `exception` method on `reporter` so
|
181
|
-
# it can show you your results as they come in.
|
182
|
-
def record(name, status, elapsed, exception=nil)
|
112
|
+
def __record(name, status, elapsed, exception=nil)
|
183
113
|
result = Result.new(name, status, elapsed, exception)
|
184
|
-
|
185
|
-
|
114
|
+
@__results << result
|
115
|
+
@__reporter.send(status, result)
|
186
116
|
end
|
187
117
|
end
|
188
118
|
|
189
|
-
#
|
119
|
+
# The main entry point.
|
190
120
|
#
|
191
|
-
#
|
192
|
-
#
|
193
|
-
class FileRunner
|
194
|
-
attr_reader :runner
|
195
|
-
|
196
|
-
# Runs the tests in the files represented by `glob`.
|
197
|
-
#
|
198
|
-
# `glob`: is any string that `Dir.glob` knows how to handle.
|
199
|
-
#
|
200
|
-
# Accepts the following options:
|
201
|
-
# `:reporter`: any object that responds_to the reporter
|
202
|
-
# interface
|
203
|
-
# (see 'lib/tst/reporters.rb' for details)
|
204
|
-
#
|
205
|
-
# `:load_paths`: an Array of directories to be added to
|
206
|
-
# the load path before running the tests.
|
207
|
-
#
|
208
|
-
# Note that `run` makes a new Runner each time it's called,
|
209
|
-
# allowing it to be called several times on the same
|
210
|
-
# FileRunner instance while still doing the right thing.
|
211
|
-
def run(glob, options={})
|
212
|
-
@runner = Runner.new options[:reporter]
|
213
|
-
load_files(glob, options[:load_paths] || [])
|
214
|
-
runner.run!
|
215
|
-
end
|
216
|
-
|
217
|
-
# Collects incoming tests and hands them off to the `runner`.
|
218
|
-
def <<(test)
|
219
|
-
runner << test
|
220
|
-
end
|
221
|
-
|
222
|
-
# Modifies the load path if necessary and loads all the
|
223
|
-
# test files.
|
224
|
-
def load_files(glob, load_paths)
|
225
|
-
load_paths.each { |path| $:.unshift(path) }
|
226
|
-
Dir[glob].each { |file| load(file, true) }
|
227
|
-
end
|
228
|
-
end
|
229
|
-
|
230
|
-
# Module-level accessor to a FileRunner instance.
|
231
|
-
def self.file_runner
|
232
|
-
@file_runner ||= FileRunner.new
|
233
|
-
end
|
234
|
-
|
235
|
-
# Hands a test off to `file_runner`. This is called by
|
236
|
-
# the top-level `tst` method (i.e., the one you use to
|
237
|
-
# write your tests with).
|
238
|
-
def self.add_test(name, &block)
|
239
|
-
file_runner << Test.new(name, &block)
|
240
|
-
end
|
241
|
-
|
242
|
-
# The module-level API entry point.
|
243
|
-
#
|
244
|
-
# An example from Tst's own Rakefile:
|
121
|
+
# glob - a String defining which test files to run.
|
122
|
+
# Passed through to Dir[].
|
245
123
|
#
|
246
|
-
#
|
247
|
-
#
|
248
|
-
#
|
249
|
-
#
|
250
|
-
# end
|
124
|
+
# Accepted options:
|
125
|
+
# :load_paths - an Array of directories to add to the load path.
|
126
|
+
# :reporter - a reporter instance (see 'lib/tst/reporters.rb'
|
127
|
+
# for docs on reporters)
|
251
128
|
def self.run(glob, options={})
|
252
|
-
|
129
|
+
options = default_options.merge(options)
|
130
|
+
$:.unshift(*options[:load_paths])
|
131
|
+
results = Results.new
|
132
|
+
reporter = options[:reporter]
|
133
|
+
Dir[glob].each { |file| Runner.new(file, reporter, results) }
|
134
|
+
reporter.summarize(results)
|
253
135
|
end
|
254
|
-
end
|
255
136
|
|
256
|
-
# The `
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
#
|
261
|
-
# tst "the answer is correct" do
|
262
|
-
# answer = Answer.new
|
263
|
-
# assert_equal 42, answer
|
264
|
-
# end
|
265
|
-
def tst(name=nil, &block)
|
266
|
-
Tst.add_test(name, &block)
|
137
|
+
# The default options for `run`.
|
138
|
+
def self.default_options
|
139
|
+
{ :reporter => Reporters::Plain.new, :load_paths => [] }
|
140
|
+
end
|
267
141
|
end
|
data/lib/tst/reporters/plain.rb
CHANGED
@@ -15,6 +15,7 @@ module Tst
|
|
15
15
|
@results = results
|
16
16
|
summary = ["\n"] + failures + exceptions + conclusion
|
17
17
|
summary.each { |line| io.puts(line) }
|
18
|
+
nil
|
18
19
|
end
|
19
20
|
|
20
21
|
def failures
|
@@ -62,12 +63,9 @@ module Tst
|
|
62
63
|
end
|
63
64
|
|
64
65
|
def conclusion
|
65
|
-
[ "#{
|
66
|
+
[ "#{passed}, #{failed}, #{raised} in %.6fs" % results.elapsed ]
|
66
67
|
end
|
67
68
|
|
68
|
-
def elapsed
|
69
|
-
"Ran %d tests in %.6fs" % [results.count, results.elapsed]
|
70
|
-
end
|
71
69
|
def passed; "#{results.successes.count} passed" end
|
72
70
|
def failed; "#{results.failures.count} failed" end
|
73
71
|
def raised; "#{results.exceptions.count} raised" end
|
@@ -76,7 +74,7 @@ module Tst
|
|
76
74
|
backtrace.reject do |line|
|
77
75
|
line =~ BACKTRACE_FILTER
|
78
76
|
end.map do |line|
|
79
|
-
line.gsub("#{Dir.pwd}/", "")
|
77
|
+
line.gsub("#{Dir.pwd}/", "").gsub(/:in.*$/, '')
|
80
78
|
end
|
81
79
|
end
|
82
80
|
|
data/test/plain_reporter.rb
CHANGED
@@ -11,46 +11,58 @@ end
|
|
11
11
|
|
12
12
|
tst_runner_output "test/fixtures/success.rb", <<-end
|
13
13
|
.
|
14
|
-
|
14
|
+
1 passed, 0 failed, 0 raised in X.XXXs
|
15
15
|
end
|
16
16
|
|
17
17
|
tst_runner_output "test/fixtures/failure.rb", <<-end
|
18
18
|
F
|
19
|
-
F1: Failure: Truthiness -
|
20
|
-
exp:
|
19
|
+
F1: Failure: Truthiness - "one failing test"
|
20
|
+
exp: "not false or nil"
|
21
21
|
got: false
|
22
|
-
* test/fixtures/failure.rb:2
|
23
|
-
* test/
|
22
|
+
* test/fixtures/failure.rb:2
|
23
|
+
* test/fixtures/failure.rb:1
|
24
|
+
* test/plain_reporter.rb:7
|
25
|
+
* test/plain_reporter.rb:4
|
26
|
+
* test/plain_reporter.rb:17
|
24
27
|
|
25
|
-
|
28
|
+
0 passed, 1 failed, 0 raised in X.XXXs
|
26
29
|
end
|
27
30
|
|
28
31
|
tst_runner_output "test/fixtures/exception.rb", <<-end
|
29
32
|
E
|
30
|
-
E1: #<RuntimeError: I'm a teapot> -
|
31
|
-
* test/fixtures/exception.rb:2
|
32
|
-
* test/
|
33
|
+
E1: #<RuntimeError: I'm a teapot> - "one 'exceptional' test"
|
34
|
+
* test/fixtures/exception.rb:2
|
35
|
+
* test/fixtures/exception.rb:1
|
36
|
+
* test/plain_reporter.rb:7
|
37
|
+
* test/plain_reporter.rb:4
|
38
|
+
* test/plain_reporter.rb:31
|
33
39
|
|
34
|
-
|
40
|
+
0 passed, 0 failed, 1 raised in X.XXXs
|
35
41
|
end
|
36
42
|
|
37
43
|
tst_runner_output "test/fixtures/{exception,success,failure}.rb", <<-end
|
38
44
|
E.F
|
39
|
-
F1: Failure: Truthiness -
|
40
|
-
exp:
|
45
|
+
F1: Failure: Truthiness - "one failing test"
|
46
|
+
exp: "not false or nil"
|
41
47
|
got: false
|
42
|
-
* test/fixtures/failure.rb:2
|
43
|
-
* test/
|
48
|
+
* test/fixtures/failure.rb:2
|
49
|
+
* test/fixtures/failure.rb:1
|
50
|
+
* test/plain_reporter.rb:7
|
51
|
+
* test/plain_reporter.rb:4
|
52
|
+
* test/plain_reporter.rb:43
|
44
53
|
|
45
|
-
E1: #<RuntimeError: I'm a teapot> -
|
46
|
-
* test/fixtures/exception.rb:2
|
47
|
-
* test/
|
54
|
+
E1: #<RuntimeError: I'm a teapot> - "one 'exceptional' test"
|
55
|
+
* test/fixtures/exception.rb:2
|
56
|
+
* test/fixtures/exception.rb:1
|
57
|
+
* test/plain_reporter.rb:7
|
58
|
+
* test/plain_reporter.rb:4
|
59
|
+
* test/plain_reporter.rb:43
|
48
60
|
|
49
|
-
|
61
|
+
1 passed, 1 failed, 1 raised in X.XXXs
|
50
62
|
end
|
51
63
|
|
52
64
|
tst_runner_output "test/fixtures/does_not_exist.rb", <<-end
|
53
65
|
|
54
|
-
|
66
|
+
0 passed, 0 failed, 0 raised in X.XXXs
|
55
67
|
end
|
56
68
|
|
data/test/test.rb
CHANGED
@@ -1,23 +1,5 @@
|
|
1
|
-
|
2
|
-
# which helps mitigate state leakage...
|
3
|
-
tst "tests don't have access to top-level instance variables" do
|
4
|
-
@outside = "I'm outside"
|
1
|
+
def hello; 'hello' end
|
5
2
|
|
6
|
-
|
7
|
-
|
8
|
-
end.run
|
9
|
-
|
10
|
-
assert_equal "I'm outside", @outside
|
11
|
-
end
|
12
|
-
|
13
|
-
# ... but ruby block scope can be a bitch.
|
14
|
-
tst "for better or for worse, local variables are fair game" do
|
15
|
-
outside = "I'm outside"
|
16
|
-
|
17
|
-
Tst::Test.new "local variable" do
|
18
|
-
outside = "I'm inside, muahahaha!"
|
19
|
-
end.run
|
20
|
-
|
21
|
-
assert_equal "I'm inside, muahahaha!", outside
|
3
|
+
tst "access to methods defined in the file" do
|
4
|
+
assert_equal 'hello', hello
|
22
5
|
end
|
23
|
-
|
data/test/test2.rb
ADDED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tst
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-08-
|
12
|
+
date: 2012-08-27 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: A small testing library that tries not to do too much.
|
15
15
|
email: satchmorun@gmail.com
|
@@ -32,6 +32,7 @@ files:
|
|
32
32
|
- test/fixtures/success.rb
|
33
33
|
- test/plain_reporter.rb
|
34
34
|
- test/test.rb
|
35
|
+
- test/test2.rb
|
35
36
|
homepage: http://github.com/satchmorun/tst
|
36
37
|
licenses:
|
37
38
|
- MIT
|
@@ -64,3 +65,4 @@ test_files:
|
|
64
65
|
- test/fixtures/success.rb
|
65
66
|
- test/plain_reporter.rb
|
66
67
|
- test/test.rb
|
68
|
+
- test/test2.rb
|