test-unit 1.2.3
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/History.txt +5 -0
- data/Manifest.txt +48 -0
- data/README.txt +27 -0
- data/Rakefile +15 -0
- data/bin/testrb +5 -0
- data/lib/test/unit.rb +280 -0
- data/lib/test/unit/assertionfailederror.rb +14 -0
- data/lib/test/unit/assertions.rb +622 -0
- data/lib/test/unit/autorunner.rb +220 -0
- data/lib/test/unit/collector.rb +43 -0
- data/lib/test/unit/collector/dir.rb +108 -0
- data/lib/test/unit/collector/objectspace.rb +34 -0
- data/lib/test/unit/error.rb +56 -0
- data/lib/test/unit/failure.rb +51 -0
- data/lib/test/unit/testcase.rb +160 -0
- data/lib/test/unit/testresult.rb +80 -0
- data/lib/test/unit/testsuite.rb +76 -0
- data/lib/test/unit/ui/console/testrunner.rb +127 -0
- data/lib/test/unit/ui/fox/testrunner.rb +268 -0
- data/lib/test/unit/ui/gtk/testrunner.rb +416 -0
- data/lib/test/unit/ui/gtk2/testrunner.rb +465 -0
- data/lib/test/unit/ui/testrunnermediator.rb +68 -0
- data/lib/test/unit/ui/testrunnerutilities.rb +46 -0
- data/lib/test/unit/ui/tk/testrunner.rb +260 -0
- data/lib/test/unit/util/backtracefilter.rb +40 -0
- data/lib/test/unit/util/observable.rb +90 -0
- data/lib/test/unit/util/procwrapper.rb +48 -0
- data/lib/test/unit/version.rb +7 -0
- data/sample/adder.rb +13 -0
- data/sample/subtracter.rb +12 -0
- data/sample/tc_adder.rb +18 -0
- data/sample/tc_subtracter.rb +18 -0
- data/sample/ts_examples.rb +7 -0
- data/test/collector/test_dir.rb +406 -0
- data/test/collector/test_objectspace.rb +98 -0
- data/test/runit/test_assert.rb +402 -0
- data/test/runit/test_testcase.rb +91 -0
- data/test/runit/test_testresult.rb +144 -0
- data/test/runit/test_testsuite.rb +49 -0
- data/test/test_assertions.rb +528 -0
- data/test/test_error.rb +26 -0
- data/test/test_failure.rb +33 -0
- data/test/test_testcase.rb +275 -0
- data/test/test_testresult.rb +104 -0
- data/test/test_testsuite.rb +129 -0
- data/test/util/test_backtracefilter.rb +41 -0
- data/test/util/test_observable.rb +102 -0
- data/test/util/test_procwrapper.rb +36 -0
- metadata +128 -0
@@ -0,0 +1,220 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'test/unit/ui/testrunnerutilities'
|
3
|
+
require 'optparse'
|
4
|
+
|
5
|
+
module Test
|
6
|
+
module Unit
|
7
|
+
class AutoRunner
|
8
|
+
def self.run(force_standalone=false, default_dir=nil, argv=ARGV, &block)
|
9
|
+
r = new(force_standalone || standalone?, &block)
|
10
|
+
r.base = default_dir
|
11
|
+
r.process_args(argv)
|
12
|
+
r.run
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.standalone?
|
16
|
+
return false unless("-e" == $0)
|
17
|
+
ObjectSpace.each_object(Class) do |klass|
|
18
|
+
return false if(klass < TestCase)
|
19
|
+
end
|
20
|
+
true
|
21
|
+
end
|
22
|
+
|
23
|
+
RUNNERS = {
|
24
|
+
:console => proc do |r|
|
25
|
+
require 'test/unit/ui/console/testrunner'
|
26
|
+
Test::Unit::UI::Console::TestRunner
|
27
|
+
end,
|
28
|
+
:gtk => proc do |r|
|
29
|
+
require 'test/unit/ui/gtk/testrunner'
|
30
|
+
Test::Unit::UI::GTK::TestRunner
|
31
|
+
end,
|
32
|
+
:gtk2 => proc do |r|
|
33
|
+
require 'test/unit/ui/gtk2/testrunner'
|
34
|
+
Test::Unit::UI::GTK2::TestRunner
|
35
|
+
end,
|
36
|
+
:fox => proc do |r|
|
37
|
+
require 'test/unit/ui/fox/testrunner'
|
38
|
+
Test::Unit::UI::Fox::TestRunner
|
39
|
+
end,
|
40
|
+
:tk => proc do |r|
|
41
|
+
require 'test/unit/ui/tk/testrunner'
|
42
|
+
Test::Unit::UI::Tk::TestRunner
|
43
|
+
end,
|
44
|
+
}
|
45
|
+
|
46
|
+
OUTPUT_LEVELS = [
|
47
|
+
[:silent, UI::SILENT],
|
48
|
+
[:progress, UI::PROGRESS_ONLY],
|
49
|
+
[:normal, UI::NORMAL],
|
50
|
+
[:verbose, UI::VERBOSE],
|
51
|
+
]
|
52
|
+
|
53
|
+
COLLECTORS = {
|
54
|
+
:objectspace => proc do |r|
|
55
|
+
require 'test/unit/collector/objectspace'
|
56
|
+
c = Collector::ObjectSpace.new
|
57
|
+
c.filter = r.filters
|
58
|
+
c.collect($0.sub(/\.rb\Z/, ''))
|
59
|
+
end,
|
60
|
+
:dir => proc do |r|
|
61
|
+
require 'test/unit/collector/dir'
|
62
|
+
c = Collector::Dir.new
|
63
|
+
c.filter = r.filters
|
64
|
+
c.pattern.concat(r.pattern) if(r.pattern)
|
65
|
+
c.exclude.concat(r.exclude) if(r.exclude)
|
66
|
+
c.base = r.base
|
67
|
+
$:.push(r.base) if r.base
|
68
|
+
c.collect(*(r.to_run.empty? ? ['.'] : r.to_run))
|
69
|
+
end,
|
70
|
+
}
|
71
|
+
|
72
|
+
attr_reader :suite
|
73
|
+
attr_accessor :output_level, :filters, :to_run, :pattern, :exclude, :base, :workdir
|
74
|
+
attr_writer :runner, :collector
|
75
|
+
|
76
|
+
def initialize(standalone)
|
77
|
+
Unit.run = true
|
78
|
+
@standalone = standalone
|
79
|
+
@runner = RUNNERS[:console]
|
80
|
+
@collector = COLLECTORS[(standalone ? :dir : :objectspace)]
|
81
|
+
@filters = []
|
82
|
+
@to_run = []
|
83
|
+
@output_level = UI::NORMAL
|
84
|
+
@workdir = nil
|
85
|
+
yield(self) if(block_given?)
|
86
|
+
end
|
87
|
+
|
88
|
+
def process_args(args = ARGV)
|
89
|
+
begin
|
90
|
+
options.order!(args) {|arg| @to_run << arg}
|
91
|
+
rescue OptionParser::ParseError => e
|
92
|
+
puts e
|
93
|
+
puts options
|
94
|
+
$! = nil
|
95
|
+
abort
|
96
|
+
else
|
97
|
+
@filters << proc{false} unless(@filters.empty?)
|
98
|
+
end
|
99
|
+
not @to_run.empty?
|
100
|
+
end
|
101
|
+
|
102
|
+
def options
|
103
|
+
@options ||= OptionParser.new do |o|
|
104
|
+
o.banner = "Test::Unit automatic runner."
|
105
|
+
o.banner << "\nUsage: #{$0} [options] [-- untouched arguments]"
|
106
|
+
|
107
|
+
o.on
|
108
|
+
o.on('-r', '--runner=RUNNER', RUNNERS,
|
109
|
+
"Use the given RUNNER.",
|
110
|
+
"(" + keyword_display(RUNNERS) + ")") do |r|
|
111
|
+
@runner = r
|
112
|
+
end
|
113
|
+
|
114
|
+
if(@standalone)
|
115
|
+
o.on('-b', '--basedir=DIR', "Base directory of test suites.") do |b|
|
116
|
+
@base = b
|
117
|
+
end
|
118
|
+
|
119
|
+
o.on('-w', '--workdir=DIR', "Working directory to run tests.") do |w|
|
120
|
+
@workdir = w
|
121
|
+
end
|
122
|
+
|
123
|
+
o.on('-a', '--add=TORUN', Array,
|
124
|
+
"Add TORUN to the list of things to run;",
|
125
|
+
"can be a file or a directory.") do |a|
|
126
|
+
@to_run.concat(a)
|
127
|
+
end
|
128
|
+
|
129
|
+
@pattern = []
|
130
|
+
o.on('-p', '--pattern=PATTERN', Regexp,
|
131
|
+
"Match files to collect against PATTERN.") do |e|
|
132
|
+
@pattern << e
|
133
|
+
end
|
134
|
+
|
135
|
+
@exclude = []
|
136
|
+
o.on('-x', '--exclude=PATTERN', Regexp,
|
137
|
+
"Ignore files to collect against PATTERN.") do |e|
|
138
|
+
@exclude << e
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
o.on('-n', '--name=NAME', String,
|
143
|
+
"Runs tests matching NAME.",
|
144
|
+
"(patterns may be used).") do |n|
|
145
|
+
n = (%r{\A/(.*)/\Z} =~ n ? Regexp.new($1) : n)
|
146
|
+
case n
|
147
|
+
when Regexp
|
148
|
+
@filters << proc{|t| n =~ t.method_name ? true : nil}
|
149
|
+
else
|
150
|
+
@filters << proc{|t| n == t.method_name ? true : nil}
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
o.on('-t', '--testcase=TESTCASE', String,
|
155
|
+
"Runs tests in TestCases matching TESTCASE.",
|
156
|
+
"(patterns may be used).") do |n|
|
157
|
+
n = (%r{\A/(.*)/\Z} =~ n ? Regexp.new($1) : n)
|
158
|
+
case n
|
159
|
+
when Regexp
|
160
|
+
@filters << proc{|t| n =~ t.class.name ? true : nil}
|
161
|
+
else
|
162
|
+
@filters << proc{|t| n == t.class.name ? true : nil}
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
o.on('-I', "--load-path=DIR[#{File::PATH_SEPARATOR}DIR...]",
|
167
|
+
"Appends directory list to $LOAD_PATH.") do |dirs|
|
168
|
+
$LOAD_PATH.concat(dirs.split(File::PATH_SEPARATOR))
|
169
|
+
end
|
170
|
+
|
171
|
+
o.on('-v', '--verbose=[LEVEL]', OUTPUT_LEVELS,
|
172
|
+
"Set the output level (default is verbose).",
|
173
|
+
"(" + keyword_display(OUTPUT_LEVELS) + ")") do |l|
|
174
|
+
@output_level = l || UI::VERBOSE
|
175
|
+
end
|
176
|
+
|
177
|
+
o.on('--',
|
178
|
+
"Stop processing options so that the",
|
179
|
+
"remaining options will be passed to the",
|
180
|
+
"test."){o.terminate}
|
181
|
+
|
182
|
+
o.on('-h', '--help', 'Display this help.'){puts o; exit}
|
183
|
+
|
184
|
+
o.on_tail
|
185
|
+
o.on_tail('Deprecated options:')
|
186
|
+
|
187
|
+
o.on_tail('--console', 'Console runner (use --runner).') do
|
188
|
+
warn("Deprecated option (--console).")
|
189
|
+
@runner = RUNNERS[:console]
|
190
|
+
end
|
191
|
+
|
192
|
+
o.on_tail('--gtk', 'GTK runner (use --runner).') do
|
193
|
+
warn("Deprecated option (--gtk).")
|
194
|
+
@runner = RUNNERS[:gtk]
|
195
|
+
end
|
196
|
+
|
197
|
+
o.on_tail('--fox', 'Fox runner (use --runner).') do
|
198
|
+
warn("Deprecated option (--fox).")
|
199
|
+
@runner = RUNNERS[:fox]
|
200
|
+
end
|
201
|
+
|
202
|
+
o.on_tail
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def keyword_display(array)
|
207
|
+
list = array.collect {|e, *| e.to_s}
|
208
|
+
Array === array or list.sort!
|
209
|
+
list.collect {|e| e.sub(/^(.)([A-Za-z]+)(?=\w*$)/, '\\1[\\2]')}.join(", ")
|
210
|
+
end
|
211
|
+
|
212
|
+
def run
|
213
|
+
@suite = @collector[self]
|
214
|
+
result = @runner[self] or return false
|
215
|
+
Dir.chdir(@workdir) if @workdir
|
216
|
+
result.run(@suite, @output_level).passed?
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Test
|
2
|
+
module Unit
|
3
|
+
module Collector
|
4
|
+
def initialize
|
5
|
+
@filters = []
|
6
|
+
end
|
7
|
+
|
8
|
+
def filter=(filters)
|
9
|
+
@filters = case(filters)
|
10
|
+
when Proc
|
11
|
+
[filters]
|
12
|
+
when Array
|
13
|
+
filters
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_suite(destination, suite)
|
18
|
+
to_delete = suite.tests.find_all{|t| !include?(t)}
|
19
|
+
to_delete.each{|t| suite.delete(t)}
|
20
|
+
destination << suite unless(suite.size == 0)
|
21
|
+
end
|
22
|
+
|
23
|
+
def include?(test)
|
24
|
+
return true if(@filters.empty?)
|
25
|
+
@filters.each do |filter|
|
26
|
+
result = filter[test]
|
27
|
+
if(result.nil?)
|
28
|
+
next
|
29
|
+
elsif(!result)
|
30
|
+
return false
|
31
|
+
else
|
32
|
+
return true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
true
|
36
|
+
end
|
37
|
+
|
38
|
+
def sort(suites)
|
39
|
+
suites.sort_by{|s| s.name}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'test/unit/testsuite'
|
2
|
+
require 'test/unit/collector'
|
3
|
+
|
4
|
+
module Test
|
5
|
+
module Unit
|
6
|
+
module Collector
|
7
|
+
class Dir
|
8
|
+
include Collector
|
9
|
+
|
10
|
+
attr_reader :pattern, :exclude
|
11
|
+
attr_accessor :base
|
12
|
+
|
13
|
+
def initialize(dir=::Dir, file=::File, object_space=::ObjectSpace, req=nil)
|
14
|
+
super()
|
15
|
+
@dir = dir
|
16
|
+
@file = file
|
17
|
+
@object_space = object_space
|
18
|
+
@req = req
|
19
|
+
@pattern = [/\btest_.*\.rb\Z/m]
|
20
|
+
@exclude = []
|
21
|
+
@base = nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def collect(*from)
|
25
|
+
basedir = @base
|
26
|
+
$:.push(basedir) if basedir
|
27
|
+
if(from.empty?)
|
28
|
+
recursive_collect('.', find_test_cases)
|
29
|
+
elsif(from.size == 1)
|
30
|
+
recursive_collect(from.first, find_test_cases)
|
31
|
+
else
|
32
|
+
suites = []
|
33
|
+
from.each do |f|
|
34
|
+
suite = recursive_collect(f, find_test_cases)
|
35
|
+
suites << suite unless(suite.tests.empty?)
|
36
|
+
end
|
37
|
+
suite = TestSuite.new("[#{from.join(', ')}]")
|
38
|
+
sort(suites).each{|s| suite << s}
|
39
|
+
suite
|
40
|
+
end
|
41
|
+
ensure
|
42
|
+
$:.delete_at($:.rindex(basedir)) if basedir
|
43
|
+
end
|
44
|
+
|
45
|
+
def find_test_cases(ignore=[])
|
46
|
+
cases = []
|
47
|
+
@object_space.each_object(Class) do |c|
|
48
|
+
cases << c if(c < TestCase && !ignore.include?(c))
|
49
|
+
end
|
50
|
+
ignore.concat(cases)
|
51
|
+
cases
|
52
|
+
end
|
53
|
+
|
54
|
+
def recursive_collect(name, already_gathered)
|
55
|
+
sub_suites = []
|
56
|
+
path = realdir(name)
|
57
|
+
if @file.directory?(path)
|
58
|
+
dir_name = name unless name == '.'
|
59
|
+
@dir.entries(path).each do |e|
|
60
|
+
next if(e == '.' || e == '..')
|
61
|
+
e_name = dir_name ? @file.join(dir_name, e) : e
|
62
|
+
if @file.directory?(realdir(e_name))
|
63
|
+
next if /\ACVS\z/ =~ e
|
64
|
+
sub_suite = recursive_collect(e_name, already_gathered)
|
65
|
+
sub_suites << sub_suite unless(sub_suite.empty?)
|
66
|
+
else
|
67
|
+
next if /~\z/ =~ e_name or /\A\.\#/ =~ e
|
68
|
+
if @pattern and !@pattern.empty?
|
69
|
+
next unless @pattern.any? {|pat| pat =~ e_name}
|
70
|
+
end
|
71
|
+
if @exclude and !@exclude.empty?
|
72
|
+
next if @exclude.any? {|pat| pat =~ e_name}
|
73
|
+
end
|
74
|
+
collect_file(e_name, sub_suites, already_gathered)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
else
|
78
|
+
collect_file(name, sub_suites, already_gathered)
|
79
|
+
end
|
80
|
+
suite = TestSuite.new(@file.basename(name))
|
81
|
+
sort(sub_suites).each{|s| suite << s}
|
82
|
+
suite
|
83
|
+
end
|
84
|
+
|
85
|
+
def collect_file(name, suites, already_gathered)
|
86
|
+
dir = @file.dirname(@file.expand_path(name, @base))
|
87
|
+
$:.unshift(dir)
|
88
|
+
if(@req)
|
89
|
+
@req.require(name)
|
90
|
+
else
|
91
|
+
require(name)
|
92
|
+
end
|
93
|
+
find_test_cases(already_gathered).each{|t| add_suite(suites, t.suite)}
|
94
|
+
ensure
|
95
|
+
$:.delete_at($:.rindex(dir)) if(dir)
|
96
|
+
end
|
97
|
+
|
98
|
+
def realdir(path)
|
99
|
+
if @base
|
100
|
+
@file.join(@base, path)
|
101
|
+
else
|
102
|
+
path
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Author:: Nathaniel Talbott.
|
2
|
+
# Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved.
|
3
|
+
# License:: Ruby license.
|
4
|
+
|
5
|
+
require 'test/unit/collector'
|
6
|
+
|
7
|
+
module Test
|
8
|
+
module Unit
|
9
|
+
module Collector
|
10
|
+
class ObjectSpace
|
11
|
+
include Collector
|
12
|
+
|
13
|
+
NAME = 'collected from the ObjectSpace'
|
14
|
+
|
15
|
+
def initialize(source=::ObjectSpace)
|
16
|
+
super()
|
17
|
+
@source = source
|
18
|
+
end
|
19
|
+
|
20
|
+
def collect(name=NAME)
|
21
|
+
suite = TestSuite.new(name)
|
22
|
+
sub_suites = []
|
23
|
+
@source.each_object(Class) do |klass|
|
24
|
+
if(Test::Unit::TestCase > klass)
|
25
|
+
add_suite(sub_suites, klass.suite)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
sort(sub_suites).each{|s| suite << s}
|
29
|
+
suite
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
#--
|
2
|
+
#
|
3
|
+
# Author:: Nathaniel Talbott.
|
4
|
+
# Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved.
|
5
|
+
# License:: Ruby license.
|
6
|
+
|
7
|
+
require 'test/unit/util/backtracefilter'
|
8
|
+
|
9
|
+
module Test
|
10
|
+
module Unit
|
11
|
+
|
12
|
+
# Encapsulates an error in a test. Created by
|
13
|
+
# Test::Unit::TestCase when it rescues an exception thrown
|
14
|
+
# during the processing of a test.
|
15
|
+
class Error
|
16
|
+
include Util::BacktraceFilter
|
17
|
+
|
18
|
+
attr_reader(:test_name, :exception)
|
19
|
+
|
20
|
+
SINGLE_CHARACTER = 'E'
|
21
|
+
|
22
|
+
# Creates a new Error with the given test_name and
|
23
|
+
# exception.
|
24
|
+
def initialize(test_name, exception)
|
25
|
+
@test_name = test_name
|
26
|
+
@exception = exception
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns a single character representation of an error.
|
30
|
+
def single_character_display
|
31
|
+
SINGLE_CHARACTER
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns the message associated with the error.
|
35
|
+
def message
|
36
|
+
"#{@exception.class.name}: #{@exception.message}"
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns a brief version of the error description.
|
40
|
+
def short_display
|
41
|
+
"#@test_name: #{message.split("\n")[0]}"
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns a verbose version of the error description.
|
45
|
+
def long_display
|
46
|
+
backtrace = filter_backtrace(@exception.backtrace).join("\n ")
|
47
|
+
"Error:\n#@test_name:\n#{message}\n #{backtrace}"
|
48
|
+
end
|
49
|
+
|
50
|
+
# Overridden to return long_display.
|
51
|
+
def to_s
|
52
|
+
long_display
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|