1 # $Id: assertion.rb,v 1.7 2012/04/17 02:49:40 machan Exp $
2
3 module TmStd
4
5 module Exception
6
7 class Abstract < StandardError; end
8
9 class AssertionFail < Abstract; end
10 class AssertionError < Abstract; end
11 class SubclassResponsibility < Abstract; end
12
13 class LogfileOpenError < Abstract; end # Need 'exception.rb'..
14
15 end # TmStd::Exception
16
17
18
19 module Assertion
20 def self.disable!(yes_or_no = true)
21 @disable = if yes_or_no then true else false end
22
23 nil
24 end
25
26
27 def self.disable?
28 @disable
29 end
30
31
32 def self.kind_of(actual, expected, msg_fmt = nil, *msg_args)
33 if Assertion.disable?
34 return actual
35 end
36
37 unless expected.kind_of?(Class)
38 raise TmStd::Exception::AssertionError
39 end
40 unless (! msg_fmt) || msg_fmt.kind_of?(String)
41 raise TmStd::Exception::AssertionError
42 end
43
44 unless actual.kind_of?(expected)
45 Assertion.__print_box__(
46 'A is kind of E',
47 {
48 :message => [msg_fmt, msg_args],
49 :expected_type => expected.to_s
50 }, {
51 :actual_type => actual.class.to_s,
52 :actual_value => actual.to_s
53 }
54 )
55 raise TmStd::Exception::AssertionFail
56 end
57
58 actual
59 end
60
61
62 def self.opt_kind_of(actual, expected, msg_fmt = nil, *msg_args)
63 if Assertion.disable?
64 return actual
65 end
66
67 unless expected.kind_of?(Class)
68 raise TmStd::Exception::AssertionError
69 end
70 unless (! msg_fmt) || msg_fmt.kind_of?(String)
71 raise TmStd::Exception::AssertionError
72 end
73
74 unless (! actual) || actual.kind_of?(expected)
75 Assertion.__print_box__(
76 'A is kind of E, or nil',
77 {
78 :message => [msg_fmt, msg_args],
79 :expected_type => expected.to_s
80 }, {
81 :actual_type => actual.class.to_s,
82 :actual_value => actual.to_s
83 }
84 )
85 raise TmStd::Exception::AssertionFail
86 end
87
88 actual
89 end
90
91
92 def self.tuple_of(actual, expected, msg_fmt = nil, *msg_args)
93 if Assertion.disable?
94 return actual
95 end
96
97 unless expected.kind_of?(Array)
98 raise TmStd::Exception::AssertionError
99 end
100 unless expected.length >= 2
101 raise TmStd::Exception::AssertionError
102 end
103 unless (! msg_fmt) || msg_fmt.kind_of?(String)
104 raise TmStd::Exception::AssertionError
105 end
106
107 unless actual.kind_of?(Array)
108 Assertion.__print_box__(
109 'A is kind of Array (tuple-of)',
110 {
111 :message => [msg_fmt, msg_args],
112 :expected_type => 'Array'
113 }, {
114 :actual_type => actual.class.to_s,
115 :actual_value => actual.to_s
116 }
117 )
118 raise TmStd::Exception::AssertionFail
119 end
120
121 unless actual.length == expected.length
122 Assertion.__print_box__(
123 format("Length of A is %d (tuple-of)", expected.length),
124 {
125 :message => [msg_fmt, msg_args],
126 :expected_type => format(
127 "[%s] (Array)",
128 expected.map { |c| c.to_s }.join(', ')
129 )
130 }, {
131 :actual_type => format(
132 "[%s] (Array)",
133 actual.map { |v| v.class.to_s }.join(', ')
134 ),
135 :actual_value => format(
136 "[\n %s\n]",
137 actual.map { |v| v.to_s }.join(",\n ")
138 )
139 }
140 )
141 raise TmStd::Exception::AssertionFail
142 end
143
144 (0 .. (actual.length - 1)).each do |i|
145 unless actual[i].kind_of?(expected[i])
146 Assertion.__print_box__(
147 format(
148 "the #%d of A is kind of %s (tuple-of)",
149 i + 1, expected[i]
150 ),
151 {
152 :message => [msg_fmt, msg_args],
153 :expected_type => format(
154 "[%s] (Array)",
155 expected.map { |c| c.to_s }.join(', ')
156 )
157 }, {
158 :actual_type => format(
159 "[%s] (Array)",
160 actual.map { |v| v.class.to_s }.join(', ')
161 ),
162 :actual_value => format(
163 "[\n %s\n]",
164 actual.map { |v| v.to_s }.join(",\n ")
165 )
166 }
167 )
168 raise TmStd::Exception::AssertionFail
169 end
170 end
171
172 actual
173 end
174
175
176 def self.instance_of(actual, expected, msg_fmt = nil, *msg_args)
177 if Assertion.disable?
178 return actual
179 end
180
181 unless expected.kind_of?(Class)
182 raise TmStd::Exception::AssertionError
183 end
184 unless (! msg_fmt) || msg_fmt.kind_of?(String)
185 raise TmStd::Exception::AssertionError
186 end
187
188 unless actual.instance_of?(expected)
189 Assertion.__print_box__(
190 'A is instance of E',
191 {
192 :message => [msg_fmt, msg_args],
193 :expected_type => expected.to_s
194 }, {
195 :actual_type => actual.class.to_s,
196 :actual_value => actual.to_s
197 }
198 )
199 raise TmStd::Exception::AssertionFail
200 end
201
202 actual
203 end
204
205
206 def self.subclass_of(actual, expected, msg_fmt = nil, *msg_args)
207 if Assertion.disable?
208 return actual
209 end
210
211 unless expected.kind_of?(Class)
212 raise TmStd::Exception::AssertionError
213 end
214 unless (! msg_fmt) || msg_fmt.kind_of?(String)
215 raise TmStd::Exception::AssertionError
216 end
217
218 unless actual.kind_of?(Class)
219 Assertion.__print_box__(
220 'A is kind of Class (subclass-of)',
221 {
222 :message => [msg_fmt, msg_args],
223 :expected_type => 'Class or Module'
224 }, {
225 :actual_type => actual.class.to_s,
226 :actual_value => actual.to_s
227 }
228 )
229 raise TmStd::Exception::AssertionFail
230 end
231
232 unless actual <= expected
233 Assertion.__print_box__(
234 'A is subclass of E',
235 {
236 :message => [msg_fmt, msg_args],
237 :expected_type => expected.to_s
238 }, {
239 :actual_type => actual.class.to_s,
240 :actual_value => actual.to_s
241 }
242 )
243 raise TmStd::Exception::AssertionFail
244 end
245
246 actual
247 end
248
249
250 def self.nil(actual = nil, msg_fmt = nil, *msg_args)
251 return nil if Assertion.disable?
252
253 unless (! msg_fmt) || msg_fmt.kind_of?(String)
254 raise TmStd::Exception::AssertionError
255 end
256
257 unless actual.equal?(nil)
258 Assertion.__print_box__(
259 'A is nil',
260 {
261 :message => [msg_fmt, msg_args]
262 }, {
263 :actual_type => actual.class.to_s,
264 :actual_value => actual.to_s
265 }
266 )
267 raise TmStd::Exception::AssertionFail
268 end
269
270 nil
271 end
272
273
274 def self.not_nil(actual, msg_fmt = nil, *msg_args)
275 if Assertion.disable?
276 return actual
277 end
278
279 unless (! msg_fmt) || msg_fmt.kind_of?(String)
280 raise TmStd::Exception::AssertionError
281 end
282
283 unless (! actual.equal?(nil))
284 Assertion.__print_box__(
285 "A isn't nil",
286 {
287 :message => [msg_fmt, msg_args]
288 }, {
289 :actual_type => actual.class.to_s,
290 :actual_value => actual.to_s
291 }
292 )
293 raise TmStd::Exception::AssertionFail
294 end
295
296 actual
297 end
298
299
300 def self.boolean(actual, msg_fmt = nil, *msg_args)
301 if Assertion.disable?
302 return actual
303 end
304
305 unless (! msg_fmt) || msg_fmt.kind_of?(String)
306 raise TmStd::Exception::AssertionError
307 end
308
309 unless actual == true || actual == false
310 Assertion.__print_box__(
311 'A is true or false',
312 {
313 :message => [msg_fmt, msg_args]
314 }, {
315 :actual_type => actual.class.to_s,
316 :actual_value => actual.to_s
317 }
318 )
319 raise TmStd::Exception::AssertionFail
320 end
321
322 actual
323 end
324
325
326 def self.assert(cond, msg_fmt = nil, *msg_args)
327 return nil if Assertion.disable?
328
329 unless (! msg_fmt) || msg_fmt.kind_of?(String)
330 raise TmStd::Exception::AssertionError
331 end
332
333 unless cond
334 Assertion.__print_box__(
335 nil,
336 { :message => [msg_fmt, msg_args] }
337 )
338 raise TmStd::Exception::AssertionFail
339 end
340
341 nil
342 end
343
344
345 def self.abort(msg_fmt = nil, *msg_args)
346 unless (! msg_fmt) || msg_fmt.kind_of?(String)
347 raise TmStd::Exception::AssertionError
348 end
349
350 Assertion.__print_box__(
351 nil,
352 { :message => [msg_fmt, msg_args] }
353 )
354 raise TmStd::Exception::AssertionFail
355
356 nil
357 end
358
359
360
361 DISPLAY_WIDTH = 80
362 LINE_LENGTH = DISPLAY_WIDTH - 2
363
364 TOP_LINE = '+' + ('=' * (LINE_LENGTH - 1))
365 SEPARATE_LINE = '|' + ('-' * (LINE_LENGTH - 1))
366 BOTTOM_LINE = '+' + ('=' * (LINE_LENGTH - 1))
367
368
369 def self.__print_box__(title, rows, opt_rows = {})
370 if title && (! title.kind_of?(String))
371 raise TmStd::Exception::AssertionError
372 end
373 unless rows.kind_of?(Hash)
374 raise TmStd::Exception::AssertionError
375 end
376 unless opt_rows.kind_of?(Hash)
377 raise TmStd::Exception::AssertionError
378 end
379
380 message = nil
381 expected_type = nil
382 actual_type = nil
383 actual_value = nil
384 for key, val in rows.merge(opt_rows)
385 unless key.kind_of?(Symbol)
386 raise TmStd::Exception::AssertionError
387 end
388
389 case key
390 when :message
391 unless val.kind_of?(Array)
392 raise TmStd::Exception::AssertionError
393 end
394 unless val.length == 2
395 raise TmStd::Exception::AssertionError
396 end
397 msg_fmt, msg_args = val
398
399 unless (! msg_fmt) || msg_fmt.kind_of?(String)
400 raise TmStd::Exception::AssertionError
401 end
402 unless (! msg_args) || msg_args.kind_of?(Array)
403 raise TmStd::Exception::AssertionError
404 end
405
406 message = if msg_fmt
407 format(msg_fmt, *msg_args)
408 else
409 nil
410 end
411 when :expected_type
412 unless val.kind_of?(String)
413 raise TmStd::Exception::AssertionError
414 end
415
416 expected_type = val
417 when :actual_type
418 unless val.kind_of?(String)
419 raise TmStd::Exception::AssertionError
420 end
421
422 actual_type = val
423 when :actual_value
424 unless val.kind_of?(String)
425 raise TmStd::Exception::AssertionError
426 end
427
428 actual_value = val
429 else
430 raise TmStd::Exception::AssertionError
431 end
432 end
433 rows_is_empty = [message, expected_type].all? { |x| ! x }
434 opt_rows_is_empty = [actual_type, actual_value].all? { |x| ! x }
435 box_is_empty = rows_is_empty && opt_rows_is_empty
436
437 formated_title =
438 if title
439 format " ASSERTION FAIL!! : %s. ", title
440 else
441 ' ASSERTION FAIL!! '
442 end
443 len = (LINE_LENGTH / 2).to_i - (formated_title.length / 2).to_i
444 top_line = [
445 TOP_LINE[0, len], formated_title, TOP_LINE[(len * -1), len]
446 ].join
447
448
449 $stderr.puts ''
450
451 $stderr.puts top_line
452
453 if box_is_empty
454 return
455 end
456
457 if msg_fmt
458 $stderr.puts "|[MESSAGE]"
459 Assertion.__print_line__ format(msg_fmt, *msg_args)
460 end
461
462 if expected_type
463 $stderr.puts "|[EXPECTED(E) TYPE]"
464 Assertion.__print_line__ expected_type
465 end
466
467 if (! rows_is_empty) && (! opt_rows_is_empty)
468 $stderr.puts SEPARATE_LINE
469 end
470
471 unless opt_rows_is_empty
472 if actual_type
473 $stderr.puts "|[ACTUAL(A) TYPE]"
474 Assertion.__print_line__ actual_type
475 end
476
477 if actual_value
478 $stderr.puts "|[ACTUAL(A) VALUE]"
479 Assertion.__print_line__ actual_value
480 end
481 end
482 $stderr.puts BOTTOM_LINE
483
484 nil
485 end
486
487
488 def self.__print_line__(str)
489 unless str.kind_of?(String)
490 raise TmStd::Exception::AssertionError
491 end
492
493 str.each_line do |line|
494 $stderr.puts '| ' + line
495 end
496
497 nil
498 end
499 end # TmStd::Assertion
500
501
502 end # TmStd