minitest-bisect 1.5.1 → 1.7.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '039c173b7cc6976666b776aaa73002f584a372dcc797362bfed5e7afcf9fe8c1'
4
- data.tar.gz: f806ca88ff544455cd14e2ec0f3a7885d6ecb06d57e5b56e3a782a9fab69ad76
3
+ metadata.gz: 52bae214fa2f36196af3ec54139c2bec839de200e8dee1015f916b56a666a69b
4
+ data.tar.gz: 15a204ca83b0da8a8773e565f3bc40c439713edacef4a1d66435f2f9938edf6e
5
5
  SHA512:
6
- metadata.gz: 72fd7368da5f8f48118d3d6392e2df08ac6a8fe471c55a902606c157a7b8f27bc517f5d6e98f8a1a9c616c1fec6720b8293e06300baad88c22336dcc579f12c9
7
- data.tar.gz: f8f6c77ed11d3322871856fbf89da78dbfa2d730eb386a06450aff6fef36abedb55ee9b4eb89e8d6a75c3d12f298db0c35a38771aa6fc6ab75577e8596aac9c9
6
+ metadata.gz: 12c4227163ccd825b06f3c745bafa5a59725327e8b313c68a99cc732cea488c1cdda723c1e229d6ac50683e669594820a643c6d2bd0c5ac17867e75397969d10
7
+ data.tar.gz: '09994a51e53f704d642d27da154c835ba99b39bfbc2ddefa98e77a4357abfe062084628b6fb8c5efd9b596a641e562e595b3b0f80e196997d8bba5002c1448e5'
checksums.yaml.gz.sig CHANGED
Binary file
data/History.rdoc CHANGED
@@ -1,3 +1,29 @@
1
+ === 1.7.0 / 2023-07-06
2
+
3
+ * 1 major enhancement:
4
+
5
+ * Extend bisect_methods to do "inverse" run (eg false positives) via -n=/RE/ argument.
6
+
7
+ * 4 minor enhancements:
8
+
9
+ * Added example_inverse.rb
10
+ * Collapsed examples from directories to individual files.
11
+ * Refactor: push command generation from #run down to #bisect_methods.
12
+ * build_files_cmd no longer calls reset (zero effect change).
13
+
14
+ * 4 bug fixes:
15
+
16
+ * 100% documentation coverage.
17
+ * Fix server process ID to be a string to match rest of args.
18
+ * Fix shebang cmd on bin/minitest_bisect.
19
+ * Print known bad methods with found culprit methods in final run.
20
+
21
+ === 1.6.0 / 2022-05-23
22
+
23
+ * 1 minor enhancement:
24
+
25
+ * Removed #bisect_files and mode accessor. Just deal with methods only for now.
26
+
1
27
  === 1.5.1 / 2019-09-22
2
28
 
3
29
  * 1 bug fix:
data/Manifest.txt CHANGED
@@ -4,24 +4,10 @@ Manifest.txt
4
4
  README.rdoc
5
5
  Rakefile
6
6
  bin/minitest_bisect
7
- example-many/helper.rb
8
- example-many/test_bad1.rb
9
- example-many/test_bad2.rb
10
- example-many/test_bad3.rb
11
- example-many/test_bad4.rb
12
- example-many/test_bad5.rb
13
- example-many/test_bad6.rb
14
- example-many/test_bad7.rb
15
- example-many/test_bad8.rb
16
- example/helper.rb
17
- example/test_bad1.rb
18
- example/test_bad2.rb
19
- example/test_bad3.rb
20
- example/test_bad4.rb
21
- example/test_bad5.rb
22
- example/test_bad6.rb
23
- example/test_bad7.rb
24
- example/test_bad8.rb
7
+ example.rb
8
+ example_helper.rb
9
+ example_inverse.rb
10
+ example_many.rb
25
11
  lib/minitest/bisect.rb
26
12
  lib/minitest/find_minimal_combination.rb
27
13
  test/minitest/test_bisect.rb
data/README.rdoc CHANGED
@@ -19,10 +19,13 @@ what minitest-bisect does best.
19
19
 
20
20
  == FEATURES/PROBLEMS:
21
21
 
22
- * minitest_bisect first runs your tests on a per-file basis to
23
- minimize the number of tests you need to sift through.
24
- * minitest_bisect next runs the minimized files and figures out your
25
- exact failure reproduction.
22
+ * normal mode: runs your tests with a fixed seed and minimizes the
23
+ tests to find a minimal set to reproduce the failure.
24
+ * inverted mode: runs your tests with a fixed seed and a starting
25
+ failure and minimizes the tests to find a minimal set to reproduce
26
+ the false positive.
27
+ * Includes Enumerable#find_minimal_combination and
28
+ #find_minimal_combination_and_count.
26
29
 
27
30
  == SYNOPSIS:
28
31
 
@@ -94,8 +97,7 @@ So, you run the tests again, but this time with minitest_bisect.
94
97
  Provide the seed given in the failure so the tests always run in the
95
98
  same order and reproduce every time.
96
99
 
97
- minitest_bisect will first minimize the number of files, then it will
98
- turn around and minimize the number of methods.
100
+ minitest_bisect will minimize the number of methods.
99
101
 
100
102
  % minitest_bisect example --seed 314
101
103
  reproducing... in 203.83 sec
@@ -114,7 +116,7 @@ turn around and minimize the number of methods.
114
116
 
115
117
  Minimal methods found in 11 steps:
116
118
 
117
- Culprit methods: ["TestBad1#test_bad1_1"]
119
+ Culprit methods: ["TestBad1#test_bad1_1", "TestBad4#test_bad4_4"]
118
120
 
119
121
  ruby -Itest:lib -e 'require "./example/test_bad1.rb" ; require "./example/test_bad2.rb" ; require "./example/test_bad3.rb" ; require "./example/test_bad4.rb" ; require "./example/test_bad5.rb" ; require "./example/test_bad6.rb" ; require "./example/test_bad7.rb" ; require "./example/test_bad8.rb"' -- --seed 314 -n "/^(?:TestBad1#(?:test_bad1_1)|TestBad4#(?:test_bad4_4))$/"
120
122
 
@@ -148,9 +150,47 @@ have and how long they take, the minimization might take a long time,
148
150
  but each iteration can reduce the number of tests so it should get
149
151
  quicker with time.
150
152
 
