ZenTest 4.11.2 → 4.12.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'autotest'
4
-
5
- Autotest.parse_options
6
- Autotest.runner.run
@@ -1,74 +0,0 @@
1
- #!/usr/bin/env ruby -w
2
-
3
- require 'multiruby'
4
-
5
- ENV.delete 'RUBYOPT'
6
-
7
- ARGV << "help" if ARGV.empty?
8
-
9
- Dir.chdir Multiruby.root_dir
10
- Multiruby.setup_dirs(false)
11
-
12
- ARGV.each do |spec|
13
- case spec
14
- when "-h", "--help", "help" then
15
- Multiruby.help
16
- exit 0
17
- when "the_usual" then # TODO: update #help
18
- ARGV.push(*Multiruby::TAGS.map { |v| "mri:tar:#{v.gsub(/_/, '.')}" })
19
- ARGV << "build" << "update:rubygems"
20
- system "multigem install --no-ri --no-rdoc rake minitest ZenTest gemcutter rubyforge hoe"
21
- when "build" then
22
- Multiruby.build_and_install
23
- when "clean" then
24
- Multiruby.clean
25
- when "list" then
26
- Multiruby.list
27
- when /rm:(.*)/ then
28
- Multiruby.rm $1
29
- when "rubygems:merge" then
30
- Multiruby.merge_rubygems
31
- when "rubygems:update", "update:rubygems" then
32
- Multiruby.update_rubygems
33
- ARGV << "build"
34
- when "update" then
35
- Multiruby.update
36
- when "tags" then
37
- p Multiruby.tags
38
- when "mri:svn:current" then
39
- ARGV << "mri:svn:releases" << "mri:svn:branches" << "build"
40
- when "mri:svn:releases" then
41
- Multiruby::TAGS.each do |v|
42
- latest = Multiruby.mri_latest_tag v
43
- abort "Can't find tag #{v}" unless latest
44
- ARGV << "mri:svn:tag:#{latest}:mri_rel_#{v}"
45
- end
46
- ARGV << "build"
47
- when /mri:svn:branch:(.*)/ then
48
- ver = "branches/ruby_#{$1}" unless ver == "trunk"
49
- Multiruby.svn_co "#{Multiruby::MRI_SVN}/#{$1}", "mri_#{$1}"
50
- ARGV << "build"
51
- when "mri:svn:branches" then
52
- Multiruby::BRANCHES.each do |v|
53
- ARGV << "mri:svn:branch:#{v}"
54
- end
55
- ARGV << "build"
56
- when /mri:svn:tag:(.*):(.*)/ then
57
- Multiruby.svn_co "#{Multiruby::MRI_SVN}/tags/#{$1}", $2
58
- ARGV << "build"
59
- when /mri:svn:tag:(.*)/ then
60
- ARGV << "mri:svn:tag:#{$1}:#{$1}" << "build"
61
- when /mri:list:(.*)/ then
62
- v = $1
63
- ver = v[/\d+\.\d+/]
64
- url = "#{Multiruby::RUBY_URL}/#{ver}/"
65
-
66
- puts Multiruby.matching_versions(url, v).join("\n")
67
- when /mri:tar:(.*)/ then
68
- Multiruby.fetch_tar $1
69
- ARGV << "build"
70
- else
71
- warn "unknown spec #{spec}"
72
- end
73
- end
74
-
@@ -1,16 +0,0 @@
1
- # -*- ruby -*-
2
-
3
- # require 'autotest/autoupdate'
4
- # require 'autotest/bundler'
5
- # require 'autotest/isolate'
6
- # require 'autotest/once'
7
- # require 'autotest/rcov'
8
- # require 'autotest/restart'
9
- # require 'autotest/timestamp'
10
-
11
- # Autotest::AutoUpdate.sleep_time = o
12
- # Autotest::AutoUpdate.update_cmd = o
13
- # Autotest::Isolate.dir = o
14
- # Autotest::RCov.command = o
15
- # Autotest::RCov.pattern = o
16
- # Autotest::RCov.options = o
@@ -1,901 +0,0 @@
1
- require "find"
2
- require "rbconfig"
3
-
4
- ##
5
- # Autotest continuously scans the files in your project for changes
6
- # and runs the appropriate tests. Test failures are run until they
7
- # have all passed. Then the full test suite is run to ensure that
8
- # nothing else was inadvertantly broken.
9
- #
10
- # If you want Autotest to start over from the top, hit ^C once. If
11
- # you want Autotest to quit, hit ^C twice.
12
- #
13
- # Rails:
14
- #
15
- # The autotest command will automatically discover a Rails directory
16
- # by looking for config/environment.rb. When Rails is discovered,
17
- # autotest uses RailsAutotest to perform file mappings and other work.
18
- # See RailsAutotest for details.
19
- #
20
- # Plugins:
21
- #
22
- # Plugins are available by creating a .autotest file either in your
23
- # project root or in your home directory. You can then write event
24
- # handlers in the form of:
25
- #
26
- # Autotest.add_hook hook_name { |autotest| ... }
27
- #
28
- # The available hooks are listed in +ALL_HOOKS+.
29
- #
30
- # See example_dot_autotest.rb for more details.
31
- #
32
- # If a hook returns a true value, it signals to autotest that the hook
33
- # was handled and should not continue executing hooks.
34
- #
35
- # Naming:
36
- #
37
- # Autotest uses a simple naming scheme to figure out how to map
38
- # implementation files to test files following the Test::Unit naming
39
- # scheme.
40
- #
41
- # * Test files must be stored in test/
42
- # * Test files names must start with test_
43
- # * Test class names must start with Test
44
- # * Implementation files must be stored in lib/
45
- # * Implementation files must match up with a test file named
46
- # test_.*<impl-name>.rb
47
- #
48
- # Strategy:
49
- #
50
- # 1. Find all files and associate them from impl <-> test.
51
- # 2. Run all tests.
52
- # 3. Scan for failures.
53
- # 4. Detect changes in ANY (ruby?. file, rerun all failures + changed files.
54
- # 5. Until 0 defects, goto 3.
55
- # 6. When 0 defects, goto 2.
56
-
57
- class Autotest
58
-
59
- RUBY19 = defined? Encoding
60
-
61
- T0 = Time.at 0
62
-
63
- ALL_HOOKS = [ :all_good, :died, :green, :initialize,
64
- :post_initialize, :interrupt, :quit, :ran_command,
65
- :red, :reset, :run_command, :updated, :waiting ]
66
-
67
- def self.options
68
- @@options ||= {}
69
- end
70
-
71
- def options
72
- self.class.options
73
- end
74
-
75
- HOOKS = Hash.new { |h,k| h[k] = [] }
76
-
77
- unless defined? WINDOZE then
78
- WINDOZE = /mswin|mingw/ =~ RbConfig::CONFIG['host_os']
79
- SEP = WINDOZE ? '&' : ';'
80
- end
81
-
82
- @@discoveries = []
83
-
84
- def self.parse_options args = ARGV
85
- require 'optparse'
86
- options = {
87
- :args => args.dup
88
- }
89
-
90
- OptionParser.new do |opts|
91
- opts.banner = <<-BANNER.gsub(/^ /, '')
92
- Continuous testing for your ruby app.
93
-
94
- Autotest automatically tests code that has changed. It assumes
95
- the code is in lib, and tests are in test/test_*.rb. Autotest
96
- uses plugins to control what happens. You configure plugins
97
- with require statements in the .autotest file in your
98
- project base directory, and a default configuration for all
99
- your projects in the .autotest file in your home directory.
100
-
101
- Usage:
102
- autotest [options]
103
- BANNER
104
-
105
- opts.on "-f", "--fast-start", "Do not run full tests at start" do
106
- options[:no_full_after_start] = true
107
- end
108
-
109
- opts.on("-c", "--no-full-after-failed",
110
- "Do not run all tests on red->green") do
111
- options[:no_full_after_failed] = true
112
- end
113
-
114
- opts.on "-d", "--debug", "Debug mode, for reporting bugs." do
115
- require "pp"
116
- options[:debug] = true
117
- end
118
-
119
- opts.on "-v", "--verbose", "Be annoyingly verbose (debugs .autotest)." do
120
- options[:verbose] = true
121
- end
122
-
123
- opts.on "-q", "--quiet", "Be quiet." do
124
- options[:quiet] = true
125
- end
126
-
127
- opts.on("-r", "--rc CONF", String, "Override path to config file") do |o|
128
- options[:rc] = Array(o)
129
- end
130
-
131
- opts.on("-s", "--style STYLE", String,
132
- "Manually specify test style. (default: autodiscover)") do |style|
133
- options[:style] = Array(style)
134
- end
135
-
136
- opts.on("-w", "--warnings", "Turn on ruby warnings") do
137
- $-w = true
138
- end
139
-
140
- opts.on "-h", "--help", "Show this." do
141
- puts opts
142
- exit 1
143
- end
144
- end.parse! args
145
-
146
- Autotest.options.merge! options
147
-
148
- options
149
- end
150
-
151
- ##
152
- # Calculates the autotest runner to use to run the tests.
153
- #
154
- # Can be overridden with --style, otherwise uses ::autodiscover.
155
-
156
- def self.runner
157
- style = options[:style] || Autotest.autodiscover
158
- target = Autotest
159
-
160
- unless style.empty? then
161
- mod = "autotest/#{style.join "_"}"
162
- puts "loading #{mod}"
163
- begin
164
- require mod
165
- rescue LoadError
166
- abort "Autotest style #{mod} doesn't seem to exist. Aborting."
167
- end
168
- target = Autotest.const_get(style.map {|s| s.capitalize}.join)
169
- end
170
-
171
- target
172
- end
173
-
174
- ##
175
- # Add a proc to the collection of discovery procs. See
176
- # +autodiscover+.
177
-
178
- def self.add_discovery &proc
179
- @@discoveries << proc
180
- end
181
-
182
- ##
183
- # Automatically find all potential autotest runner styles by
184
- # searching your loadpath, vendor/plugins, and rubygems for
185
- # "autotest/discover.rb". If found, that file is loaded and it
186
- # should register discovery procs with autotest using
187
- # +add_discovery+. That proc should return one or more strings
188
- # describing the user's current environment. Those styles are then
189
- # combined to dynamically invoke an autotest plugin to suite your
190
- # environment. That plugin should define a subclass of Autotest with
191
- # a corresponding name.
192
- #
193
- # === Process:
194
- #
195
- # 1. All autotest/discover.rb files loaded.
196
- # 2. Those procs determine your styles (eg ["rails", "rspec"]).
197
- # 3. Require file by sorting styles and joining (eg 'autotest/rails_rspec').
198
- # 4. Invoke run method on appropriate class (eg Autotest::RailsRspec.run).
199
- #
200
- # === Example autotest/discover.rb:
201
- #
202
- # Autotest.add_discovery do
203
- # "rails" if File.exist? 'config/environment.rb'
204
- # end
205
- #
206
-
207
- def self.autodiscover
208
- require 'rubygems'
209
-
210
- # *sigh*
211
- #
212
- # This is needed for rspec's hacky discovery mechanism. For some
213
- # reason rspec2 added generators that create
214
- # "autotest/discover.rb" right in the project directory instead of
215
- # keeping it in the rspec gem and properly deciding that the
216
- # project is an rspec based project or not. See the url for more
217
- # details:
218
- #
219
- # http://rubyforge.org/tracker/?func=detail&atid=1678&aid=28775&group_id=419
220
- #
221
- # For the record, the sane way to do it is the bacon way:
222
- #
223
- # "Since version 1.0, there is autotest support. You need to tag
224
- # your test directories (test/ or spec/) by creating an .bacon
225
- # file there. Autotest then will find it."
226
- #
227
- # I'm submitting a counter-patch to rspec to fix stuff properly,
228
- # but for now I'm stuck with this because their brokenness is
229
- # documented in multiple books.
230
- #
231
- # I'm removing this code once a sane rspec goes out.
232
-
233
- hacky_discovery = Gem::Specification.any? { |s| s.name =~ /^rspec/ }
234
- $: << '.' if hacky_discovery
235
-
236
- Gem.find_files("autotest/discover*").each do |f|
237
- load f
238
- end
239
-
240
- # call all discovery procs and determine the style to use
241
- @@discoveries.map{ |proc| proc.call }.flatten.compact.sort.uniq
242
- end
243
-
244
- ##
245
- # Initialize and run the system.
246
-
247
- def self.run
248
- new.run
249
- end
250
-
251
- attr_writer :known_files
252
- attr_accessor :completed_re
253
- attr_accessor :extra_class_map
254
- attr_accessor :extra_files
255
- attr_accessor :failed_results_re
256
- attr_accessor :files_to_test
257
- attr_accessor :find_directories
258
- attr_accessor :find_order
259
- attr_accessor :interrupted
260
- attr_accessor :last_mtime
261
- attr_accessor :latest_results
262
- attr_accessor :libs
263
- attr_accessor :order # TODO: deprecate and remove
264
- attr_accessor :output
265
- attr_accessor :prefix
266
- attr_accessor :results
267
- attr_accessor :sleep
268
- attr_accessor :tainted
269
- attr_accessor :test_mappings
270
- attr_accessor :testlib
271
- attr_accessor :testprefix
272
- attr_accessor :unit_diff
273
- attr_accessor :wants_to_quit
274
-
275
- alias tainted? tainted
276
-
277
- ##
278
- # Initialize the instance and then load the user's .autotest file, if any.
279
-
280
- def initialize
281
- # these two are set directly because they're wrapped with
282
- # add/remove/clear accessor methods
283
- @exception_list = []
284
- @child = nil
285
- self.test_mappings = []
286
-
287
- self.completed_re =
288
- /\d+ (tests|runs), \d+ assertions, \d+ failures, \d+ errors(, \d+ skips)?/
289
- self.extra_class_map = {}
290
- self.extra_files = []
291
- self.failed_results_re = /^\s*\d+\) (?:Failure|Error):\n(.*?)(?: [\(\[](.*?)[\)\]])?:$/
292
- self.files_to_test = new_hash_of_arrays
293
- self.find_order = []
294
- self.known_files = nil
295
- self.libs = %w[. lib test].join(File::PATH_SEPARATOR)
296
- self.order = :random
297
- self.output = $stderr
298
- self.prefix = nil
299
- self.sleep = 1
300
- self.testlib = "minitest/autorun" # TODO: rename
301
- self.testprefix = "gem 'minitest'" # TODO: rename
302
-
303
- specified_directories = ARGV.reject { |arg| arg.start_with?("-") } # options are not directories
304
- self.find_directories = specified_directories.empty? ? ['.'] : specified_directories
305
- self.unit_diff = nil
306
- self.latest_results = nil
307
-
308
- # file in /lib -> run test in /test
309
- self.add_mapping(/^lib\/.*\.rb$/) do |filename, _|
310
- possible = File.basename(filename).gsub '_', '_?'
311
- files_matching %r%^test/.*#{possible}$%
312
- end
313
-
314
- # file in /test -> run it
315
- self.add_mapping(/^test.*\/test_.*rb$/) do |filename, _|
316
- filename
317
- end
318
-
319
- default_configs = [File.expand_path('~/.autotest'), './.autotest']
320
- configs = options[:rc] || default_configs
321
-
322
- configs.each do |f|
323
- load f if File.exist? f
324
- end
325
- end
326
-
327
- def debug
328
- find_files_to_test
329
-
330
- puts "Known test files:"
331
- puts
332
- pp files_to_test.keys.sort
333
-
334
- class_map = self.class_map
335
-
336
- puts
337
- puts "Known class map:"
338
- puts
339
- pp class_map
340
- end
341
-
342
- def class_map
343
- class_map = Hash[*self.find_order.grep(/^test/).map { |f| # TODO: ugly
344
- [path_to_classname(f), f]
345
- }.flatten]
346
- class_map.merge! self.extra_class_map
347
- class_map
348
- end
349
-
350
- ##
351
- # Repeatedly run failed tests, then all tests, then wait for changes
352
- # and carry on until killed.
353
-
354
- def run
355
- hook :initialize
356
- hook :post_initialize
357
-
358
- reset
359
- add_sigint_handler
360
-
361
- self.last_mtime = Time.now if options[:no_full_after_start]
362
-
363
- self.debug if options[:debug]
364
-
365
- loop do
366
- begin # ^c handler
367
- get_to_green
368
- if tainted? and not options[:no_full_after_failed] then
369
- rerun_all_tests
370
- else
371
- hook :all_good
372
- end
373
- wait_for_changes
374
- rescue Interrupt
375
- break if wants_to_quit
376
- reset
377
- end
378
- end
379
- hook :quit
380
- puts
381
- rescue Exception => err
382
- hook(:died, err) or (
383
- warn "Unhandled exception: #{err}"
384
- warn err.backtrace.join("\n ")
385
- warn "Quitting"
386
- )
387
- end
388
-
389
- ##
390
- # Keep running the tests after a change, until all pass.
391
-
392
- def get_to_green
393
- begin
394
- run_tests
395
- wait_for_changes unless all_good
396
- end until all_good
397
- end
398
-
399
- ##
400
- # Look for files to test then run the tests and handle the results.
401
-
402
- def run_tests
403
- new_mtime = self.find_files_to_test
404
- return unless new_mtime
405
- self.last_mtime = new_mtime
406
-
407
- cmd = self.make_test_cmd self.files_to_test
408
- return if cmd.empty?
409
-
410
- hook :run_command, cmd
411
-
412
- puts cmd unless options[:quiet]
413
-
414
- old_sync = $stdout.sync
415
- $stdout.sync = true
416
- self.results = []
417
- line = []
418
- begin
419
- open "| #{cmd}", "r" do |f|
420
- until f.eof? do
421
- c = f.getc or break
422
- if RUBY19 then
423
- print c
424
- else
425
- putc c
426
- end
427
- line << c
428
- if c == ?\n then
429
- self.results << if RUBY19 then
430
- line.join
431
- else
432
- line.pack "c*"
433
- end
434
- line.clear
435
- end
436
- end
437
- end
438
- ensure
439
- $stdout.sync = old_sync
440
- end
441
- hook :ran_command
442
- self.results = self.results.join
443
-
444
- handle_results self.results
445
- end
446
-
447
- ############################################################
448
- # Utility Methods, not essential to reading of logic
449
-
450
- ##
451
- # Installs a sigint handler.
452
-
453
- def add_sigint_handler
454
- trap 'INT' do
455
- Process.kill "KILL", @child if @child
456
-
457
- if self.interrupted then
458
- self.wants_to_quit = true
459
- else
460
- unless hook :interrupt then
461
- puts "Interrupt a second time to quit"
462
- self.interrupted = true
463
- Kernel.sleep 1.5
464
- end
465
- raise Interrupt, nil # let the run loop catch it
466
- end
467
- end
468
- end
469
-
470
- ##
471
- # Installs a sigquit handler
472
-
473
- def add_sigquit_handler
474
- trap 'QUIT' do
475
- restart
476
- end
477
- end
478
-
479
- def restart
480
- Process.kill "KILL", @child if @child
481
-
482
- cmd = [$0, *options[:args]]
483
-
484
- index = $LOAD_PATH.index RbConfig::CONFIG["sitelibdir"]
485
-
486
- if index then
487
- extra = $LOAD_PATH[0...index]
488
- cmd = [Gem.ruby, "-I", extra.join(":")] + cmd
489
- end
490
-
491
- puts cmd.join(" ") if options[:verbose]
492
-
493
- exec(*cmd)
494
- end
495
-
496
- ##
497
- # If there are no files left to test (because they've all passed),
498
- # then all is good.
499
-
500
- def all_good
501
- files_to_test.empty?
502
- end
503
-
504
- ##
505
- # Convert a path in a string, s, into a class name, changing
506
- # underscores to CamelCase, etc.
507
-
508
- def path_to_classname s
509
- sep = File::SEPARATOR
510
- f = s.sub(/^test#{sep}/, '').sub(/\.rb$/, '').split sep
511
- f = f.map { |path| path.split(/_|(\d+)/).map { |seg| seg.capitalize }.join }
512
- f = f.map { |path| path =~ /^Test/ ? path : "Test#{path}" }
513
-
514
- f.join '::'
515
- end
516
-
517
- ##
518
- # Returns a hash mapping a file name to the known failures for that
519
- # file.
520
-
521
- def consolidate_failures failed
522
- filters = new_hash_of_arrays
523
-
524
- class_map = self.class_map
525
-
526
- failed.each do |method, klass|
527
- if class_map.has_key? klass then
528
- filters[class_map[klass]] << method
529
- else
530
- output.puts "Unable to map class #{klass} to a file"
531
- end
532
- end
533
-
534
- filters
535
- end
536
-
537
- ##
538
- # Find the files to process, ignoring temporary files, source
539
- # configuration management files, etc., and return a Hash mapping
540
- # filename to modification time.
541
-
542
- def find_files
543
- result = {}
544
- targets = self.find_directories + self.extra_files
545
- self.find_order.clear
546
-
547
- targets.each do |target|
548
- order = []
549
- Find.find target do |f|
550
- Find.prune if f =~ self.exceptions
551
- Find.prune if f =~ /^\.\/tmp/ # temp dir, used by isolate
552
-
553
- next unless File.file? f
554
- next if f =~ /(swp|~|rej|orig)$/ # temporary/patch files
555
- next if f =~ /(,v)$/ # RCS files
556
- next if f =~ /\/\.?#/ # Emacs autosave/cvs merge files
557
-
558
- filename = f.sub(/^\.\//, '')
559
-
560
- result[filename] = File.stat(filename).mtime rescue next
561
- order << filename
562
- end
563
- self.find_order.push(*order.sort)
564
- end
565
-
566
- result
567
- end
568
-
569
- ##
570
- # Find the files which have been modified, update the recorded
571
- # timestamps, and use this to update the files to test. Returns
572
- # the latest mtime of the files modified or nil when nothing was
573
- # modified.
574
-
575
- def find_files_to_test files = find_files
576
- updated = files.select { |filename, mtime| self.last_mtime < mtime }
577
-
578
- # nothing to update or initially run
579
- unless updated.empty? || self.last_mtime.to_i == 0 then
580
- p updated if options[:verbose]
581
-
582
- hook :updated, updated
583
- end
584
-
585
- updated.map { |f,m| test_files_for f }.flatten.uniq.each do |filename|
586
- self.files_to_test[filename] # creates key with default value
587
- end
588
-
589
- if updated.empty? then
590
- nil
591
- else
592
- files.values.max
593
- end
594
- end
595
-
596
- ##
597
- # Check results for failures, set the "bar" to red or green, and if
598
- # there are failures record this.
599
-
600
- def handle_results results
601
- results = results.gsub(/\e\[\d+m/, '') # strip ascii color
602
- failed = results.scan(self.failed_results_re).map { |m, k|
603
- k, m = $1, $2 if m =~ /(\w+)\#(\w+)/ # minitest 5 output
604
- [m, k]
605
- }
606
-
607
- completed = results[self.completed_re]
608
-
609
- if completed then
610
- completed = completed.scan(/(\d+) (\w+)/).map { |v, k| [k, v.to_i] }
611
-
612
- self.latest_results = Hash[*completed.flatten]
613
- self.files_to_test = consolidate_failures failed
614
-
615
- color = failed.empty? ? :green : :red
616
- hook color
617
- else
618
- self.latest_results = nil
619
- end
620
-
621
- self.tainted = true unless self.files_to_test.empty?
622
- end
623
-
624
- ##
625
- # Lazy accessor for the known_files hash.
626
-
627
- def known_files
628
- unless @known_files then
629
- @known_files = {}
630
- find_order.each {|f| @known_files[f] = true }
631
- end
632
- @known_files
633
- end
634
-
635
- ##
636
- # Generate the commands to test the supplied files
637
-
638
- def make_test_cmd files_to_test
639
- if options[:debug] then
640
- puts "Files to test:"
641
- puts
642
- pp files_to_test
643
- puts
644
- end
645
-
646
- cmds = []
647
- full, partial = reorder(files_to_test).partition { |k,v| v.empty? }
648
-
649
- diff = self.unit_diff
650
- diff = " | #{diff}" if diff and diff !~ /^\|/
651
-
652
- unless full.empty? then
653
- classes = full.map {|k,v| k}.flatten.uniq
654
- classes.unshift testlib
655
- classes = classes.join " "
656
- cmds << "#{ruby_cmd} -e \"#{testprefix}; %w[#{classes}].each { |f| require f }\"#{diff}"
657
- end
658
-
659
- partial.each do |klass, methods|
660
- regexp = Regexp.union(*methods).source
661
- cmds << "#{ruby_cmd} #{klass} -n \"/^(#{regexp})$/\"#{diff}"
662
- end
663
-
664
- cmds.join "#{SEP} "
665
- end
666
-
667
- def new_hash_of_arrays
668
- Hash.new { |h,k| h[k] = [] }
669
- end
670
-
671
- def reorder files_to_test
672
- case self.order
673
- when :alpha then
674
- files_to_test.sort_by { |k,v| k }
675
- when :reverse then
676
- files_to_test.sort_by { |k,v| k }.reverse
677
- when :random then
678
- max = files_to_test.size
679
- files_to_test.sort_by { |k,v| rand max }
680
- when :natural then
681
- (self.find_order & files_to_test.keys).map { |f| [f, files_to_test[f]] }
682
- else
683
- raise "unknown order type: #{self.order.inspect}"
684
- end
685
- end
686
-
687
- ##
688
- # Rerun the tests from cold (reset state)
689
-
690
- def rerun_all_tests
691
- reset
692
- run_tests
693
-
694
- hook :all_good if all_good
695
- end
696
-
697
- ##
698
- # Clear all state information about test failures and whether
699
- # interrupts will kill autotest.
700
-
701
- def reset
702
- self.files_to_test.clear
703
- self.find_order.clear
704
-
705
- self.interrupted = false
706
- self.known_files = nil
707
- self.last_mtime = T0
708
- self.tainted = false
709
- self.wants_to_quit = false
710
-
711
- hook :reset
712
- end
713
-
714
- ##
715
- # Determine and return the path of the ruby executable.
716
-
717
- def ruby
718
- ruby = ENV['RUBY']
719
- ruby ||= File.join(RbConfig::CONFIG['bindir'],
720
- RbConfig::CONFIG['ruby_install_name'])
721
-
722
- ruby.gsub! File::SEPARATOR, File::ALT_SEPARATOR if File::ALT_SEPARATOR
723
-
724
- return ruby
725
- end
726
-
727
- ##
728
- # Returns the base of the ruby command.
729
-
730
- def ruby_cmd
731
- "#{prefix}#{ruby} -I#{libs} -rubygems"
732
- end
733
-
734
- ##
735
- # Return the name of the file with the tests for filename by finding
736
- # a +test_mapping+ that matches the file and executing the mapping's
737
- # proc.
738
-
739
- def test_files_for filename
740
- result = []
741
-
742
- self.test_mappings.each do |file_re, proc|
743
- if filename =~ file_re then
744
- result = [proc.call(filename, $~)].
745
- flatten.sort.uniq.select { |f| known_files[f] }
746
- break unless result.empty?
747
- end
748
- end
749
-
750
- pp :test_file_for => [filename, result.first] if result and options[:debug]
751
-
752
- output.puts "No tests matched #{filename}" if
753
- options[:verbose] and result.empty?
754
-
755
- return result
756
- end
757
-
758
- ##
759
- # Sleep then look for files to test, until there are some.
760
-
761
- def wait_for_changes
762
- hook :waiting
763
- Kernel.sleep self.sleep until find_files_to_test
764
- end
765
-
766
- ############################################################
767
- # File Mappings:
768
-
769
- ##
770
- # Returns all known files in the codebase matching +regexp+.
771
-
772
- def files_matching regexp
773
- self.find_order.select { |k| k =~ regexp }
774
- end
775
-
776
- ##
777
- # Adds a file mapping, optionally prepending the mapping to the
778
- # front of the list if +prepend+ is true. +regexp+ should match a
779
- # file path in the codebase. +proc+ is passed a matched filename and
780
- # Regexp.last_match. +proc+ should return an array of tests to run.
781
- #
782
- # For example, if test_helper.rb is modified, rerun all tests:
783
- #
784
- # at.add_mapping(/test_helper.rb/) do |f, _|
785
- # at.files_matching(/^test.*rb$/)
786
- # end
787
-
788
- def add_mapping regexp, prepend = false, &proc
789
- if prepend then
790
- @test_mappings.unshift [regexp, proc]
791
- else
792
- @test_mappings.push [regexp, proc]
793
- end
794
- nil
795
- end
796
-
797
- ##
798
- # Removed a file mapping matching +regexp+.
799
-
800
- def remove_mapping regexp
801
- @test_mappings.delete_if do |k,v|
802
- k == regexp
803
- end
804
- nil
805
- end
806
-
807
- ##
808
- # Clears all file mappings. This is DANGEROUS as it entirely
809
- # disables autotest. You must add at least one file mapping that
810
- # does a good job of rerunning appropriate tests.
811
-
812
- def clear_mappings
813
- @test_mappings.clear
814
- nil
815
- end
816
-
817
- ############################################################
818
- # Exceptions:
819
-
820
- ##
821
- # Adds +regexp+ to the list of exceptions for find_file. This must
822
- # be called _before_ the exceptions are compiled.
823
-
824
- def add_exception regexp
825
- raise "exceptions already compiled" if defined? @exceptions
826
-
827
- @exception_list << regexp
828
- nil
829
- end
830
-
831
- ##
832
- # Removes +regexp+ to the list of exceptions for find_file. This
833
- # must be called _before_ the exceptions are compiled.
834
-
835
- def remove_exception regexp
836
- raise "exceptions already compiled" if defined? @exceptions
837
- @exception_list.delete regexp
838
- nil
839
- end
840
-
841
- ##
842
- # Clears the list of exceptions for find_file. This must be called
843
- # _before_ the exceptions are compiled.
844
-
845
- def clear_exceptions
846
- raise "exceptions already compiled" if defined? @exceptions
847
- @exception_list.clear
848
- nil
849
- end
850
-
851
- ##
852
- # Return a compiled regexp of exceptions for find_files or nil if no
853
- # filtering should take place. This regexp is generated from
854
- # +exception_list+.
855
-
856
- def exceptions
857
- unless defined? @exceptions then
858
- @exceptions = if @exception_list.empty? then
859
- nil
860
- else
861
- Regexp.union(*@exception_list)
862
- end
863
- end
864
-
865
- @exceptions
866
- end
867
-
868
- ############################################################
869
- # Hooks:
870
-
871
- ##
872
- # Call the event hook named +name+, passing in optional args
873
- # depending on the hook itself.
874
- #
875
- # Returns false if no hook handled the event.
876
- #
877
- # === Hook Writers!
878
- #
879
- # This executes all registered hooks <em>until one returns truthy</em>.
880
- # Pay attention to the return value of your block!
881
-
882
- def hook name, *args
883
- deprecated = {
884
- # none currently
885
- }
886
-
887
- if deprecated[name] and not HOOKS[name].empty? then
888
- warn "hook #{name} has been deprecated, use #{deprecated[name]}"
889
- end
890
-
891
- HOOKS[name].any? { |plugin| plugin[self, *args] }
892
- end
893
-
894
- ##
895
- # Add the supplied block to the available hooks, with the given
896
- # name.
897
-
898
- def self.add_hook name, &block
899
- HOOKS[name] << block
900
- end
901
- end