summaryrefslogtreecommitdiff
path: root/tool/lib
diff options
context:
space:
mode:
authorNobuyoshi Nakada <nobu@ruby-lang.org>2021-09-18 16:05:26 +0900
committerNobuyoshi Nakada <nobu@ruby-lang.org>2021-10-04 20:46:47 +0900
commitc4570acc86837fefa542a678dfdaba73cdd1fd03 (patch)
tree3727981f05a359b1fca4fb9df050b26f5c46ddf0 /tool/lib
parent44b2e32fb670e5e704f5721cf973cdc77d54a315 (diff)
Refactor ordering of tests
* Split the sorting types into classes. * Apply the same sorting to method sorting under the parallel test.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/4862
Diffstat (limited to 'tool/lib')
-rw-r--r--tool/lib/test/unit.rb113
-rw-r--r--tool/lib/test/unit/testcase.rb40
2 files changed, 96 insertions, 57 deletions
diff --git a/tool/lib/test/unit.rb b/tool/lib/test/unit.rb
index bfa1964963..5fbb8db1a9 100644
--- a/tool/lib/test/unit.rb
+++ b/tool/lib/test/unit.rb
@@ -57,6 +57,84 @@ module Test
class PendedError < AssertionFailedError; end
+ module Order
+ class NoSort
+ def initialize(seed)
+ end
+
+ def sort_by_name(list)
+ list
+ end
+
+ alias sort_by_string sort_by_name
+
+ def group(list)
+ # JIT first
+ jit, others = list.partition {|e| /test_jit/ =~ e}
+ jit + others
+ end
+ end
+
+ class Alpha < NoSort
+ def sort_by_name(list)
+ list.sort_by(&:name)
+ end
+
+ def sort_by_string(list)
+ list.sort
+ end
+
+ end
+
+ # shuffle test suites based on CRC32 of their names
+ Shuffle = Struct.new(:seed, :salt) do
+ def initialize(seed)
+ self.class::CRC_TBL ||= (0..255).map {|i|
+ (0..7).inject(i) {|c,| (c & 1 == 1) ? (0xEDB88320 ^ (c >> 1)) : (c >> 1) }
+ }.freeze
+
+ salt = [seed].pack("V").unpack1("H*")
+ super(seed, "\n#{salt}".freeze).freeze
+ end
+
+ def sort_by_name(list)
+ list.sort_by {|e| randomize_key(e.name)}
+ end
+
+ def sort_by_string(list)
+ list.sort_by {|e| randomize_key(e)}
+ end
+
+ def group(list)
+ list
+ end
+
+ private
+
+ def crc32(str, crc32 = 0xffffffff)
+ crc_tbl = self.class::CRC_TBL
+ str.each_byte do |data|
+ crc32 = crc_tbl[(crc32 ^ data) & 0xff] ^ (crc32 >> 8)
+ end
+ crc32
+ end
+
+ def randomize_key(name)
+ crc32(salt, crc32(name)) ^ 0xffffffff
+ end
+ end
+
+ Types = {
+ random: Shuffle,
+ alpha: Alpha,
+ sorted: Alpha,
+ nosort: NoSort,
+ }
+ Types.default_proc = proc {|_, order|
+ raise "Unknown test_order: #{order.inspect}"
+ }
+ end
+
module RunCount # :nodoc: all
@@run_count = 0
@@ -103,13 +181,13 @@ module Test
order = options[:test_order]
if seed = options[:seed]
order ||= :random
- srand(seed)
- else
- seed = options[:seed] = srand % 100_000
- srand(seed)
+ elsif order == :random
+ seed = options[:seed] = rand(0x10000)
orig_args.unshift "--seed=#{seed}"
end
Test::Unit::TestCase.test_order = order if order
+ order = Test::Unit::TestCase.test_order
+ @order = Test::Unit::Order::Types[order].new(seed)
@help = "\n" + orig_args.map { |s|
" " + (s =~ /[\s|&<>$()]/ ? s.inspect : s)
@@ -139,7 +217,8 @@ module Test
(options[:filter] ||= []) << a
end
- opts.on '--test-order=random|alpha|sorted|nosort', [:random, :alpha, :sorted, :nosort] do |a|
+ orders = Test::Unit::Order::Types.keys
+ opts.on "--test-order=#{orders.join('|')}", orders do |a|
options[:test_order] = a
end
end
@@ -545,16 +624,7 @@ module Test
# Require needed thing for parallel running
require 'timeout'
- @tasks = @files.dup # Array of filenames.
-
- case Test::Unit::TestCase.test_order
- when :random
- @tasks.shuffle!
- else
- # JIT first
- ts = @tasks.group_by{|e| /test_jit/ =~ e ? 0 : 1}
- @tasks = ts[0] + ts[1] if ts.size == 2
- end
+ @tasks = @order.group(@order.sort_by_string(@files)) # Array of filenames.
@need_quit = false
@dead_workers = [] # Array of dead workers.
@@ -1302,6 +1372,8 @@ module Test
suites = Test::Unit::TestCase.send "#{type}_suites"
return if suites.empty?
+ suites = @order.sort_by_name(suites)
+
puts
puts "# Running #{type}s:"
puts
@@ -1356,6 +1428,12 @@ module Test
filter = options[:filter]
all_test_methods = suite.send "#{type}_methods"
+ if filter
+ all_test_methods.select! {|method|
+ filter === method || filter === "#{suite}##{method}"
+ }
+ end
+ all_test_methods = @order.sort_by_name(all_test_methods)
leakchecker = LeakChecker.new
if ENV["LEAK_CHECKER_TRACE_OBJECT_ALLOCATION"]
@@ -1363,10 +1441,7 @@ module Test
trace = true
end
- assertions = all_test_methods.filter_map { |method|
- if filter
- next unless filter === method || filter === "#{suite}##{method}"
- end
+ assertions = all_test_methods.map { |method|
inst = suite.new method
inst._assertions = 0
diff --git a/tool/lib/test/unit/testcase.rb b/tool/lib/test/unit/testcase.rb
index 241421d6d9..4cc1aae3e4 100644
--- a/tool/lib/test/unit/testcase.rb
+++ b/tool/lib/test/unit/testcase.rb
@@ -159,7 +159,6 @@ module Test
start_time = Time.now
result = ""
- srand(runner.options[:seed])
begin
@passed = nil
@@ -267,46 +266,11 @@ module Test
end
def self.test_suites # :nodoc:
- suites = @@test_suites.keys
-
- case self.test_order
- when :random
- # shuffle test suites based on CRC32 of their names
- salt = "\n" + rand(1 << 32).to_s
- crc_tbl = (0..255).map do |i|
- (0..7).inject(i) {|c,| (c & 1 == 1) ? (0xEDB88320 ^ (c >> 1)) : (c >> 1) }
- end
- suites = suites.sort_by do |suite|
- crc32 = 0xffffffff
- "#{suite.name}#{salt}".each_byte do |data|
- crc32 = crc_tbl[(crc32 ^ data) & 0xff] ^ (crc32 >> 8)
- end
- crc32 ^ 0xffffffff
- end
- when :nosort
- suites
- else
- suites.sort_by { |ts| ts.name.to_s }
- end
+ @@test_suites.keys
end
def self.test_methods # :nodoc:
- methods = public_instance_methods(true).grep(/^test/).map { |m| m.to_s }
-
- case self.test_order
- when :parallel
- max = methods.size
- ParallelEach.new methods.sort.sort_by { rand max }
- when :random then
- max = methods.size
- methods.sort.sort_by { rand max }
- when :alpha, :sorted then
- methods.sort
- when :nosort
- methods
- else
- raise "Unknown test_order: #{self.test_order.inspect}"
- end
+ public_instance_methods(true).grep(/^test/)
end
##