ZenTest 3.7.2 → 3.8.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/bin/multiruby CHANGED
@@ -80,6 +80,11 @@ Dir.chdir root_dir do
80
80
  end
81
81
  end
82
82
  end
83
+
84
+ # pick up rubinius - allows for simple symlinks to your build dir
85
+ Dir.chdir('install') do
86
+ versions.push(*Dir["rubinius*"])
87
+ end
83
88
  end
84
89
 
85
90
  versions = ENV['VERSIONS'].split(/:/) if ENV.has_key? 'VERSIONS'
@@ -87,6 +92,8 @@ versions = ENV['VERSIONS'].split(/:/) if ENV.has_key? 'VERSIONS'
87
92
  results = {}
88
93
  versions.each do |version|
89
94
  ruby = "#{root_dir}/install/#{version}/bin/ruby"
95
+ ruby.sub!(/bin.ruby/, 'shotgun/rubinius') if version =~ /rubinius/
96
+
90
97
  puts
91
98
  puts "VERSION = #{version}"
92
99
  puts
@@ -1,6 +1,8 @@
1
1
  # -*- ruby -*-
2
2
 
3
3
  # require 'autotest/autoupdate'
4
+ # require 'autotest/camping'
5
+ # require 'autotest/cctray'
4
6
  # require 'autotest/emacs'
5
7
  # require 'autotest/fixtures'
6
8
  # require 'autotest/growl'
data/lib/autotest.rb CHANGED
@@ -119,12 +119,14 @@ class Autotest
119
119
  @@discoveries.map { |proc| proc.call }.flatten.compact.sort.uniq
120
120
  end
121
121
 
122
+ ##
123
+ # Initialize and run the system.
124
+
122
125
  def self.run
123
126
  new.run
124
127
  end
125
128
 
