baretest 0.4.0.pre3 → 0.4.0

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/MANIFEST.txt CHANGED
@@ -5,11 +5,16 @@ bin/baretest
5
5
  doc/baretest.rdoc
6
6
  doc/mocking_stubbing_test_doubles.rdoc
7
7
  doc/news/news-0.3.0.rdoc
8
+ doc/news/news-0.4.0.rdoc
8
9
  doc/quickref.rdoc
9
10
  doc/whats_going_on.rdoc
10
11
  doc/writing_tests.rdoc
12
+ examples/README_EXAMPLES.rdoc
13
+ examples/components/mocha.rb
11
14
  examples/components/rack-test.rb
15
+ examples/components/rr.rb
12
16
  examples/irb_mode/failures.rb
17
+ examples/isolation/example1.rb
13
18
  examples/rake/test.rake
14
19
  examples/tests/01_basics_I.rb
15
20
  examples/tests/02_basics_II_helpers.rb
data/README.rdoc CHANGED
@@ -87,48 +87,44 @@ right one: `rake gem:install GEM=gem1.9`
87
87
 
88
88
  Usage:
89
89
 
90
- baretest [options] [glob, ...]
91
-
92
- Glob defaults to 'test/**/*.rb'
93
- Providing a directory as glob is equivalent to dir/**/*.rb
94
- Options:
95
- -f, --format FORMAT use FORMAT for output
96
- -F, --formats show available formats
97
- -d, --debug set debugging flags (set $DEBUG to true)
98
- -i, --interactive drop into IRB on error or failure
99
- -s, --setup FILE specify setup file
100
- -v, --version print the version and exit
101
- -w, --warn turn warnings on for your script
102
-
103
-
104
-
105
- == Planned Features
106
-
107
- * Word-wrapping for CLI runner
108
- * baretest --init \[LAYOUT], to create the necessary directory structure
109
- * Detect whether baretest is run from an interactive terminal or not and adjust
110
- defaults (no-color e.g.)
111
- * Alternative CLI runner with status implicit via colored/bg-colored descriptions
112
- * Alternative CLI runner which prints the name of the test prior the label and rewrites
113
- the line when the test has executed to add status & coloring.
114
- * Simple stubbing with automatic cleanup at teardown. Example:
115
-
116
- assert "Should require a single file listed in :requires option." do |a|
117
- file = 'foo/bar'
118
- stub(Kernel, :require) do |file, *args| a.touch(file) end
119
- ::Test::Suite.create(nil, nil, :requires => file)
90
+ baretest [command] [options] *(selector | -selector)
91
+ command: The command to run. See `baretest commands`
92
+ options: The flags and options, see in the "Options" section.
93
+ selector: The tests to run. Example:
94
+ baretest -- test/suite/a -test/suite/a/x @tag -@other %failure -%pending
95
+ Defaults to 'test/{suite,unit,integration,system}
96
+ See `baretest selectors` to get more information
120
97
 
121
- touched file
122
- end
123
-
124
- * A redmine plugin
125
- * --fail-all flag, to test/review diagnostics of tests (no idea how to do that yet)
126
-
127
-
128
-
129
- == Rejected Features
98
+ Default command is 'run', which runs the testsuite or the provided testfiles.
99
+
100
+ Options:
101
+
102
+ --commands overview over the commands
103
+ -d, --debug set debugging flags (set $DEBUG to true)
104
+ -i, --interactive drop into IRB on error or failure. Use 'help!' in the irb session for more information
105
+ -f, --format FORMAT use FORMAT for output, see `baretest formats`
106
+ -s, --setup FILE specify setup file
107
+ -w, --warn turn warnings on for your script
108
+ -h, --help help for usage and flags
109
+ -v, --version print the version and exit
110
+ --init Deprecated form for `baretest --init`
111
+
112
+ Options for 'CLI' formatter:
113
+
114
+ -c, --[no-]color Enable/disable output coloring
115
+ -p, --[no-]profile Enable/disable profiling assertions
116
+
117
+ Environment variables for 'CLI' formatter:
118
+
119
+ * COLOR Enable/disable output coloring
120
+ * PROFILE Enable/disable profiling assertions
121
+
122
+ Environment variables:
123
+
124
+ * FORMAT use FORMAT for output, see `baretest formats`
125
+ * VERBOSE turn warnings on for your script
126
+ * INTERACTIVE drop into IRB on error or failure. Use 'help!' in the irb session for more information
130
127
 
131
- * Currently none
132
128
 
133
129
 
134
130
  == A Bit of Background
@@ -251,6 +247,11 @@ From examples/test.rb:
251
247
  * Tass
252
248
  * adding rr integration
253
249
  * reporting bugs