153
+ === But sometimes, it fails:
154
+
155
+ Sometimes a test fails by itself consistently but passes most of the
156
+ time in CI. This is a false-positive in that the test SHOULD be
157
+ failing all the time but some other test is causing a side-effect that
158
+ it making it pass. This is sometimes harder to track down and reason
159
+ about. minitest-bisect now has an "inverted" mode, where you run as
160
+ normal but point it at a failing test by name. It will then validate
161
+ that the test fails by itself but passes when run in full with the
162
+ given seed. Then it tries to isolate and answer "what is the minimal
163
+ combination of tests to run to # make this test pass?". For example:
164
+
165
+ % minitest_bisect example --seed=3 -n="/failing_test_name_regexp/"
166
+
167
+ reproducing w/ scoped failure (inverted run!)... in 0.06 sec
168
+ reproducing false positive... in 0.06 sec
169
+ # of culprit methods: 2 in 0.06 sec
170
+ # of culprit methods: 1 in 0.06 sec
171
+ # of culprit methods: 1 in 0.06 sec
172
+
173
+ Minimal methods found in 3 steps:
174
+
175
+ Culprit methods: ["TestBad1#test_make_it_go", "TestBad1#test_fail_without"]
176
+
177
+ /Users/ryan/.rubies/ruby-3.2.2/bin/ruby -Itest:lib -Ilib -e 'require "./example"' -- --seed 3 -n "/^(?:TestBad1#(?:test_make_it_go|test_fail_without))$/"
178
+
179
+ Final reproduction:
180
+
181
+ Run options: --seed 3 -n "/^(?:TestBad1#(?:test_make_it_go|test_fail_without))$/"
182
+
183
+ # Running:
184
+
185
+ ..
186
+
187
+ Finished in 0.000369s, 5420.0544 runs/s, 0.0000 assertions/s.
188
+
189
+ 2 runs, 0 assertions, 0 failures, 0 errors, 0 skips
190
+
151
191
  == REQUIREMENTS:
152
192
 
153
- * minitest 5
193
+ * minitest 5+
154
194
 
155
195
  == INSTALL:
156
196
 
data/Rakefile CHANGED
@@ -40,11 +40,7 @@ def banner text
40
40
  end
41
41
 
42
42
  def run cmd
43
- sh cmd do end
44
- end
45
-
46
- def req glob
47
- Dir["#{glob}.rb"].map { |s| "require #{s.inspect}" }.join ";"
43
+ sh cmd do end # block form lets it fail w/o halting rake
48
44
  end
49
45
 
50
46
  task :repro => :isolate do
@@ -56,10 +52,10 @@ task :repro => :isolate do
56
52
  ruby = "ruby -I.:lib"
57
53
 
58
54
  banner "Original run that causes the test order dependency bug"
59
- run "#{ruby} -e '#{req "example/test*"}' -- --seed 3911"
55
+ run "#{ruby} example.rb --seed 1"
60
56
 
61
57
  banner "Reduce the problem down to the minimal reproduction"
62
- run "#{ruby} bin/minitest_bisect -Ilib --seed 3911 example/test*.rb"
58
+ run "#{ruby} bin/minitest_bisect -Ilib --seed 1 example.rb"
63
59
  end
64
60
 
65
61
  task :many => :isolate do
@@ -71,10 +67,31 @@ task :many => :isolate do
71
67
  ruby = "ruby -I.:lib"
72
68
 
73
69
  banner "Original run that causes the test order dependency bug"
74
- run "#{ruby} -e '#{req "example-many/test*"}' -- --seed 27083"
70
+ run "#{ruby} ./example_many.rb --seed 2"
75
71
 
76
72
  banner "Reduce the problem down to the minimal reproduction"
77
- run "#{ruby} bin/minitest_bisect -Ilib --seed 27083 example-many/test*.rb"
73
+ run "#{ruby} bin/minitest_bisect -Ilib --seed 2 example_many.rb"
74
+ end
75
+
76
+ task :inverse => :isolate do
77
+ unless ENV.key? "SLEEP" then
78
+ warn "NOTE: Defaulting to sleeping 0.01 seconds per test."
79
+ warn "NOTE: Use SLEEP=0 to disable or any other value to simulate your tests."
80
+ end
81
+
82
+ ruby = "ruby -I.:lib"
83
+
84
+ banner "Original run that passes (seed 1)"
85
+ run "#{ruby} example_inverse.rb --seed 1"
86
+
87
+ banner "Original run that *looks like* a test order dependency bug (seed 3)"
88
+ run "#{ruby} example_inverse.rb --seed 3"
89
+
90
+ banner "BAD bisection (tests fail by themselves) (seed 3)"
91
+ run "#{ruby} bin/minitest_bisect -Ilib --seed 3 example_inverse.rb"
92
+
93
+ banner "Reduce the passing run down to the minimal reproduction (seed 1)"
94
+ run "#{ruby} bin/minitest_bisect -Ilib --seed 1 example_inverse.rb -n=/TestBad4#test_bad4_4$/"
78
95
  end
79
96
 
80
97
  # vim: syntax=ruby
data/bin/minitest_bisect CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/ruby -w
1
+ #!/usr/bin/env ruby -w
2
2
 
3
3
  require "minitest/bisect"
4
4
 
data/example.rb ADDED
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env ruby -w
2
+
3
+ require_relative "example_helper"
4
+
5
+ # 800 tests, test test_bad4_4 fails if test_bad1_1 runs before it
6
+ TestBad1 = create_test 1, 100, 1 => :infect
7
+ TestBad2 = create_test 2, 100
8
+ TestBad3 = create_test 3, 100
9
+ TestBad4 = create_test 4, 100, 4 => :flunk
10
+ TestBad5 = create_test 5, 100
11
+ TestBad6 = create_test 6, 100
12
+ TestBad7 = create_test 7, 100
13
+ TestBad8 = create_test 8, 100
14
+
15
+ # seed 1 == one fail
16
+ # seed 3 == all pass
17
+
18
+ # % SLEEP=0 ruby ./example.rb --seed 1
19
+ #
20
+ # and it fails, as expected. So we run it through minitest_bisect and see:
21
+ #
22
+ # reproducing... in 0.14 sec
23
+ # verifying... in 0.06 sec
24
+ # # of culprit methods: 128 in 0.08 sec
25
+ # # of culprit methods: 64 in 0.07 sec
26
+ # # of culprit methods: 64 in 0.07 sec
27
+ # # of culprit methods: 32 in 0.06 sec
28
+ # # of culprit methods: 16 in 0.06 sec
29
+ # # of culprit methods: 8 in 0.06 sec
30
+ # # of culprit methods: 4 in 0.06 sec
31
+ # # of culprit methods: 4 in 0.06 sec
32
+ # # of culprit methods: 2 in 0.06 sec
33
+ # # of culprit methods: 1 in 0.06 sec
34
+ #
35
+ # Minimal methods found in 10 steps:
36
+ #
37
+ # Culprit methods: ["TestBad1#test_bad1_1", "TestBad4#test_bad4_4"]
38
+ #
39
+ # /Users/ryan/.rubies/ruby-3.2.2/bin/ruby -Itest:lib -e 'require "././example.rb"' -- --seed 1 -n "/^(?:TestBad1#(?:test_bad1_1)|TestBad4#(?:test_bad4_4))$/"
40
+ #
41
+ # Final reproduction:
42
+ #
43
+ # Run options: --seed 1 -n "/^(?:TestBad1#(?:test_bad1_1)|TestBad4#(?:test_bad4_4))$/"
44
+ #
45
+ # # Running:
46
+ #
47
+ # .F
48
+ #
49
+ # Finished in 0.001349s, 1482.5797 runs/s, 741.2898 assertions/s.
50
+ #
51
+ # 1) Failure:
52
+ # TestBad4#test_bad4_4 [/Users/ryan/Work/p4/zss/src/minitest-bisect/dev/example.rb:20]:
53
+ # muahahaha order dependency bug!
54
+ #
55
+ # 2 runs, 1 assertions, 1 failures, 0 errors, 0 skips
56
+ #
57
+ # and that's all there is to it! You now know that test_bad4_4 fails
58
+ # only when paired with test_bad1_1 before it. You can now debug the
59
+ # two methods and see what they're both modifying/dependent on.
@@ -1,4 +1,7 @@
1
- $hosed ||= 0
1
+ require "minitest/autorun"
2
+
3
+ $good = true
4
+ $bomb = 0
2
5
 
