mega-sharp-tool 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/mega-sharp-tool.gemspec +12 -0
  3. data/minitest-6.0.6/History.rdoc +1860 -0
  4. data/minitest-6.0.6/Manifest.txt +41 -0
  5. data/minitest-6.0.6/README.rdoc +763 -0
  6. data/minitest-6.0.6/Rakefile +89 -0
  7. data/minitest-6.0.6/bin/minitest +5 -0
  8. data/minitest-6.0.6/design_rationale.rb +54 -0
  9. data/minitest-6.0.6/lib/hoe/minitest.rb +30 -0
  10. data/minitest-6.0.6/lib/minitest/assertions.rb +821 -0
  11. data/minitest-6.0.6/lib/minitest/autorun.rb +5 -0
  12. data/minitest-6.0.6/lib/minitest/benchmark.rb +452 -0
  13. data/minitest-6.0.6/lib/minitest/bisect.rb +304 -0
  14. data/minitest-6.0.6/lib/minitest/complete.rb +56 -0
  15. data/minitest-6.0.6/lib/minitest/compress.rb +94 -0
  16. data/minitest-6.0.6/lib/minitest/error_on_warning.rb +11 -0
  17. data/minitest-6.0.6/lib/minitest/expectations.rb +321 -0
  18. data/minitest-6.0.6/lib/minitest/find_minimal_combination.rb +127 -0
  19. data/minitest-6.0.6/lib/minitest/hell.rb +11 -0
  20. data/minitest-6.0.6/lib/minitest/manual_plugins.rb +4 -0
  21. data/minitest-6.0.6/lib/minitest/parallel.rb +72 -0
  22. data/minitest-6.0.6/lib/minitest/path_expander.rb +432 -0
  23. data/minitest-6.0.6/lib/minitest/pride.rb +4 -0
  24. data/minitest-6.0.6/lib/minitest/pride_plugin.rb +135 -0
  25. data/minitest-6.0.6/lib/minitest/server.rb +49 -0
  26. data/minitest-6.0.6/lib/minitest/server_plugin.rb +88 -0
  27. data/minitest-6.0.6/lib/minitest/spec.rb +324 -0
  28. data/minitest-6.0.6/lib/minitest/sprint.rb +105 -0
  29. data/minitest-6.0.6/lib/minitest/sprint_plugin.rb +39 -0
  30. data/minitest-6.0.6/lib/minitest/test.rb +232 -0
  31. data/minitest-6.0.6/lib/minitest/test_task.rb +331 -0
  32. data/minitest-6.0.6/lib/minitest.rb +1232 -0
  33. data/minitest-6.0.6/test/minitest/metametameta.rb +150 -0
  34. data/minitest-6.0.6/test/minitest/test_bisect.rb +249 -0
  35. data/minitest-6.0.6/test/minitest/test_find_minimal_combination.rb +138 -0
  36. data/minitest-6.0.6/test/minitest/test_minitest_assertions.rb +1729 -0
  37. data/minitest-6.0.6/test/minitest/test_minitest_benchmark.rb +151 -0
  38. data/minitest-6.0.6/test/minitest/test_minitest_reporter.rb +437 -0
  39. data/minitest-6.0.6/test/minitest/test_minitest_spec.rb +1095 -0
  40. data/minitest-6.0.6/test/minitest/test_minitest_test.rb +1295 -0
  41. data/minitest-6.0.6/test/minitest/test_minitest_test_task.rb +57 -0
  42. data/minitest-6.0.6/test/minitest/test_path_expander.rb +229 -0
  43. data/minitest-6.0.6/test/minitest/test_server.rb +146 -0
  44. metadata +83 -0
