diff options
author | Nobuyoshi Nakada <[email protected]> | 2021-09-18 16:05:26 +0900 |
---|---|---|
committer | Nobuyoshi Nakada <[email protected]> | 2021-10-04 20:46:47 +0900 |
commit | c4570acc86837fefa542a678dfdaba73cdd1fd03 (patch) | |
tree | 3727981f05a359b1fca4fb9df050b26f5c46ddf0 /tool/lib/test/unit.rb | |
parent | 44b2e32fb670e5e704f5721cf973cdc77d54a315 (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/test/unit.rb')
-rw-r--r-- | tool/lib/test/unit.rb | 113 |
1 files changed, 94 insertions, 19 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 |