3
6
  def create_test suffix, n_methods, bad_methods = {}
4
7
  raise ArgumentError, "Bad args" if Hash === n_methods
@@ -12,10 +15,16 @@ def create_test suffix, n_methods, bad_methods = {}
12
15
  sleep delay if delay > 0
13
16
 
14
17
  case bad_methods[n]
15
- when true then
16
- $hosed += 1
18
+ when :flunk then
19
+ flunk "muahahaha order dependency bug!" unless $good
20
+ when :infect then
21
+ $good = false
22
+ when :fix then
23
+ $good = true
24
+ when :tick then
25
+ $bomb += 1
17
26
  when Integer then
18
- flunk "muahahaha order dependency bug!" if $hosed >= bad_methods[n]
27
+ flunk "muahahaha order dependency bug!" if $bomb >= bad_methods[n]
19
28
  else
20
29
  assert true
21
30
  end
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby -w
2
+
3
+ require_relative "example_helper"
4
+
5
+ $good = false
6
+
7
+ # 800 tests, test test_bad4_4 passes if test_bad1_1 runs before it
8
+ TestBad1 = create_test 1, 100, 1 => :fix
9
+ TestBad2 = create_test 2, 100
10
+ TestBad3 = create_test 3, 100
11
+ TestBad4 = create_test 4, 100, 4 => :flunk
12
+ TestBad5 = create_test 5, 100
13
+ TestBad6 = create_test 6, 100
14
+ TestBad7 = create_test 7, 100
15
+ TestBad8 = create_test 8, 100
16
+
17
+ # seed 1 == all pass
18
+ # seed 3 == one fail
19
+
20
+ # UNLIKE the scenario spelled out in example.rb...
21
+ #
22
+ # % SLEEP=0 ruby ./example_inverse.rb --seed 1
23
+ #
24
+ # passes, but
25
+ #
26
+ # % SLEEP=0 ruby ./example_inverse.rb --seed 3
27
+ #
28
+ # has 1 failure! So we run that through minitest_bisect:
29
+ #
30
+ # % SLEEP=0 ruby -Ilib bin/minitest_bisect ./example_inverse.rb --seed 3
31
+ #
32
+ # and see:
33
+ #
34
+ # Tests fail by themselves. This may not be an ordering issue.
35
+ #
36
+ # followed by a result that doesn't actually lead to the failure.
37
+ #
38
+ # Doing a normal run of minitest_bisect in this scenario doesn't
39
+ # detect anything actually relevant. This is because we're not dealing
40
+ # with a false *negative*, we're dealing with a false *positive*. The
41
+ # question is "what makes this test pass?". So, we run it again with
42
+ # the passing seed but this time point it at the failing test by name:
43
+ #
44
+ # % SLEEP=0 ruby -Ilib bin/minitest_bisect ./example_inverse.rb --seed 1 -n=/TestBad4#test_bad4_4$/
45
+ #
46
+ # and it outputs:
47
+ #
48
+ # Culprit methods: ["TestBad1#test_bad1_1", "TestBad4#test_bad4_4"]
49
+
50
+ # and shows a minimized run with the 2 passing tests. You now know
51
+ # that test_bad4_4 passes only when paired with test_bad1_1 before it.
52
+ # You can now debug the two methods and see what they're both
53
+ # modifying/dependent on.
data/example_many.rb ADDED
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby -w
2
+
3
+ require_relative "example_helper"
4
+
5
+ TestBad1 = create_test 1, 100, 1 => :tick
6
+ TestBad2 = create_test 2, 100
7
+ TestBad3 = create_test 3, 100, 72 => :tick
8
+ TestBad4 = create_test 4, 100
9
+ TestBad5 = create_test 5, 100, 17 => :tick
10
+ TestBad6 = create_test 6, 100
11
+ TestBad7 = create_test 7, 100
12
+ TestBad8 = create_test 8, 100, 43 => 3
13
+
14
+ # seed 1 == all pass
15
+ # seed 2 == one fail
16
+
17
+ # % ruby example_many.rb --seed 2
18
+
19
+ # and it fails, as expected. So we run it through minitest_bisect and see:
20
+
21
+ # % ruby -Ilib bin/minitest_bisect example_many.rb --seed 2
22
+
23
+ # reproducing... in 0.15 sec
24
+ # verifying... in 0.06 sec
25
+ # # of culprit methods: 256 in 0.09 sec
26
+ # ... 82 more bisections ...
27
+ # # of culprit methods: 3 in 0.06 sec
28
+ #
29
+ # Minimal methods found in 84 steps:
30
+ #
31
+ # Culprit methods: ["TestBad3#test_bad3_72", "TestBad5#test_bad5_17", "TestBad1#test_bad1_1", "TestBad8#test_bad8_43"]
32
+ #
33
+ # /Users/ryan/.rubies/ruby-3.2.2/bin/ruby -Itest:lib -e 'require "./example_many.rb"' -- --seed 2 -n "/^(?:TestBad3#(?:test_bad3_72)|TestBad5#(?:test_bad5_17)|TestBad1#(?:test_bad1_1)|TestBad8#(?:test_bad8_43))$/"
34
+ #
35
+ # Final reproduction:
36
+ #
37
+ # Run options: --seed 2 -n "/^(?:TestBad3#(?:test_bad3_72)|TestBad5#(?:test_bad5_17)|TestBad1#(?:test_bad1_1)|TestBad8#(?:test_bad8_43))$/"
38
+ #
39
+ # # Running:
40
+ #
41
+ # ...F
42
+ #
43
+ # Finished in 0.001404s, 2849.0028 runs/s, 712.2507 assertions/s.
44
+ #
45
+ # 1) Failure:
46
+ # TestBad8#test_bad8_43 [/Users/ryan/Work/p4/zss/src/minitest-bisect/dev/example_many.rb:20]:
47
+ # muahahaha order dependency bug!
48
+ #
49
+ # 4 runs, 1 assertions, 1 failures, 0 errors, 0 skips
50
+ #
51
+ # and that's all there is to it! You now know that the failing test
52
+ # fails only when paired with the other 3 tests before it. You can now
53
+ # debug the 4 methods and see what they're all modifying/dependent on.
@@ -4,10 +4,15 @@ require "shellwords"
4
4
  require "rbconfig"
5
5
  require "path_expander"
6
6
 
