ZenTest 3.7.2 → 3.8.0

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