250
+ * robgleeson
251
+ * Introducing me to rack-test
252
+ * Feedback
253
+
254
+
254
255
 
255
256
  == Known bugs
256
257
 
@@ -258,6 +259,17 @@ Currently none.
258
259
 
259
260
 
260
261
 
262
+ == Known issues
263
+
264
+ * A setup that raises an exception will cause all teardowns to not be executed.
265
+ This will change in a future release as follows: a setup that raises an
266
+ exception will only cause teardowns defined on the same suite not to be
267
+ executed.
268
+ * --interactive can't be used to investigate problems in setup or teardown
269
+ * Inherited skip reasons are not reported
270
+
271
+
272
+
261
273
  == Foot Notes
262
274
  <sup>1</sup>:: The abbreviated form without support code and output formatters.
263
275
  The normal code is expanded to more lines for readability.
data/bin/baretest CHANGED
@@ -51,7 +51,7 @@ Command "run" do
51
51
 
52
52
  o :commands
53
53
  o :debug, '-d', '--debug', :Boolean, "set debugging flags (set $DEBUG to true)"
54
- o :interactive, '-i', '--interactive', :Boolean, "drop into IRB on error or failure"
54
+ o :interactive, '-i', '--interactive', :Boolean, "drop into IRB on error or failure. Use 'help!' in the irb session for more information"
55
55
  o :format, '-f', '--format FORMAT', :String, "use FORMAT for output, see `baretest formats`"
56
56
  o :setup_file, '-s', '--setup FILE', :File, "specify setup file"
57
57
  o :verbose, '-w', '--warn', :Boolean, "turn warnings on for your script"
@@ -80,12 +80,47 @@ Command "run" do
80
80
  o :help
81
81
  end
82
82
 
83
- command "formats"
84
- command "env"
85
- command "version"
86
- command "commands"
87
- command "selectors"
88
- command "help"
83
+ command "reset" do
84
+ usage
85
+
86
+ virtual_argument :command
87
+ end
88
+
89
+ command "formats" do
90
+ usage
91
+
92
+ virtual_argument :command
93
+ end
94
+
95
+ command "env" do
96
+ usage
97
+
98
+ virtual_argument :command
99
+ end
100
+
101
+ command "version" do
102
+ usage
103
+
104
+ virtual_argument :command
105
+ end
106
+
107
+ command "commands" do
108
+ usage
109
+
110
+ virtual_argument :command
111
+ end
112
+
113
+ command "selectors" do
114
+ usage
115
+
116
+ virtual_argument :command
117
+ end
118
+
119
+ command "help" do
120
+ usage
121
+
122
+ virtual_argument :command
123
+ end
89
124
  end
90
125
 
91
126
 
@@ -135,6 +170,8 @@ Command.with(ARGV) do
135
170
  exit(success ? 0 : 1)
136
171
  when "init" # create the test directory
137
172
  BareTest::CommandLine.init(arguments, options)
173
+ when "reset" # trash runtime stats & caching
174
+ BareTest::CommandLine.reset(arguments, options)
138
175
  when "formats" # list available formats
139
176
  BareTest::CommandLine.formats(arguments, options)
140
177
  when "env" # show information about baretest (config, version, paths, ...)
@@ -1,6 +1,7 @@
1
- NEWS
1
+ = NEWS
2
+
3
+ == baretest version 0.3.0
2
4
 
3
- For baretest version 0.3.0
4
5
  * Setup-variations
5
6
  * skip-method and Skip < StandardError
6
7
  * Persist data (independently of the test directory) over multiple runs