7
+ module Minitest; end # :nodoc:
8
+
9
+ ##
10
+ # Minitest::Bisect helps you isolate and debug random test failures.
11
+
7
12
  class Minitest::Bisect
8
- VERSION = "1.5.1"
13
+ VERSION = "1.7.0" # :nodoc:
9
14
 
10
- class PathExpander < ::PathExpander
15
+ class PathExpander < ::PathExpander # :nodoc:
11
16
  TEST_GLOB = "**/{test_*,*_test,spec_*,*_spec}.rb" # :nodoc:
12
17
 
13
18
  attr_accessor :rb_flags
@@ -39,7 +44,7 @@ class Minitest::Bisect
39
44
  end
40
45
 
41
46
  mtbv = ENV["MTB_VERBOSE"].to_i
42
- SHH = case
47
+ SHH = case # :nodoc:
43
48
  when mtbv == 1 then " > /dev/null"
44
49
  when mtbv >= 2 then nil
45
50
  else " > /dev/null 2>&1"
@@ -51,21 +56,48 @@ class Minitest::Bisect
51
56
  RbConfig::CONFIG['ruby_install_name'] +
52
57
  RbConfig::CONFIG['EXEEXT']).sub(/.*\s.*/m, '"\&"')
53
58
 
54
- attr_accessor :tainted, :failures, :culprits, :mode, :seen_bad
59
+ ##
60
+ # True if this run has seen a failure.
61
+
62
+ attr_accessor :tainted
55
63
  alias :tainted? :tainted
56
64
 
65
+ ##
66
+ # Failures seen in this run. Shape:
67
+ #
68
+ # {"file.rb"=>{"Class"=>["test_method1", "test_method2"] ...} ...}
69
+
70
+ attr_accessor :failures
71
+
72
+ ##
73
+ # An array of tests seen so far. NOT cleared by #reset.
74
+
75
+ attr_accessor :culprits
76
+
77
+ attr_accessor :seen_bad # :nodoc:
78
+
79
+ ##
80
+ # Top-level runner. Instantiate and call +run+, handling exceptions.
81
+
57
82
  def self.run files
58
83
  new.run files
59
84
  rescue => e
60
85
  warn e.message
86
+ warn "Try running with MTB_VERBOSE=2 to verify."
61
87
  exit 1
62
88
  end
63
89
 
90
+ ##
91
+ # Instantiate a new Bisect.
92
+
64
93
  def initialize
65
94
  self.culprits = []
66
95
  self.failures = Hash.new { |h, k| h[k] = Hash.new { |h2, k2| h2[k2] = [] } }
67
96
  end
68
97
 
98
+ ##
99
+ # Reset per-bisect-run variables.
100
+
69
101
  def reset
70
102
  self.seen_bad = false
71
103
  self.tainted = false
@@ -73,23 +105,23 @@ class Minitest::Bisect
73
105
  # not clearing culprits on purpose
74
106
  end
75
107
 
108
+ ##
109
+ # Instance-level runner. Handles Minitest::Server, argument
110
+ # processing, and invoking +bisect_methods+.
111
+
76
112
  def run args
77
113
  Minitest::Server.run self
78
114
 
79
115
  cmd = nil
80
116
 
81
- if :until_I_have_negative_filtering_in_minitest != 0 then
82
- mt_flags = args.dup
83
- expander = Minitest::Bisect::PathExpander.new mt_flags
117
+ mt_flags = args.dup
118
+ expander = Minitest::Bisect::PathExpander.new mt_flags
84
119
 
85
- files = expander.process
86
- rb_flags = expander.rb_flags
87
- mt_flags += ["--server", $$]
120
+ files = expander.process
121
+ rb_flags = expander.rb_flags
122
+ mt_flags += ["--server", $$.to_s]
88
123
 
89
- cmd = bisect_methods build_files_cmd(files, rb_flags, mt_flags)
90
- else
91
- cmd = bisect_methods bisect_files args
92
- end
124
+ cmd = bisect_methods files, rb_flags, mt_flags
93
125
 
94
126
  puts "Final reproduction:"
95
127
  puts
@@ -99,70 +131,87 @@ class Minitest::Bisect
99
131
  Minitest::Server.stop
100
132
  end
101
133
 
102
- def bisect_files files
103
- self.mode = :files
104
-
105
- files, flags = files.partition { |arg| File.file? arg }
106
- rb_flags, mt_flags = flags.partition { |arg| arg =~ /^-I/ }
107
- mt_flags += ["--server", $$]
108
-
109
- puts "reproducing..."
110
- system "#{build_files_cmd files, rb_flags, mt_flags} #{SHH}"
111
- abort "Reproduction run passed? Aborting. Try running with MTB_VERBOSE=2 to verify." unless tainted?
112
- puts "reproduced"
113
-
114
- found, count = files.find_minimal_combination_and_count do |test|
115
- puts "# of culprit files: #{test.size}"
116
-
117
- system "#{build_files_cmd test, rb_flags, mt_flags} #{SHH}"
118
-
119
- self.tainted?
134
+ ##
135
+ # Normal: find "what is the minimal combination of tests to run to
136
+ # make X fail?"
137
+ #
138
+ # Run with: minitest_bisect ... --seed=N
139
+ #
140
+ # 1. Verify the failure running normally with the seed.
141
+ # 2. If no failure, punt.
142
+ # 3. If no passing tests before failure, punt. (No culprits == no debug)
143
+ # 4. Verify the failure doesn't fail in isolation.
144
+ # 5. If it still fails by itself, warn that it might not be an ordering
145
+ # issue.
146
+ # 6. Cull all tests after the failure, they're not involved.
147
+ # 7. Bisect the culprits + bad until you find a minimal combo that fails.
148
+ # 8. Display minimal combo by running one last time.
149
+ #
150
+ # Inverted: find "what is the minimal combination of tests to run to
151
+ # make this test pass?"
152
+ #
153
+ # Run with: minitest_bisect ... --seed=N -n="/failing_test_name_regexp/"
154
+ #
155
+ # 1. Verify the failure by running normally w/ the seed and -n=/.../
156
+ # 2. If no failure, punt.
157
+ # 3. Verify the passing case by running everything.
158
+ # 4. If failure, punt. This is not a false positive.
159
+ # 5. Cull all tests after the bad test from #1, they're not involved.
160
+ # 6. Bisect the culprits + bad until you find a minimal combo that passes.
161
+ # 7. Display minimal combo by running one last time.
162
+
163
+ def bisect_methods files, rb_flags, mt_flags
164
+ bad_names, mt_flags = mt_flags.partition { |s| s =~ /^(?:-n|--name)/ }
165
+ normal = bad_names.empty?
166
+ inverted = !normal
167
+
168
+ if inverted then
169
+ time_it "reproducing w/ scoped failure (inverted run!)...", build_methods_cmd(build_files_cmd(files, rb_flags, mt_flags + bad_names))
170
+ raise "No failures. Probably not a false positive. Aborting." if failures.empty?
171
+ bad = map_failures
120
172
  end
121
173
 
