tst 0.0.2 → 0.0.3

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.
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