Project

General

Profile

Bug #1555 ยป autorunner.rb

Add --output option and 3rd parm to run() - howardk (Howard Kapustein), 06/02/2009 03:52 PM

 
1
#\ruby\lib\ruby\1.8\test\unit\autorunner.rb
2
require 'test/unit'
3
require 'test/unit/ui/testrunnerutilities'
4
require 'optparse'
5

    
6
module Test
7
  module Unit
8
    class AutoRunner
9
      def self.run(force_standalone=false, default_dir=nil, argv=ARGV, &block)
10
        r = new(force_standalone || standalone?, &block)
11
        r.base = default_dir
12
        r.process_args(argv)
13
        r.run
14
      end
15

    
16
      def self.standalone?
17
        return false unless("-e" == $0)
18
        ObjectSpace.each_object(Class) do |klass|
19
          return false if(klass < TestCase)
20
        end
21
        true
22
      end
23

    
24
      RUNNERS = {
25
        :console => proc do |r|
26
          require 'test/unit/ui/console/testrunner'
27
          Test::Unit::UI::Console::TestRunner
28
        end,
29
        :gtk => proc do |r|
30
          require 'test/unit/ui/gtk/testrunner'
31
          Test::Unit::UI::GTK::TestRunner
32
        end,
33
        :gtk2 => proc do |r|
34
          require 'test/unit/ui/gtk2/testrunner'
35
          Test::Unit::UI::GTK2::TestRunner
36
        end,
37
        :fox => proc do |r|
38
          require 'test/unit/ui/fox/testrunner'
39
          Test::Unit::UI::Fox::TestRunner
40
        end,
41
        :tk => proc do |r|
42
          require 'test/unit/ui/tk/testrunner'
43
          Test::Unit::UI::Tk::TestRunner
44
        end,
45
      }
46

    
47
      OUTPUT_LEVELS = [
48
        [:silent, UI::SILENT],
49
        [:progress, UI::PROGRESS_ONLY],
50
        [:normal, UI::NORMAL],
51
        [:verbose, UI::VERBOSE],
52
      ]
53

    
54
      COLLECTORS = {
55
        :objectspace => proc do |r|
56
          require 'test/unit/collector/objectspace'
57
          c = Collector::ObjectSpace.new
58
          c.filter = r.filters
59
          c.collect($0.sub(/\.rb\Z/, ''))
60
        end,
61
        :dir => proc do |r|
62
          require 'test/unit/collector/dir'
63
          c = Collector::Dir.new
64
          c.filter = r.filters
65
          c.pattern.concat(r.pattern) if(r.pattern)
66
          c.exclude.concat(r.exclude) if(r.exclude)
67
          c.base = r.base
68
          $:.push(r.base) if r.base
69
          c.collect(*(r.to_run.empty? ? ['.'] : r.to_run))
70
        end,
71
      }
72

    
73
      attr_reader :suite
74
      attr_accessor :output_level, :filters, :to_run, :pattern, :exclude, :base, :workdir
75
      attr_accessor :output_io
76
      attr_writer :runner, :collector
77

    
78
      def initialize(standalone)
79
        Unit.run = true
80
        @standalone = standalone
81
        @runner = RUNNERS[:console]
82
        @collector = COLLECTORS[(standalone ? :dir : :objectspace)]
83
        @filters = []
84
        @to_run = []
85
        @output_level = UI::NORMAL
86
        @workdir = nil
87
        @output_io = STDOUT
88
        yield(self) if(block_given?)
89
      end
90

    
91
      def process_args(args = ARGV)
92
        begin
93
          options.order!(args) {|arg| @to_run << arg}
94
        rescue OptionParser::ParseError => e
95
          puts e
96
          puts options
97
          $! = nil
98
          abort
99
        else
100
          @filters << proc{false} unless(@filters.empty?)
101
        end
102
        not @to_run.empty?
103
      end
104

    
105
      def options
106
        @options ||= OptionParser.new do |o|
107
          o.banner = "Test::Unit automatic runner."
108
          o.banner << "\nUsage: #{$0} [options] [-- untouched arguments]"
109

    
110
          o.on
111
          o.on('-r', '--runner=RUNNER', RUNNERS,
112
               "Use the given RUNNER.",
113
               "(" + keyword_display(RUNNERS) + ")") do |r|
114
            @runner = r
115
          end
116

    
117
          if(@standalone)
118
            o.on('-b', '--basedir=DIR', "Base directory of test suites.") do |b|
119
              @base = b
