3
3
module Test
4
4
module Unit
5
5
module Assertions
6
+ def assert_raises ( *exp , &b )
7
+ raise NoMethodError , "use assert_raise" , caller
8
+ end
9
+
6
10
def _assertions = n # :nodoc:
7
11
@_assertions = n
8
12
end
@@ -16,16 +20,24 @@ def _assertions # :nodoc:
16
20
17
21
def message msg = nil , ending = nil , &default
18
22
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 || "." } "
23
+ ending ||= ( ending_pattern = /(?<!\. )\z / ; "." )
24
+ ending_pattern ||= /(?<!#{ Regexp . quote ( ending ) } )\z /
25
+ msg = msg . call if Proc === msg
26
+ ary = [ msg , ( default . call if default ) ] . compact . reject ( &:empty? )
27
+ ary . map! { |str | str . to_s . sub ( ending_pattern , ending ) }
28
+ begin
29
+ ary . join ( "\n " )
30
+ rescue Encoding ::CompatibilityError
31
+ ary . map ( &:b ) . join ( "\n " )
32
+ end
22
33
}
23
34
end
24
35
end
25
36
26
37
module CoreAssertions
27
38
require_relative 'envutil'
28
39
require 'pp'
40
+ nil . pretty_inspect
29
41
30
42
def mu_pp ( obj ) #:nodoc:
31
43
obj . pretty_inspect . chomp
@@ -101,13 +113,13 @@ def syntax_check(code, fname, line)
101
113
def assert_no_memory_leak ( args , prepare , code , message = nil , limit : 2.0 , rss : false , **opt )
102
114
# TODO: consider choosing some appropriate limit for RJIT and stop skipping this once it does not randomly fail
103
115
pend 'assert_no_memory_leak may consider RJIT memory usage as leak' if defined? ( RubyVM ::RJIT ) && RubyVM ::RJIT . enabled?
116
+ # For previous versions which implemented MJIT
117
+ pend 'assert_no_memory_leak may consider MJIT memory usage as leak' if defined? ( RubyVM ::MJIT ) && RubyVM ::MJIT . enabled?
104
118
105
119
require_relative 'memory_status'
106
120
raise Test ::Unit ::PendedError , "unsupported platform" unless defined? ( Memory ::Status )
107
121
108
- token = "\e [7;1m#{ $$. to_s } :#{ Time . now . strftime ( '%s.%L' ) } :#{ rand ( 0x10000 ) . to_s ( 16 ) } :\e [m"
109
- token_dump = token . dump
110
- token_re = Regexp . quote ( token )
122
+ token_dump , token_re = new_test_token
111
123
envs = args . shift if Array === args and Hash === args . first
112
124
args = [
113
125
"--disable=gems" ,
@@ -167,27 +179,15 @@ def assert_nothing_raised(*args)
167
179
msg = args . pop
168
180
end
169
181
begin
170
- line = __LINE__ ; yield
171
- rescue Test ::Unit ::PendedError
182
+ yield
183
+ rescue Test ::Unit ::PendedError , * ( Test :: Unit :: AssertionFailedError if args . empty? )
172
184
raise
173
- rescue Exception => e
174
- bt = e . backtrace
175
- as = e . instance_of? ( Test ::Unit ::AssertionFailedError )
176
- if as
177
- ans = /\A #{ Regexp . quote ( __FILE__ ) } :#{ line } :in /o
178
- bt . reject! { |ln | ans =~ ln }
179
- end
180
- if ( ( args . empty? && !as ) ||
181
- args . any? { |a | a . instance_of? ( Module ) ? e . is_a? ( a ) : e . class == a } )
182
- msg = message ( msg ) {
183
- "Exception raised:\n <#{ mu_pp ( e ) } >\n " +
184
- "Backtrace:\n " +
185
- e . backtrace . map { |frame | " #{ frame } " } . join ( "\n " )
186
- }
187
- raise Test ::Unit ::AssertionFailedError , msg . call , bt
188
- else
189
- raise
190
- end
185
+ rescue *( args . empty? ? Exception : args ) => e
186
+ msg = message ( msg ) {
187
+ "Exception raised:\n <#{ mu_pp ( e ) } >\n " "Backtrace:\n " <<
188
+ Test . filter_backtrace ( e . backtrace ) . map { |frame | " #{ frame } " } . join ( "\n " )
189
+ }
190
+ raise Test ::Unit ::AssertionFailedError , msg . call , e . backtrace
191
191
end
192
192
end
193
193
@@ -244,13 +244,17 @@ def assert_ruby_status(args, test_stdin="", message=nil, **opt)
244
244
245
245
ABORT_SIGNALS = Signal . list . values_at ( *%w" ILL ABRT BUS SEGV TERM " )
246
246
247
- def separated_runner ( out = nil )
247
+ def separated_runner ( token , out = nil )
248
248
include ( *Test ::Unit ::TestCase . ancestors . select { |c | !c . is_a? ( Class ) } )
249
249
out = out ? IO . new ( out , 'w' ) : STDOUT
250
250
at_exit {
251
- out . puts [ Marshal . dump ( $!) ] . pack ( 'm' ) , "assertions=#{ self . _assertions } "
251
+ out . puts " #{ token } <error>" , [ Marshal . dump ( $!) ] . pack ( 'm' ) , "#{ token } </error>" , " #{ token } assertions=#{ self . _assertions } "
252
252
}
253
- Test ::Unit ::Runner . class_variable_set ( :@@stop_auto_run , true ) if defined? ( Test ::Unit ::Runner )
253
+ if defined? ( Test ::Unit ::Runner )
254
+ Test ::Unit ::Runner . class_variable_set ( :@@stop_auto_run , true )
255
+ elsif defined? ( Test ::Unit ::AutoRunner )
256
+ Test ::Unit ::AutoRunner . need_auto_run = false
257
+ end
254
258
end
255
259
256
260
def assert_separately ( args , file = nil , line = nil , src , ignore_stderr : nil , **opt )
@@ -260,22 +264,24 @@ def assert_separately(args, file = nil, line = nil, src, ignore_stderr: nil, **o
260
264
line ||= loc . lineno
261
265
end
262
266
capture_stdout = true
263
- unless /mswin|mingw/ =~ RUBY_PLATFORM
267
+ unless /mswin|mingw/ =~ RbConfig :: CONFIG [ 'host_os' ]
264
268
capture_stdout = false
265
269
opt [ :out ] = Test ::Unit ::Runner . output if defined? ( Test ::Unit ::Runner )
266
270
res_p , res_c = IO . pipe
267
271
opt [ :ios ] = [ res_c ]
268
272
end
273
+ token_dump , token_re = new_test_token
269
274
src = <<eom
270
275
# -*- coding: #{ line += __LINE__ ; src . encoding } ; -*-
271
276
BEGIN {
272
277
require "test/unit";include Test::Unit::Assertions;require #{ __FILE__ . dump } ;include Test::Unit::CoreAssertions
273
- separated_runner #{ res_c &.fileno }
278
+ separated_runner #{ token_dump } , #{ res_c &.fileno || 'nil' }
274
279
}
275
280
#{ line -= __LINE__ ; src }
276
281
eom
277
282
args = args . dup
278
283
args . insert ( ( Hash === args . first ? 1 : 0 ) , "-w" , "--disable=gems" , *$:. map { |l | "-I#{ l } " } )
284
+ args << "--debug" if RUBY_ENGINE == 'jruby' # warning: tracing (e.g. set_trace_func) will not capture all events without --debug flag
279
285
stdout , stderr , status = EnvUtil . invoke_ruby ( args , src , capture_stdout , true , **opt )
280
286
ensure
281
287
if res_c
@@ -288,9 +294,9 @@ def assert_separately(args, file = nil, line = nil, src, ignore_stderr: nil, **o
288
294
raise if $!
289
295
abort = status . coredump? || ( status . signaled? && ABORT_SIGNALS . include? ( status . termsig ) )
290
296
assert ( !abort , FailDesc [ status , nil , stderr ] )
291
- self . _assertions += res [ /^assertions=(\d +)/ , 1 ] . to_i
297
+ self . _assertions += res [ /^#{ token_re } assertions=(\d +)/ , 1 ] . to_i
292
298
begin
293
- res = Marshal . load ( res . unpack1 ( "m" ) )
299
+ res = Marshal . load ( res [ /^ #{ token_re } <error> \n \K .* \n (?= #{ token_re } < \/ error>$)/m ] . unpack1 ( "m" ) )
294
300
rescue => marshal_error
295
301
ignore_stderr = nil
296
302
res = nil
@@ -463,7 +469,7 @@ def assert_raise_with_message(exception, expected, msg = nil, &block)
463
469
ex
464
470
end
465
471
466
- MINI_DIR = File . join ( File . dirname ( File . expand_path ( __FILE__ ) ) , "minitest " ) #:nodoc:
472
+ TEST_DIR = File . join ( __dir__ , "test/unit " ) #:nodoc:
467
473
468
474
# :call-seq:
469
475
# assert(test, [failure_message])
@@ -483,7 +489,7 @@ def assert(test, *msgs)
483
489
when nil
484
490
msgs . shift
485
491
else
486
- bt = caller . reject { |s | s . start_with? ( MINI_DIR ) }
492
+ bt = caller . reject { |s | s . start_with? ( TEST_DIR ) }
487
493
raise ArgumentError , "assertion message must be String or Proc, but #{ msg . class } was given." , bt
488
494
end unless msgs . empty?
489
495
super
@@ -506,7 +512,7 @@ def assert_respond_to(obj, (meth, *priv), msg = nil)
506
512
return assert obj . respond_to? ( meth , *priv ) , msg
507
513
end
508
514
#get rid of overcounting
509
- if caller_locations ( 1 , 1 ) [ 0 ] . path . start_with? ( MINI_DIR )
515
+ if caller_locations ( 1 , 1 ) [ 0 ] . path . start_with? ( TEST_DIR )
510
516
return if obj . respond_to? ( meth )
511
517
end
512
518
super ( obj , meth , msg )
@@ -529,17 +535,17 @@ def assert_not_respond_to(obj, (meth, *priv), msg = nil)
529
535
return assert !obj . respond_to? ( meth , *priv ) , msg
530
536
end
531
537
#get rid of overcounting
532
- if caller_locations ( 1 , 1 ) [ 0 ] . path . start_with? ( MINI_DIR )
538
+ if caller_locations ( 1 , 1 ) [ 0 ] . path . start_with? ( TEST_DIR )
533
539
return unless obj . respond_to? ( meth )
534
540
end
535
541
refute_respond_to ( obj , meth , msg )
536
542
end
537
543
538
- # pattern_list is an array which contains regexp and :*.
544
+ # pattern_list is an array which contains regexp, string and :*.
539
545
# :* means any sequence.
540
546
#
541
547
# pattern_list is anchored.
542
- # Use [:*, regexp, :*] for non-anchored match.
548
+ # Use [:*, regexp/string , :*] for non-anchored match.
543
549
def assert_pattern_list ( pattern_list , actual , message = nil )
544
550
rest = actual
545
551
anchored = true
@@ -548,11 +554,13 @@ def assert_pattern_list(pattern_list, actual, message=nil)
548
554
anchored = false
549
555
else
550
556
if anchored
551
- match = / \A #{ pattern } / . match ( rest )
557
+ match = rest . rindex ( pattern , 0 )
552
558
else
553
- match = pattern . match ( rest )
559
+ match = rest . index ( pattern )
554
560
end
555
- unless match
561
+ if match
562
+ post_match = $~ ? $~. post_match : rest [ match +pattern . size ..-1 ]
563
+ else
556
564
msg = message ( msg ) {
557
565
expect_msg = "Expected #{ mu_pp pattern } \n "
558
566
if /\n [^\n ]/ =~ rest
@@ -569,7 +577,7 @@ def assert_pattern_list(pattern_list, actual, message=nil)
569
577
}
570
578
assert false , msg
571
579
end
572
- rest = match . post_match
580
+ rest = post_match
573
581
anchored = true
574
582
end
575
583
}
@@ -596,14 +604,14 @@ def assert_warn(*args)
596
604
597
605
def assert_deprecated_warning ( mesg = /deprecated/ )
598
606
assert_warning ( mesg ) do
599
- Warning [ :deprecated ] = true
607
+ Warning [ :deprecated ] = true if Warning . respond_to? ( :[]= )
600
608
yield
601
609
end
602
610
end
603
611
604
612
def assert_deprecated_warn ( mesg = /deprecated/ )
605
613
assert_warn ( mesg ) do
606
- Warning [ :deprecated ] = true
614
+ Warning [ :deprecated ] = true if Warning . respond_to? ( :[]= )
607
615
yield
608
616
end
609
617
end
@@ -641,7 +649,7 @@ def initialize
641
649
642
650
def for ( key )
643
651
@count += 1
644
- yield
652
+ yield key
645
653
rescue Exception => e
646
654
@failures [ key ] = [ @count , e ]
647
655
end
@@ -695,7 +703,7 @@ def assert_join_threads(threads, message = nil)
695
703
msg = "exceptions on #{ errs . length } threads:\n " +
696
704
errs . map { |t , err |
697
705
"#{ t . inspect } :\n " +
698
- RUBY_VERSION >= "2.5.0" ? err . full_message ( highlight : false , order : :top ) : err . message
706
+ ( err . respond_to? ( :full_message ) ? err . full_message ( highlight : false , order : :top ) : err . message )
699
707
} . join ( "\n ---\n " )
700
708
if message
701
709
msg = "#{ message } \n #{ msg } "
@@ -730,21 +738,36 @@ def assert_all_assertions_foreach(msg = nil, *keys, &block)
730
738
end
731
739
alias all_assertions_foreach assert_all_assertions_foreach
732
740
733
- def message ( msg = nil , *args , &default ) # :nodoc:
734
- if Proc === msg
735
- super ( nil , *args ) do
736
- ary = [ msg . call , ( default . call if default ) ] . compact . reject ( &:empty? )
737
- if 1 < ary . length
738
- ary [ 0 ...-1 ] = ary [ 0 ...-1 ] . map { |str | str . sub ( /(?<!\. )\z / , '.' ) }
739
- end
740
- begin
741
- ary . join ( "\n " )
742
- rescue Encoding ::CompatibilityError
743
- ary . map ( &:b ) . join ( "\n " )
744
- end
741
+ # Expect +seq+ to respond to +first+ and +each+ methods, e.g.,
742
+ # Array, Range, Enumerator::ArithmeticSequence and other
743
+ # Enumerable-s, and each elements should be size factors.
744
+ #
745
+ # :yield: each elements of +seq+.
746
+ def assert_linear_performance ( seq , rehearsal : nil , pre : -> ( n ) { n } )
747
+ first = seq . first
748
+ *arg = pre . call ( first )
749
+ times = ( 0 ..( rehearsal || ( 2 * first ) ) ) . map do
750
+ st = Process . clock_gettime ( Process ::CLOCK_MONOTONIC )
751
+ yield ( *arg )
752
+ t = ( Process . clock_gettime ( Process ::CLOCK_MONOTONIC ) - st )
753
+ assert_operator 0 , :<= , t
754
+ t . nonzero?
755
+ end
756
+ times . compact!
757
+ tmin , tmax = times . minmax
758
+ tmax *= tmax / tmin
759
+ tmax = 10 **Math . log10 ( tmax ) . ceil
760
+
761
+ seq . each do |i |
762
+ next if i == first
763
+ t = tmax * i . fdiv ( first )
764
+ *arg = pre . call ( i )
765
+ message = "[#{ i } ]: in #{ t } s"
766
+ Timeout . timeout ( t , Timeout ::Error , message ) do
767
+ st = Process . clock_gettime ( Process ::CLOCK_MONOTONIC )
768
+ yield ( *arg )
769
+ assert_operator ( Process . clock_gettime ( Process ::CLOCK_MONOTONIC ) - st ) , :<= , t , message
745
770
end
746
- else
747
- super
748
771
end
749
772
end
750
773
@@ -763,6 +786,11 @@ def diff(exp, act)
763
786
end
764
787
q . output
765
788
end
789
+
790
+ def new_test_token
791
+ token = "\e [7;1m#{ $$. to_s } :#{ Time . now . strftime ( '%s.%L' ) } :#{ rand ( 0x10000 ) . to_s ( 16 ) } :\e [m"
792
+ return token . dump , Regexp . quote ( token )
793
+ end
766
794
end
767
795
end
768
796
end
0 commit comments