126
- attr_accessor(:exceptions,
127
- :extra_class_map,
129
+ attr_accessor(:extra_class_map,
128
130
  :extra_files,
129
131
  :files,
130
132
  :files_to_test,
@@ -134,12 +136,14 @@ class Autotest
134
136
  :output,
135
137
  :results,
136
138
  :tainted,
137
- :test_mappings,
138
139
  :unit_diff,
139
140
  :wants_to_quit)
140
141
 
142
+ ##
143
+ # Initialize the instance and then load the user's .autotest file, if any.
144
+
141
145
  def initialize
142
- @exceptions = []
146
+ @exception_list = []
143
147
  @extra_class_map = {}
144
148
  @extra_files = []
145
149
  @files = Hash.new Time.at(0)
@@ -148,43 +152,43 @@ class Autotest
148
152
  @output = $stderr
149
153
  @sleep = 1
150
154
  @unit_diff = "unit_diff -u"
155
+ @test_mappings = {}
151
156
 
152
- @test_mappings = {
153
- /^lib\/.*\.rb$/ => proc { |filename, _|
154
- files_matching %r%^test/.*#{File.basename(filename).gsub '_', '_?'}$%
155
- },
156
- /^test.*\/test_.*rb$/ => proc { |filename, _|
157
- filename
158
- }
159
- }
157
+ self.add_mapping(/^lib\/.*\.rb$/) do |filename, _|
158
+ possible = File.basename(filename).gsub '_', '_?'
159
+ files_matching %r%^test/.*#{possible}$%
160
+ end
160
161
 
161
- hook :initialize
162
+ self.add_mapping(/^test.*\/test_.*rb$/) do |filename, _|
163
+ filename
164
+ end
162
165
 
163
- if @exceptions.empty? then
164
- @exceptions = nil
165
- else
166
- @exceptions = Regexp.union(*@exceptions)
166
+ [File.expand_path('~/.autotest'), './.autotest'].each do |f|
167
+ load f if File.exist? f
167
168
  end
168
169
  end
169
170
 
170
- # Repeatedly run failed tests, then all tests, then
171
- # wait for changes and carry on until killed.
171
+ ##
172
+ # Repeatedly run failed tests, then all tests, then wait for changes
173
+ # and carry on until killed.
174
+
172
175
  def run
173
- hook :run
176
+ hook :initialize
177
+ hook :run # TODO: phase out
174
178
  reset
175
179
  add_sigint_handler
176
180
 
177
181
  loop do # ^c handler
178
182
  begin
179
183
  get_to_green
180
- if @tainted then
184
+ if self.tainted then
181
185
  rerun_all_tests
182
186
  else
183
187
  hook :all_good
184
188
  end
185
189
  wait_for_changes
186
190
  rescue Interrupt
187
- if @wants_to_quit then
191
+ if self.wants_to_quit then
188
192
  break
189
193
  else
190
194
  reset
@@ -194,7 +198,9 @@ class Autotest
194
198
  hook :quit
195
199
  end
196
200
 
201
+ ##
197
202
  # Keep running the tests after a change, until all pass.
203
+
198
204
  def get_to_green
199
205
  until all_good do
200
206
  run_tests
@@ -202,19 +208,20 @@ class Autotest
202
208
  end
203
209
  end
204
210
 
205
- # Look for files to test then run the tests and
206
- # handle the results.
211
+ ##
212
+ # Look for files to test then run the tests and handle the results.
213
+
207
214
  def run_tests
208
215
  hook :run_command
209
216
 
210
- find_files_to_test # failed + changed/affected
211
- cmd = make_test_cmd @files_to_test
217
+ self.find_files_to_test # failed + changed/affected
218
+ cmd = self.make_test_cmd self.files_to_test
212
219
 
213
220
  puts cmd
214
221
 
215
222
  old_sync = $stdout.sync
216
223
  $stdout.sync = true
217
- @results = []
224
+ self.results = []
218
225
  line = []
219
226
  begin
220
227
  open("| #{cmd}", "r") do |f|
@@ -223,11 +230,11 @@ class Autotest
223
230
  putc c
224
231
  line << c
225
232
  if c == ?\n then
226
- @results << if RUBY_VERSION >= "1.9" then
227
- line.join
228
- else
229
- line.pack "c*"
230
- end
233
+ self.results << if RUBY_VERSION >= "1.9" then
234
+ line.join
235
+ else
236
+ line.pack "c*"
237
+ end
231
238
  line.clear
232
239
  end
233
240
  end
@@ -236,26 +243,25 @@ class Autotest
236
243
  $stdout.sync = old_sync
237
244
  end
238
245
  hook :ran_command
239
- @results = @results.join
246
+ self.results = self.results.join
240
247
 
241
- handle_results(@results)
248
+ handle_results(self.results)
242
249
  end
243
250
 
244
251
  ############################################################
245
252
  # Utility Methods, not essential to reading of logic
246
253
 
247
- def add_mapping(regexp, &proc)
248
- self.test_mappings[regexp] = proc
249
- end
254
+ ##
255
+ # Installs a sigint handler.
250
256
 
251
257
  def add_sigint_handler
252
258
  trap 'INT' do
253
- if @interrupted then
254
- @wants_to_quit = true
259
+ if self.interrupted then
260
+ self.wants_to_quit = true
255
261
  else
256
262
  unless hook :interrupt then
257
263
  puts "Interrupt a second time to quit"
258
- @interrupted = true
264
+ self.interrupted = true
259
265
  sleep 1.5
260
266
  end
261
267
  raise Interrupt, nil # let the run loop catch it
@@ -263,16 +269,18 @@ class Autotest
263
269
  end
264
270
  end
265
271
 
266
- # If there are no files left to test
267
- # (because they've all passed),
272
+ ##
273
+ # If there are no files left to test (because they've all passed),
268
274
  # then all is good.
275
+
269
276
  def all_good
270
- @files_to_test.empty?
277
+ files_to_test.empty?
271
278
  end
272
279
 
273
- # Convert a path in a string, s, into a
274
- # class name, changing underscores to CamelCase,
275
- # etc
280
+ ##
281
+ # Convert a path in a string, s, into a class name, changing
282
+ # underscores to CamelCase, etc.
283
+
276
284
  def path_to_classname(s)
277
285
  sep = File::SEPARATOR
278
286
  f = s.sub(/^test#{sep}/, '').sub(/\.rb$/, '').split(sep)
@@ -281,35 +289,43 @@ class Autotest
281
289
  f.join('::')
282
290
  end
283
291
 
292
+ ##
293
+ # Returns a hash mapping a file name to the known failures for that
294
+ # file.
295
+
284
296
  def consolidate_failures(failed)
285
297
  filters = Hash.new { |h,k| h[k] = [] }
286
298
 
287
- class_map = Hash[*@files.keys.grep(/^test/).map { |f| [path_to_classname(f), f] }.flatten]
299
+ class_map = Hash[*self.files.keys.grep(/^test/).map { |f|
300
+ [path_to_classname(f), f]
301
+ }.flatten]
288
302
  class_map.merge!(self.extra_class_map)
289
303
 
290
304
  failed.each do |method, klass|
291
305
  if class_map.has_key? klass then
292
306
  filters[class_map[klass]] << method
293
307
  else
294
- @output.puts "Unable to map class #{klass} to a file"
308
+ output.puts "Unable to map class #{klass} to a file"
295
309
  end
296
310
  end
297
311
 
298
312
  return filters
299
313
  end
300
314
 
301
- # Find the files to process, ignoring temporary files,
302
- # source configuration management files, etc., and return
303
- # a Hash mapping filename to modification time.
315
+ ##
316
+ # Find the files to process, ignoring temporary files, source
317
+ # configuration management files, etc., and return a Hash mapping
318
+ # filename to modification time.
319
+
304
320
  def find_files
305
321
  result = {}
306
322
  targets = ['.'] + self.extra_files
307
323
 
308
324
  Find.find(*targets) do |f|
309
- Find.prune if @exceptions and f =~ @exceptions
325
+ Find.prune if f =~ self.exceptions
310
326
 
311
327
  next if test ?d, f
312
- next if f =~ /(swp|~|rej|orig)$/ # temporary/patch files
328
+ next if f =~ /(swp|~|rej|orig)$/ # temporary/patch files
313
329
  next if f =~ /\/\.?#/ # Emacs autosave/cvs merge files
314
330
 
315
331
  filename = f.sub(/^\.\//, '')
@@ -320,73 +336,83 @@ class Autotest
320
336
  return result
321
337
  end
322
338
 
323
- # Find the files which have been modified, update
324
- # the recorded timestamps, and use this to update
325
- # the files to test. Returns true if any file is
326
- # newer than the previously recorded most recent
339
+ ##
340
+ # Find the files which have been modified, update the recorded
341
+ # timestamps, and use this to update the files to test. Returns true
342
+ # if any file is newer than the previously recorded most recent
327
343
  # file.
344
+
328
345
  def find_files_to_test(files=find_files)
329
346
  updated = files.select { |filename, mtime|
330
- @files[filename] < mtime
347
+ self.files[filename] < mtime
331
348
  }
332
349
 
333
- p updated if $v unless updated.empty? or @last_mtime.to_i == 0
350
+ p updated if $v unless updated.empty? or self.last_mtime.to_i == 0
334
351
 
335
352
  # TODO: keep an mtime at app level and drop the files hash
336
353
  updated.each do |filename, mtime|
337
- @files[filename] = mtime
354
+ self.files[filename] = mtime
338
355
  end
339
356
 
340
357
  updated.each do |filename, mtime|
341
358
  tests_for_file(filename).each do |f|
342
- @files_to_test[f] # creates key with default value
359
+ self.files_to_test[f] # creates key with default value
343
360
  end
344
361
  end
345
362
 
346
- previous = @last_mtime
347
- @last_mtime = @files.values.max
348
- @last_mtime > previous
363
+ previous = self.last_mtime
364
+ self.last_mtime = self.files.values.max
365
+ self.last_mtime > previous
349
366
  end
350
367
 
351
- # Check results for failures, set the "bar" to red or
352
- # green, and if there are failures record this.
368
+ ##
369
+ # Check results for failures, set the "bar" to red or green, and if
370
+ # there are failures record this.
371
+
353
372
  def handle_results(results)
354
373
  failed = results.scan(/^\s+\d+\) (?:Failure|Error):\n(.*?)\((.*?)\)/)
355
374
  completed = results =~ /\d+ tests, \d+ assertions, \d+ failures, \d+ errors/
356
375
 
357
- @files_to_test = consolidate_failures failed if completed
376
+ self.files_to_test = consolidate_failures failed if completed
358
377
 
359
- hook completed && @files_to_test.empty? ? :green : :red unless $TESTING
378
+ hook completed && self.files_to_test.empty? ? :green : :red unless $TESTING
360
379
 
361
- @tainted = true unless @files_to_test.empty?
380
+ self.tainted = true unless self.files_to_test.empty?
362
381
  end
363
382
 
383
+ ##
364
384
  # Generate the commands to test the supplied files
385
+
365
386
  def make_test_cmd files_to_test
366
387
  cmds = []
367
388
  full, partial = files_to_test.partition { |k,v| v.empty? }
368
389
 
369
390
  unless full.empty? then
370
391
  classes = full.map {|k,v| k}.flatten.uniq.sort.join(' ')
371
- cmds << "#{ruby} -I#{@libs} -rtest/unit -e \"%w[#{classes}].each { |f| require f }\" | #{unit_diff}"
392
+ cmds << "#{ruby} -I#{libs} -rtest/unit -e \"%w[#{classes}].each { |f| require f }\" | #{unit_diff}"
372
393
  end
373
394
 
374
395
  partial.each do |klass, methods|
375
- cmds << "#{ruby} -I#{@libs} #{klass} -n \"/^(#{Regexp.union(*methods).source})$/\" | #{unit_diff}"
396
+ regexp = Regexp.union(*methods).source
397
+ cmds << "#{ruby} -I#{libs} #{klass} -n \"/^(#{regexp})$/\" | #{unit_diff}"
376
398
  end
377
399
 
378
400
  return cmds.join("#{SEP} ")
379
401
  end
380
402
 
403
+ ##
381
404
  # Rerun the tests from cold (reset state)
405
+
382
406
  def rerun_all_tests
383
407
  reset
384
408
  run_tests
385
409
  hook :all_good if all_good
386
410
  end
387
411
 
388
- # Clear all state information about test failures
389
- # and whether interrupts will kill autotest.
412
+ ##
413
+ # Clear all state information about test failures and whether
414
+ # interrupts will kill autotest.
415
+
390
416
  def reset
391
417
  @interrupted = @wants_to_quit = false
392
418
  @files.clear
@@ -397,7 +423,9 @@ class Autotest
397
423
  hook :reset
398
424
  end
399
425
 
400
- # determine and return the path of the ruby executable.
426
+ ##
427
+ # Determine and return the path of the ruby executable.
428
+
401
429
  def ruby
402
430
  ruby = File.join(Config::CONFIG['bindir'],
403
431
  Config::CONFIG['ruby_install_name'])
@@ -409,20 +437,23 @@ class Autotest
409
437
  return ruby
410
438
  end
411
439
 
440
+ ##
441
+ # Return the name of the file with the tests for filename by finding
442
+ # a +test_mapping+ that matches the file and executing the mapping's
443
+ # proc.
412
444
 
413
- # Return the name of the file with the tests for
414
- # filename.
415
445
  def tests_for_file(filename)
416
446
  result = @test_mappings.find { |file_re, ignored| filename =~ file_re }
417
447
  result = result.nil? ? [] : Array(result.last.call(filename, $~))
418
448
 
419
- @output.puts "Dunno! #{filename}" if ($VERBOSE or $TESTING) and result.empty?
449
+ output.puts "Dunno! #{filename}" if ($v or $TESTING) and result.empty?
420
450
 
421
451
  result.sort.uniq
422
452
  end
423
453
 
424
- # Sleep then look for files to test, until there
425
- # are some.
454
+ ##
455
+ # Sleep then look for files to test, until there are some.
456
+
426
457
  def wait_for_changes
427
458
  hook :waiting
428
459
  begin
@@ -430,30 +461,115 @@ class Autotest
430
461
  end until find_files_to_test
431
462
  end
432
463
 
464
+ ############################################################
465
+ # File Mappings:
466
+
467
+ ##
468
+ # Returns all known files in the codebase matching +regexp+.
469
+
433
470
  def files_matching regexp
434
471
  @files.keys.select { |k|
435
472
  k =~ regexp
436
473
  }
437
474
  end
438
475
 
476
+ ##
477
+ # Adds a file mapping. +regexp+ should match a file path in the
478
+ # codebase. +proc+ is passed a matched filename and
479
+ # Regexp.last_match. +proc+ should return an array of tests to run.
480
+ #
481
+ # For example, if test_helper.rb is modified, rerun all tests:
482
+ #
483
+ # at.add_mapping(/test_helper.rb/) do |f, _|
484
+ # at.files_matching(/^test.*rb$/)
485
+ # end
486
+
487
+ def add_mapping(regexp, &proc)
488
+ @test_mappings[regexp] = proc
489
+ end
490
+
491
+ ##
492
+ # Removed a file mapping matching +regexp+.
493
+
494
+ def remove_mapping regexp
495
+ @test_mappings.delete regexp
496
+ end
497
+
498
+ ##
499
+ # Clears all file mappings. This is DANGEROUS as it entirely
500
+ # disables autotest. You must add at least one file mapping that
501
+ # does a good job of rerunning appropriate tests.
502
+
503
+ def clear_mappings
504
+ @test_mappings.clear
505
+ end
506
+
507
+ ############################################################
508
+ # Exceptions:
509
+
510
+ ##
511
+ # Adds +regexp+ to the list of exceptions for find_file. This must
512
+ # be called _before_ the exceptions are compiled.
513
+
514
+ def add_exception regexp
515
+ raise "exceptions already compiled" if defined? @exceptions
516
+ @exception_list << regexp
517
+ end
518
+
519
+ ##
520
+ # Removes +regexp+ to the list of exceptions for find_file. This
521
+ # must be called _before_ the exceptions are compiled.
522
+
523
+ def remove_exception regexp
524
+ raise "exceptions already compiled" if defined? @exceptions
525
+ @exception_list.delete regexp
526
+ end
527
+
528
+ ##
529
+ # Clears the list of exceptions for find_file. This must be called
530
+ # _before_ the exceptions are compiled.
531
+
532
+ def clear_exceptions
533
+ raise "exceptions already compiled" if defined? @exceptions
534
+ @exception_list.clear
535
+ end
536
+
537
+ ##
538
+ # Return a compiled regexp of exceptions for find_files or nil if no
539
+ # filtering should take place. This regexp is generated from
540
+ # @exception_list.
541
+
542
+ def exceptions
543
+ unless defined? @exceptions then
544
+ if @exception_list.empty? then
545
+ @exceptions = nil
546
+ else
547
+ @exceptions = Regexp.union(*@exception_list)
548
+ end
549
+ end
550
+
551
+ @exceptions
552
+ end
553
+
439
554
  ############################################################
440
555
  # Hooks:
441
556
 
557
+ ##
558
+ # Call the event hook named +name+, executing all registered hooks
559
+ # until one returns true. Returns false if no hook handled the
560
+ # event.
561
+
442
562
  def hook(name)
443
563
  HOOKS[name].inject(false) do |handled,plugin|
444
564
  plugin[self] || handled
445
565
  end
446
566
  end
447
567
 
448
- # Add the supplied block to the available hooks, with
449
- # the given name.
568
+ ##
569
+ # Add the supplied block to the available hooks, with the given
570
+ # name.
571
+
450
572
  def self.add_hook(name, &block)
451
573
  HOOKS[name] << block
452
574
  end
453
575
  end
454
-
455
- if test ?f, './.autotest' then
456
- load './.autotest'
457
- elsif test ?f, File.expand_path('~/.autotest') then
458
- load File.expand_path('~/.autotest')
459
- end