Repository navigation
Expand file tree
/
Copy pathtest_integer_overflows.rb
More file actions
executable file
·666 lines (606 loc) · 25.1 KB
/
Copy pathtest_integer_overflows.rb
File metadata and controls
executable file
·666 lines (606 loc) · 25.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
# Tests to (a) show issues/bugs, and (b) test patches for these, for jira.codehaus.org.
# In the following: IntMin = -9223372036854775808, which is (-2)**(64 - 1).
# #JRUBY-6612: some problems with JRuby seeming to not detect Java Long arithmetic overflows
# # IntMin * -1 #=> 9223372036854775808;
# # -1 * IntMin #=> -9223372036854775808;
# In the second example JRuby was not detecting the integer overflow.
# The first patch for this fixed the problem in jruby-1.7.0.preview1,
# but created a much less serious problem:
# # IntMin * 1 #=> -9223372036854775808 Fixnum;
# # 1 * IntMin #=> -9223372036854775808 Bignum;
# This problem is fixed in jruby-1.7.0.preview2.
# #JRUBY-6777: RubyFixnum.java - two methods assert false, to detect some long integer overflows
# # IntMin / -1: -9223372036854775808;
# # IntMin.divmod(-1): [-9223372036854775808, 0];
# Fixed in jruby-1.7.0.preview2.
# #JRUBY-6778: Possible long integer overflow bug in Integer#succ in RubyInteger.java
# # 9223372036854775807.succ #=> -9223372036854775808;
# Fixed in jruby-1.7.0.preview2.
# VVT.logfile = "path/smalltest-jruby-.txt"
require 'test/unit'
class VVT < Test::Unit::TestCase
BIT_SIZES = [ 30, 31, 32, 33, 62, 63, 64, 65 ]
def test_integer_overflows
BIT_SIZES.each do |nbits|
checks_for_integer_overflow(nbits)
end
end
def test_integer_iteration_for_overflows
BIT_SIZES.each do |nbits|
checks_for_integer_iteration_overflows(nbits)
end
end
def checks_for_integer_overflow(nbits)
reset_subcounts()
return unless nbits >= 6
nbits_int_min = n_bits_integer_min(nbits)
nbits_int_max = n_bits_integer_max(nbits)
# (1) Test for whether integer addition and negation seems OK,
# because we need these to be reliable for the remaining tests.
check_integer_add_overflow(nbits_int_max, 1)
check_integer_add_overflow(nbits_int_min, -1)
check_integer_negate_overflow(nbits_int_max)
check_integer_negate_overflow(nbits_int_min)
return if sub_notOK?() # stop here if any of the above tests are failed
# (2) Test for non-iteration integer overflows.
# The problems for JRuby-1.6.7.2, JRuby-1.7.0.preview1
# seem to be fixed by patches used in JRuby-1.7.0.preview2.
# In the following: IntMin = -9223372036854775808, which is -(2**(64 - 1));
# IntMax = 9223372036854775807, which is 2**(64 - 1) - 1.
check_integer_succ(nbits_int_max - 1)
#* next line:[JRUBY-6778]: integer overflow: JRuby-1.6.7.2, JRuby-1.7.0.preview1;
# 9223372036854775807.succ #=> -9223372036854775808;
# IntMax.succ #=> IntMin;
check_integer_succ(nbits_int_max) # [JRUBY-6778]
check_integer_succ(nbits_int_max + 1)
check_integer_multiply_by_0_or_1_or_minus_1(nbits_int_min, 0) # OK
check_integer_multiply_by_0_or_1_or_minus_1(0, nbits_int_min) # OK
check_integer_multiply_by_0_or_1_or_minus_1(nbits_int_min, -1) # OK
#* next line:[JRUBY-6612]: integer overflow: JRuby-1.6.7.2;
# -1 * -9223372036854775808 #=> -9223372036854775808;
# -1 * IntMin #=> IntMin;
# patch for this corrected this bug but created new bug just below
check_integer_multiply_by_0_or_1_or_minus_1(-1, nbits_int_min) # [JRUBY-6612]
#* next line: incorrect class of result: JRuby-1.7.0.preview1;
# patch for [JRUBY-6612] corrected that bug but created this new less serious bug:
# 1 * -9223372036854775808 #=> -9223372036854775808 Bignum;
# 1 * IntMin #=> -9223372036854775808 Bignum; should be Fixnum IntMin
check_integer_multiply_by_0_or_1_or_minus_1( 1, nbits_int_min) # OK in preview2
check_integer_multiply_by_0_or_1_or_minus_1(nbits_int_min, 1) # OK
check_integer_divide_by_1_or_minus_1(nbits_int_min, 1)
check_integer_divmod_by_1_or_minus_1(nbits_int_min, 1)
#* next line:[JRUBY-6777]: integer overflow: JRuby-1.6.7.2, JRuby-1.7.0.preview1;
# -9223372036854775808 / -1 #=> -9223372036854775808;
# IntMin / -1 #=> IntMin;
check_integer_divide_by_1_or_minus_1(nbits_int_min, -1) # [JRUBY-6777]
#* next line:[JRUBY-6777]: integer overflow: JRuby-1.6.7.2, JRuby-1.7.0.preview1;
# -9223372036854775808.divmod(-1) #=> [-9223372036854775808, 0];
# IntMin.divmod(-1) #=> [IntMin, 0];
check_integer_divmod_by_1_or_minus_1(nbits_int_min, -1) # [JRUBY-6777]
end
def check_integer_add_overflow(av, bv)
reset_actual_expected_etc()
return unless av.kind_of?(Integer) && bv.kind_of?(Integer)
@expected = vv = vvs = vvv = nil
if av == 0 && bv == 0 then @expected = 0
elsif av == 0 then @expected = bv
elsif bv == 0 then @expected = av
elsif av == 1 then vv = vvs = 1; vvv = bv
elsif av == -1 then vv = vvs = -1; vvv = bv
elsif bv == 1 then vv = vvs = 1; vvv = av
elsif bv == -1 then vv = vvs = -1; vvv = av
elsif bv > 0 then vv = bv; vvs = 1; vvv = av
elsif bv < 0 then vv = bv; vvs = -1; vvv = av
else return
end
unless @expected then
begin
@expected = vv + vvv
qok = (if vvs == 1 then @expected > vvv else @expected < vvv end)
qok &&= (-vv + @expected) == vvv
@expected = inzpect(@expected) + "_???" unless qok
rescue
@expected = "???_" + inzpect($!) + "_???"
end
end
@text = "#{inzpect(av)} + #{inzpect(bv)}"
begin
@actual = av + bv
rescue
@exception = $!
end
process_test_result()
end
def check_integer_succ(nv)
reset_actual_expected_etc()
@text = "#{inzpect(nv)}.succ"
begin
@expected = 1 + nv
qok = @expected > nv
qok &&= (-1 + @expected) == nv
@expected = inzpect(@expected) + "_???" unless qok
rescue
@expected = "???_" + inzpect($!) + "_???"
end
begin
@actual = nv.succ
rescue
@exception = $!
end
process_test_result()
end
def check_integer_negate_overflow(nv)
reset_actual_expected_etc()
return unless nv.kind_of?(Integer)
@text = "negate #{inzpect(nv)}"
begin
# This gets the expected value of negate by using subtract,
# which may be a problem if "a subtract b" is implemented as "a plus negate b",
# or if "negate n" is implemented as "0 subtract n".
@expected = 0 - nv
negexp = 0 - @expected
qok = negexp == nv && negexp.class == nv.class &&
if nv > 0 then @expected < 0 && @expected.class == nv.class
elsif nv < 0 then @expected > 0 && (-1 + @expected).class == nv.class
else @expected.zero? && nv.zero? &&
@expected == nv && @expected.class == nv.class
end
@expected = inzpect(@expected) + "_???" unless qok
rescue
@expected = "???_" + inzpect($!) + "_???"
end
begin
@actual = -nv
rescue
@exception = $!
end
process_test_result()
end
def check_integer_multiply_by_0_or_1_or_minus_1(av, bv)
reset_actual_expected_etc()
return unless av.kind_of?(Integer) && bv.kind_of?(Integer)
@expected = if av == 0 || bv == 0 then 0
elsif av == 1 then bv
elsif bv == 1 then av
elsif av == -1 then
if bv < 0 then -(bv + 1) + 1 else -bv end
elsif bv == -1 then
if bv < 0 then -(av + 1) + 1 else -av end
else nil
end
return unless @expected
@text = "#{inzpect(av)} * #{inzpect(bv)}"
begin
@actual = av * bv
rescue
@exception = $!
end
process_test_result()
end
def check_integer_divide_by_1_or_minus_1(av, bv)
return unless av.kind_of?(Integer) && bv.kind_of?(Integer)
reset_actual_expected_etc()
@expected = if bv == 1 then av
elsif bv == -1 then -(av + 1) + 1
else nil
end
return unless @expected
@text = "#{inzpect(av)} / #{inzpect(bv)}"
begin
@actual = av / bv
rescue
@exception = $!
end
process_test_result()
end
def check_integer_divmod_by_1_or_minus_1(av, bv)
return unless av.kind_of?(Integer) && bv.kind_of?(Integer)
reset_actual_expected_etc()
@expected = if bv == 1 then [av, 0]
elsif bv == -1 then [-(av + 1) + 1, 0]
else nil
end
return unless @expected
@text = "#{inzpect(av)}.divmod(#{inzpect(bv)})"
begin
@actual = av.divmod(bv)
rescue
@exception = $!
end
process_test_result()
end
def checks_for_integer_iteration_overflows(nbits)
# This mainly tests for incorrect detection of integer overflow in integer iterations.
reset_subcounts()
return unless nbits >= 6
nbits_int_min = n_bits_integer_min(nbits)
nbits_int_max = n_bits_integer_max(nbits)
# (1) Test if integer iteration seems OK for some "likely" integer overflows.
# The idea is to "assert false, quickly" if there are "likely" integer overflows.
#* next lines seem OK in: JRuby-1.6.7.2, JRuby-1.7.0.preview1;
# next line was in [JRUBY-6779] as an example of Range#each working as expected
check_integer_range_each(nbits_int_max - 1...nbits_int_max) # [JRUBY-6779] OK in JRuby-1.6, etc
check_range_step(nbits_int_max - 1...nbits_int_max, 1)
check_range_step(nbits_int_max...nbits_int_max + 1, 1)
#* next lines: integer overflow: JRuby-1.6.7.2, JRuby-1.7.0.preview1;
# next three lines are OK in JRuby-1.7.0.preview2 because of [JRUBY-6778] #succ patch
check_integer_range_each(nbits_int_max.. nbits_int_max + 1) # [JRUBY-6779] OK in preview2
check_integer_range_each(nbits_int_max...nbits_int_max + 1) # [JRUBY-6779] OK in preview2
check_integer_range_each(nbits_int_max...nbits_int_max + 1)
# but the next two lines seem still notOK in JRuby-1.7.0.preview2
check_integer_range_each(nbits_int_max ..nbits_int_max) # [JRUBY-6779]
check_integer_range_each(nbits_int_max - 1..nbits_int_max) # [JRUBY-6779]
check_integer_downto(nbits_int_min, nbits_int_min)
check_integer_upto(nbits_int_max, nbits_int_max)
check_numeric_step(nbits_int_max - 1, nbits_int_max - 1, 2) # [JRUBY-6790]
check_numeric_step(nbits_int_max, nbits_int_max, 1) # [JRUBY-6790]
check_numeric_step(nbits_int_min, nbits_int_min, -1)
check_range_step(nbits_int_max..nbits_int_max, 1)
check_range_step(nbits_int_max - 1..nbits_int_max, 2)
check_range_step(nbits_int_max - 1..nbits_int_max - 1, 2)
check_range_step(nbits_int_max - 1...nbits_int_max, 2)
#* next lines test for plausible but incorrect detection of iteration integer overflow
#* next lines: integer overflow: JRuby-1.6.7.2, JRuby-1.7.0.preview1;
check_numeric_step(nbits_int_min + 1, nbits_int_max - 1, nbits_int_max - 2)
check_numeric_step(nbits_int_max - 1, nbits_int_min + 1, nbits_int_min + 3)
check_range_step(nbits_int_min + 1..nbits_int_max - 1, nbits_int_max - 2)
check_range_step(nbits_int_min + 1...nbits_int_max, nbits_int_max - 2)
return if sub_notOK?() # stop here if any of the above tests are failed
# If there aren't any "likely" integer overflows then do many more tests,
# hoping to detect any "unlikely" integer overflows.
nn0 = nbits_int_max - 7
nn2 = nbits_int_max + 7
nn = nn0 - 1
while (nn += 1) <= nn2 do
nnn = nn0 - 1
while (nnn += 1) <= nn2 do
check_integer_downto(nn, nnn)
check_integer_upto(nn, nnn)
check_integer_range_each(nn..nnn)
check_integer_range_each(nn...nnn)
check_numeric_step(nn, nnn, 1)
check_numeric_step(nn, nnn, 2)
check_range_step(nn..nnn, 1)
check_range_step(nn...nnn, 1)
check_range_step(nn..nnn, 2)
check_range_step(nn...nnn, 2)
end
end
end
# individual tests
def check_integer_downto(fromv, tov)
@text = inzpect(fromv) + ".downto(" + inzpect(tov) + ")"
set_numeric_expected_iterations(fromv, tov, -1, false, false)
@expected = fromv
@iterations = []
begin
@actual = fromv.downto(tov) do |iv|
@iterations << iv
break if @iterations.size >= @max_num_iterations
end
rescue
@exception = $!
end
process_test_result()
end
def check_integer_upto(fromv, tov)
@text = inzpect(fromv) + ".upto(" + inzpect(tov) + ")"
set_numeric_expected_iterations(fromv, tov, 1, false, false)
@expected = fromv
@iterations = []
begin
@actual = fromv.upto(tov) do |iv|
@iterations << iv
break if @iterations.size >= @max_num_iterations
end
rescue
@exception = $!
end
process_test_result()
end
def check_integer_range_each(rangev)
@text = "(" + inzpect(rangev) + ").each"
set_numeric_expected_iterations(rangev.begin, rangev.end, 1, false, rangev.exclude_end?)
@expected = rangev
@iterations = []
begin
@actual = rangev.each do |iv|
@iterations << iv
break if @iterations.size >= @max_num_iterations
end
rescue
@exception = $!
end
process_test_result()
end
def check_numeric_step(fromv, tov, stepv)
@text = inzpect(fromv) + ".step(" + inzpect(tov) + ", " + inzpect(stepv) + ")"
efromv = fromv; etov = tov; estepv = stepv
if efromv.kind_of?(Float) || etov.kind_of?(Float) || estepv.kind_of?(Float) then
efromv = efromv.to_f; etov = etov.to_f; estepv = estepv.to_f
end
set_numeric_expected_iterations(efromv, etov, estepv, false, false)
@expected = fromv
if @expected_exception then
@expected_exception = ArgumentError.exception("step can't be 0")
@expected_iterations = []
@expected = nil
end
@iterations = []
begin
@actual = fromv.step(tov, stepv) do |iv|
@iterations << iv
break if @iterations.size >= @max_num_iterations
end
rescue
@exception = $!
end
process_test_result()
end
def check_range_step(rangev, stepv)
@text = "(" + inzpect(rangev) + ").step(" + inzpect(stepv) + ")"
efromv = rangev.begin; etov = rangev.end; estepv = stepv
if efromv.kind_of?(Float) || etov.kind_of?(Float) || estepv.kind_of?(Float) then
efromv = efromv.to_f; etov = etov.to_f; estepv = estepv.to_f
end
set_numeric_expected_iterations(efromv, etov, estepv, false, rangev.exclude_end?)
@expected = rangev
if @expected_exception || stepv < 0 then
@expected_exception = if stepv < 0 then
ArgumentError.exception("step can't be negative")
else
ArgumentError.exception("step can't be 0")
end
@expected_iterations = []
@expected = nil
end
@iterations = []
begin
@actual = rangev.step(stepv) do |iv|
@iterations << iv
break if @iterations.size >= @max_num_iterations
end
rescue
@exception = $!
end
process_test_result()
end
#############################
# Test support methods follow
#############################
def ruby_run_info_const(symv, altv = nil)
if Module.const_defined?(symv) then
Module.const_get(symv)
else
altv
end
end
DEFAULT_RECUR_MAX_DEPTH = 3
IS_JRUBY = !! RUBY_PLATFORM.to_s.downcase.index("java")
def JRuby?()
IS_JRUBY
end
Infinity = 1.0 / 0.0
# Min and max values of N-bit signed integers are
# used for tests that integer overflow detection is working.
# 31-bit signed integers: MRI Ruby Fixnum;
# 32-bit signed integers: Java int, C long, etc;
# 63-bit signed integers: MRI Ruby Fixnum;
# 64-bit signed integers: Java long, JRuby Ruby Fixnum;
def n_bits_integer_min(nbits)
return nil if nbits < 1
# Calculate -(2**(nbits - 1)) using only addition
# to avoid relying on powers (or multiply) being correctly implemented.
# This may be slow but that should not matter for the types of tests that
# this is intended for. (You can "cache" values if speed is a problem.)
min_intv = -1 # starting min value, for a 1_bit signed integer
nbitsi = 0
while (nbitsi += 1) < nbits do
prev_min_intv = min_intv
unless (min_intv += min_intv) < prev_min_intv then
raise "ERROR overflow calculating -(2**(nbits - 1)) for nbits=#{nbits}"
end
end
return min_intv
end
#
def n_bits_integer_max(nbits)
(minv = n_bits_integer_min(nbits)) && -(minv + 1)
end
def Rational_loaded?()
return defined?(Rational)
end
attr_accessor :exclude_tests_level, :normal_tests_level
def setup()
# initialize test result counts and test controls
@numOK = @numNotOK = @numExceptions = 0
reset_subcounts()
reset_actual_expected_etc()
@logfile = nil
@exclude_tests_level = nil # controls excluding some tests
@normal_tests_level = 8
@recur_max_depth = DEFAULT_RECUR_MAX_DEPTH # max depth for #not_equal?
# next instance variable allows you to limit the number of iterations in a test
# in case the actual number of iterations is much larger than expected (or infinite)
@max_num_iterations = nil
# next instance variable is the allowed margin of the actual number of iterations
# over the expected number of iterations
@max_num_iterations_margin = 2
end
def reset_actual_expected_etc()
@actual = @iterations = @exception = nil
@expected = @expected_iterations = @expected_exception = nil
@max_num_iterations = nil
end
def reset_subcounts()
@sub_numOK = @sub_numNotOK = @sub_numExceptions = 0
end
def sub_notOK?()
(@sub_numNotOK && @sub_numNotOK != 0) ||
(@sub_numExceptions && @sub_numExceptions != 0)
end
def not_equal?(actualv, expectedv, recur_max_depthv = nil)
return true if actualv.class != expectedv.class
recur_max_depthv ||= @recur_max_depth || DEFAULT_RECUR_MAX_DEPTH
recur_max_depthv -= 1
case actualv
when Exception then
return actualv.to_s != expectedv.to_s # focus equality on the exception message
when Array then
if recur_max_depthv >= 0 then
ii2 = if actualv.size < expectedv.size then actualv.size else expectedv.size end
iii = vvv = nil
ii = -1
while (ii += 1) < ii2 do
if (vvv = not_equal?(actualv[ii], expectedv[ii], recur_max_depthv)) then
iii = ii
break
end
end
if iii || actualv.size != expectedv.size then
vvv = [] unless vvv.kind_of?(Array)
vvv << (iii || ii2)
return vvv
end
end
end
return ! (actualv == expectedv) # use normal equality checking
end
def inzpect(valuev, recur_max_depthv = nil,
first_diff_indexes = nil, first_diff_indexv = nil)
# Similar to "inspect" but has different options for showing arrays.
# And for Bignum values shows class as well as value: for example: -123456789_big;
# the reason for this is that it is possible that a numeric value is correct
# but that the expected value is Fixnum and the actual value is Bignum,
# and we want the output to be clear about the type of value.
recur_max_depthv ||= @recur_max_depth || DEFAULT_RECUR_MAX_DEPTH
recur_max_depthv -= 1
case valuev
when Array then
if recur_max_depthv >= 0 then
if first_diff_indexes.kind_of?(Array) then
first_diff_indexv ||= first_diff_indexes.size
first_diff_indexv -= 1
else
first_diff_indexv = nil
end
resultv = "["
if valuev.size > 0 then
iidiff_indexv = if first_diff_indexes.kind_of?(Array) then
first_diff_indexes[first_diff_indexv]
else
-1
end
iidiff_indexv = -1 if iidiff_indexv >= valuev.size
ii = 0
if ii == iidiff_indexv then
iidiff_indexv = -1
fdixs = first_diff_indexes
fdixv = first_diff_indexv
else
fdixs = fdixv = nil
end
resultv << inzpect(valuev[ii], recur_max_depthv, fdixs, fdixv)
if valuev.size > 1 then
prev_ii = ii
if prev_ii < iidiff_indexv then
if prev_ii < (ii = iidiff_indexv - 1) then
resultv << (if prev_ii + 1 == ii then ", " else ",...@#{ii}:" end) <<
inzpect(valuev[ii], recur_max_depthv, nil, nil)
prev_ii = ii
end
ii = iidiff_indexv
iidiff_indexv = -1
resultv << (if prev_ii + 1 == ii then ", " else ",...@#{ii}:" end) <<
inzpect(valuev[ii], recur_max_depthv,
first_diff_indexes, first_diff_indexv)
prev_ii = ii
end
if prev_ii < (ii = valuev.size - 1) then
resultv << (if prev_ii + 1 == ii then ", " else ",...@#{ii}:" end) <<
inzpect(valuev[ii], recur_max_depthv, nil, nil)
end
end
end
resultv << "]"
return resultv
end
when Range then
# Note recursive calls in next line!!!
return inzpect(valuev.begin) <<
(if valuev.exclude_end? then "..." else ".." end) <<
inzpect(valuev.end)
when Exception then
return valuev.class.name + ":" << valuev.to_s.inspect
when Integer, Float, NilClass, TrueClass, FalseClass then
return valuev.inspect
else
unless Rational_loaded? && valuev.class == Rational then
return valuev.class.name + ":v:" << valuev.inspect
end
end
valuev.inspect
end
def process_test_result()
# For readability in making tests, this method relies on instance variables being set.
# It calls "process_test_result_private" which (mostly) does not use instance variables.
process_test_result_private(@actual, @expected,
@iterations, @expected_iterations,
@exception, @expected_exception,
@text)
end
def process_test_result_private(actual_resultv, expected_resultv,
actual_iterationsv, expected_iterationsv,
actual_exceptionv, expected_exceptionv,
test_textv = nil)
if expected_resultv.kind_of?(Exception) && expected_exceptionv.nil? then
expected_exceptionv = expected_resultv
expected_resultv = nil
end
msgv = test_textv << " #=>"
msgv << " != " << inzpect(expected_resultv, nil, not_equal?(actual_iterationsv, expected_iterationsv), nil)
assert_equal(actual_resultv, expected_resultv, msgv)
msgv = test_textv << " #=>"
msgv << " != " << inzpect(expected_iterationsv, nil, not_equal?(actual_resultv, expected_resultv), nil)
assert_equal(actual_iterationsv, expected_iterationsv, msgv)
msgv = test_textv << " #=>"
msgv << " != " << inzpect(expected_exceptionv, nil, not_equal?(actual_exceptionv, expected_exceptionv), nil)
assert_equal(actual_exceptionv, expected_exceptionv, msgv)
end
def set_numeric_expected_iterations(fromv, tov, stepv, exclude_fromv, exclude_tov)
# set up expected numeric iterated values
reset_actual_expected_etc()
if stepv == 0 then
@expected_exception = true
return
end
@expected_iterations = [] # store expected iterated values in an array
# next line sets the appropriate check for the end of the iteration
symv = if stepv > 0 then
if exclude_tov then :< else :<= end
else
if exclude_tov then :> else :>= end
end
itvalue = fromv
num_steps = 0 # count the steps from fromv: needed for Float (etc) iterations
if exclude_fromv then
# Depending on the type of iteration, this might need to be changed
# if stepv is a very small Float or BigDecimal, etc.
itvalue += stepv
num_steps += 1
end
while itvalue.__send__(symv, tov) do
@expected_iterations << itvalue
num_steps += 1 # needed for Float (etc) iterations
if itvalue.kind_of?(Float) ||
(defined?(BigDecimal) && itvalue.kind_of?(BigDecimal)) then
itvalue = fromv + stepv * num_steps
else
itvalue += stepv
end
end
# next line anticipates unexpected infinite or very large loops in tests of iterators
@max_num_iterations = @expected_iterations.size + (@max_num_iterations_margin || 2)
return
end
end