@@ -0,0 +1,9 @@
1
+ = NEWS
2
+
3
+ == baretest version 0.4.0
4
+
5
+ * Components
6
+ * Integration of mocha
7
+ * Integration of RR
8
+ * Integration of rack-test
9
+ * Improved `baretest` executable
@@ -0,0 +1,14 @@
1
+ = README
2
+
3
+ == Examples
4
+
5
+ The examples directory shall serve to quickly lead you into using baretest.
6
+
7
+ === Directories
8
+
9
+ components:: Contains examples on how to use components that ship with baretest
10
+ itself.
11
+ irb_mode:: Examples to help you explore baretest when run with the -i flag.
12
+ rake:: Example rake tasks to use baretest from within rake.
13
+ tests:: Several example files, ordered by difficulty, each dealing with a
14
+ topic, containing suites that explain the topic.
@@ -0,0 +1,22 @@
1
+ class User; end
2
+
3
+ BareTest.suite "Mocha", :use => :mocha do
4
+ suite "When mocking the 'find' method on the 'User' class to return :jane" do
5
+ setup do
6
+ User.expects(:find).with(42).returns(:jane)
7
+ end
8
+
9
+ assert "Calling User.find returns :jane" do
10
+ same :jane, User.find(42)
11
+ end
12
+
13
+ assert "Calling User.find will make it notice reception of that method" do
14
+ User.find(42)
15
+ true
16
+ end
17
+
18
+ assert "Fails when not calling find and asserting its reception" do
19
+ true
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,49 @@
1
+ class User; end
2
+
3
+ BareTest.suite "RR", :use => :rr do
4
+ suite "When stubbing the 'find' method on the 'User' class to return :jane" do
5
+ setup do
6
+ stub(User).find(42) { :jane }
7
+ end
8
+
9
+ assert "Spying on having received 'find' fails with no call being done" do
10
+ received(User).find(42).call # don't forget the final '.call' here!
11
+ end
12
+
13
+ assert "User.find(42) returns :jane" do
14
+ same :jane, User.find(42)
15
+ end
16
+
17
+ assert "User.find(123) fails as it is an unexpected method invocation" do
18
+ User.find(123)
19
+ end
20
+
21
+ assert "Spying on having received 'find' succeeds with the call being done" do
22
+ User.find(42)
23
+ received(User).find(42).call
24
+ true # poor, but right now you have to do that
25
+ end
26
+ end
27
+
28
+ suite "When mocking the 'find' method on the 'User' class to return :jane" do
29
+ setup do
30
+ mock(User).find(42) { :jane }
31
+ end
32
+
33
+ assert "Fails when not calling find" do
34
+ true # still fails, as the mock expectation is not satisfied
35
+ end
36
+
37
+ assert "User.find(42) returns :jane" do
38
+ same :jane, User.find(42)
39
+ end
40
+
41
+ assert "User.find(123) fails as it is an unexpected method invocation" do
42
+ User.find(123)
43
+ end
44
+
45
+ assert "User.find(42) will satisfy the mock expectation and thus succeed" do
46
+ User.find(42)
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,16 @@
1
+ class Foo
2
+ def foo
3
+ "foo"
4
+ end
5
+ end
6
+
7
+ BareTest.suite "Isolation example" do
8
+ assert "Do some silly stuff" do
9
+ ::Foo.class_eval do def foo; "bar"; end; end
10
+ equal "bar", ::Foo.new.foo
11
+ end
12
+
13
+ assert "Unaffected by prior silly stuff" do
14
+ equal "foo", ::Foo.new.foo
15
+ end
16
+ end
@@ -115,11 +115,13 @@ module BareTest
115
115
  elsif !@block
116
116
  status = Status.new(self, :pending)
117
117
  else
118
- context = ::BareTest::Assertion::Context.new(self)
119
- status = execute_phase(:setup, context, with_setup.map { |s| [[s.value], s.block] }) if with_setup
120
- status = execute_phase(:exercise, context, @block) unless status
121
- status = execute_phase(:teardown, context, and_teardown.map { |t| [nil, t] }) unless (status || !and_teardown)
122
- status ||= Status.new(self, :success, context)
118
+ handlers = @suite ? @suite.ancestors.inject({}) { |handlers, suite| handlers.merge(suite.verification_exception_handlers) } : nil
119
+ context = ::BareTest::Assertion::Context.new(self)
120
+ status = execute_phase(:setup, context, with_setup.map { |s| [[s.value], s.block] }) if with_setup
121
+ setup_failed = status
122
+ status = execute_phase(:exercise, context, @block, handlers) unless status
123
+ teardown_status = execute_phase(:teardown, context, and_teardown.map { |t| [nil, t] }) unless (setup_failed || !and_teardown)
124
+ status = status || teardown_status || Status.new(self, :success, context)
123
125
  end
124
126
 
125
127
  status
@@ -130,7 +132,7 @@ module BareTest
130
132
  # will generate a full Status instance.
131
133
  # This is for practical reasons - it means you can go through several
132
134
  # phases, looking for the first non-nil one.
133
- def execute_phase(name, context, code)
135
+ def execute_phase(name, context, code, handlers=nil)
134
136
  status = nil
135
137
  skip_reason = nil
136
138
  failure_reason = nil
@@ -154,6 +156,12 @@ module BareTest
154
156
  status = :manually_skipped
155
157
  skip_reason = skip.message
156
158
  rescue Exception => exception
159
+ exception_class = exception.class
160
+ handled_by = handlers && handlers.find { |handling, handler| exception_class <= handling }
161
+ if handled_by then
162
+ handler = handled_by.last
163
+ return handler.call(self, context, exception) # FIXME: ugly mid-method return - work around it returning a complete Status
164
+ end
157
165
  status = :error
158
166
  failure_reason = "An error occurred during #{name}: #{exception}"
159
167
  exception = exception