122
- puts
123
- puts "Minimal files found in #{count} steps:"
124
- puts
125
- cmd = build_files_cmd found, rb_flags, mt_flags
126
- puts cmd
127
- cmd
128
- end
129
-
130
- def bisect_methods cmd
131
- self.mode = :methods
174
+ cmd = build_files_cmd(files, rb_flags, mt_flags)
132
175
 
133
- time_it "reproducing...", build_methods_cmd(cmd)
176
+ msg = normal ? "reproducing..." : "reproducing false positive..."
177
+ time_it msg, build_methods_cmd(cmd)
134
178
 
135
- unless tainted? then
136
- $stderr.puts "Reproduction run passed? Aborting."
137
- abort "Try running with MTB_VERBOSE=2 to verify."
179
+ if normal then
180
+ raise "Reproduction run passed? Aborting." unless tainted?
181
+ raise "Verification failed. No culprits? Aborting." if culprits.empty? && seen_bad
182
+ else
183
+ raise "Reproduction failed? Not false positive. Aborting." if tainted?
184
+ raise "Verification failed. No culprits? Aborting." if culprits.empty? || seen_bad
138
185
  end
139
186
 
140
- bad = map_failures
187
+ if normal then
188
+ bad = map_failures
141
189
 
142
- raise "Nothing to verify against because every test failed. Aborting." if
143
- culprits.empty? && seen_bad
190
+ time_it "verifying...", build_methods_cmd(cmd, [], bad)
144
191
 
145
- time_it "verifying...", build_methods_cmd(cmd, [], bad)
192
+ new_bad = map_failures
146
193
 
147
- new_bad = map_failures
148
-
149
- if bad == new_bad then
150
- warn "Tests fail by themselves. This may not be an ordering issue."
194
+ if bad == new_bad then
195
+ warn "Tests fail by themselves. This may not be an ordering issue."
196
+ end
151
197
  end
152
198
 
199
+ idx = culprits.index bad.first
200
+ self.culprits = culprits.take idx+1 if idx # cull tests after bad
201
+
153
202
  # culprits populated by initial reproduction via minitest/server
154
203
  found, count = culprits.find_minimal_combination_and_count do |test|
155
204
  prompt = "# of culprit methods: #{test.size}"
156
205
 
157
206
  time_it prompt, build_methods_cmd(cmd, test, bad)
158
207
 
159
- self.tainted?
208
+ normal == tainted? # either normal and failed, or inverse and passed
160
209
  end
161
210
 
162
211
  puts
163
212
  puts "Minimal methods found in #{count} steps:"
164
213
  puts
165
- puts "Culprit methods: %p" % [found]
214
+ puts "Culprit methods: %p" % [found + bad]
166
215
  puts
167
216
  cmd = build_methods_cmd cmd, found, bad
168
217
  puts cmd.sub(/--server \d+/, "")
@@ -170,14 +219,14 @@ class Minitest::Bisect
170
219
  cmd
171
220
  end
172
221
 
173
- def time_it prompt, cmd
222
+ def time_it prompt, cmd # :nodoc:
174
223
  print prompt
175
224
  t0 = Time.now
176
225
  system "#{cmd} #{SHH}"
177
226
  puts " in %.2f sec" % (Time.now - t0)
178
227
  end
179
228
 
180
- def map_failures
229
+ def map_failures # :nodoc:
181
230
  # from: {"file.rb"=>{"Class"=>["test_method1", "test_method2"]}}
182
231
  # to: ["Class#test_method1", "Class#test_method2"]
183
232
  failures.values.map { |h|
@@ -185,15 +234,31 @@ class Minitest::Bisect
185
234
  }.flatten.sort
186
235
  end
187
236
 
188
- def build_files_cmd culprits, rb, mt
189
- reset
190
-
237
+ def build_files_cmd culprits, rb, mt # :nodoc:
191
238
  tests = culprits.flatten.compact.map { |f| %(require "./#{f}") }.join " ; "
192
239
 