@@ -0,0 +1,304 @@
1
+ require_relative "find_minimal_combination"
2
+ require_relative "server"
3
+ require "shellwords"
4
+ require "rbconfig"
5
+ require_relative "path_expander" # this is gonna break some shit?
6
+
7
+ module Minitest; end # :nodoc:
8
+
9
+ ##
10
+ # Minitest::Bisect helps you isolate and debug random test failures.
11
+
12
+ class Minitest::Bisect
13
+ VERSION = "1.8.0" # :nodoc:
14
+
15
+ class PathExpander < Minitest::VendoredPathExpander # :nodoc:
16
+ TEST_GLOB = "**/{test_*,*_test,spec_*,*_spec}.rb" # :nodoc:
17
+
18
+ attr_accessor :rb_flags
19
+
20
+ def initialize args = ARGV # :nodoc:
21
+ super args, TEST_GLOB, "test"
22
+ self.rb_flags = %w[]
23
+ end
24
+
25
+ ##
26
+ # Overrides PathExpander#process_flags to filter out ruby flags
27
+ # from minitest flags. Only supports -I<paths>, -d, and -w for
28
+ # ruby.
29
+
30
+ def process_flags flags
31
+ flags.reject { |flag| # all hits are truthy, so this works out well
32
+ case flag
33
+ when /^-I(.*)/ then
34
+ rb_flags << flag
35
+ when /^-d/ then
36
+ rb_flags << flag
37
+ when /^-w/ then
38
+ rb_flags << flag
39
+ else
40
+ false
41
+ end
42
+ }
43
+ end
44
+ end
45
+
46
+ mtbv = ENV["MTB_VERBOSE"].to_i
47
+ SHH = case # :nodoc:
48
+ when mtbv == 1 then " > /dev/null"
49
+ when mtbv >= 2 then nil
50
+ else " > /dev/null 2>&1"
51
+ end
52
+
53
+ # Borrowed from rake
54
+ RUBY = ENV['RUBY'] ||
55
+ File.join(RbConfig::CONFIG['bindir'],
56
+ RbConfig::CONFIG['ruby_install_name'] +
57
+ RbConfig::CONFIG['EXEEXT']).sub(/.*\s.*/m, '"\&"')
58
+
59
+ ##
60
+ # True if this run has seen a failure.
61
+
62
+ attr_accessor :tainted
63
+ alias :tainted? :tainted
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
+
82
+ def self.run files
83
+ new.run files
84
+ rescue => e
85
+ warn e.message
86
+ warn "Try running with MTB_VERBOSE=2 to verify."
87
+ exit 1
88
+ end
89
+
90
+ ##
91
+ # Instantiate a new Bisect.
92
+
93
+ def initialize
94
+ self.culprits = []
95
+ self.failures = Hash.new { |h, k| h[k] = Hash.new { |h2, k2| h2[k2] = [] } }
96
+ end
97
+
98
+ ##
99
+ # Reset per-bisect-run variables.
100
+
101
+ def reset
102
+ self.seen_bad = false
103
+ self.tainted = false
104
+ failures.clear
105
+ # not clearing culprits on purpose
106
+ end
107
+
108
+ ##
109
+ # Instance-level runner. Handles Minitest::Server, argument
110
+ # processing, and invoking +bisect_methods+.
111
+
112
+ def run args
113
+ Minitest::Server.run self
114
+
115
+ cmd = nil
116
+
117
+ mt_flags = args.dup
118
+ expander = Minitest::Bisect::PathExpander.new mt_flags
119
+
120
+ files = expander.process.to_a
121
+ rb_flags = expander.rb_flags
122
+ mt_flags += ["--server", $$.to_s]
123
+
124
+ cmd = bisect_methods files, rb_flags, mt_flags
125
+
126
+ puts "Final reproduction:"
127
+ puts
128
+
129
+ system({"MINITEST_SERVER" => "1"}, cmd.sub(/--server \d+/, "", ))
130
+ ensure
131
+ Minitest::Server.stop
132
+ end
133
+
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
172
+ end
173
+
174
+ cmd = build_files_cmd(files, rb_flags, mt_flags)
175
+
176
+ msg = normal ? "reproducing..." : "reproducing false positive..."
177
+ time_it msg, build_methods_cmd(cmd)
178
+
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
185
+ end
186
+
187
+ if normal then
188
+ bad = map_failures
189
+
190
+ time_it "verifying...", build_methods_cmd(cmd, [], bad)
191
+
192
+ new_bad = map_failures
193
+
194
+ if bad == new_bad then
195
+ warn "Tests fail by themselves. This may not be an ordering issue."
196
+ end
197
+ end
198
+
199
+ idx = culprits.index bad.first
200
+ self.culprits = culprits.take idx+1 if idx # cull tests after bad
201
+
202
+ # culprits populated by initial reproduction via minitest/server
203
+ found, count = culprits.find_minimal_combination_and_count do |test|
204
+ prompt = "# of culprit methods: #{test.size}"
205
+
206
+ time_it prompt, build_methods_cmd(cmd, test, bad)
207
+
208
+ normal == tainted? # either normal and failed, or inverse and passed
209
+ end
210
+
211
+ puts
212
+ puts "Minimal methods found in #{count} steps:"
213
+ puts
214
+ puts "Culprit methods: %p" % [found + bad]
215
+ puts
216
+ cmd = build_methods_cmd cmd, found, bad
217
+ puts cmd.sub(/--server \d+/, "")
218
+ puts
219
+ cmd
220
+ end
221
+
222
+ def time_it prompt, cmd # :nodoc:
223
+ print prompt
224
+ t0 = Time.now
225
+ system({"MINITEST_SERVER" => "1"}, "#{cmd} #{SHH}")
226
+ puts " in %.2f sec" % (Time.now - t0)
227
+ end
228
+
229
+ def map_failures # :nodoc:
230
+ # from: {"file.rb"=>{"Class"=>["test_method1", "test_method2"]}}
231
+ # to: ["Class#test_method1", "Class#test_method2"]
232
+ failures.values.map { |h|
233
+ h.map { |k,vs| vs.map { |v| "#{k}##{v}" } }
234
+ }.flatten.sort
235
+ end
236
+
237
+ def build_files_cmd culprits, rb, mt, cmd:$0 # :nodoc:
238
+ ([cmd] + rb + culprits + mt).shelljoin
239
+ end
240
+
241
+ def build_methods_cmd cmd, culprits = [], bad = nil # :nodoc:
242
+ reset
243
+
244
+ if bad then
245
+ re = build_re culprits + bad
246
+
247
+ cmd += " -n \"#{re}\"" if bad
248
+ end
249
+
250
+ if ENV["MTB_VERBOSE"].to_i >= 1 then
251
+ puts
252
+ puts cmd
253
+ puts
254
+ end
255
+
256
+ cmd
257
+ end
258
+
259
+ def build_re bad # :nodoc:
260
+ re = []
261
+
262
+ # bad by class, you perv
263
+ bbc = bad.map { |s| s.split(/#/, 2) }.group_by(&:first)
264
+
265
+ bbc.each do |klass, methods|
266
+ methods = methods.map(&:last).flatten.uniq.map { |method|
267
+ re_escape method
268
+ }
269
+
270
+ methods = methods.join "|"
271
+ re << /#{re_escape klass}#(?:#{methods})/.to_s[7..-2] # (?-mix:...)
272
+ end
273
+
274
+ re = re.join("|").to_s.gsub(/-mix/, "")
275
+
276
+ "/^(?:#{re})$/"
277
+ end
278
+
279
+ def re_escape str # :nodoc:
280
+ str.gsub(/([`'"!?&\[\]\(\)\{\}\|\+])/, '\\\\\1')
281
+ end
282
+
283
+ ############################################################
284
+ # Server Methods:
285
+
286
+ def minitest_start # :nodoc:
287
+ self.failures.clear
288
+ end
289
+
290
+ def minitest_result file, klass, method, fails, assertions, time # :nodoc:
291
+ fails.reject! { |fail| Minitest::Skip === fail }
292
+
293
+ if fails.empty? then
294
+ culprits << "#{klass}##{method}" unless seen_bad # UGH
295
+ else
296
+ self.seen_bad = true
297
+ end
298
+
299
+ return if fails.empty?
300
+
301
+ self.tainted = true
302
+ self.failures[file][klass] << method
303
+ end
304
+ end
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env -S ruby
2
+
3
+ # :stopdoc:
4
+
5
+ require "optparse"
6
+ require "shellwords"
7
+
8
+ # complete -o bashdefault -f -C 'ruby lib/minitest/complete.rb' minitest
9
+ # using eg:
10
+ # COMP_LINE="blah test/test_file.rb -n test_pattern"
11
+ # or test directly with:
12
+ # ./lib/minitest/complete.rb test/test_file.rb -n test_pattern
13
+
14
+ argv = Shellwords.split ENV["COMP_LINE"] || ARGV.join(" ")
15
+ comp_re = nil
16
+
17
+ begin
18
+ OptionParser.new do |opts|
19
+ # part of my unofficial embedded gem "makeoptparseworkwell"
20
+ def opts.topdict(name) = (name.length > 1 ? top.long : top.short)
21
+ def opts.alias(from, to) = (dict = topdict(from) ; dict[to] = dict[from])
22
+
23
+ opts.on "-n", "--name [METHOD]", "minitest option" do |m|
24
+ comp_re = Regexp.new m
25
+ end
26
+
27
+ opts.alias "name", "include"
28
+ opts.alias "name", "exclude"
29
+ opts.alias "n", "i"
30
+ opts.alias "n", "e"
31
+ opts.alias "n", "x"
32
+ end.parse! argv
33
+ rescue
34
+ retry # ignore options passed to Ruby
35
+ end
36
+
37
+ path = argv.find_all { |f| File.file? f }.last
38
+
39
+ exit unless comp_re && path
40
+
41
+ require "prism"
42
+
43
+ names, queue = [], [Prism.parse_file(path).value]
44
+
45
+ while node = queue.shift do
46
+ if node.type == :def_node then
47
+ name = node.name
48
+ names << name if name =~ comp_re
49
+ else
50
+ queue.concat node.compact_child_nodes # no need to process def body
51
+ end
52
+ end
53
+
54
+ puts names.sort
55
+
56
+ # :startdoc:
@@ -0,0 +1,94 @@
1
+ module Minitest
2
+ ##
3
+ # Compresses backtraces.
4
+
5
+ module Compress
6
+
7
+ ##
8
+ # Takes a backtrace (array of strings) and compresses repeating
9
+ # cycles in it to make it more readable.
10
+
11
+ def compress orig
12
+ ary = orig
13
+
14
+ eswo = ->(a, n, off) { # each_slice_with_offset
15
+ if off.zero? then
16
+ a.each_slice n
17
+ else
18
+ # [ ...off... [...n...] [...n...] ... ]
19
+ front, back = a.take(off), a.drop(off)
20
+ [front].chain back.each_slice n
21
+ end
22
+ }
23
+
24
+ 3.times do # maybe don't use loop do here?
25
+ index = ary # [ a b c b c b c d ]
26
+ .size
27
+ .times # 0...size
28
+ .group_by { |i| ary[i] } # { a: [0] b: [1 3 5], c: [2 4 6], d: [7] }
29
+
30
+ order = index
31
+ .reject { |k, v| v.size == 1 } # { b: [1 3 5], c: [2 4 6] }
32
+ .sort_by { |k, a1| ### sort by max dist + min offset
33
+ d = a1.each_cons(2).sum { |a2, b| b-a2 }
34
+ [-d, a1.first]
35
+ } # b: [1 3 5] c: [2 4 6]
36
+
37
+ ranges = order
38
+ .map { |k, a1| # [[1..2 3..4] [2..3 4..5]]
39
+ a1
40
+ .each_cons(2)
41
+ .map { |a2, b| a2..b-1 }
42
+ }
43
+
44
+ big_ranges = ranges
45
+ .flat_map { |a| # [1..2 3..4 2..3 4..5]
46
+ a.sort_by { |r| [-r.size, r.first] }.first 5
47
+ }
48
+ .first(100)
49
+
50
+ culprits = big_ranges
51
+ .map { |r|
52
+ eswo[ary, r.size, r.begin] # [o1 s1 s1 s2 s2]
53
+ .chunk_while { |a, b| a == b } # [[o1] [s1 s1] [s2 s2]]
54
+ .map { |a| [a.size, a.first] } # [[1 o1] [2 s1] [2 s2]]
55
+ }
56
+ .select { |chunks|
57
+ chunks.any? { |a| a.first > 1 } # compressed anything?
58
+ }
59
+
60
+ min = culprits
61
+ .min_by { |a| a.flatten.size } # most compressed
62
+
63
+ break unless min
64
+
65
+ ary = min.flat_map { |(n, lines)|
66
+ if n > 1 then
67
+ [[n, compress(lines)]] # [o1 [2 s1] [2 s2]]
68
+ else
69
+ lines
70
+ end
71
+ }
72
+ end
73
+
74
+ format = ->(lines) {
75
+ lines.flat_map { |line|
76
+ case line
77
+ when Array then
78
+ n, lines = line
79
+ lines = format[lines]
80
+ [
81
+ " +->> #{n} cycles of #{lines.size} lines:",
82
+ *lines.map { |s| " | #{s}" },
83
+ " +-<<",
84
+ ]
85
+ else
86
+ line
87
+ end
88
+ }
89
+ }
90
+
91
+ format[ary]
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,11 @@
1
+ module Minitest
2
+
3
+ module ErrorOnWarning # :nodoc:
4
+ def warn message, category: nil
5
+ message = "[#{category}] #{message}" if category
6
+ raise UnexpectedWarning, message
7
+ end
8
+ end
9
+
10
+ ::Warning.singleton_class.prepend ErrorOnWarning
11
+ end