@@ -128,6 +128,13 @@ module BareTest
128
128
  end
129
129
  module_function :init
130
130
 
131
+ # Remove all files that store state, cache things etc. from persistence.
132
+ def reset(arguments, options)
133
+ options[:persistence] ||= Persistence.new
134
+ options[:persistence].clear
135
+ end
136
+ module_function :reset
137
+
131
138
  # Shows all formats available in run's -f/--format option.
132
139
  def formats(arguments, options)
133
140
  puts "Available formats:"
@@ -165,6 +172,9 @@ module BareTest
165
172
  Create a basic skeleton of directories and files to contain baretests test-
166
173
  suite. Non-destructive (existing files won't be overriden or deleted).
167
174
 
175
+ \e[1mreset\e[0m (default command)
176
+ Delete persistent data collected from previous runs.
177
+
168
178
  \e[1mrun\e[0m (default command)
169
179
  Run the tests and display information about them.
170
180
 
@@ -198,7 +208,7 @@ module BareTest
198
208
  as otherwise baretest will try to interpret them as short options (like -f).
199
209
 
200
210
  \e[1mExample\e[0m
201
- `baretest -- test/suite -test/suite/foo :a -:b #failure -#pending`
211
+ `baretest -- test/suite -test/suite/foo :a -:b %failure -%pending`
202
212
 
203
213
  This will run all tests that
204
214
  * Are in the directory test/suite or any of its subdirectories
@@ -216,7 +226,7 @@ module BareTest
216
226
  * Directories are equivalent to `directory/**/*` patterns
217
227
 
218
228
  \e[1mTags\e[0m
219
- Tags are preceeded with an :.
229
+ Tags are preceeded with a ':'.
220
230
  Examples:
221
231
  baretest :focus
222
232
  baretest -- -:hocus
@@ -224,9 +234,10 @@ module BareTest
224
234
 
225
235
  \e[1mLast-run-status\e[0m
226
236
  Last run states are preceeded with a %.
227
- * %success, %failure, %error, %skipped, %pending
237
+ * %new, %success, %failure, %error, %skipped, %pending
228
238
  * %error, %skipped and %pending are a subset of %failure
229
239
  * %pending is a subset of %skipped
240
+ * %new matches tests that are run for the very first time
230
241
 
231
242
  END_OF_DESCRIPTION
232
243
 
@@ -71,6 +71,7 @@ module BareTest
71
71
  "nesting! - a >-separated list of suite descriptions this assertion is nested",
72
72
  "description! - this assertion's description",
73
73
  "code! - the code of this assertion",
74
+ "eval! - eval (from_line, number_of_lines) or (from_line..to_line)",
74
75
  #"restart! - Restart this irb session, resetting everything",
75
76
  "irb_help - irb's original help",
76
77
  "q - Quit - alias to irb's exit",
@@ -174,6 +175,29 @@ module BareTest
174
175
  end
175
176
  end
176
177
 
178
+ def eval!(from, number=nil, explicit_binding=nil)
179
+ if code = @__assertion__.code then
180
+ if from.is_a?(Range) then
181
+ number = from.end-from.begin+1
182
+ from = from.begin
183
+ end
184
+ number ||= 1
185
+ total_lines = code.chomp.count("\n")-1
186
+ first_line = @__assertion__.line
187
+ if !from.between?(first_line, first_line+total_lines-1)
188
+ puts "From must be between #{first_line} and #{first_line+total_lines-1}"
189
+ elsif !number.between?(0, total_lines)
190
+ puts "Number must be between 1 and #{total_lines}"
191
+ else
192
+ from -= first_line-1
193
+ puts "Evaluating: ", *code.split(/\n/)[from, number]
194
+ eval(code.split(/\n/)[from, number].join("\n"), explicit_binding || context.workspace.binding) # this 'context' comes from irb
195
+ end
196
+ else
197
+ puts "Code could not be extracted"
198
+ end
199
+ end
200
+
177
201
  # Prepend the line number in front of ever line
178
202
  def insert_line_numbers(code, start_line=1) # :nodoc:
179
203
  digits = Math.log10(start_line+code.count("\n")).floor+1
@@ -202,11 +226,11 @@ module BareTest
202
226
  case rv.status
203
227
  when :failure
204
228
  start_irb_failure_mode(assertion, rv)
205
- irb_mode_for_assertion(assertion, rv, with_setup)
229
+ irb_mode_for_assertion(assertion, rv, with_setup, assertion.suite.ancestry_teardown)
206
230
  stop_irb_mode
207
231
  when :error
208
232
  start_irb_error_mode(assertion, rv)
209
- irb_mode_for_assertion(assertion, rv, with_setup)
233
+ irb_mode_for_assertion(assertion, rv, with_setup, assertion.suite.ancestry_teardown)
210
234
  stop_irb_mode
211
235
  # with other states, irb-mode is not started
212
236
  end
@@ -271,14 +295,17 @@ module BareTest
271
295
  # Drop into an irb shell in the context of the assertion passed as an argument.
272
296
  # Uses Assertion#clean_copy(AssertionContext) to create the context.
273
297
  # Adds the code into irb's history.
274
- def irb_mode_for_assertion(assertion, status, with_setup) # :nodoc:
275
- irb_context = ::BareTest::Assertion::Context.new(assertion)
276
- irb_context.extend IRBContext
277
- irb_context.__status__ = status
278
- assertion.execute_phase(:setup, irb_context, with_setup.map { |s| s.block })
298
+ def irb_mode_for_assertion(assertion, status, with_setup, and_teardown) # :nodoc:
299
+ handlers = @suite ? @suite.ancestors.inject({}) { |handlers, suite| handlers.merge(suite.verification_exception_handlers) } : nil
300
+ context = ::BareTest::Assertion::Context.new(assertion)
301
+ context.extend IRBContext
302
+ context.__status__ = status
303
+
304
+ status = assertion.execute_phase(:setup, context, with_setup.map { |s| [[s.value], s.block] }) if with_setup
305
+ setup_failed = status
279
306
 
280
307
  $stdout = StringIO.new # HAX - silencing 'irb: warn: can't alias help from irb_help.' - find a better way
281
- irb = IRB::Irb.new(IRB::WorkSpace.new(irb_context))
308
+ irb = IRB::Irb.new(IRB::WorkSpace.new(context))
282
309
  $stdout = STDOUT # /HAX
283
310
  # HAX - cargo cult, taken from irb.rb, not yet really understood.
284
311
  IRB.conf[:IRB_RC].call(irb.context) if IRB.conf[:IRB_RC] # loads the irbrc?
@@ -294,7 +321,7 @@ module BareTest
294
321
 
295
322
  catch(:IRB_EXIT) do irb.eval_input end
296
323
 
297
- assertion.execute_phase(:teardown, irb_context, assertion.suite.ancestry_teardown)
324
+ teardown_status = assertion.execute_phase(:teardown, context, and_teardown.map { |t| [nil, t] }) unless (setup_failed || !and_teardown)
298
325
  end
299
326
 
300
327
  # Invoked when we leave the irb session
@@ -14,6 +14,11 @@ require 'fileutils'
14
14
 
15
15
  module BareTest
16
16
 
17
+ # A simple file based storage. This is used to persist data between runs
18
+ # of baretest (caching data, keeping the last run's states for filtering,
19
+ # etc.)
20
+ # The data is stored in ~/.baretest, per project. A file with the name pattern
21
+ #
17
22
  class Persistence
18
23
 
19
24
  # The default storage path base (~/.baretest)
@@ -30,7 +35,16 @@ module BareTest
30
35
  }
31
36
  unless found then
32
37
  found = UID.hex_uid
33
- File.open(".baretest_id_#{found}", "w") {} # no File::touch, evil
38
+ File.open(".baretest_id_#{found}", "w") { |fh|
39
+ # The content of this file is irrelevant, only its name. So lets
40
+ # add a little bit of explaining text in case somebody wonders about
41
+ # the purpose of this file.
42
+ fh.write(
43
+ "This file is used by baretest to find the persisted data in your ~/.baretest directory.\n" \
44
+ "Deleting this file will result in orphaned persistence data.\n" \
45
+ "See `baretest help reset`."
46
+ )
47
+ }
34
48
  end
35
49
 
36
50
  found
@@ -53,6 +67,12 @@ module BareTest
53
67
  @storage_dir = File.expand_path(storage_dir || self.class.storage_path)
54
68
  @project_dir = File.expand_path(project_dir || ".")
55
69
  @project_id = self.class.determine_project_id(@project_dir)
70
+ stat = File.stat(@project_dir)
71
+ store('project', {
72
+ :project_directory => @project_dir,
73
+ :project_directory_inode => stat.ino,
74
+ :project_directory_device => stat.dev
75
+ })
56
76
  end
57
77
 
58
78
  # Stores data to a file.
@@ -90,5 +110,36 @@ module BareTest
90
110
  default
91
111
  end
92
112
  end
113
+
114
+ # Deletes the file for the given filename.
115
+ # filename:: A relative path. Empty directories are recursively deleted
116
+ # up to (but without) Persistence#storage_dir. The path is
117
+ # relative to Persistence#storage_dir
118
+ def delete(filename)
119
+ raise "Invalid filename: #{filename}" if filename =~ %r{\A\.\./|/\.\./\z}
120
+ project_storage_dir = "#{@storage_dir}/#{@project_id}"
121
+ path = "#{project_storage_dir}/#{filename}.yaml"
122
+
123
+ File.delete(path)
124
+ container = File.dirname(path)
125
+ while container != project_storage_dir
126
+ begin
127
+ Dir.delete(container)
128
+ rescue Errno::ENOTEMPTY
129
+ break
130
+ else
131
+ container = File.dirname(container)
132
+ end
133
+ end
134
+ end
135
+
136
+ # Remove all files that store state, cache things etc.
137
+ def clear
138
+ delete('final_states')
139
+ end
140
+
141
+ private
142
+ def assert_valid_filename(filename)
143
+ end
93
144
  end
94
145
  end
@@ -74,7 +74,7 @@ module BareTest
74
74
  }
75
75
 
76
76
  def run_all(*args)
77
- puts "Running all tests#{' verbosly' if $VERBOSE}"
77
+ puts "Running all tests#{' verbosly' if @options[:verbose]}"
78
78
 
79
79
  @depth = 0
80
80
  @deferred = []
@@ -129,7 +129,7 @@ module BareTest
129
129
 
130
130
  printf(Formats[rv.status], StatusLabel[rv.status], ' '*@depth, interpolated_description(assertion, setup))
131
131
  if rv.status == :error then
132
- backtrace = $VERBOSE ? rv.exception.backtrace : rv.exception.backtrace.first(1)
132
+ backtrace = @options[:verbose] ? rv.exception.backtrace : rv.exception.backtrace.first(1)
133
133
  elsif rv.status == :failure
134
134
  backtrace = ["#{assertion.file}:#{assertion.line}"]
135
135
  end
@@ -59,20 +59,20 @@ module BareTest
59
59
  # The failure/error/skipping/pending reason.
60
60
  # Returns nil if there's no reason, a string otherwise
61
61
  # Options:
62
- # :default:: Reason to return if no reason is present
63
- # :separator:: String used to separate multiple reasons
64
- # :indent:: A String, the indentation to use. Prefixes every line.
65
- # :first_indent: A String, used to indent the first line only (replaces indent).
62
+ # :default:: Reason to return if no reason is present
63
+ # :separator:: String used to separate multiple reasons
64
+ # :indent:: A String, the indentation to use. Prefixes every line.
65
+ # :first_indent:: A String, used to indent the first line only (replaces indent).
66
66
  def reason(opt=nil)
67
67
  if opt then
68
68
  default, separator, indent, first_indent =
69
69
  *opt.values_at(:default, :separator, :indent, :first_indent)
70
70
  reason = @skip_reason || @failure_reason || default
71
71
  return nil unless reason
72
- reason = Array(reason)
72
+ reason = reason.kind_of?(Array) ? reason : [reason]
73
73
  reason = reason.join(separator || "\n")
74
74
  reason = reason.gsub(/^/, indent) if indent
75
- reason = reason.gsub(/^#{Regexp.escape(indent)}/, first_indent) if first_indent
75
+ reason = reason.gsub(/\A#{Regexp.escape(indent)}/, first_indent) if first_indent
76
76
  reason
77
77
  else
78
78
  @reason.empty? ? nil : @reason.join("\n")
@@ -49,6 +49,8 @@ module BareTest
49
49
  # All things this suite is tagged with, see Suite::new for more information
50
50
  attr_reader :tags
51
51
 
52
+ attr_reader :verification_exception_handlers # :nodoc:
53
+
52
54
  # A list of valid options Suite::new accepts
53
55
  ValidOptions = [:skip, :requires, :use, :provides, :depends_on, :tags]
54
56
 
@@ -90,6 +92,7 @@ module BareTest
90
92
  @setup = {nil => []}
91
93
  @components = []
92
94
  @teardown = []
95
+ @verification_exception_handlers = {}
93
96
  if @parent then
94
97
  @ancestors = [self, *@parent.ancestors]
95
98
  @depends_on = @parent.depends_on
@@ -132,6 +135,17 @@ module BareTest
132
135
  end
133
136
  end
134
137
 
138
+ # Experimental
139
+ # Define handlers for specific exception classes. The handler gets
140
+ # the assertion, the phase and the exception yielded and is expected
141
+ # to return a BareTest::Status.
142
+ def handle_verification_exceptions(*exception_classes, &block) # :nodoc:
143
+ exception_classes.each do |exception_class|
144
+ raise "Already registered a verification exception handler for class #{exception_class}" if @verification_exception_handlers[exception_class]
145
+ @verification_exception_handlers[exception_class] = block
146
+ end
147
+ end
148
+
135
149
  # Instruct this suite to require the given files.
136
150
  # The suite is skipped if a file can't be loaded.
137
151
  def requires(*paths)
@@ -164,10 +178,10 @@ module BareTest
164
178
  # The failure/error/skipping/pending reason.
165
179
  # Returns nil if there's no reason, a string otherwise
166
180
  # Options:
167
- # :default:: Reason to return if no reason is present
168
- # :separator:: String used to separate multiple reasons
169
- # :indent:: A String, the indentation to use. Prefixes every line.
170
- # :first_indent: A String, used to indent the first line only (replaces indent).
181
+ # :default:: Reason to return if no reason is present
182
+ # :separator:: String used to separate multiple reasons
183
+ # :indent:: A String, the indentation to use. Prefixes every line.
184
+ # :first_indent:: A String, used to indent the first line only (replaces indent).
171
185
  def reason(opt=nil)
172
186
  if opt then
173
187
  default, separator, indent, first_indent =
data/lib/baretest/uid.rb CHANGED
@@ -13,8 +13,7 @@ module BareTest
13
13
  # 'macaddr').
14
14
  class UID
15
15
 
16
- # :nodoc:
17
- Epoch = Time.utc(2000,1,1).to_i
16
+ Epoch = Time.utc(2000,1,1).to_i # :nodoc:
18
17
 
19
18
  # The numeric value of the uid (an Integer)
20
19
  attr_reader :value
@@ -3,20 +3,16 @@
3
3
 
4
4
  # This file provides integration with the "mocha" mocking framework.
5
5
 
6
+ BareTest.new_component :mocha do
7
+ BareTest.require 'mocha'
6
8
 
7
- # Load this file and get integration with the "rr" mocking framework.
9
+ BareTest::Assertion::Context.send :include, Mocha::API
8
10
 
9
- BareTest.new_component :mocha do
10
- require 'mocha'
11
-
12
- BareTest::Assertion::Context.send :include Mocha::API
13
-
14
11
  teardown do
15
12
  begin
16
13
  mocha_verify
17
14
  rescue Mocha::ExpectationError => e
18
- @reason = e.message
19
- @status = :failure
15
+ raise ::BareTest::Assertion::Failure, e.message
20
16
  ensure
21
17
  mocha_teardown
22
18
  end
@@ -1,17 +1,21 @@
1
- # Original by Tass`
2
- # Adapted to :use framework by apeiros
3
-
4
1
  BareTest.new_component :rr do
5
- require 'rr'
2
+ BareTest.require 'rr'
6
3
 
7
4
  BareTest::Assertion::Context.send :include, RR::Adapters::RRMethods
8
5
 
6
+ handle_verification_exceptions RR::Errors::RRError do |assertion, phase, exception|
7
+ ::BareTest::Status.new(assertion, :failure, :verify, nil, exception.message)
8
+ end
9
+
9
10
  teardown do
10
11
  begin
11
12
  ::RR.verify
12
- rescue ::RR::Errors => e
13
- @reason = e.message
14
- @status = :failure
13
+ rescue ::RR::Errors::RRError => e
14
+ raise ::BareTest::Assertion::Failure, e.message
15
+ else
16
+ nil
17
+ ensure
18
+ RR.reset
15
19
  end
16
20
  end
17
21
  end
@@ -21,7 +21,7 @@ module BareTest
21
21
  TINY = 0
22
22
 
23
23
  # Prerelease number - nil for release versions
24
- PRERELEASE = 3
24
+ PRERELEASE = nil
25
25
 
26
26
  # The version as a string
27
27
  STRING = %{#{MAJOR}.#{MINOR||0}.#{TINY||0}#{".pre#{PRERELEASE}" if PRERELEASE}}
data/lib/baretest.rb CHANGED
@@ -57,12 +57,10 @@ module BareTest
57
57
  end
58
58
 
59
59
  # The standard glob used by baretest to load test files
60
- # :nodoc:
61
- DefaultInitialPositiveGlob = 'test/{suite,unit,isolation,integration,system}/**/*.rb'
60
+ DefaultInitialPositiveGlob = 'test/{suite,unit,isolation,integration,system}/**/*.rb' # :nodoc:
62
61
 
63
62
  # Selectors that are valid to be passed into process_selectors
64
- # :nodoc:
65
- ValidStateSelectors = [:new, :success, :failure, :error, :skipped, :pending]
63
+ ValidStateSelectors = [:new, :success, :failure, :error, :skipped, :pending] # :nodoc:
66
64
 
67
65
  class << self
68
66
  # A hash of components - available via BareTest::use(name) and
@@ -120,9 +118,17 @@ module BareTest
120
118
  files.each do |glob|
121
119
  glob = "#{glob}/**/*.rb" if File.directory?(glob)
122
120
  Dir.glob(glob) { |path|
123
- helper_path = path.sub(%r{^test/(suite|unit|integration|system)/}, 'test/helper/\1/')
121
+ helper_path = path.sub(%r{((?:^|/)test)/(suite|unit|integration|system)/}, '\1/helper/\2/')
124
122
  exists = (helper_path != path && File.exist?(helper_path))
125
- puts(exists ? "Loading helper file #{helper_path}" : "No helper file #{helper_path} to load") if verbose
123
+ if verbose then
124
+ if helper_path == path then
125
+ puts "Could not resolve helper path for path #{path}"
126
+ elsif exists
127
+ puts "Loading helper file #{helper_path}"
128
+ else
129
+ puts "No helper file #{helper_path} to load"
130
+ end
131
+ end
126
132
  load(helper_path) if exists
127
133
  puts "Loading test file #{path}" if verbose
128
134
  load(path)
@@ -239,6 +245,35 @@ module BareTest
239
245
  def self.use(component)
240
246
  @toplevel_suite.use(component)
241
247
  end
248
+
249
+ # Tries to require a file, if it fails, it will require rubygems and retries
250
+ def self.require(*paths)
251
+ paths.each do |path|
252
+ begin
253
+ Kernel.require path
254
+ rescue LoadError
255
+ begin
256
+ Kernel.require 'rubygems'
257
+ rescue LoadError
258
+ end
259
+ Kernel.instance_method(:require).bind(self).call path # ugly, but at least until rubygems 1.3.5, Kernel.require isn't overriden
260
+ end
261
+ end
262
+ end
263
+
264
+ # Returns the absolute path to the external file
265
+ # Example
266
+ # suite "#mkdir" do
267
+ # setup do
268
+ # @base = BareTest.external('suite_mkdir') # => "/.../PROJECT/test/external/suite_mkdir"
269
+ def self.external(*path)
270
+ File.join(test_directory, 'external', *path)
271
+ end
272
+
273
+ # Returns the absolute path to the test directory
274
+ def self.test_directory
275
+ File.expand_path(path, 'test')
276
+ end
242
277
  end
243
278
 
244
279
 
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: baretest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0.pre3
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 4
8
+ - 0
9
+ version: 0.4.0
5
10
  platform: ruby
6
11
  authors:
7
12
  - Stefan Rusterholz
@@ -9,7 +14,7 @@ autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2010-02-24 00:00:00 +01:00
17
+ date: 2010-03-18 00:00:00 +01:00
13
18
  default_executable:
14
19
  dependencies: []
15
20
 
@@ -31,11 +36,16 @@ files:
31
36
  - doc/baretest.rdoc
32
37
  - doc/mocking_stubbing_test_doubles.rdoc
33
38
  - doc/news/news-0.3.0.rdoc
39
+ - doc/news/news-0.4.0.rdoc
34
40
  - doc/quickref.rdoc
35
41
  - doc/whats_going_on.rdoc
36
42
  - doc/writing_tests.rdoc
43
+ - examples/README_EXAMPLES.rdoc
44
+ - examples/components/mocha.rb
37
45
  - examples/components/rack-test.rb
46
+ - examples/components/rr.rb
38
47
  - examples/irb_mode/failures.rb
48
+ - examples/isolation/example1.rb
39
49
  - examples/rake/test.rake
40
50
  - examples/tests/01_basics_I.rb
41
51
  - examples/tests/02_basics_II_helpers.rb
@@ -119,25 +129,27 @@ rdoc_options:
119
129
  - --tab-width
120
130
  - "2"
121
131
  - -t
122
- - baretest-0.4.0.pre3
132
+ - baretest-0.4.0
123
133
  require_paths:
124
134
  - lib
125
135
  required_ruby_version: !ruby/object:Gem::Requirement
126
136
  requirements:
127
137
  - - ">="
128
138
  - !ruby/object:Gem::Version
139
+ segments:
140
+ - 0
129
141
  version: "0"
130
- version:
131
142
  required_rubygems_version: !ruby/object:Gem::Requirement
132
143
  requirements:
133
- - - ">"
144
+ - - ">="
134
145
  - !ruby/object:Gem::Version
135
- version: 1.3.1
136
- version:
146
+ segments:
147
+ - 0
148
+ version: "0"
137
149
  requirements: []
138
150
 
139
151
  rubyforge_project: baretest
140
- rubygems_version: 1.3.5
152
+ rubygems_version: 1.3.6
141
153
  signing_key:
142
154
  specification_version: 3
143
155
  summary: "A testframework that doesn\xE2\x80\x99t stand in your way or forces you to learn a new language. Two methods is all that is required to know. If you need it, it provides you with all kinds of features to support you writing your tests."