193
240
  %(#{RUBY} #{rb.shelljoin} -e '#{tests}' -- #{mt.map(&:to_s).shelljoin})
194
241
  end
195
242
 
196
- def build_re bad
243
+ def build_methods_cmd cmd, culprits = [], bad = nil # :nodoc:
244
+ reset
245
+
246
+ if bad then
247
+ re = build_re culprits + bad
248
+
249
+ cmd += " -n \"#{re}\"" if bad
250
+ end
251
+
252
+ if ENV["MTB_VERBOSE"].to_i >= 1 then
253
+ puts
254
+ puts cmd
255
+ puts
256
+ end
257
+
258
+ cmd
259
+ end
260
+
261
+ def build_re bad # :nodoc:
197
262
  re = []
198
263
 
199
264
  # bad by class, you perv
@@ -213,44 +278,24 @@ class Minitest::Bisect
213
278
  "/^(?:#{re})$/"
214
279
  end
215
280
 
216
- def re_escape str
281
+ def re_escape str # :nodoc:
217
282
  str.gsub(/([`'"!?&\[\]\(\)\{\}\|\+])/, '\\\\\1')
218
283
  end
219
284
 
220
- def build_methods_cmd cmd, culprits = [], bad = nil
221
- reset
222
-
223
- if bad then
224
- re = build_re culprits + bad
225
-
226
- cmd += " -n \"#{re}\"" if bad
227
- end
228
-
229
- if ENV["MTB_VERBOSE"].to_i >= 1 then
230
- puts
231
- puts cmd
232
- puts
233
- end
234
-
235
- cmd
236
- end
237
-
238
285
  ############################################################
239
286
  # Server Methods:
240
287
 
241
- def minitest_start
288
+ def minitest_start # :nodoc:
242
289
  self.failures.clear
243
290
  end
244
291
 
245
- def minitest_result file, klass, method, fails, assertions, time
292
+ def minitest_result file, klass, method, fails, assertions, time # :nodoc:
246
293
  fails.reject! { |fail| Minitest::Skip === fail }
247
294
 
248
- if mode == :methods then
249
- if fails.empty? then
250
- culprits << "#{klass}##{method}" unless seen_bad # UGH
251
- else
252
- self.seen_bad = true
253
- end
295
+ if fails.empty? then
296
+ culprits << "#{klass}##{method}" unless seen_bad # UGH
297
+ else
298
+ self.seen_bad = true
254
299
  end
255
300
 
256
301
  return if fails.empty?
@@ -1,10 +1,13 @@
1
1
  #!/usr/bin/ruby -w
2
2
 
3
- module Minitest; end
3
+ ##
4
+ # Finds the minimal combination of a collection of items that satisfy
5
+ # +test+.
4
6
 
5
7
  class ComboFinder
6
8
  ##
7
- # Find the minimal combination of a collection of items that satisfy +test+.
9
+ # Find the minimal combination of a collection of items that satisfy
10
+ # +test+.
8
11
  #
9
12
  # If you think of the collection as a binary tree, this algorithm
10
13
  # does a breadth first search of the combinations that satisfy
@@ -79,11 +82,11 @@ class ComboFinder
79
82
  ary
80
83
  end
81
84
 
82
- def d s = ""
85
+ def d s = "" # :nodoc:
83
86
  warn s if ENV["MTB_DEBUG"]
84
87
  end
85
88
 
86
- def cache_result result, data, cache
89
+ def cache_result result, data, cache # :nodoc:
87
90
  cache[data] = true
88
91
 
89
92
  return result if result
@@ -103,7 +106,7 @@ class ComboFinder
103
106
  end
104
107
  end
105
108
 
106
- class Array
109
+ class Array # :nodoc:
107
110
  ##
108
111
  # Find the minimal combination of a collection of items that satisfy +test+.
109
112
 
@@ -8,6 +8,7 @@ class TestMinitest::TestBisect < Minitest::Test
8
8
 
9
9
  def setup
10
10
  self.bisect = Minitest::Bisect.new
11
+ bisect.reset
11
12
  end
12
13
 
13
14
  def test_class_run
@@ -124,9 +125,6 @@ class TestMinitest::TestBisect < Minitest::Test
124
125
  end
125
126
 
126
127
  def test_minitest_result
127
- bisect.mode = :methods
128
- bisect.reset
129
-
130
128
  bisect.minitest_result "file.rb", "TestClass", "test_method", [], 1, 1
131
129
 
132
130
  assert_equal false, bisect.tainted
@@ -135,9 +133,6 @@ class TestMinitest::TestBisect < Minitest::Test
135
133
  end
136
134
 
137
135
  def test_minitest_result_skip
138
- bisect.mode = :methods
139
- bisect.reset
140
-
141
136
  fail = Minitest::Skip.new("woot")
142
137
 
143
138
  bisect.minitest_result "file.rb", "TestClass", "test_method", [fail], 1, 1
@@ -148,9 +143,6 @@ class TestMinitest::TestBisect < Minitest::Test
148
143
  end
149
144
 
150
145
  def test_minitest_result_fail
151
- bisect.mode = :methods
152
- bisect.reset
153
-
154
146
  fail = Minitest::Assertion.new "msg"
155
147
 
156
148
  bisect.minitest_result "file.rb", "TestClass", "test_method", [fail], 1, 1
@@ -163,9 +155,6 @@ class TestMinitest::TestBisect < Minitest::Test
163
155
  end
164
156
 
165
157
  def test_minitest_result_error
166
- bisect.mode = :methods
167
- bisect.reset
168
-
169
158
  fail = Minitest::UnexpectedError.new RuntimeError.new("woot")
170
159
 
171
160
  bisect.minitest_result "file.rb", "TestClass", "test_method", [fail], 1, 1
@@ -10,93 +10,99 @@ describe Array, :find_minimal_combination do
10
10
  lambda { |sample| bad & sample == bad }
11
11
  end
12
12
 
13
+ def record_and_check(tests, *bad)
14
+ lambda { |test| tests << test.join; bad & test == bad }
15
+ end
16
+
17
+ def parse_trials s
18
+ s.lines.map { |s| s.chomp.sub(/#.*/, '').delete " " }.reject(&:empty?)
19
+ end
20
+
13
21
  def assert_steps input, bad, exp
14
22
  tests = []
15
23
 
16
- found = input.find_minimal_combination do |test|
17
- tests << test
18
- bad & test == bad
19
- end
24
+ found = input.find_minimal_combination(&record_and_check(tests, *bad))
20
25
 
21
26
  assert_equal bad, found, "algorithm is bad"
22
27
 
23
- assert_equal exp, tests
28
+ assert_equal parse_trials(exp), tests
24
29
  end
25
30
 
26
- def test_ordering_best_case
27
- a = (0..15).to_a
28
- bad = [0, 1]
29
- exp = [[0, 1, 2, 3, 4, 5, 6, 7],
30
- [0, 1, 2, 3],
31
- [0, 1],
32
- [0],
33
- [1],
34
- [0, 1]]
35
-
36
- assert_steps a, bad, exp
31
+ HEX = "0123456789ABCDEF".chars.to_a
32
+
33
+ # lvl collection
34
+ #
35
+ # 0 | A
36
+ # 1 | B C
37
+ # 2 | D E F G
38
+ # 3 | H I J K L M N O
39
+ # |
40
+ # 4 | 0123456789ABCDEF
41
+
42
+ def test_ordering_best_case_1
43
+ ary = HEX
44
+ bad = %w[0]
45
+ exp = <<~EOT
46
+ #123456789ABCDEF
47
+ 01234567 # HIT! -- level 1 = B, C
48
+ 0123 # HIT! -- level 2 = D, E
49
+ 01 # HIT! -- level 3 = H, I
50
+ 0 # HIT!
51
+ EOT
52
+
53
+ assert_steps ary, bad, exp
37
54
  end
38
55
 
39
- def test_ordering
40
- a = (0..15).to_a
41
- bad = [0, 15]
42
-
43
- # lvl collection
44
- #
45
- # 0 | A
46
- # 1 | B C
47
- # 2 | D E F G
48
- # 3 | H I J K L M N O
49
- # 4 | 0 1 2 3 4 5 6 7 8 9 A B C D E F
50
- #
51
- # 0 +++++++++++++++++++++++++++++++
52
- # 1 ---------------
53
- # 1 ---------------
54
- # 2 ------- -------
55
- # 2 +++++++ +++++++
56
- # 3 xxxxxxx
57
- # 3 xxxxxxx
58
- # 3 --- ---
59
- # 3 +++ +++
60
- # 4 xxx
61
- # 4 xxx
62
- # 4 - -
63
- # 4 + +
64
- #
65
- # - = miss
66
- # + = hit
67
- # x = unwanted test
68
-
69
- exp = [
70
- # level 1 = B, C
71
- [0, 1, 2, 3, 4, 5, 6, 7],
72
- [8, 9, 10, 11, 12, 13, 14, 15],
73
-
74
- # level 2 = DF, DG, EF, EG
75
- [0, 1, 2, 3, 8, 9, 10, 11],
76
- [0, 1, 2, 3, 12, 13, 14, 15],
77
-
78
- # level 3
79
- # [0, 1, 2, 3], # I think this is bad, we've tested B
80
- # [12, 13, 14, 15], # again, bad, we've tested C
81
- [0, 1, 12, 13],
82
- [0, 1, 14, 15],
83
-
84
- # level 4
85
- # [0, 1],
86
- # [14, 15],
87
- [0, 14],
88
- [0, 15],
89
- ]
90
-
91
- assert_steps a, bad, exp
56
+ def test_ordering_best_case_2
57
+ ary = HEX
58
+ bad = %w[0 1]
59
+ exp = <<~EOT
60
+ 01234567 # HIT! -- level 1 = B, C
61
+ 0123 # HIT! -- level 2 = D, E
62
+ 01 # HIT! -- level 3 = H, I
63
+ 0 # miss -- level 4 = 0, 1, n_combos = 1
64
+ 1 # miss
65
+ 01 # HIT! -- level 3 = H, n_combos = 2
66
+ EOT
67
+
68
+ assert_steps ary, bad, exp
92
69
  end
93
70
 
94
- make_my_diffs_pretty!
71
+ def test_ordering
72
+ ary = HEX
73
+ bad = %w[1 F]
74
+ exp = <<~EOT
75
+ 01234567 # miss -- level 1 = B, C
76
+ 89ABCDEF # miss
77
+ 0123 89AB # miss -- level 2 = DF, DG, EF, EG
78
+ 0123 CDEF # HIT!
79
+ 01 CD # miss -- level 3 = HN, HO
80
+ 01 EF # HIT!
81
+ 0 E # miss -- level 4 = 0E, 0F, 1E, 1F
82
+ 0 F # miss
83
+ 1 E # miss
84
+ 1 F # HIT!
85
+ EOT
86
+
87
+ assert_steps ary, bad, exp
88
+ end
95
89
 
96
90
  def self.test_find_minimal_combination max, *bad
97
- define_method "test_find_minimal_combination_#{max}_#{bad.join "_"}" do
91
+ define_method "%s_%s_%s" % [__method__, max, bad.join("_")] do
98
92
  a = (1..max).to_a
99
- _(a.find_minimal_combination(&check(*bad))).must_equal bad
93
+
94
+ assert_equal bad, a.find_minimal_combination(&check(*bad))
95
+ end
96
+ end
97
+
98
+ def self.test_find_minimal_combination_and_count max, nsteps, *bad
99
+ define_method "%s_%s_%s_%s" % [__method__, max, nsteps, bad.join("_")] do
100
+ a = (1..max).to_a
101
+
102
+ found, count = a.find_minimal_combination_and_count(&check(*bad))
103
+
104
+ assert_equal bad, found
105
+ assert_equal nsteps, count
100
106
  end
101
107
  end
102
108
 
@@ -119,7 +125,14 @@ describe Array, :find_minimal_combination do
119
125
  test_find_minimal_combination 1023, 7, 15, 166, 1001
120
126
  test_find_minimal_combination 1023, 1000, 1001, 1002
121
127
  test_find_minimal_combination 1023, 1001, 1003, 1005, 1007
128
+ test_find_minimal_combination 1024, 1001, 1003, 1005, 1007
129
+ test_find_minimal_combination 1024, 1, 1024
130
+
131
+ test_find_minimal_combination_and_count 1024, 12, 1, 2
132
+ test_find_minimal_combination_and_count 1024, 23, 1, 1023
133
+ test_find_minimal_combination_and_count 1024, 24, 1, 1024
134
+ test_find_minimal_combination_and_count 1023, 26, 1, 1023
122
135
 
123
- # test_find_minimal_combination 1024, 1001, 1003, 1005, 1007
124
- # test_find_minimal_combination 1023, 1001, 1003, 1005, 1007
136
+ test_find_minimal_combination_and_count 1024, 93, 1001, 1003, 1005, 1007
137
+ test_find_minimal_combination_and_count 1023, 93, 1001, 1003, 1005, 1007
125
138
  end
data.tar.gz.sig CHANGED
@@ -1,3 +1 @@
1
- h���
2
- ��U$�P،�3��]�1j*�&��d��7ta���]��ޫ��D��Q��-���-��SnT������U2��ӗ�����6y
3
-
1
+ �;+�K�>]@+��^c�T�Zɫ;�Mag��R[�0q*q钮�O������Gge�|�NC�5~͚**�4�!'���w9����?SV<��wq�=?,��Obx��05{�5�r�ThG:�ﶉ�6{��'�T�VJ͌��;ꉂ�J4>r��~����Ű�] �G<J�f����G���¯.> �.vg�=���2�_�֝�#WI���|�A�L((l] B������F�׼�9⻛u
metadata CHANGED
@@ -1,18 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: minitest-bisect
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.1
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Davis
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain:
11
11
  - |
12
12
  -----BEGIN CERTIFICATE-----
13
- MIIDPjCCAiagAwIBAgIBAzANBgkqhkiG9w0BAQsFADBFMRMwEQYDVQQDDApyeWFu
13
+ MIIDPjCCAiagAwIBAgIBBzANBgkqhkiG9w0BAQsFADBFMRMwEQYDVQQDDApyeWFu
14
14
  ZC1ydWJ5MRkwFwYKCZImiZPyLGQBGRYJemVuc3BpZGVyMRMwEQYKCZImiZPyLGQB
15
- GRYDY29tMB4XDTE4MTIwNDIxMzAxNFoXDTE5MTIwNDIxMzAxNFowRTETMBEGA1UE
15
+ GRYDY29tMB4XDTIzMDEwMTA3NTExN1oXDTI0MDEwMTA3NTExN1owRTETMBEGA1UE
16
16
  AwwKcnlhbmQtcnVieTEZMBcGCgmSJomT8ixkARkWCXplbnNwaWRlcjETMBEGCgmS
17
17
  JomT8ixkARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALda
18
18
  b9DCgK+627gPJkB6XfjZ1itoOQvpqH1EXScSaba9/S2VF22VYQbXU1xQXL/WzCkx
@@ -22,14 +22,14 @@ cert_chain:
22
22
  qhtV7HJxNKuPj/JFH0D2cswvzznE/a5FOYO68g+YCuFi5L8wZuuM8zzdwjrWHqSV
23
23
  gBEfoTEGr7Zii72cx+sCAwEAAaM5MDcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAw
24
24
  HQYDVR0OBBYEFEfFe9md/r/tj/Wmwpy+MI8d9k/hMA0GCSqGSIb3DQEBCwUAA4IB
25
- AQCbJwLmpJR2PomLU+Zzw3KRzH/hbyUWc/ftru71AopZ1fy4iY9J/BW5QYKVYwbP
26
- V0FSBWtvfI/RdwfKGtuGhPKECZgmLieGuZ3XCc09qPu1bdg7i/tu1p0t0c6163ku
27
- nDMDIC/t/DAFK0TY9I3HswuyZGbLW7rgF0DmiuZdN/RPhHq2pOLMLXJmFclCb/im
28
- 9yToml/06TJdUJ5p64mkBs0TzaK66DIB1Smd3PdtfZqoRV+EwaXMdx0Hb3zdR1JR
29
- Em82dBUFsipwMLCYj39kcyHWAxyl6Ae1Cn9r/ItVBCxoeFdrHjfavnrIEoXUt4bU
30
- UfBugfLD19bu3nvL+zTAGx/U
25
+ AQAkg3y+PBnBAPWdxxITm5sPHqdWQgSyCpRA20o4LTuWr8BWhSXBkfQNa7cY6fOn
26
+ xyM34VPzBFbExv6XOGDfOMFBVaYTHuN9peC/5/umL7kLl+nflXzL2QA7K6LYj5Bg
27
+ sM574Onr0dZDM6Vn69bzQ7rBIFDfK/OhlPzqKZad4nsdcsVH8ODCiT+ATMIZyz5K
28
+ WCnNtqlyiWXI8tdTpahDgcUwfcN/oN7v4K8iU5IbLJX6HQ5DKgmKjfb6XyMth16k
29
+ ROfWo9Uyp8ba/j9eVG14KkYRaLydAY1MNQk2yd3R5CGfeOpD1kttxjoypoUJ2dOG
30
+ nsNBRuQJ1UfiCG97a6DNm+Fr
31
31
  -----END CERTIFICATE-----
32
- date: 2019-09-23 00:00:00.000000000 Z
32
+ date: 2023-07-06 00:00:00.000000000 Z
33
33
  dependencies:
34
34
  - !ruby/object:Gem::Dependency
35
35
  name: minitest-server
@@ -99,14 +99,14 @@ dependencies:
99
99
  requirements:
100
100
  - - "~>"
101
101
  - !ruby/object:Gem::Version
102
- version: '3.18'
102
+ version: '4.0'
103
103
  type: :development
104
104
  prerelease: false
105
105
  version_requirements: !ruby/object:Gem::Requirement
106
106
  requirements:
107
107
  - - "~>"
108
108
  - !ruby/object:Gem::Version
109
- version: '3.18'
109
+ version: '4.0'
110
110
  description: |-
111
111
  Hunting down random test failures can be very very difficult,
112
112
  sometimes impossible, but minitest-bisect makes it easy.
@@ -135,24 +135,10 @@ files:
135
135
  - README.rdoc
136
136
  - Rakefile
137
137
  - bin/minitest_bisect
138
- - example-many/helper.rb
139
- - example-many/test_bad1.rb
140
- - example-many/test_bad2.rb
141
- - example-many/test_bad3.rb
142
- - example-many/test_bad4.rb
143
- - example-many/test_bad5.rb
144
- - example-many/test_bad6.rb
145
- - example-many/test_bad7.rb
146
- - example-many/test_bad8.rb
147
- - example/helper.rb
148
- - example/test_bad1.rb
149
- - example/test_bad2.rb
150
- - example/test_bad3.rb
151
- - example/test_bad4.rb
152
- - example/test_bad5.rb
153
- - example/test_bad6.rb
154
- - example/test_bad7.rb
155
- - example/test_bad8.rb
138
+ - example.rb
139
+ - example_helper.rb
140
+ - example_inverse.rb
141
+ - example_many.rb
156
142
  - lib/minitest/bisect.rb
157
143
  - lib/minitest/find_minimal_combination.rb
158
144
  - test/minitest/test_bisect.rb
@@ -160,8 +146,9 @@ files:
160
146
  homepage: https://github.com/seattlerb/minitest-bisect
161
147
  licenses:
162
148
  - MIT
163
- metadata: {}
164
- post_install_message:
149
+ metadata:
150
+ homepage_uri: https://github.com/seattlerb/minitest-bisect
151
+ post_install_message:
165
152
  rdoc_options:
166
153
  - "--main"
167
154
  - README.rdoc
@@ -178,8 +165,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
178
165
  - !ruby/object:Gem::Version
179
166
  version: '0'
180
167
  requirements: []
181
- rubygems_version: 3.0.6
182
- signing_key:
168
+ rubygems_version: 3.4.10
169
+ signing_key:
183
170
  specification_version: 4
184
171
  summary: Hunting down random test failures can be very very difficult, sometimes impossible,
185
172
  but minitest-bisect makes it easy
metadata.gz.sig CHANGED
Binary file
data/example/helper.rb DELETED
@@ -1,25 +0,0 @@
1
- $hosed ||= false
2
-
3
- def create_test suffix, n_methods, bad_methods = {}
4
- raise ArgumentError, "Bad args" if Hash === n_methods
5
-
6
- delay = (ENV["SLEEP"] || 0.01).to_f
7
-
8
- Class.new(Minitest::Test) do
9
- n_methods.times do |n|
10
- n += 1
11
- define_method "test_bad#{suffix}_#{n}" do
12
- sleep delay if delay > 0
13
-
14
- case bad_methods[n]
15
- when true then
16
- flunk "muahahaha order dependency bug!" if $hosed
17
- when false then
18
- $hosed = true
19
- else
20
- assert true
21
- end
22
- end
23
- end
24
- end
25
- end
data/example/test_bad1.rb DELETED
@@ -1,4 +0,0 @@
1
- require "minitest/autorun"
2
- require_relative "helper"
3
-
4
- TestBad1 = create_test 1, 100, 1 => false
data/example/test_bad2.rb DELETED
@@ -1,4 +0,0 @@
1
- require "minitest/autorun"
2
- require_relative "helper"
3
-
4
- TestBad2 = create_test 2, 100
data/example/test_bad3.rb DELETED
@@ -1,4 +0,0 @@
1
- require "minitest/autorun"
2
- require_relative "helper"
3
-
4
- TestBad3 = create_test 3, 100
data/example/test_bad4.rb DELETED
@@ -1,4 +0,0 @@
1
- require "minitest/autorun"
2
- require_relative "helper"
3
-
4
- TestBad4 = create_test 4, 100, 4 => true
data/example/test_bad5.rb DELETED
@@ -1,4 +0,0 @@
1
- require "minitest/autorun"
2
- require_relative "helper"
3
-
4
- TestBad5 = create_test 5, 100
data/example/test_bad6.rb DELETED
@@ -1,4 +0,0 @@
1
- require "minitest/autorun"
2
- require_relative "helper"
3
-
4
- TestBad6 = create_test 6, 100
data/example/test_bad7.rb DELETED
@@ -1,4 +0,0 @@
1
- require "minitest/autorun"
2
- require_relative "helper"
3
-
4
- TestBad7 = create_test 7, 100
data/example/test_bad8.rb DELETED
@@ -1,4 +0,0 @@
1
- require "minitest/autorun"
2
- require_relative "helper"
3
-
4
- TestBad8 = create_test 8, 100
@@ -1,4 +0,0 @@
1
- require "minitest/autorun"
2
- require_relative "helper"
3
-
4
- TestBad1 = create_test 1, 100, 1 => true
@@ -1,4 +0,0 @@
1
- require "minitest/autorun"
2
- require_relative "helper"
3
-
4
- TestBad2 = create_test 2, 100
@@ -1,4 +0,0 @@
1
- require "minitest/autorun"
2
- require_relative "helper"
3
-
4
- TestBad3 = create_test 3, 100, 72 => true
@@ -1,4 +0,0 @@
1
- require "minitest/autorun"
2
- require_relative "helper"
3
-
4
- TestBad4 = create_test 4, 100
@@ -1,4 +0,0 @@
1
- require "minitest/autorun"
2
- require_relative "helper"
3
-
4
- TestBad5 = create_test 5, 100, 17 => true
@@ -1,4 +0,0 @@
1
- require "minitest/autorun"
2
- require_relative "helper"
3
-
4
- TestBad6 = create_test 6, 100
@@ -1,4 +0,0 @@
1
- require "minitest/autorun"
2
- require_relative "helper"
3
-
4
- TestBad7 = create_test 7, 100
@@ -1,4 +0,0 @@
1
- require "minitest/autorun"
2
- require_relative "helper"
3
-
4
- TestBad8 = create_test 8, 100, 43 => 3