json 2.5.1 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +5 -5
  3. data/README.md +3 -3
  4. data/VERSION +1 -1
  5. data/ext/json/ext/generator/generator.c +1 -11
  6. data/ext/json/ext/parser/extconf.rb +1 -0
  7. data/ext/json/ext/parser/parser.c +2972 -1813
  8. data/ext/json/ext/parser/parser.h +5 -1
  9. data/ext/json/ext/parser/parser.rl +66 -28
  10. data/json.gemspec +2 -8
  11. data/lib/json/pure/parser.rb +1 -1
  12. data/lib/json/version.rb +1 -1
  13. data/lib/json.rb +1 -1
  14. metadata +6 -87
  15. data/Gemfile +0 -14
  16. data/lib/json/ext/.keep +0 -0
  17. data/tests/fixtures/fail10.json +0 -1
  18. data/tests/fixtures/fail11.json +0 -1
  19. data/tests/fixtures/fail12.json +0 -1
  20. data/tests/fixtures/fail13.json +0 -1
  21. data/tests/fixtures/fail14.json +0 -1
  22. data/tests/fixtures/fail18.json +0 -1
  23. data/tests/fixtures/fail19.json +0 -1
  24. data/tests/fixtures/fail2.json +0 -1
  25. data/tests/fixtures/fail20.json +0 -1
  26. data/tests/fixtures/fail21.json +0 -1
  27. data/tests/fixtures/fail22.json +0 -1
  28. data/tests/fixtures/fail23.json +0 -1
  29. data/tests/fixtures/fail24.json +0 -1
  30. data/tests/fixtures/fail25.json +0 -1
  31. data/tests/fixtures/fail27.json +0 -2
  32. data/tests/fixtures/fail28.json +0 -2
  33. data/tests/fixtures/fail29.json +0 -1
  34. data/tests/fixtures/fail3.json +0 -1
  35. data/tests/fixtures/fail30.json +0 -1
  36. data/tests/fixtures/fail31.json +0 -1
  37. data/tests/fixtures/fail32.json +0 -1
  38. data/tests/fixtures/fail4.json +0 -1
  39. data/tests/fixtures/fail5.json +0 -1
  40. data/tests/fixtures/fail6.json +0 -1
  41. data/tests/fixtures/fail7.json +0 -1
  42. data/tests/fixtures/fail8.json +0 -1
  43. data/tests/fixtures/fail9.json +0 -1
  44. data/tests/fixtures/obsolete_fail1.json +0 -1
  45. data/tests/fixtures/pass1.json +0 -56
  46. data/tests/fixtures/pass15.json +0 -1
  47. data/tests/fixtures/pass16.json +0 -1
  48. data/tests/fixtures/pass17.json +0 -1
  49. data/tests/fixtures/pass2.json +0 -1
  50. data/tests/fixtures/pass26.json +0 -1
  51. data/tests/fixtures/pass3.json +0 -6
  52. data/tests/json_addition_test.rb +0 -199
  53. data/tests/json_common_interface_test.rb +0 -169
  54. data/tests/json_encoding_test.rb +0 -107
  55. data/tests/json_ext_parser_test.rb +0 -15
  56. data/tests/json_fixtures_test.rb +0 -40
  57. data/tests/json_generator_test.rb +0 -399
  58. data/tests/json_generic_object_test.rb +0 -82
  59. data/tests/json_parser_test.rb +0 -497
  60. data/tests/json_string_matching_test.rb +0 -38
  61. data/tests/lib/core_assertions.rb +0 -763
  62. data/tests/lib/envutil.rb +0 -365
  63. data/tests/lib/find_executable.rb +0 -22
  64. data/tests/lib/helper.rb +0 -4
  65. data/tests/ractor_test.rb +0 -30
  66. data/tests/test_helper.rb +0 -17