120
            end
121

    
122
            o.on('-w', '--workdir=DIR', "Working directory to run tests.") do |w|
123
              @workdir = w
124
            end
125

    
126
            o.on('-a', '--add=TORUN', Array,
127
                 "Add TORUN to the list of things to run;",
128
                 "can be a file or a directory.") do |a|
129
              @to_run.concat(a)
130
            end
131

    
132
            @pattern = []
133
            o.on('-p', '--pattern=PATTERN', Regexp,
134
                 "Match files to collect against PATTERN.") do |e|
135
              @pattern << e
136
            end
137

    
138
            @exclude = []
139
            o.on('-x', '--exclude=PATTERN', Regexp,
140
                 "Ignore files to collect against PATTERN.") do |e|
141
              @exclude << e
142
            end
143
          end
144

    
145
          o.on('-n', '--name=NAME', String,
146
               "Runs tests matching NAME.",
147
               "(patterns may be used).") do |n|
148
            n = (%r{\A/(.*)/\Z} =~ n ? Regexp.new($1) : n)
149
            case n
150
            when Regexp
151
              @filters << proc{|t| n =~ t.method_name ? true : nil}
152
            else
153
              @filters << proc{|t| n == t.method_name ? true : nil}
154
            end
155
          end
156

    
157
          o.on('-o', '--output=[+]FILE', String,
158
               "Write output to FILE.",
159
               "Use '+' to append; FILE = STDOUT, STDERR or filename (default=STDOUT)") do |f|
160
            case f
161
            when nil, '', 'STDOUT'
162
              @output_io = STDOUT
163
            when 'STDERR'
164
              @output_io = STDERR
165
            else
166
              if f =~ /^\+/
167
                @output_io = File.new(f[1..f.length], 'a')
168
              else
169
                @output_io = File.new(f, 'w')
170
              end
171
            end
172
          end
173

    
174
          o.on('-t', '--testcase=TESTCASE', String,
175
               "Runs tests in TestCases matching TESTCASE.",
176
               "(patterns may be used).") do |n|
177
            n = (%r{\A/(.*)/\Z} =~ n ? Regexp.new($1) : n)
178
            case n
179
            when Regexp
180
              @filters << proc{|t| n =~ t.class.name ? true : nil}
181
            else
182
              @filters << proc{|t| n == t.class.name ? true : nil}
183
            end
184
          end
185

    
186
          o.on('-I', "--load-path=DIR[#{File::PATH_SEPARATOR}DIR...]",
187
               "Appends directory list to $LOAD_PATH.") do |dirs|
188
            $LOAD_PATH.concat(dirs.split(File::PATH_SEPARATOR))
189
          end
190

    
191
          o.on('-v', '--verbose=[LEVEL]', OUTPUT_LEVELS,
192
               "Set the output level (default is verbose).",
193
               "(" + keyword_display(OUTPUT_LEVELS) + ")") do |l|
194
            @output_level = l || UI::VERBOSE
195
          end
196

    
197
          o.on('--',
198
               "Stop processing options so that the",
199
               "remaining options will be passed to the",
200
               "test."){o.terminate}
201

    
202
          o.on('-h', '--help', 'Display this help.'){puts o; exit}
203

    
204
          o.on_tail
205
          o.on_tail('Deprecated options:')
206

    
207
          o.on_tail('--console', 'Console runner (use --runner).') do
208
            warn("Deprecated option (--console).")
209
            @runner = RUNNERS[:console]
210
          end
211

    
212
          o.on_tail('--gtk', 'GTK runner (use --runner).') do
213
            warn("Deprecated option (--gtk).")
214
            @runner = RUNNERS[:gtk]
215
          end
216

    
217
          o.on_tail('--fox', 'Fox runner (use --runner).') do
218
            warn("Deprecated option (--fox).")
219
            @runner = RUNNERS[:fox]
220
          end
221

    
222
          o.on_tail
223
        end
224
      end
225

    
226
      def keyword_display(array)
227
        list = array.collect {|e, *| e.to_s}
228
        Array === array or list.sort!
229
        list.collect {|e| e.sub(/^(.)([A-Za-z]+)(?=\w*$)/, '\\1[\\2]')}.join(", ")
230
      end
231

    
232
      def run
233
        @suite = @collector[self]
234
        result = @runner[self] or return false
235
        Dir.chdir(@workdir) if @workdir
236
        result.run(@suite, @output_level, @output_io).passed?
237
      end
238
    end
239
  end
240
end