piko-max-mod 0.0.1
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.
- checksums.yaml +7 -0
- data/piko-max-mod.gemspec +12 -0
- data/test-unit-3.7.8/BSDL +24 -0
- data/test-unit-3.7.8/COPYING +64 -0
- data/test-unit-3.7.8/PSFL +271 -0
- data/test-unit-3.7.8/README.md +108 -0
- data/test-unit-3.7.8/Rakefile +74 -0
- data/test-unit-3.7.8/bin/test-unit +5 -0
- data/test-unit-3.7.8/doc/text/getting-started.md +120 -0
- data/test-unit-3.7.8/doc/text/how-to.md +90 -0
- data/test-unit-3.7.8/doc/text/news.md +2070 -0
- data/test-unit-3.7.8/lib/test/unit/assertion-failed-error.rb +60 -0
- data/test-unit-3.7.8/lib/test/unit/assertions.rb +2536 -0
- data/test-unit-3.7.8/lib/test/unit/attribute-matcher.rb +26 -0
- data/test-unit-3.7.8/lib/test/unit/attribute.rb +228 -0
- data/test-unit-3.7.8/lib/test/unit/auto-runner-loader.rb +17 -0
- data/test-unit-3.7.8/lib/test/unit/autorunner.rb +654 -0
- data/test-unit-3.7.8/lib/test/unit/code-snippet-fetcher.rb +58 -0
- data/test-unit-3.7.8/lib/test/unit/collector/descendant.rb +20 -0
- data/test-unit-3.7.8/lib/test/unit/collector/dir.rb +110 -0
- data/test-unit-3.7.8/lib/test/unit/collector/load.rb +201 -0
- data/test-unit-3.7.8/lib/test/unit/collector/objectspace.rb +35 -0
- data/test-unit-3.7.8/lib/test/unit/collector/xml.rb +249 -0
- data/test-unit-3.7.8/lib/test/unit/collector.rb +104 -0
- data/test-unit-3.7.8/lib/test/unit/color-scheme.rb +225 -0
- data/test-unit-3.7.8/lib/test/unit/color.rb +134 -0
- data/test-unit-3.7.8/lib/test/unit/data-sets.rb +127 -0
- data/test-unit-3.7.8/lib/test/unit/data.rb +371 -0
- data/test-unit-3.7.8/lib/test/unit/diff.rb +745 -0
- data/test-unit-3.7.8/lib/test/unit/error.rb +158 -0
- data/test-unit-3.7.8/lib/test/unit/exception-handler.rb +82 -0
- data/test-unit-3.7.8/lib/test/unit/failure.rb +169 -0
- data/test-unit-3.7.8/lib/test/unit/fault-location-detector.rb +104 -0
- data/test-unit-3.7.8/lib/test/unit/fixture.rb +304 -0
- data/test-unit-3.7.8/lib/test/unit/notification.rb +138 -0
- data/test-unit-3.7.8/lib/test/unit/omission.rb +198 -0
- data/test-unit-3.7.8/lib/test/unit/pending.rb +155 -0
- data/test-unit-3.7.8/lib/test/unit/priority.rb +194 -0
- data/test-unit-3.7.8/lib/test/unit/process-test-result.rb +55 -0
- data/test-unit-3.7.8/lib/test/unit/process-worker.rb +87 -0
- data/test-unit-3.7.8/lib/test/unit/runner/console.rb +86 -0
- data/test-unit-3.7.8/lib/test/unit/runner/emacs.rb +8 -0
- data/test-unit-3.7.8/lib/test/unit/runner/xml.rb +15 -0
- data/test-unit-3.7.8/lib/test/unit/sub-test-result.rb +59 -0
- data/test-unit-3.7.8/lib/test/unit/test-process-run-context.rb +21 -0
- data/test-unit-3.7.8/lib/test/unit/test-run-context.rb +16 -0
- data/test-unit-3.7.8/lib/test/unit/test-suite-creator.rb +103 -0
- data/test-unit-3.7.8/lib/test/unit/test-suite-process-runner.rb +205 -0
- data/test-unit-3.7.8/lib/test/unit/test-suite-runner.rb +132 -0
- data/test-unit-3.7.8/lib/test/unit/test-suite-thread-runner.rb +96 -0
- data/test-unit-3.7.8/lib/test/unit/test-thread-run-context.rb +23 -0
- data/test-unit-3.7.8/lib/test/unit/testcase.rb +1058 -0
- data/test-unit-3.7.8/lib/test/unit/testresult.rb +132 -0
- data/test-unit-3.7.8/lib/test/unit/testsuite.rb +133 -0
- data/test-unit-3.7.8/lib/test/unit/ui/console/outputlevel.rb +15 -0
- data/test-unit-3.7.8/lib/test/unit/ui/console/testrunner.rb +891 -0
- data/test-unit-3.7.8/lib/test/unit/ui/emacs/testrunner.rb +49 -0
- data/test-unit-3.7.8/lib/test/unit/ui/testrunner.rb +53 -0
- data/test-unit-3.7.8/lib/test/unit/ui/testrunnermediator.rb +131 -0
- data/test-unit-3.7.8/lib/test/unit/ui/testrunnerutilities.rb +41 -0
- data/test-unit-3.7.8/lib/test/unit/ui/xml/testrunner.rb +225 -0
- data/test-unit-3.7.8/lib/test/unit/util/backtracefilter.rb +65 -0
- data/test-unit-3.7.8/lib/test/unit/util/memory-usage.rb +47 -0
- data/test-unit-3.7.8/lib/test/unit/util/method-owner-finder.rb +28 -0
- data/test-unit-3.7.8/lib/test/unit/util/observable.rb +86 -0
- data/test-unit-3.7.8/lib/test/unit/util/output.rb +32 -0
- data/test-unit-3.7.8/lib/test/unit/util/procwrapper.rb +48 -0
- data/test-unit-3.7.8/lib/test/unit/version.rb +5 -0
- data/test-unit-3.7.8/lib/test/unit/warning.rb +3 -0
- data/test-unit-3.7.8/lib/test/unit/worker-context.rb +20 -0
- data/test-unit-3.7.8/lib/test/unit.rb +521 -0
- data/test-unit-3.7.8/lib/test-unit.rb +19 -0
- data/test-unit-3.7.8/sample/adder.rb +13 -0
- data/test-unit-3.7.8/sample/subtracter.rb +12 -0
- data/test-unit-3.7.8/sample/test_adder.rb +20 -0
- data/test-unit-3.7.8/sample/test_subtracter.rb +20 -0
- data/test-unit-3.7.8/sample/test_user.rb +23 -0
- metadata +117 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#--
|
|
2
|
+
#
|
|
3
|
+
# Author:: Kouhei Sutou
|
|
4
|
+
# Copyright::
|
|
5
|
+
# * Copyright (c) 2011 Kouhei Sutou <tt><kou@clear-code.com></tt>
|
|
6
|
+
# License:: Ruby license.
|
|
7
|
+
|
|
8
|
+
require_relative "data-sets"
|
|
9
|
+
|
|
10
|
+
module Test
|
|
11
|
+
module Unit
|
|
12
|
+
class TestSuiteCreator # :nodoc:
|
|
13
|
+
class << self
|
|
14
|
+
def test_method?(test_case, method_name)
|
|
15
|
+
/\Atest./ =~ method_name.to_s or
|
|
16
|
+
test_case.find_attribute(method_name, :test)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def initialize(test_case)
|
|
21
|
+
@test_case = test_case
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def create
|
|
25
|
+
suite = TestSuite.new(@test_case.name, @test_case)
|
|
26
|
+
collect_test_names.each do |test_name|
|
|
27
|
+
data_sets = extract_data_sets(test_name)
|
|
28
|
+
if data_sets
|
|
29
|
+
data_sets.each do |label, data|
|
|
30
|
+
append_test(suite, test_name) do |test|
|
|
31
|
+
test.assign_test_data(label, data)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
else
|
|
35
|
+
append_test(suite, test_name)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
append_test(suite, "default_test") if suite.empty?
|
|
39
|
+
suite
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
def extract_data_sets(test_name)
|
|
44
|
+
data_sets = @test_case.find_attribute(test_name,
|
|
45
|
+
:data,
|
|
46
|
+
:recursive => false)
|
|
47
|
+
data_method_name = "data_#{test_name}"
|
|
48
|
+
test = @test_case.new(test_name)
|
|
49
|
+
if test.respond_to?(data_method_name)
|
|
50
|
+
data_method = test.method(data_method_name)
|
|
51
|
+
if data_method.arity <= 0
|
|
52
|
+
data_sets ||= DataSets.new
|
|
53
|
+
data_sets << data_method
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
data_sets
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def append_test(suite, test_name)
|
|
60
|
+
test = @test_case.new(test_name)
|
|
61
|
+
yield(test) if block_given?
|
|
62
|
+
suite << test if test.valid?
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def collect_test_names
|
|
66
|
+
methods = @test_case.public_instance_methods(true)
|
|
67
|
+
super_test_case = @test_case.superclass
|
|
68
|
+
methods -= super_test_case.public_instance_methods(true)
|
|
69
|
+
methods |= @test_case.public_instance_methods(false)
|
|
70
|
+
method_names = methods.collect(&:to_s)
|
|
71
|
+
test_names = method_names.find_all do |method_name|
|
|
72
|
+
self.class.test_method?(@test_case, method_name)
|
|
73
|
+
end
|
|
74
|
+
__send__("sort_test_names_in_#{@test_case.test_order}_order", test_names)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def sort_test_names_in_alphabetic_order(test_names)
|
|
78
|
+
test_names.sort
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def sort_test_names_in_random_order(test_names)
|
|
82
|
+
test_names.sort_by {rand(test_names.size)}
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def sort_test_names_in_defined_order(test_names)
|
|
86
|
+
added_method_names = @test_case.added_method_names
|
|
87
|
+
test_names.sort do |test1, test2|
|
|
88
|
+
test1_defined_order = added_method_names.index(test1)
|
|
89
|
+
test2_defined_order = added_method_names.index(test2)
|
|
90
|
+
if test1_defined_order and test2_defined_order
|
|
91
|
+
test1_defined_order <=> test2_defined_order
|
|
92
|
+
elsif test1_defined_order
|
|
93
|
+
1
|
|
94
|
+
elsif test2_defined_order
|
|
95
|
+
-1
|
|
96
|
+
else
|
|
97
|
+
test1 <=> test2
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
#--
|
|
2
|
+
#
|
|
3
|
+
# Author:: Tsutomu Katsube.
|
|
4
|
+
# Copyright:: Copyright (c) 2025 Tsutomu Katsube. All rights reserved.
|
|
5
|
+
# License:: Ruby license.
|
|
6
|
+
|
|
7
|
+
require "socket"
|
|
8
|
+
|
|
9
|
+
require_relative "process-test-result"
|
|
10
|
+
require_relative "sub-test-result"
|
|
11
|
+
require_relative "test-process-run-context"
|
|
12
|
+
require_relative "test-suite-runner"
|
|
13
|
+
|
|
14
|
+
module Test
|
|
15
|
+
module Unit
|
|
16
|
+
class TestSuiteProcessRunner < TestSuiteRunner
|
|
17
|
+
MAIN_TO_WORKER_INPUT_FILENO = 3
|
|
18
|
+
WORKER_TO_MAIN_OUTPUT_FILENO = 4
|
|
19
|
+
|
|
20
|
+
class << self
|
|
21
|
+
class Worker
|
|
22
|
+
attr_reader :main_to_worker_output, :worker_to_main_input
|
|
23
|
+
def initialize(pid, main_to_worker_output, worker_to_main_input)
|
|
24
|
+
@pid = pid
|
|
25
|
+
@main_to_worker_output = main_to_worker_output
|
|
26
|
+
@worker_to_main_input = worker_to_main_input
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def receive
|
|
30
|
+
Marshal.load(@worker_to_main_input)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def send(data)
|
|
34
|
+
Marshal.dump(data, @main_to_worker_output)
|
|
35
|
+
@main_to_worker_output.flush
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def wait
|
|
39
|
+
begin
|
|
40
|
+
Process.waitpid(@pid)
|
|
41
|
+
ensure
|
|
42
|
+
begin
|
|
43
|
+
@main_to_worker_output.close
|
|
44
|
+
ensure
|
|
45
|
+
@worker_to_main_input.close
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def run_all_tests(result, options)
|
|
52
|
+
n_workers = TestSuiteRunner.n_workers
|
|
53
|
+
test_suite = options[:test_suite]
|
|
54
|
+
|
|
55
|
+
start_tcp_server do |tcp_server|
|
|
56
|
+
workers = []
|
|
57
|
+
begin
|
|
58
|
+
n_workers.times do |i|
|
|
59
|
+
load_paths = options[:load_paths]
|
|
60
|
+
base_directory = options[:base_directory]
|
|
61
|
+
test_paths = options[:test_paths]
|
|
62
|
+
command_line = [Gem.ruby, File.join(__dir__, "process-worker.rb")]
|
|
63
|
+
load_paths.each do |load_path|
|
|
64
|
+
command_line << "--load-path" << load_path
|
|
65
|
+
end
|
|
66
|
+
unless base_directory.nil?
|
|
67
|
+
command_line << "--base-directory" << base_directory
|
|
68
|
+
end
|
|
69
|
+
command_line << "--worker-id" << (i + 1).to_s
|
|
70
|
+
if Gem.win_platform?
|
|
71
|
+
local_address = tcp_server.local_address
|
|
72
|
+
command_line << "--ip-address" << local_address.ip_address
|
|
73
|
+
command_line << "--ip-port" << local_address.ip_port.to_s
|
|
74
|
+
end
|
|
75
|
+
command_line.concat(test_paths)
|
|
76
|
+
if Gem.win_platform?
|
|
77
|
+
# On Windows, file descriptors 3 and above cannot be passed to
|
|
78
|
+
# child processes.
|
|
79
|
+
pid = spawn(*command_line)
|
|
80
|
+
# They are replaced later. This is just for ensuring calling
|
|
81
|
+
# `Process.waitpid(pid)` on error.
|
|
82
|
+
workers << Worker.new(pid, nil, nil)
|
|
83
|
+
else
|
|
84
|
+
main_to_worker_input, main_to_worker_output = IO.pipe
|
|
85
|
+
worker_to_main_input, worker_to_main_output = IO.pipe
|
|
86
|
+
pid = spawn(*command_line, {MAIN_TO_WORKER_INPUT_FILENO => main_to_worker_input,
|
|
87
|
+
WORKER_TO_MAIN_OUTPUT_FILENO => worker_to_main_output})
|
|
88
|
+
main_to_worker_input.close
|
|
89
|
+
worker_to_main_output.close
|
|
90
|
+
workers << Worker.new(pid, main_to_worker_output, worker_to_main_input)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
if Gem.win_platform?
|
|
94
|
+
workers = workers.collect do
|
|
95
|
+
data_socket = tcp_server.accept
|
|
96
|
+
pid = Marshal.load(data_socket)
|
|
97
|
+
Worker.new(pid, data_socket, data_socket)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
run_context = TestProcessRunContext.new(self)
|
|
102
|
+
yield(run_context)
|
|
103
|
+
run_context.progress_block.call(TestSuite::STARTED, test_suite.name)
|
|
104
|
+
run_context.progress_block.call(TestSuite::STARTED_OBJECT, test_suite)
|
|
105
|
+
|
|
106
|
+
worker_inputs = workers.collect(&:worker_to_main_input)
|
|
107
|
+
until run_context.test_names.empty? do
|
|
108
|
+
select_each_worker(worker_inputs, workers) do |_, worker, data|
|
|
109
|
+
case data[:status]
|
|
110
|
+
when :ready
|
|
111
|
+
test_name = run_context.test_names.shift
|
|
112
|
+
break if test_name.nil?
|
|
113
|
+
worker.send(test_name)
|
|
114
|
+
when :result
|
|
115
|
+
add_result(result, data)
|
|
116
|
+
when :event
|
|
117
|
+
emit_event(options[:event_listener], data)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
workers.each do |worker|
|
|
122
|
+
worker.send(nil)
|
|
123
|
+
end
|
|
124
|
+
until worker_inputs.empty? do
|
|
125
|
+
select_each_worker(worker_inputs, workers) do |worker_to_main_input, worker, data|
|
|
126
|
+
case data[:status]
|
|
127
|
+
when :result
|
|
128
|
+
add_result(result, data)
|
|
129
|
+
when :event
|
|
130
|
+
emit_event(options[:event_listener], data)
|
|
131
|
+
when :done
|
|
132
|
+
worker_inputs.delete(worker_to_main_input)
|
|
133
|
+
worker.send(nil)
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
ensure
|
|
138
|
+
workers.each do |worker|
|
|
139
|
+
worker.wait
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
run_context.progress_block.call(TestSuite::FINISHED, test_suite.name)
|
|
144
|
+
run_context.progress_block.call(TestSuite::FINISHED_OBJECT, test_suite)
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
private
|
|
149
|
+
def start_tcp_server
|
|
150
|
+
if Gem.win_platform?
|
|
151
|
+
TCPServer.open("127.0.0.1", 0) do |tcp_server|
|
|
152
|
+
yield(tcp_server)
|
|
153
|
+
end
|
|
154
|
+
else
|
|
155
|
+
yield
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def select_each_worker(worker_inputs, workers)
|
|
160
|
+
readables, = IO.select(worker_inputs)
|
|
161
|
+
readables.each do |worker_to_main_input|
|
|
162
|
+
worker = workers.find do |w|
|
|
163
|
+
w.worker_to_main_input == worker_to_main_input
|
|
164
|
+
end
|
|
165
|
+
data = worker.receive
|
|
166
|
+
yield(worker_to_main_input, worker, data)
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def add_result(result, data)
|
|
171
|
+
action = data[:action]
|
|
172
|
+
args = data[:args]
|
|
173
|
+
result.__send__(action, *args)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def emit_event(event_listener, data)
|
|
177
|
+
event_name = data[:event_name]
|
|
178
|
+
args = data[:args]
|
|
179
|
+
event_listener.call(event_name, *args)
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def run(worker_context, &progress_block)
|
|
184
|
+
worker_context.run_context.progress_block = progress_block
|
|
185
|
+
run_tests_recursive(@test_suite, worker_context, &progress_block)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
private
|
|
189
|
+
def run_tests_recursive(test_suite, worker_context, &progress_block)
|
|
190
|
+
run_context = worker_context.run_context
|
|
191
|
+
if test_suite.have_fixture?
|
|
192
|
+
run_context.test_names << test_suite.name
|
|
193
|
+
else
|
|
194
|
+
test_suite.tests.each do |test|
|
|
195
|
+
if test.is_a?(TestSuite)
|
|
196
|
+
run_tests_recursive(test, worker_context, &progress_block)
|
|
197
|
+
else
|
|
198
|
+
run_context.test_names << test.name
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#--
|
|
2
|
+
#
|
|
3
|
+
# Author:: Nathaniel Talbott.
|
|
4
|
+
# Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved.
|
|
5
|
+
# Copyright:: Copyright (c) 2008-2011 Kouhei Sutou. All rights reserved.
|
|
6
|
+
# Copyright:: Copyright (c) 2024-2025 Tsutomu Katsube. All rights reserved.
|
|
7
|
+
# License:: Ruby license.
|
|
8
|
+
|
|
9
|
+
require "etc"
|
|
10
|
+
|
|
11
|
+
require_relative "test-run-context"
|
|
12
|
+
|
|
13
|
+
module Test
|
|
14
|
+
module Unit
|
|
15
|
+
class TestSuiteRunner
|
|
16
|
+
@n_workers = Etc.respond_to?(:nprocessors) ? Etc.nprocessors : 1
|
|
17
|
+
class << self
|
|
18
|
+
def run_all_tests(result, options)
|
|
19
|
+
yield(TestRunContext.new(self))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def n_workers
|
|
23
|
+
@n_workers
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def n_workers=(n)
|
|
27
|
+
@n_workers = n
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def initialize(test_suite)
|
|
32
|
+
@test_suite = test_suite
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def run(worker_context, &progress_block)
|
|
36
|
+
yield(TestSuite::STARTED, @test_suite.name)
|
|
37
|
+
yield(TestSuite::STARTED_OBJECT, @test_suite)
|
|
38
|
+
run_startup(worker_context)
|
|
39
|
+
run_tests(worker_context, &progress_block)
|
|
40
|
+
ensure
|
|
41
|
+
begin
|
|
42
|
+
run_shutdown(worker_context)
|
|
43
|
+
ensure
|
|
44
|
+
yield(TestSuite::FINISHED, @test_suite.name)
|
|
45
|
+
yield(TestSuite::FINISHED_OBJECT, @test_suite)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
def run_startup(worker_context)
|
|
51
|
+
test_case = @test_suite.test_case
|
|
52
|
+
return if test_case.nil? or !test_case.respond_to?(:startup)
|
|
53
|
+
test_case.worker_id = worker_context.id
|
|
54
|
+
begin
|
|
55
|
+
test_case.startup
|
|
56
|
+
rescue Exception => e
|
|
57
|
+
raise unless handle_exception(e, worker_context.result)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def run_tests(worker_context, &progress_block)
|
|
62
|
+
@test_suite.tests.each do |test|
|
|
63
|
+
run_test(test, worker_context, &progress_block)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def run_test(test, worker_context)
|
|
68
|
+
finished_is_yielded = false
|
|
69
|
+
finished_object_is_yielded = false
|
|
70
|
+
previous_event_name = nil
|
|
71
|
+
event_listener = lambda do |event_name, *args|
|
|
72
|
+
case previous_event_name
|
|
73
|
+
when Test::Unit::TestCase::STARTED
|
|
74
|
+
if event_name != Test::Unit::TestCase::STARTED_OBJECT
|
|
75
|
+
yield(Test::Unit::TestCase::STARTED_OBJECT, test)
|
|
76
|
+
end
|
|
77
|
+
when Test::Unit::TestCase::FINISHED
|
|
78
|
+
if event_name != Test::Unit::TestCase::FINISHED_OBJECT
|
|
79
|
+
yield(Test::Unit::TestCase::FINISHED_OBJECT, test)
|
|
80
|
+
end
|
|
81
|
+
finished_object_is_yielded = true
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
case event_name
|
|
85
|
+
when Test::Unit::TestCase::STARTED
|
|
86
|
+
finished_is_yielded = false
|
|
87
|
+
finished_object_is_yielded = false
|
|
88
|
+
when Test::Unit::TestCase::FINISHED
|
|
89
|
+
finished_is_yielded = true
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
previous_event_name = event_name
|
|
93
|
+
yield(event_name, *args)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
if test.method(:run).parameters[0] == [:req, :worker_context]
|
|
97
|
+
test.run(worker_context, &event_listener)
|
|
98
|
+
else
|
|
99
|
+
# For backward compatibility. There are scripts that overrides
|
|
100
|
+
# Test::Unit::TestCase#run without keyword arguments.
|
|
101
|
+
test.run(worker_context.result, &event_listener)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
if finished_is_yielded and not finished_object_is_yielded
|
|
105
|
+
yield(Test::Unit::TestCase::FINISHED_OBJECT, test)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def run_shutdown(worker_context)
|
|
110
|
+
test_case = @test_suite.test_case
|
|
111
|
+
return if test_case.nil? or !test_case.respond_to?(:shutdown)
|
|
112
|
+
test_case.worker_id = worker_context.id
|
|
113
|
+
begin
|
|
114
|
+
test_case.shutdown
|
|
115
|
+
rescue Exception => e
|
|
116
|
+
raise unless handle_exception(e, worker_context.result)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def handle_exception(exception, result)
|
|
121
|
+
case exception
|
|
122
|
+
when *ErrorHandler::PASS_THROUGH_EXCEPTIONS
|
|
123
|
+
false
|
|
124
|
+
else
|
|
125
|
+
result.add_error(Error.new(@test_suite.test_case.name, exception))
|
|
126
|
+
true
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#--
|
|
2
|
+
#
|
|
3
|
+
# Author:: Tsutomu Katsube.
|
|
4
|
+
# Copyright:: Copyright (c) 2024-2025 Tsutomu Katsube. All rights reserved.
|
|
5
|
+
# License:: Ruby license.
|
|
6
|
+
|
|
7
|
+
require_relative "sub-test-result"
|
|
8
|
+
require_relative "test-suite-runner"
|
|
9
|
+
require_relative "test-thread-run-context"
|
|
10
|
+
|
|
11
|
+
module Test
|
|
12
|
+
module Unit
|
|
13
|
+
class TestSuiteThreadRunner < TestSuiteRunner
|
|
14
|
+
class << self
|
|
15
|
+
def run_all_tests(result, options)
|
|
16
|
+
n_workers = TestSuiteRunner.n_workers
|
|
17
|
+
test_suite = options[:test_suite]
|
|
18
|
+
|
|
19
|
+
queue = Thread::Queue.new
|
|
20
|
+
run_context = TestThreadRunContext.new(self, queue)
|
|
21
|
+
yield(run_context)
|
|
22
|
+
run_context.progress_block.call(TestSuite::STARTED, test_suite.name)
|
|
23
|
+
run_context.progress_block.call(TestSuite::STARTED_OBJECT, test_suite)
|
|
24
|
+
run_context.parallel_unsafe_tests.each(&:call)
|
|
25
|
+
n_workers.times do
|
|
26
|
+
queue << nil
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
workers = []
|
|
30
|
+
sub_exceptions = []
|
|
31
|
+
n_workers.times do |i|
|
|
32
|
+
workers << Thread.new(i + 1) do |worker_id|
|
|
33
|
+
begin
|
|
34
|
+
loop do
|
|
35
|
+
task = queue.pop
|
|
36
|
+
break if task.nil?
|
|
37
|
+
catch do |stop_tag|
|
|
38
|
+
task.call(stop_tag, worker_id)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
rescue Exception => exception
|
|
42
|
+
sub_exceptions << exception
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
workers.each(&:join)
|
|
47
|
+
|
|
48
|
+
run_context.progress_block.call(TestSuite::FINISHED, test_suite.name)
|
|
49
|
+
run_context.progress_block.call(TestSuite::FINISHED_OBJECT, test_suite)
|
|
50
|
+
|
|
51
|
+
sub_exceptions.each do |exception|
|
|
52
|
+
raise exception
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def run(worker_context, &progress_block)
|
|
58
|
+
worker_context.run_context.progress_block = progress_block
|
|
59
|
+
run_tests_recursive(@test_suite, worker_context, &progress_block)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
def run_tests_recursive(test_suite, worker_context, &progress_block)
|
|
64
|
+
run_context = worker_context.run_context
|
|
65
|
+
if test_suite.have_fixture?
|
|
66
|
+
task = lambda do |stop_tag, worker_id|
|
|
67
|
+
sub_result = SubTestResult.new(worker_context.result)
|
|
68
|
+
sub_result.stop_tag = stop_tag
|
|
69
|
+
sub_runner = TestSuiteRunner.new(test_suite)
|
|
70
|
+
sub_worker_context = WorkerContext.new(worker_id, run_context, sub_result)
|
|
71
|
+
sub_runner.run(sub_worker_context, &progress_block)
|
|
72
|
+
end
|
|
73
|
+
run_context.queue << task
|
|
74
|
+
else
|
|
75
|
+
test_suite.tests.each do |test|
|
|
76
|
+
if test.is_a?(TestSuite)
|
|
77
|
+
run_tests_recursive(test, worker_context, &progress_block)
|
|
78
|
+
elsif test_suite.parallel_safe?
|
|
79
|
+
task = lambda do |stop_tag, worker_id|
|
|
80
|
+
sub_result = SubTestResult.new(worker_context.result)
|
|
81
|
+
sub_result.stop_tag = stop_tag
|
|
82
|
+
sub_worker_context = WorkerContext.new(worker_id, run_context, sub_result)
|
|
83
|
+
run_test(test, sub_worker_context, &progress_block)
|
|
84
|
+
end
|
|
85
|
+
run_context.queue << task
|
|
86
|
+
else
|
|
87
|
+
run_context.parallel_unsafe_tests << lambda do
|
|
88
|
+
run_test(test, worker_context, &progress_block)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#--
|
|
2
|
+
#
|
|
3
|
+
# Author:: Tsutomu Katsube.
|
|
4
|
+
# Copyright:: Copyright (c) 2025 Tsutomu Katsube. All rights reserved.
|
|
5
|
+
# License:: Ruby license.
|
|
6
|
+
|
|
7
|
+
require_relative "test-run-context"
|
|
8
|
+
|
|
9
|
+
module Test
|
|
10
|
+
module Unit
|
|
11
|
+
class TestThreadRunContext < TestRunContext
|
|
12
|
+
attr_reader :queue
|
|
13
|
+
attr_accessor :progress_block
|
|
14
|
+
attr_accessor :parallel_unsafe_tests
|
|
15
|
+
def initialize(runner_class, queue)
|
|
16
|
+
super(runner_class)
|
|
17
|
+
@queue = queue
|
|
18
|
+
@progress_block = nil
|
|
19
|
+
@parallel_unsafe_tests = []
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|