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