minitest-bisect 1.5.1 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
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