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 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: 220
187
+ - tst: 190
188
188
 
189
- The core of tst's testing engine is really just 122 lines (see 'tst.rb'). The
190
- other 98 is IO/reporting code.
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.2"
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
- # ### Assertions ###
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
- # *assert*, the lie detector.
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
- # ### Result ###
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 incoming `result`s and updates `count` and `elapsed`
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
- # ### Runner ###
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
- # A new Runner accepts a Reporter instance, which it delegates
144
- # to for displaying results. It defaults to the plain reporter.
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
- # Collects incoming tests.
154
- def <<(test)
155
- tests << test
84
+ def initialize(file, reporter, results)
85
+ @__reporter = reporter
86
+ @__results = results
87
+ __run_tests(file)
156
88
  end
157
89
 
158
- # Runs all the tests it has and then hands control
159
- # over to `reporter` to tell you about it.
160
- def run!
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 actual machinery for running a test.
166
- def run_test(test)
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
- test.run
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
- record(test.name, status, elapsed, exception)
109
+ __record(name, status, elapsed, exception)
177
110
  end
178
111
 
179
- # Adds a result to `results` and calls the `success`,
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
- results << result
185
- reporter.send(status, result)
114
+ @__results << result
115
+ @__reporter.send(status, result)
186
116
  end
187
117
  end
188
118
 
189
- # ### FileRunner ###
119
+ # The main entry point.
190
120
  #
191
- # A little wrapper class (around a Runner) to allow
192
- # for easily running tests that are in files.
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
- # task :test do
247
- # Tst.run 'test/*.rb',
248
- # :load_paths => ['.', 'lib'],
249
- # :reporter => Tst::Reporters::Pretty.new
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
- file_runner.run(glob, options)
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 `tst` method.
257
- #
258
- # Acts as proxy to `Tst.add_test`. This is the method you
259
- # actually call as a consumer of the library.
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
@@ -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
- [ "#{elapsed}: #{passed}, #{failed}, #{raised}." ]
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
 
@@ -11,46 +11,58 @@ end
11
11
 
12
12
  tst_runner_output "test/fixtures/success.rb", <<-end
13
13
  .
14
- Ran 1 tests in X.XXXs: 1 passed, 0 failed, 0 raised.
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 - \"one failing test\"
20
- exp: \"not false or nil\"
19
+ F1: Failure: Truthiness - "one failing test"
20
+ exp: "not false or nil"
21
21
  got: false
22
- * test/fixtures/failure.rb:2:in `block in <top (required)>'
23
- * test/plain_reporter.rb:7:in `block in tst_runner_output'
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
- Ran 1 tests in X.XXXs: 0 passed, 1 failed, 0 raised.
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> - \"one 'exceptional' test\"
31
- * test/fixtures/exception.rb:2:in `block in <top (required)>'
32
- * test/plain_reporter.rb:7:in `block in tst_runner_output'
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
- Ran 1 tests in X.XXXs: 0 passed, 0 failed, 1 raised.
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 - \"one failing test\"
40
- exp: \"not false or nil\"
45
+ F1: Failure: Truthiness - "one failing test"
46
+ exp: "not false or nil"
41
47
  got: false
42
- * test/fixtures/failure.rb:2:in `block in <top (required)>'
43
- * test/plain_reporter.rb:7:in `block in tst_runner_output'
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> - \"one 'exceptional' test\"
46
- * test/fixtures/exception.rb:2:in `block in <top (required)>'
47
- * test/plain_reporter.rb:7:in `block in tst_runner_output'
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
- Ran 3 tests in X.XXXs: 1 passed, 1 failed, 1 raised.
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
- Ran 0 tests in X.XXXs: 0 passed, 0 failed, 0 raised.
66
+ 0 passed, 0 failed, 0 raised in X.XXXs
55
67
  end
56
68
 
@@ -1,23 +1,5 @@
1
- # One nice thing is that each test gets a fresh scope,
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
- Tst::Test.new "instance variable" do
7
- @outside = "I'm inside, muahahaha!"
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
-
@@ -0,0 +1,5 @@
1
+ tst "no access to methods defined in other files" do
2
+ assert_raises NameError do
3
+ hello # defined in test.rb
4
+ end
5
+ end
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.2
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-26 00:00:00.000000000 Z
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