@@ -1,763 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Test
4
- module Unit
5
- module Assertions
6
- def _assertions= n # :nodoc:
7
- @_assertions = n
8
- end
9
-
10
- def _assertions # :nodoc:
11
- @_assertions ||= 0
12
- end
13
-
14
- ##
15
- # Returns a proc that will output +msg+ along with the default message.
16
-
17
- def message msg = nil, ending = nil, &default
18
- proc {
19
- msg = msg.call.chomp(".") if Proc === msg
20
- custom_message = "#{msg}.\n" unless msg.nil? or msg.to_s.empty?
21
- "#{custom_message}#{default.call}#{ending || "."}"
22
- }
23
- end
24
- end
25
-
26
- module CoreAssertions
27
- if defined?(MiniTest)
28
- require_relative '../../envutil'
29
- # for ruby core testing
30
- include MiniTest::Assertions
31
-
32
- # Compatibility hack for assert_raise
33
- Test::Unit::AssertionFailedError = MiniTest::Assertion
34
- else
35
- module MiniTest
36
- class Assertion < Exception; end
37
- class Skip < Assertion; end
38
- end
39
-
40
- require 'pp'
41
- require_relative 'envutil'
42
- include Test::Unit::Assertions
43
- end
44
-
45
- def mu_pp(obj) #:nodoc:
46
- obj.pretty_inspect.chomp
47
- end
48
-
49
- def assert_file
50
- AssertFile
51
- end
52
-
53
- FailDesc = proc do |status, message = "", out = ""|
54
- now = Time.now
55
- proc do
56
- EnvUtil.failure_description(status, now, message, out)
57
- end
58
- end
59
-
60
- def assert_in_out_err(args, test_stdin = "", test_stdout = [], test_stderr = [], message = nil,
61
- success: nil, **opt)
62
- args = Array(args).dup
63
- args.insert((Hash === args[0] ? 1 : 0), '--disable=gems')
64
- stdout, stderr, status = EnvUtil.invoke_ruby(args, test_stdin, true, true, **opt)
65
- desc = FailDesc[status, message, stderr]
66
- if block_given?
67
- raise "test_stdout ignored, use block only or without block" if test_stdout != []
68
- raise "test_stderr ignored, use block only or without block" if test_stderr != []
69
- yield(stdout.lines.map {|l| l.chomp }, stderr.lines.map {|l| l.chomp }, status)
70
- else
71
- all_assertions(desc) do |a|
72
- [["stdout", test_stdout, stdout], ["stderr", test_stderr, stderr]].each do |key, exp, act|
73
- a.for(key) do
74
- if exp.is_a?(Regexp)
75
- assert_match(exp, act)
76
- elsif exp.all? {|e| String === e}
77
- assert_equal(exp, act.lines.map {|l| l.chomp })
78
- else
79
- assert_pattern_list(exp, act)
80
- end
81
- end
82
- end
83
- unless success.nil?
84
- a.for("success?") do
85
- if success
86
- assert_predicate(status, :success?)
87
- else
88
- assert_not_predicate(status, :success?)
89
- end
90
- end
91
- end
92
- end
93
- status
94
- end
95
- end
96
-
97
- if defined?(RubyVM::InstructionSequence)
98
- def syntax_check(code, fname, line)
99
- code = code.dup.force_encoding(Encoding::UTF_8)
100
- RubyVM::InstructionSequence.compile(code, fname, fname, line)
101
- :ok
102
- ensure
103
- raise if SyntaxError === $!
104
- end
105
- else
106
- def syntax_check(code, fname, line)
107
- code = code.b
108
- code.sub!(/\A(?:\xef\xbb\xbf)?(\s*\#.*$)*(\n)?/n) {
109
- "#$&#{"\n" if $1 && !$2}BEGIN{throw tag, :ok}\n"
110
- }
111
- code = code.force_encoding(Encoding::UTF_8)
112
- catch {|tag| eval(code, binding, fname, line - 1)}
113
- end
114
- end
115
-
116
- def assert_no_memory_leak(args, prepare, code, message=nil, limit: 2.0, rss: false, **opt)
117
- # TODO: consider choosing some appropriate limit for MJIT and stop skipping this once it does not randomly fail
118
- pend 'assert_no_memory_leak may consider MJIT memory usage as leak' if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled?
119
-
120
- require_relative '../../memory_status'
121
- raise MiniTest::Skip, "unsupported platform" unless defined?(Memory::Status)
122
-
123
- token = "\e[7;1m#{$$.to_s}:#{Time.now.strftime('%s.%L')}:#{rand(0x10000).to_s(16)}:\e[m"
124
- token_dump = token.dump
125
- token_re = Regexp.quote(token)
126
- envs = args.shift if Array === args and Hash === args.first
127
- args = [
128
- "--disable=gems",
129
- "-r", File.expand_path("../../../memory_status", __FILE__),
130
- *args,
131
- "-v", "-",
132
- ]
133
- if defined? Memory::NO_MEMORY_LEAK_ENVS then
134
- envs ||= {}
135
- newenvs = envs.merge(Memory::NO_MEMORY_LEAK_ENVS) { |_, _, _| break }
136
- envs = newenvs if newenvs
137
- end
138
- args.unshift(envs) if envs
139
- cmd = [
140
- 'END {STDERR.puts '"#{token_dump}"'"FINAL=#{Memory::Status.new}"}',
141
- prepare,
142
- 'STDERR.puts('"#{token_dump}"'"START=#{$initial_status = Memory::Status.new}")',
143
- '$initial_size = $initial_status.size',
144
- code,
145
- 'GC.start',
146
- ].join("\n")
147
- _, err, status = EnvUtil.invoke_ruby(args, cmd, true, true, **opt)
148
- before = err.sub!(/^#{token_re}START=(\{.*\})\n/, '') && Memory::Status.parse($1)
149
- after = err.sub!(/^#{token_re}FINAL=(\{.*\})\n/, '') && Memory::Status.parse($1)
150
- assert(status.success?, FailDesc[status, message, err])
151
- ([:size, (rss && :rss)] & after.members).each do |n|
152
- b = before[n]
153
- a = after[n]
154
- next unless a > 0 and b > 0
155
- assert_operator(a.fdiv(b), :<, limit, message(message) {"#{n}: #{b} => #{a}"})
156
- end
157
- rescue LoadError
158
- pend
159
- end
160
-
161
- # :call-seq:
162
- # assert_nothing_raised( *args, &block )
163
- #
164
- #If any exceptions are given as arguments, the assertion will
165
- #fail if one of those exceptions are raised. Otherwise, the test fails
166
- #if any exceptions are raised.
167
- #
168
- #The final argument may be a failure message.
169
- #
170
- # assert_nothing_raised RuntimeError do
171
- # raise Exception #Assertion passes, Exception is not a RuntimeError
172
- # end
173
- #
174
- # assert_nothing_raised do
175
- # raise Exception #Assertion fails
176
- # end
177
- def assert_nothing_raised(*args)
178
- self._assertions += 1
179
- if Module === args.last
180
- msg = nil
181
- else
182
- msg = args.pop
183
- end
184
- begin
185
- line = __LINE__; yield
186
- rescue MiniTest::Skip
187
- raise
188
- rescue Exception => e
189
- bt = e.backtrace
190
- as = e.instance_of?(MiniTest::Assertion)
191
- if as
192
- ans = /\A#{Regexp.quote(__FILE__)}:#{line}:in /o
193
- bt.reject! {|ln| ans =~ ln}
194
- end
195
- if ((args.empty? && !as) ||
196
- args.any? {|a| a.instance_of?(Module) ? e.is_a?(a) : e.class == a })
197
- msg = message(msg) {
198
- "Exception raised:\n<#{mu_pp(e)}>\n" +
199
- "Backtrace:\n" +
200
- e.backtrace.map{|frame| " #{frame}"}.join("\n")
201
- }
202
- raise MiniTest::Assertion, msg.call, bt
203
- else
204
- raise
205
- end
206
- end
207
- end
208
-
209
- def prepare_syntax_check(code, fname = nil, mesg = nil, verbose: nil)
210
- fname ||= caller_locations(2, 1)[0]
211
- mesg ||= fname.to_s
212
- verbose, $VERBOSE = $VERBOSE, verbose
213
- case
214
- when Array === fname
215
- fname, line = *fname
216
- when defined?(fname.path) && defined?(fname.lineno)
217
- fname, line = fname.path, fname.lineno
218
- else
219
- line = 1
220
- end
221
- yield(code, fname, line, message(mesg) {
222
- if code.end_with?("\n")
223
- "```\n#{code}```\n"
224
- else
225
- "```\n#{code}\n```\n""no-newline"
226
- end
227
- })
228
- ensure
229
- $VERBOSE = verbose
230
- end
231
-
232
- def assert_valid_syntax(code, *args, **opt)
233
- prepare_syntax_check(code, *args, **opt) do |src, fname, line, mesg|
234
- yield if defined?(yield)
235
- assert_nothing_raised(SyntaxError, mesg) do
236
- assert_equal(:ok, syntax_check(src, fname, line), mesg)
237
- end
238
- end
239
- end
240
-
241
- def assert_normal_exit(testsrc, message = '', child_env: nil, **opt)
242
- assert_valid_syntax(testsrc, caller_locations(1, 1)[0])
243
- if child_env
244
- child_env = [child_env]
245
- else
246
- child_env = []
247
- end
248
- out, _, status = EnvUtil.invoke_ruby(child_env + %W'-W0', testsrc, true, :merge_to_stdout, **opt)
249
- assert !status.signaled?, FailDesc[status, message, out]
250
- end
251
-
252
- def assert_ruby_status(args, test_stdin="", message=nil, **opt)
253
- out, _, status = EnvUtil.invoke_ruby(args, test_stdin, true, :merge_to_stdout, **opt)
254
- desc = FailDesc[status, message, out]
255
- assert(!status.signaled?, desc)
256
- message ||= "ruby exit status is not success:"
257
- assert(status.success?, desc)
258
- end
259
-
260
- ABORT_SIGNALS = Signal.list.values_at(*%w"ILL ABRT BUS SEGV TERM")
261
-
262
- def separated_runner(out = nil)
263
- out = out ? IO.new(out, 'w') : STDOUT
264
- at_exit {
265
- out.puts [Marshal.dump($!)].pack('m'), "assertions=\#{self._assertions}"
266
- }
267
- Test::Unit::Runner.class_variable_set(:@@stop_auto_run, true) if defined?(Test::Unit::Runner)
268
- end
269
-
270
- def assert_separately(args, file = nil, line = nil, src, ignore_stderr: nil, **opt)
271
- unless file and line
272
- loc, = caller_locations(1,1)
273
- file ||= loc.path
274
- line ||= loc.lineno
275
- end
276
- capture_stdout = true
277
- unless /mswin|mingw/ =~ RUBY_PLATFORM
278
- capture_stdout = false
279
- opt[:out] = MiniTest::Unit.output if defined?(MiniTest::Unit)
280
- res_p, res_c = IO.pipe
281
- opt[res_c.fileno] = res_c.fileno
282
- end
283
- src = <<eom
284
- # -*- coding: #{line += __LINE__; src.encoding}; -*-
285
- BEGIN {
286
- require "test/unit";include Test::Unit::Assertions;require #{(__dir__ + "/core_assertions").dump};include Test::Unit::CoreAssertions
287
- separated_runner #{res_c&.fileno}
288
- }
289
- #{line -= __LINE__; src}
290
- eom
291
- args = args.dup
292
- args.insert((Hash === args.first ? 1 : 0), "-w", "--disable=gems", *$:.map {|l| "-I#{l}"})
293
- stdout, stderr, status = EnvUtil.invoke_ruby(args, src, capture_stdout, true, **opt)
294
- ensure
295
- if res_c
296
- res_c.close
297
- res = res_p.read
298
- res_p.close
299
- else
300
- res = stdout
301
- end
302
- raise if $!
303
- abort = status.coredump? || (status.signaled? && ABORT_SIGNALS.include?(status.termsig))
304
- assert(!abort, FailDesc[status, nil, stderr])
305
- self._assertions += res[/^assertions=(\d+)/, 1].to_i
306
- begin
307
- res = Marshal.load(res.unpack1("m"))
308
- rescue => marshal_error
309
- ignore_stderr = nil
310
- res = nil
311
- end
312
- if res and !(SystemExit === res)
313
- if bt = res.backtrace
314
- bt.each do |l|
315
- l.sub!(/\A-:(\d+)/){"#{file}:#{line + $1.to_i}"}
316
- end
317
- bt.concat(caller)
318
- else
319
- res.set_backtrace(caller)
320
- end
321
- raise res
322
- end
323
-
324
- # really is it succeed?
325
- unless ignore_stderr
326
- # the body of assert_separately must not output anything to detect error
327
- assert(stderr.empty?, FailDesc[status, "assert_separately failed with error message", stderr])
328
- end
329
- assert(status.success?, FailDesc[status, "assert_separately failed", stderr])
330
- raise marshal_error if marshal_error
331
- end
332
-
333
- # Run Ractor-related test without influencing the main test suite
334
- def assert_ractor(src, args: [], require: nil, require_relative: nil, file: nil, line: nil, ignore_stderr: nil, **opt)
335
- return unless defined?(Ractor)
336
-
337
- require = "require #{require.inspect}" if require
338
- if require_relative
339
- dir = File.dirname(caller_locations[0,1][0].absolute_path)
340
- full_path = File.expand_path(require_relative, dir)
341
- require = "#{require}; require #{full_path.inspect}"
342
- end
343
-
344
- assert_separately(args, file, line, <<~RUBY, ignore_stderr: ignore_stderr, **opt)
345
- #{require}
346
- previous_verbose = $VERBOSE
347
- $VERBOSE = nil
348
- Ractor.new {} # trigger initial warning
349
- $VERBOSE = previous_verbose
350
- #{src}
351
- RUBY
352
- end
353
-
354
- # :call-seq:
355
- # assert_throw( tag, failure_message = nil, &block )
356
- #
357
- #Fails unless the given block throws +tag+, returns the caught
358
- #value otherwise.
359
- #
360
- #An optional failure message may be provided as the final argument.
361
- #
362
- # tag = Object.new
363
- # assert_throw(tag, "#{tag} was not thrown!") do
364
- # throw tag
365
- # end
366
- def assert_throw(tag, msg = nil)
367
- ret = catch(tag) do
368
- begin
369
- yield(tag)
370
- rescue UncaughtThrowError => e
371
- thrown = e.tag
372
- end
373
- msg = message(msg) {
374
- "Expected #{mu_pp(tag)} to have been thrown"\
375
- "#{%Q[, not #{thrown}] if thrown}"
376
- }
377
- assert(false, msg)
378
- end
379
- assert(true)
380
- ret
381
- end
382
-
383
- # :call-seq:
384
- # assert_raise( *args, &block )
385
- #
386
- #Tests if the given block raises an exception. Acceptable exception
387
- #types may be given as optional arguments. If the last argument is a
388
- #String, it will be used as the error message.
389
- #
390
- # assert_raise do #Fails, no Exceptions are raised
391
- # end
392
- #
393
- # assert_raise NameError do
394
- # puts x #Raises NameError, so assertion succeeds
395
- # end
396
- def assert_raise(*exp, &b)
397
- case exp.last
398
- when String, Proc
399
- msg = exp.pop
400
- end
401
-
402
- begin
403
- yield
404
- rescue MiniTest::Skip => e
405
- return e if exp.include? MiniTest::Skip
406
- raise e
407
- rescue Exception => e
408
- expected = exp.any? { |ex|
409
- if ex.instance_of? Module then
410
- e.kind_of? ex
411
- else
412
- e.instance_of? ex
413
- end
414
- }
415
-
416
- assert expected, proc {
417
- flunk(message(msg) {"#{mu_pp(exp)} exception expected, not #{mu_pp(e)}"})
418
- }
419
-
420
- return e
421
- ensure
422
- unless e
423
- exp = exp.first if exp.size == 1
424
-
425
- flunk(message(msg) {"#{mu_pp(exp)} expected but nothing was raised"})
426
- end
427
- end
428
- end
429
-
430
- # :call-seq:
431
- # assert_raise_with_message(exception, expected, msg = nil, &block)
432
- #
433
- #Tests if the given block raises an exception with the expected
434
- #message.
435
- #
436
- # assert_raise_with_message(RuntimeError, "foo") do
437
- # nil #Fails, no Exceptions are raised
438
- # end
439
- #
440
- # assert_raise_with_message(RuntimeError, "foo") do
441
- # raise ArgumentError, "foo" #Fails, different Exception is raised
442
- # end
443
- #
444
- # assert_raise_with_message(RuntimeError, "foo") do
445
- # raise "bar" #Fails, RuntimeError is raised but the message differs
446
- # end
447
- #
448
- # assert_raise_with_message(RuntimeError, "foo") do
449
- # raise "foo" #Raises RuntimeError with the message, so assertion succeeds
450
- # end
451
- def assert_raise_with_message(exception, expected, msg = nil, &block)
452
- case expected
453
- when String
454
- assert = :assert_equal
455
- when Regexp
456
- assert = :assert_match
457
- else
458
- raise TypeError, "Expected #{expected.inspect} to be a kind of String or Regexp, not #{expected.class}"
459
- end
460
-
461
- ex = m = nil
462
- EnvUtil.with_default_internal(expected.encoding) do
463
- ex = assert_raise(exception, msg || proc {"Exception(#{exception}) with message matches to #{expected.inspect}"}) do
464
- yield
465
- end
466
- m = ex.message
467
- end
468
- msg = message(msg, "") {"Expected Exception(#{exception}) was raised, but the message doesn't match"}
469
-
470
- if assert == :assert_equal
471
- assert_equal(expected, m, msg)
472
- else
473
- msg = message(msg) { "Expected #{mu_pp expected} to match #{mu_pp m}" }
474
- assert expected =~ m, msg
475
- block.binding.eval("proc{|_|$~=_}").call($~)
476
- end
477
- ex
478
- end
479
-
480
- MINI_DIR = File.join(File.dirname(File.dirname(File.expand_path(__FILE__))), "minitest") #:nodoc:
481
-
482
- # :call-seq:
483
- # assert(test, [failure_message])
484
- #
485
- #Tests if +test+ is true.
486
- #
487
- #+msg+ may be a String or a Proc. If +msg+ is a String, it will be used
488
- #as the failure message. Otherwise, the result of calling +msg+ will be
489
- #used as the message if the assertion fails.
490
- #
491
- #If no +msg+ is given, a default message will be used.
492
- #
493
- # assert(false, "This was expected to be true")
494
- def assert(test, *msgs)
495
- case msg = msgs.first
496
- when String, Proc
497
- when nil
498
- msgs.shift
499
- else
500
- bt = caller.reject { |s| s.start_with?(MINI_DIR) }
501
- raise ArgumentError, "assertion message must be String or Proc, but #{msg.class} was given.", bt
502
- end unless msgs.empty?
503
- super
504
- end
505
-
506
- # :call-seq:
507
- # assert_respond_to( object, method, failure_message = nil )
508
- #
509
- #Tests if the given Object responds to +method+.
510
- #
511
- #An optional failure message may be provided as the final argument.
512
- #
513
- # assert_respond_to("hello", :reverse) #Succeeds
514
- # assert_respond_to("hello", :does_not_exist) #Fails
515
- def assert_respond_to(obj, (meth, *priv), msg = nil)
516
- unless priv.empty?
517
- msg = message(msg) {
518
- "Expected #{mu_pp(obj)} (#{obj.class}) to respond to ##{meth}#{" privately" if priv[0]}"
519
- }
520
- return assert obj.respond_to?(meth, *priv), msg
521
- end
522
- #get rid of overcounting
523
- if caller_locations(1, 1)[0].path.start_with?(MINI_DIR)
524
- return if obj.respond_to?(meth)
525
- end
526
- super(obj, meth, msg)
527
- end
528
-
529
- # :call-seq:
530
- # assert_not_respond_to( object, method, failure_message = nil )
531
- #
532
- #Tests if the given Object does not respond to +method+.
533
- #
534
- #An optional failure message may be provided as the final argument.
535
- #
536
- # assert_not_respond_to("hello", :reverse) #Fails
537
- # assert_not_respond_to("hello", :does_not_exist) #Succeeds
538
- def assert_not_respond_to(obj, (meth, *priv), msg = nil)
539
- unless priv.empty?
540
- msg = message(msg) {
541
- "Expected #{mu_pp(obj)} (#{obj.class}) to not respond to ##{meth}#{" privately" if priv[0]}"
542
- }
543
- return assert !obj.respond_to?(meth, *priv), msg
544
- end
545
- #get rid of overcounting
546
- if caller_locations(1, 1)[0].path.start_with?(MINI_DIR)
547
- return unless obj.respond_to?(meth)
548
- end
549
- refute_respond_to(obj, meth, msg)
550
- end
551
-
552
- # pattern_list is an array which contains regexp and :*.
553
- # :* means any sequence.
554
- #
555
- # pattern_list is anchored.
556
- # Use [:*, regexp, :*] for non-anchored match.
557
- def assert_pattern_list(pattern_list, actual, message=nil)
558
- rest = actual
559
- anchored = true
560
- pattern_list.each_with_index {|pattern, i|
561
- if pattern == :*
562
- anchored = false
563
- else
564
- if anchored
565
- match = /\A#{pattern}/.match(rest)
566
- else
567
- match = pattern.match(rest)
568
- end
569
- unless match
570
- msg = message(msg) {
571
- expect_msg = "Expected #{mu_pp pattern}\n"
572
- if /\n[^\n]/ =~ rest
573
- actual_mesg = +"to match\n"
574
- rest.scan(/.*\n+/) {
575
- actual_mesg << ' ' << $&.inspect << "+\n"
576
- }
577
- actual_mesg.sub!(/\+\n\z/, '')
578
- else
579
- actual_mesg = "to match " + mu_pp(rest)
580
- end
581
- actual_mesg << "\nafter #{i} patterns with #{actual.length - rest.length} characters"
582
- expect_msg + actual_mesg
583
- }
584
- assert false, msg
585
- end
586
- rest = match.post_match
587
- anchored = true
588
- end
589
- }
590
- if anchored
591
- assert_equal("", rest)
592
- end
593
- end
594
-
595
- def assert_warning(pat, msg = nil)
596
- result = nil
597
- stderr = EnvUtil.with_default_internal(pat.encoding) {
598
- EnvUtil.verbose_warning {
599
- result = yield
600
- }
601
- }
602
- msg = message(msg) {diff pat, stderr}
603
- assert(pat === stderr, msg)
604
- result
605
- end
606
-
607
- def assert_warn(*args)
608
- assert_warning(*args) {$VERBOSE = false; yield}
609
- end
610
-
611
- def assert_deprecated_warning(mesg = /deprecated/)
612
- assert_warning(mesg) do
613
- Warning[:deprecated] = true
614
- yield
615
- end
616
- end
617
-
618
- def assert_deprecated_warn(mesg = /deprecated/)
619
- assert_warn(mesg) do
620
- Warning[:deprecated] = true
621
- yield
622
- end
623
- end
624
-
625
- class << (AssertFile = Struct.new(:failure_message).new)
626
- include CoreAssertions
627
- def assert_file_predicate(predicate, *args)
628
- if /\Anot_/ =~ predicate
629
- predicate = $'
630
- neg = " not"
631
- end
632
- result = File.__send__(predicate, *args)
633
- result = !result if neg
634
- mesg = "Expected file ".dup << args.shift.inspect
635
- mesg << "#{neg} to be #{predicate}"
636
- mesg << mu_pp(args).sub(/\A\[(.*)\]\z/m, '(\1)') unless args.empty?
637
- mesg << " #{failure_message}" if failure_message
638
- assert(result, mesg)
639
- end
640
- alias method_missing assert_file_predicate
641
-
642
- def for(message)
643
- clone.tap {|a| a.failure_message = message}
644
- end
645
- end
646
-
647
- class AllFailures
648
- attr_reader :failures
649
-
650
- def initialize
651
- @count = 0
652
- @failures = {}
653
- end
654
-
655
- def for(key)
656
- @count += 1
657
- yield
658
- rescue Exception => e
659
- @failures[key] = [@count, e]
660
- end
661
-
662
- def foreach(*keys)
663
- keys.each do |key|
664
- @count += 1
665
- begin
666
- yield key
667
- rescue Exception => e
668
- @failures[key] = [@count, e]
669
- end
670
- end
671
- end
672
-
673
- def message
674
- i = 0
675
- total = @count.to_s
676
- fmt = "%#{total.size}d"
677
- @failures.map {|k, (n, v)|
678
- v = v.message
679
- "\n#{i+=1}. [#{fmt%n}/#{total}] Assertion for #{k.inspect}\n#{v.b.gsub(/^/, ' | ').force_encoding(v.encoding)}"
680
- }.join("\n")
681
- end
682
-
683
- def pass?
684
- @failures.empty?
685
- end
686
- end
687
-
688
- # threads should respond to shift method.
689
- # Array can be used.
690
- def assert_join_threads(threads, message = nil)
691
- errs = []
692
- values = []
693
- while th = threads.shift
694
- begin
695
- values << th.value
696
- rescue Exception
697
- errs << [th, $!]
698
- th = nil
699
- end
700
- end
701
- values
702
- ensure
703
- if th&.alive?
704
- th.raise(Timeout::Error.new)
705
- th.join rescue errs << [th, $!]
706
- end
707
- if !errs.empty?
708
- msg = "exceptions on #{errs.length} threads:\n" +
709
- errs.map {|t, err|
710
- "#{t.inspect}:\n" +
711
- RUBY_VERSION >= "2.5.0" ? err.full_message(highlight: false, order: :top) : err.message
712
- }.join("\n---\n")
713
- if message
714
- msg = "#{message}\n#{msg}"
715
- end
716
- raise MiniTest::Assertion, msg
717
- end
718
- end
719
-
720
- def assert_all_assertions(msg = nil)
721
- all = AllFailures.new
722
- yield all
723
- ensure
724
- assert(all.pass?, message(msg) {all.message.chomp(".")})
725
- end
726
- alias all_assertions assert_all_assertions
727
-
728
- def message(msg = nil, *args, &default) # :nodoc:
729
- if Proc === msg
730
- super(nil, *args) do
731
- ary = [msg.call, (default.call if default)].compact.reject(&:empty?)
732
- if 1 < ary.length
733
- ary[0...-1] = ary[0...-1].map {|str| str.sub(/(?<!\.)\z/, '.') }
734
- end
735
- begin
736
- ary.join("\n")
737
- rescue Encoding::CompatibilityError
738
- ary.map(&:b).join("\n")
739
- end
740
- end
741
- else
742
- super
743
- end
744
- end
745
-
746
- def diff(exp, act)
747
- require 'pp'
748
- q = PP.new(+"")
749
- q.guard_inspect_key do
750
- q.group(2, "expected: ") do
751
- q.pp exp
752
- end
753
- q.text q.newline
754
- q.group(2, "actual: ") do
755
- q.pp act
756
- end
757
- q.flush
758
- end
759
- q.output
760
- end
761
- end
762
- end
763
- end