test-unit-ext 0.1.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/NEWS.en +7 -0
- data/NEWS.ja +7 -0
- data/README.en +51 -0
- data/README.ja +51 -0
- data/Rakefile +106 -0
- data/html/index.html +21 -0
- data/html/news.html +18 -0
- data/html/news.html.en +18 -0
- data/html/news.html.ja +18 -0
- data/html/readme.html +42 -0
- data/html/readme.html.en +42 -0
- data/html/readme.html.ja +42 -0
- data/lib/test-unit-ext.rb +11 -0
- data/lib/test-unit-ext/always-show-result.rb +28 -0
- data/lib/test-unit-ext/backtrace-filter.rb +17 -0
- data/lib/test-unit-ext/color.rb +59 -0
- data/lib/test-unit-ext/colorized-runner.rb +101 -0
- data/lib/test-unit-ext/diff.rb +187 -0
- data/lib/test-unit-ext/long-display-for-emacs.rb +25 -0
- data/lib/test-unit-ext/metadata.rb +111 -0
- data/lib/test-unit-ext/priority.rb +186 -0
- data/lib/test-unit-ext/version.rb +3 -0
- data/misc/rd2html.rb +42 -0
- data/test/run-test.rb +14 -0
- data/test/test_color.rb +39 -0
- data/test/test_diff.rb +109 -0
- data/test/test_metadata.rb +127 -0
- metadata +83 -0
@@ -0,0 +1,186 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
|
3
|
+
require "fileutils"
|
4
|
+
|
5
|
+
module Test
|
6
|
+
module Unit
|
7
|
+
class TestCase
|
8
|
+
class << self
|
9
|
+
def inherited(sub)
|
10
|
+
super
|
11
|
+
sub.instance_variable_set("@priority_initialized", true)
|
12
|
+
sub.instance_variable_set("@priority_table", {})
|
13
|
+
sub.priority :normal
|
14
|
+
end
|
15
|
+
|
16
|
+
def include(*args)
|
17
|
+
args.reverse_each do |mod|
|
18
|
+
super(mod)
|
19
|
+
next unless defined?(@priority_initialized)
|
20
|
+
mod.instance_methods(false).each do |name|
|
21
|
+
set_priority(name)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
alias_method :method_added_without_priority, :method_added
|
27
|
+
def method_added(name)
|
28
|
+
method_added_without_priority(name)
|
29
|
+
set_priority(name) if defined?(@priority_initialized)
|
30
|
+
end
|
31
|
+
|
32
|
+
def priority(name, *tests)
|
33
|
+
singleton_class = (class << self; self; end)
|
34
|
+
priority_check_method = priority_check_method_name(name)
|
35
|
+
unless singleton_class.private_method_defined?(priority_check_method)
|
36
|
+
raise ArgumentError, "unknown priority: #{name}"
|
37
|
+
end
|
38
|
+
if tests.empty?
|
39
|
+
@current_priority = name
|
40
|
+
else
|
41
|
+
tests.each do |test|
|
42
|
+
set_priority(test, name)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def need_to_run?(test_name)
|
48
|
+
normalized_test_name = normalize_test_name(test_name)
|
49
|
+
priority = @priority_table[normalized_test_name]
|
50
|
+
return true unless priority
|
51
|
+
__send__(priority_check_method_name(priority), test_name)
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
def priority_check_method_name(priority_name)
|
56
|
+
"run_priority_#{priority_name}?"
|
57
|
+
end
|
58
|
+
|
59
|
+
def normalize_test_name(test_name)
|
60
|
+
"test_#{test_name.to_s.sub(/^test_/, '')}"
|
61
|
+
end
|
62
|
+
|
63
|
+
def set_priority(name, priority=@current_priority)
|
64
|
+
@priority_table[normalize_test_name(name)] = priority
|
65
|
+
end
|
66
|
+
|
67
|
+
def run_priority_must?(test_name)
|
68
|
+
true
|
69
|
+
end
|
70
|
+
|
71
|
+
def run_priority_important?(test_name)
|
72
|
+
rand > 0.1
|
73
|
+
end
|
74
|
+
|
75
|
+
def run_priority_high?(test_name)
|
76
|
+
rand > 0.3
|
77
|
+
end
|
78
|
+
|
79
|
+
def run_priority_normal?(test_name)
|
80
|
+
rand > 0.5
|
81
|
+
end
|
82
|
+
|
83
|
+
def run_priority_low?(test_name)
|
84
|
+
rand > 0.75
|
85
|
+
end
|
86
|
+
|
87
|
+
def run_priority_never?(test_name)
|
88
|
+
false
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def need_to_run?
|
93
|
+
!previous_test_success? or self.class.need_to_run?(@method_name)
|
94
|
+
end
|
95
|
+
|
96
|
+
alias_method :run_without_priority, :run
|
97
|
+
def run(result, &block)
|
98
|
+
run_without_priority(result, &block)
|
99
|
+
ensure
|
100
|
+
if passed?
|
101
|
+
FileUtils.touch(passed_file)
|
102
|
+
else
|
103
|
+
FileUtils.rm_f(passed_file)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
def previous_test_success?
|
109
|
+
File.exist?(passed_file)
|
110
|
+
end
|
111
|
+
|
112
|
+
def result_dir
|
113
|
+
components = [".test-result", self.class.name, @method_name.to_s]
|
114
|
+
dir = File.join(File.dirname($0), *components)
|
115
|
+
dir = File.expand_path(dir)
|
116
|
+
begin
|
117
|
+
FileUtils.mkdir_p(dir)
|
118
|
+
rescue Errno::EACCES
|
119
|
+
retry_dir = File.join(File.dirname(__FILE__), "..", *components)
|
120
|
+
retry_dir = File.expand_path(retry_dir)
|
121
|
+
raise if retry_dir == dir
|
122
|
+
dir = retry_dir
|
123
|
+
retry
|
124
|
+
end
|
125
|
+
dir
|
126
|
+
end
|
127
|
+
|
128
|
+
def passed_file
|
129
|
+
File.join(result_dir, "passed")
|
130
|
+
end
|
131
|
+
|
132
|
+
def escaped_method_name
|
133
|
+
@method_name.to_s.gsub(/[!?]$/) do |matched|
|
134
|
+
case matched
|
135
|
+
when "!"
|
136
|
+
".destructive"
|
137
|
+
when "?"
|
138
|
+
".predicate"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
class TestSuite
|
145
|
+
@@priority_mode = false
|
146
|
+
|
147
|
+
class << self
|
148
|
+
def priority_mode=(bool)
|
149
|
+
@@priority_mode = bool
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
alias_method :original_run, :run
|
154
|
+
def run(*args, &block)
|
155
|
+
priority_mode = @@priority_mode
|
156
|
+
if priority_mode
|
157
|
+
@original_tests = @tests
|
158
|
+
apply_priority
|
159
|
+
end
|
160
|
+
original_run(*args, &block)
|
161
|
+
ensure
|
162
|
+
@tests = @original_tests if priority_mode
|
163
|
+
end
|
164
|
+
|
165
|
+
def apply_priority
|
166
|
+
@tests = @tests.reject {|test| !test.need_to_run?}
|
167
|
+
end
|
168
|
+
|
169
|
+
def need_to_run?
|
170
|
+
apply_priority
|
171
|
+
!@tests.empty?
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
class AutoRunner
|
176
|
+
alias_method :options_without_priority, :options
|
177
|
+
def options
|
178
|
+
opts = options_without_priority
|
179
|
+
opts.on("--[no-]priority", "use priority mode") do |bool|
|
180
|
+
TestSuite.priority_mode = bool
|
181
|
+
end
|
182
|
+
opts
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
data/misc/rd2html.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
top = File.expand_path(File.join(File.dirname(__FILE__), ".."))
|
4
|
+
html_dir = File.join(top, "html")
|
5
|
+
|
6
|
+
require "fileutils"
|
7
|
+
|
8
|
+
css = "base.css"
|
9
|
+
kcode = "utf8"
|
10
|
+
|
11
|
+
options = [
|
12
|
+
"-I#{File.join(top, 'misc')}",
|
13
|
+
"-S",
|
14
|
+
"rd2",
|
15
|
+
"-rrd/rd2html-lib",
|
16
|
+
"--out-code=#{kcode}",
|
17
|
+
proc do |f|
|
18
|
+
"--html-title=#{File.basename(f)}"
|
19
|
+
end,
|
20
|
+
# proc do |f|
|
21
|
+
# "--with-css=#{css}"
|
22
|
+
# end,
|
23
|
+
proc do |f|
|
24
|
+
f
|
25
|
+
end
|
26
|
+
]
|
27
|
+
|
28
|
+
Dir[File.join(top, "*.{ja,en}")].each do |f|
|
29
|
+
if /(README|NEWS)\.(ja|en)\z/ =~ f
|
30
|
+
args = options.collect do |x|
|
31
|
+
if x.respond_to?(:call)
|
32
|
+
x.call(f)
|
33
|
+
else
|
34
|
+
x
|
35
|
+
end
|
36
|
+
end
|
37
|
+
output_base = File.basename(f).downcase.sub(/(ja|en)\z/, "html.\\1")
|
38
|
+
File.open(File.join(html_dir, output_base), "w") do |out|
|
39
|
+
out.puts(`ruby #{args.flatten.join(' ')}`)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/test/run-test.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift("./lib")
|
4
|
+
$LOAD_PATH.unshift("./test")
|
5
|
+
|
6
|
+
require "test-unit-ext"
|
7
|
+
|
8
|
+
Dir.glob("test/**/test_*.rb") do |test|
|
9
|
+
begin
|
10
|
+
require test
|
11
|
+
rescue LoadError
|
12
|
+
puts "Can't load: #{test}: #{$!.message}"
|
13
|
+
end
|
14
|
+
end
|
data/test/test_color.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'test-unit-ext'
|
2
|
+
|
3
|
+
class TestColor < Test::Unit::TestCase
|
4
|
+
def test_color_escape_sequence
|
5
|
+
assert_escape_sequence(["31"], color("red"))
|
6
|
+
assert_escape_sequence(["32", "1"], color("green", :bold => true))
|
7
|
+
assert_escape_sequence(["0"], color("reset"))
|
8
|
+
assert_escape_sequence(["45"], color("magenta", :foreground => false))
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_mix_color_escape_sequence
|
12
|
+
assert_escape_sequence(["34", "1"],
|
13
|
+
mix_color([color("blue"),
|
14
|
+
color("none", :bold => true)]))
|
15
|
+
assert_escape_sequence(["34", "1", "4"],
|
16
|
+
mix_color([color("blue"),
|
17
|
+
color("none", :bold => true)]) +
|
18
|
+
color("none", :underline => true))
|
19
|
+
assert_escape_sequence(["34", "1", "4"],
|
20
|
+
color("blue") +
|
21
|
+
color("none", :bold => true) +
|
22
|
+
color("none", :underline => true))
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
def color(name, options={})
|
27
|
+
Test::Color.new(name, options)
|
28
|
+
end
|
29
|
+
|
30
|
+
def mix_color(colors)
|
31
|
+
Test::MixColor.new(colors)
|
32
|
+
end
|
33
|
+
|
34
|
+
def assert_escape_sequence(expected, color)
|
35
|
+
assert_equal(expected, color.sequence)
|
36
|
+
assert_match(/\e\[(?:\d+;)*\d+m/, color.escape_sequence)
|
37
|
+
assert_equal(expected, color.escape_sequence[2..-2].split(";"))
|
38
|
+
end
|
39
|
+
end
|
data/test/test_diff.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'test-unit-ext'
|
2
|
+
|
3
|
+
class TestDiff < Test::Unit::TestCase
|
4
|
+
def test_to_indexes
|
5
|
+
assert_to_indexes({"abc def" => [0, 2], "abc" => [1]},
|
6
|
+
["abc def", "abc", "abc def"])
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_longest_match
|
10
|
+
assert_longest_match([0, 1, 3],
|
11
|
+
%w(b c d), %w(a b c d x y z),
|
12
|
+
0, 2, 0, 7)
|
13
|
+
assert_longest_match([1, 2, 2],
|
14
|
+
%w(b c d), %w(a b c d x y z),
|
15
|
+
1, 2, 0, 6)
|
16
|
+
assert_longest_match([0, 0, 0],
|
17
|
+
%w(a b), %w(c),
|
18
|
+
0, 1, 0, 0)
|
19
|
+
assert_longest_match([1, 0, 2],
|
20
|
+
%w(q a b x c d), %w(a b y c d f),
|
21
|
+
0, 5, 0, 5)
|
22
|
+
end
|
23
|
+
|
24
|
+
def _test_matching_blocks
|
25
|
+
assert_matching_blocks([[0, 0, 2],
|
26
|
+
[3, 2, 2],
|
27
|
+
[5, 4, 0]],
|
28
|
+
%w(a b x c d), %w(a b c d))
|
29
|
+
assert_matching_blocks([[1, 0, 2],
|
30
|
+
[4, 3, 2],
|
31
|
+
[6, 6, 0]],
|
32
|
+
%w(q a b x c d), %q(a b y c d f))
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_operations
|
36
|
+
assert_operations([[:delete, 0, 1, 0, 0],
|
37
|
+
[:equal, 1, 3, 0, 2],
|
38
|
+
[:replace, 3, 4, 2, 3],
|
39
|
+
[:equal, 4, 6, 3, 5],
|
40
|
+
[:insert, 6, 6, 5, 6]],
|
41
|
+
%w(q a b x c d), %w(a b y c d f))
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_same_contents
|
45
|
+
assert_ndiff(" aaa", ["aaa"], ["aaa"])
|
46
|
+
assert_ndiff(" aaa\n" \
|
47
|
+
" bbb",
|
48
|
+
["aaa", "bbb"], ["aaa", "bbb"])
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_deleted
|
52
|
+
assert_ndiff(" aaa\n" \
|
53
|
+
" bbb\n" \
|
54
|
+
"- bbb",
|
55
|
+
["aaa", "bbb"], ["aaa"])
|
56
|
+
assert_ndiff(" aaa\n" \
|
57
|
+
" bbb\n" \
|
58
|
+
"- bbb\n" \
|
59
|
+
"- ccc\n" \
|
60
|
+
"- ddd",
|
61
|
+
["aaa", "bbb", "ccc", "ddd"], ["aaa"])
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_format_diff_point
|
65
|
+
assert_format_diff_point(["- \tabcDefghiJkl",
|
66
|
+
"? \t ^ ^ ^",
|
67
|
+
"+ \t\tabcdefGhijkl",
|
68
|
+
"? \t ^ ^ ^"],
|
69
|
+
"\tabcDefghiJkl",
|
70
|
+
"\t\tabcdefGhijkl",
|
71
|
+
" ^ ^ ^ ",
|
72
|
+
"+ ^ ^ ^ ")
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
def assert_to_indexes(expected, to)
|
77
|
+
matcher = Test::Diff::SequenceMatcher.new([""], to)
|
78
|
+
assert_equal(expected, matcher.instance_variable_get("@to_indexes"))
|
79
|
+
end
|
80
|
+
|
81
|
+
def assert_longest_match(expected, from, to,
|
82
|
+
from_start, from_end,
|
83
|
+
to_start, to_end)
|
84
|
+
matcher = Test::Diff::SequenceMatcher.new(from, to)
|
85
|
+
assert_equal(expected, matcher.longest_match(from_start, from_end,
|
86
|
+
to_start, to_end))
|
87
|
+
end
|
88
|
+
|
89
|
+
def assert_matching_blocks(expected, from, to)
|
90
|
+
matcher = Test::Diff::SequenceMatcher.new(from, to)
|
91
|
+
assert_equal(expected, matcher.matching_blocks)
|
92
|
+
end
|
93
|
+
|
94
|
+
def assert_operations(expected, from, to)
|
95
|
+
matcher = Test::Diff::SequenceMatcher.new(from, to)
|
96
|
+
assert_equal(expected, matcher.operations)
|
97
|
+
end
|
98
|
+
|
99
|
+
def assert_ndiff(expected, from, to)
|
100
|
+
assert_equal(expected, Test::Diff.ndiff(from, to))
|
101
|
+
end
|
102
|
+
|
103
|
+
def assert_format_diff_point(expected, from_line, to_line, from_tags, to_tags)
|
104
|
+
differ = Test::Diff::Differ.new([""], [""])
|
105
|
+
assert_equal(expected, differ.send(:format_diff_point,
|
106
|
+
from_line, to_line,
|
107
|
+
from_tags, to_tags))
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'test-unit-ext'
|
2
|
+
|
3
|
+
class TestMetadata < Test::Unit::TestCase
|
4
|
+
class TestStack < Test::Unit::TestCase
|
5
|
+
class << self
|
6
|
+
def suite
|
7
|
+
Test::Unit::TestSuite.new(name)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Stack
|
12
|
+
def initialize
|
13
|
+
@data = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def push(data)
|
17
|
+
@data.push(data)
|
18
|
+
end
|
19
|
+
|
20
|
+
def peek
|
21
|
+
@data[-2]
|
22
|
+
end
|
23
|
+
|
24
|
+
def empty?
|
25
|
+
@data.empty?
|
26
|
+
end
|
27
|
+
|
28
|
+
def size
|
29
|
+
@data.size + 11
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def setup
|
34
|
+
@stack = Stack.new
|
35
|
+
end
|
36
|
+
|
37
|
+
metadata :category, :accessor
|
38
|
+
def test_peek
|
39
|
+
@stack.push(1)
|
40
|
+
@stack.push(2)
|
41
|
+
assert_equal(2, @stack.peek)
|
42
|
+
end
|
43
|
+
|
44
|
+
metadata :bug, 1234
|
45
|
+
def test_bug_1234
|
46
|
+
assert_equal(0, @stack.size)
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_no_metadata
|
50
|
+
assert(@stack.empty?)
|
51
|
+
@stack.push(1)
|
52
|
+
assert(!@stack.empty?)
|
53
|
+
assert_equal(1, @stack.size)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_set_metadata
|
58
|
+
test_for_bug_1234 = TestStack.new("test_bug_1234")
|
59
|
+
assert_equal({:bug => 1234}, test_for_bug_1234.metadata)
|
60
|
+
|
61
|
+
test_no_metadata = TestStack.new("test_no_metadata")
|
62
|
+
assert_equal({}, test_no_metadata.metadata)
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_show_metadata
|
66
|
+
assert_stack_size_line = search_line('assert_equal(0, @stack.size)')
|
67
|
+
assert_peek_line = search_line('assert_equal(2, @stack.peek)')
|
68
|
+
first_arg_end_line = search_line("\"<11>.\"],")
|
69
|
+
method_name = "test_show_metadata"
|
70
|
+
assert_result(["Failure:\n" \
|
71
|
+
"test_peek(TestMetadata::TestStack)\n" \
|
72
|
+
" category: accessor\n" \
|
73
|
+
"#{__FILE__}:#{assert_peek_line}:in `test_peek'\n" \
|
74
|
+
"#{__FILE__}:#{first_arg_end_line}:in `#{method_name}':\n" \
|
75
|
+
"<2> expected but was\n" \
|
76
|
+
"<1>.",
|
77
|
+
"Failure:\n" \
|
78
|
+
"test_bug_1234(TestMetadata::TestStack)\n" \
|
79
|
+
" bug: 1234\n" \
|
80
|
+
"#{__FILE__}:#{assert_stack_size_line}:in `test_bug_1234'\n" \
|
81
|
+
"#{__FILE__}:#{first_arg_end_line}:in `#{method_name}':\n" \
|
82
|
+
"<0> expected but was\n" \
|
83
|
+
"<11>."],
|
84
|
+
[],
|
85
|
+
["test_peek", "test_bug_1234"])
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_not_show_metadata
|
89
|
+
assert_line = search_line('assert_equal(1, @stack.size')
|
90
|
+
first_arg_end_line = search_line("\"<12>.\"],")
|
91
|
+
method_name = "test_not_show_metadata"
|
92
|
+
assert_result(["Failure:\n" \
|
93
|
+
"test_no_metadata(TestMetadata::TestStack)\n" \
|
94
|
+
"#{__FILE__}:#{assert_line}:in `test_no_metadata'\n" \
|
95
|
+
"#{__FILE__}:#{first_arg_end_line}:in `#{method_name}':\n" \
|
96
|
+
"<1> expected but was\n" \
|
97
|
+
"<12>."],
|
98
|
+
[],
|
99
|
+
["test_no_metadata"])
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
def search_line(pattern)
|
104
|
+
if pattern.is_a?(String)
|
105
|
+
pattern = /#{Regexp.escape(pattern)}/
|
106
|
+
end
|
107
|
+
File.open(__FILE__) do |file|
|
108
|
+
while line = file.gets
|
109
|
+
return file.lineno if pattern =~ line
|
110
|
+
end
|
111
|
+
end
|
112
|
+
nil
|
113
|
+
end
|
114
|
+
|
115
|
+
def assert_result(failure_results, error_results, names)
|
116
|
+
tests = names.collect {|name| TestStack.new(name)}
|
117
|
+
result = Test::Unit::TestResult.new
|
118
|
+
mark = /\A#{Regexp.escape(__FILE__)}:#{__LINE__ + 1}/
|
119
|
+
tests.each {|test| test.run(result) {}}
|
120
|
+
failures = result.instance_variable_get("@failures")
|
121
|
+
errors = result.instance_variable_get("@errors")
|
122
|
+
failures.each {|f| f.location.reject! {|l| mark =~ l}}
|
123
|
+
assert_equal([failure_results, error_results],
|
124
|
+
[failures.collect {|failure| failure.long_display},
|
125
|
+
errors.collect {|error| error.long_display}])
|
126
|
+
end
|
127
|
+
end
|