baretest 0.4.0.pre3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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."