activeldap 0.10.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/CHANGES +6 -30
  2. data/README +4 -2
  3. data/Rakefile +7 -0
  4. data/data/locale/en/LC_MESSAGES/active-ldap.mo +0 -0
  5. data/data/locale/ja/LC_MESSAGES/active-ldap.mo +0 -0
  6. data/examples/al-admin/po/en/al-admin.po +3 -3
  7. data/examples/al-admin/po/ja/al-admin.po +3 -3
  8. data/examples/al-admin/po/nl/al-admin.po +3 -3
  9. data/lib/active_ldap/adapter/base.rb +0 -2
  10. data/lib/active_ldap/base.rb +4 -2
  11. data/lib/active_ldap/get_text_support.rb +3 -11
  12. data/lib/active_ldap/operations.rb +1 -0
  13. data/lib/active_ldap/schema/syntaxes.rb +5 -3
  14. data/lib/active_ldap/validations.rb +25 -15
  15. data/lib/active_ldap.rb +1 -1
  16. data/po/en/active-ldap.po +1 -1
  17. data/po/ja/active-ldap.po +1 -1
  18. data/rails/plugin/active_ldap/init.rb +1 -1
  19. data/test/run-test.rb +2 -0
  20. data/test/test_base.rb +63 -1
  21. data/test/test_syntax.rb +3 -2
  22. data/test-unit-ext/NEWS.en +28 -0
  23. data/test-unit-ext/NEWS.ja +28 -0
  24. data/test-unit-ext/README.en +247 -0
  25. data/test-unit-ext/README.ja +246 -0
  26. data/test-unit-ext/Rakefile +111 -0
  27. data/{test → test-unit-ext/lib}/test-unit-ext/always-show-result.rb +0 -0
  28. data/test-unit-ext/lib/test-unit-ext/assertions.rb +40 -0
  29. data/test-unit-ext/lib/test-unit-ext/attributes.rb +129 -0
  30. data/{test → test-unit-ext/lib}/test-unit-ext/backtrace-filter.rb +0 -0
  31. data/test-unit-ext/lib/test-unit-ext/color.rb +59 -0
  32. data/test-unit-ext/lib/test-unit-ext/colorized-runner.rb +111 -0
  33. data/test-unit-ext/lib/test-unit-ext/diff.rb +516 -0
  34. data/{test → test-unit-ext/lib}/test-unit-ext/long-display-for-emacs.rb +0 -0
  35. data/test-unit-ext/lib/test-unit-ext/notification.rb +79 -0
  36. data/test-unit-ext/lib/test-unit-ext/omission.rb +96 -0
  37. data/test-unit-ext/lib/test-unit-ext/pending.rb +97 -0
  38. data/{test → test-unit-ext/lib}/test-unit-ext/priority.rb +25 -53
  39. data/test-unit-ext/lib/test-unit-ext/version.rb +3 -0
  40. data/test-unit-ext/lib/test-unit-ext/xml-report.rb +224 -0
  41. data/test-unit-ext/lib/test-unit-ext.rb +16 -0
  42. data/test-unit-ext/misc/rd2html.rb +42 -0
  43. data/test-unit-ext/test/run-test.rb +14 -0
  44. data/test-unit-ext/test/test_attributes.rb +139 -0
  45. data/test-unit-ext/test/test_color.rb +39 -0
  46. data/test-unit-ext/test/test_diff.rb +475 -0
  47. data/test-unit-ext/test/test_notification.rb +32 -0
  48. data/test-unit-ext/test/test_omission.rb +64 -0
  49. data/test-unit-ext/test/test_pending.rb +64 -0
  50. data/test-unit-ext/test/test_priority.rb +88 -0
  51. data/test-unit-ext/test/test_xml_report.rb +161 -0
  52. metadata +34 -7
  53. data/test/test-unit-ext.rb +0 -4
@@ -0,0 +1,516 @@
1
+ # port of Python's difflib.
2
+
3
+ module Test
4
+ module Diff
5
+ class SequenceMatcher
6
+ def initialize(from, to, &junk_predicate)
7
+ @from = from
8
+ @to = to
9
+ @junk_predicate = junk_predicate
10
+ update_to_indexes
11
+ end
12
+
13
+ def longest_match(from_start, from_end, to_start, to_end)
14
+ best_info = find_best_match_position(from_start, from_end,
15
+ to_start, to_end)
16
+ unless @junks.empty?
17
+ args = [from_start, from_end, to_start, to_end]
18
+ best_info = adjust_best_info_with_junk_predicate(false, best_info,
19
+ *args)
20
+ best_info = adjust_best_info_with_junk_predicate(true, best_info,
21
+ *args)
22
+ end
23
+
24
+ best_info
25
+ end
26
+
27
+ def blocks
28
+ @blocks ||= compute_blocks
29
+ end
30
+
31
+ def operations
32
+ @operations ||= compute_operations
33
+ end
34
+
35
+ def grouped_operations(context_size=nil)
36
+ context_size ||= 3
37
+ _operations = operations
38
+ _operations = [[:equal, 0, 0, 0, 0]] if _operations.empty?
39
+ expand_edge_equal_operations!(_operations, context_size)
40
+
41
+ group_window = context_size * 2
42
+ groups = []
43
+ group = []
44
+ _operations.each do |tag, from_start, from_end, to_start, to_end|
45
+ if tag == :equal and from_end - from_start > group_window
46
+ group << [tag,
47
+ from_start,
48
+ [from_end, from_start + context_size].min,
49
+ to_start,
50
+ [to_end, to_start + context_size].min]
51
+ groups << group
52
+ group = []
53
+ from_start = [from_start, from_end - context_size].max
54
+ to_start = [to_start, to_end - context_size].max
55
+ end
56
+ group << [tag, from_start, from_end, to_start, to_end]
57
+ end
58
+ groups << group unless group.empty?
59
+ groups
60
+ end
61
+
62
+ def ratio
63
+ @ratio ||= compute_ratio
64
+ end
65
+
66
+ private
67
+ def update_to_indexes
68
+ @to_indexes = {}
69
+ @junks = {}
70
+ each = @to.is_a?(String) ? :each_byte : :each
71
+ i = 0
72
+ @to.send(each) do |item|
73
+ @to_indexes[item] ||= []
74
+ @to_indexes[item] << i
75
+ i += 1
76
+ end
77
+
78
+ return if @junk_predicate.nil?
79
+ @to_indexes = @to_indexes.reject do |key, value|
80
+ junk = @junk_predicate.call(key)
81
+ @junks[key] = true if junk
82
+ junk
83
+ end
84
+ end
85
+
86
+ def find_best_match_position(from_start, from_end, to_start, to_end)
87
+ best_from, best_to, best_size = from_start, to_start, 0
88
+ sizes = {}
89
+ from_start.upto(from_end) do |from_index|
90
+ _sizes = {}
91
+ (@to_indexes[@from[from_index]] || []).each do |to_index|
92
+ next if to_index < to_start
93
+ break if to_index > to_end
94
+ size = _sizes[to_index] = (sizes[to_index - 1] || 0) + 1
95
+ if size > best_size
96
+ best_from = from_index - size + 1
97
+ best_to = to_index - size + 1
98
+ best_size = size
99
+ end
100
+ end
101
+ sizes = _sizes
102
+ end
103
+ [best_from, best_to, best_size]
104
+ end
105
+
106
+ def adjust_best_info_with_junk_predicate(should_junk, best_info,
107
+ from_start, from_end,
108
+ to_start, to_end)
109
+ best_from, best_to, best_size = best_info
110
+ while best_from > from_start and best_to > to_start and
111
+ (should_junk ?
112
+ @junks.has_key?(@to[best_to - 1]) :
113
+ !@junks.has_key?(@to[best_to - 1])) and
114
+ @from[best_from - 1] == @to[best_to - 1]
115
+ best_from -= 1
116
+ best_to -= 1
117
+ best_size += 1
118
+ end
119
+
120
+ while best_from + best_size < from_end and
121
+ best_to + best_size < to_end and
122
+ (should_junk ?
123
+ @junks.has_key?(@to[best_to + best_size]) :
124
+ !@junks.has_key?(@to[best_to + best_size])) and
125
+ @from[best_from + best_size] == @to[best_to + best_size]
126
+ best_size += 1
127
+ end
128
+
129
+ [best_from, best_to, best_size]
130
+ end
131
+
132
+ def matches
133
+ @matches ||= compute_matches
134
+ end
135
+
136
+ def compute_matches
137
+ matches = []
138
+ queue = [[0, @from.size, 0, @to.size]]
139
+ until queue.empty?
140
+ from_start, from_end, to_start, to_end = queue.pop
141
+ match = longest_match(from_start, from_end - 1, to_start, to_end - 1)
142
+ match_from_index, match_to_index, size = match
143
+ unless size.zero?
144
+ if from_start < match_from_index and
145
+ to_start < match_to_index
146
+ queue.push([from_start, match_from_index,
147
+ to_start, match_to_index])
148
+ end
149
+ matches << match
150
+ if match_from_index + size < from_end and
151
+ match_to_index + size < to_end
152
+ queue.push([match_from_index + size, from_end,
153
+ match_to_index + size, to_end])
154
+ end
155
+ end
156
+ end
157
+ matches.sort_by do |(from_index, to_index, match_size)|
158
+ from_index
159
+ end
160
+ end
161
+
162
+ def compute_blocks
163
+ blocks = []
164
+ current_from_index = current_to_index = current_size = 0
165
+ matches.each do |from_index, to_index, size|
166
+ if current_from_index + current_size == from_index and
167
+ current_to_index + current_size == to_index
168
+ current_size += size
169
+ else
170
+ unless current_size.zero?
171
+ blocks << [current_from_index, current_to_index, current_size]
172
+ end
173
+ current_from_index = from_index
174
+ current_to_index = to_index
175
+ current_size = size
176
+ end
177
+ end
178
+ unless current_size.zero?
179
+ blocks << [current_from_index, current_to_index, current_size]
180
+ end
181
+
182
+ blocks << [@from.size, @to.size, 0]
183
+ blocks
184
+ end
185
+
186
+ def compute_operations
187
+ from_index = to_index = 0
188
+ operations = []
189
+ blocks.each do |match_from_index, match_to_index, size|
190
+ tag = determine_tag(from_index, to_index,
191
+ match_from_index, match_to_index)
192
+ if tag != :equal
193
+ operations << [tag,
194
+ from_index, match_from_index,
195
+ to_index, match_to_index]
196
+ end
197
+
198
+ from_index, to_index = match_from_index + size, match_to_index + size
199
+ if size > 0
200
+ operations << [:equal,
201
+ match_from_index, from_index,
202
+ match_to_index, to_index]
203
+ end
204
+ end
205
+ operations
206
+ end
207
+
208
+ def compute_ratio
209
+ matches = blocks.inject(0) {|result, block| result + block[-1]}
210
+ length = @from.length + @to.length
211
+ if length.zero?
212
+ 1.0
213
+ else
214
+ 2.0 * matches / length
215
+ end
216
+ end
217
+
218
+ def determine_tag(from_index, to_index,
219
+ match_from_index, match_to_index)
220
+ if from_index < match_from_index and to_index < match_to_index
221
+ :replace
222
+ elsif from_index < match_from_index
223
+ :delete
224
+ elsif to_index < match_to_index
225
+ :insert
226
+ else
227
+ :equal
228
+ end
229
+ end
230
+
231
+ def expand_edge_equal_operations!(_operations, context_size)
232
+ tag, from_start, from_end, to_start, to_end = _operations[0]
233
+ if tag == :equal
234
+ _operations[0] = [tag,
235
+ [from_start, from_end - context_size].max,
236
+ from_end,
237
+ [to_start, to_end - context_size].max,
238
+ to_end]
239
+ end
240
+
241
+ tag, from_start, from_end, to_start, to_end = _operations[-1]
242
+ if tag == :equal
243
+ _operations[-1] = [tag,
244
+ from_start,
245
+ [from_end, from_start + context_size].min,
246
+ to_start,
247
+ [to_end, to_start + context_size].min]
248
+ end
249
+ end
250
+ end
251
+
252
+ class Differ
253
+ def initialize(from, to)
254
+ @from = from
255
+ @to = to
256
+ end
257
+
258
+ private
259
+ def tag(mark, contents)
260
+ contents.collect {|content| "#{mark}#{content}"}
261
+ end
262
+ end
263
+
264
+ class ReadableDiffer < Differ
265
+ def diff(options={})
266
+ result = []
267
+ matcher = SequenceMatcher.new(@from, @to)
268
+ matcher.operations.each do |args|
269
+ tag, from_start, from_end, to_start, to_end = args
270
+ case tag
271
+ when :replace
272
+ result.concat(diff_lines(from_start, from_end, to_start, to_end))
273
+ when :delete
274
+ result.concat(tag_deleted(@from[from_start...from_end]))
275
+ when :insert
276
+ result.concat(tag_inserted(@to[to_start...to_end]))
277
+ when :equal
278
+ result.concat(tag_equal(@from[from_start...from_end]))
279
+ else
280
+ raise "unknown tag: #{tag}"
281
+ end
282
+ end
283
+ result
284
+ end
285
+
286
+ private
287
+ def tag_deleted(contents)
288
+ tag("- ", contents)
289
+ end
290
+
291
+ def tag_inserted(contents)
292
+ tag("+ ", contents)
293
+ end
294
+
295
+ def tag_equal(contents)
296
+ tag(" ", contents)
297
+ end
298
+
299
+ def tag_difference(contents)
300
+ tag("? ", contents)
301
+ end
302
+
303
+ def find_diff_line_info(from_start, from_end, to_start, to_end)
304
+ best_ratio = 0.74
305
+ from_equal_index = to_equal_index = nil
306
+ from_best_index = to_best_index = nil
307
+
308
+ to_start.upto(to_end - 1) do |to_index|
309
+ from_start.upto(from_end - 1) do |from_index|
310
+ if @from[from_index] == @to[to_index]
311
+ from_equal_index ||= from_index
312
+ to_equal_index ||= to_index
313
+ next
314
+ end
315
+
316
+ matcher = SequenceMatcher.new(@from[from_index], @to[to_index],
317
+ &method(:space_character?))
318
+ if matcher.ratio > best_ratio
319
+ best_ratio = matcher.ratio
320
+ from_best_index = from_index
321
+ to_best_index = to_index
322
+ end
323
+ end
324
+ end
325
+
326
+ [best_ratio,
327
+ from_equal_index, to_equal_index,
328
+ from_best_index, to_best_index]
329
+ end
330
+
331
+ def diff_lines(from_start, from_end, to_start, to_end)
332
+ cut_off = 0.75
333
+
334
+ info = find_diff_line_info(from_start, from_end, to_start, to_end)
335
+ best_ratio, from_equal_index, to_equal_index, *info = info
336
+ from_best_index, to_best_index = info
337
+
338
+ if best_ratio < cut_off
339
+ if from_equal_index.nil?
340
+ tagged_from = tag_deleted(@from[from_start...from_end])
341
+ tagged_to = tag_inserted(@to[to_start...to_end])
342
+ if to_end - to_start < from_end - from_start
343
+ return tagged_to + tagged_from
344
+ else
345
+ return tagged_from + tagged_to
346
+ end
347
+ end
348
+ from_best_index = from_equal_index
349
+ to_best_index = to_equal_index
350
+ best_ratio = 1.0
351
+ end
352
+
353
+ _diff_lines(from_start, from_best_index, to_start, to_best_index) +
354
+ diff_line(@from[from_best_index], @to[to_best_index]) +
355
+ _diff_lines(from_best_index + 1, from_end, to_best_index + 1, to_end)
356
+ end
357
+
358
+ def _diff_lines(from_start, from_end, to_start, to_end)
359
+ if from_start < from_end
360
+ if to_start < to_end
361
+ diff_lines(from_start, from_end, to_start, to_end)
362
+ else
363
+ tag_deleted(@from[from_start...from_end])
364
+ end
365
+ else
366
+ tag_inserted(@to[to_start...to_end])
367
+ end
368
+ end
369
+
370
+ def diff_line(from_line, to_line)
371
+ from_tags = ""
372
+ to_tags = ""
373
+ matcher = SequenceMatcher.new(from_line, to_line,
374
+ &method(:space_character?))
375
+ matcher.operations.each do |tag, from_start, from_end, to_start, to_end|
376
+ from_length = from_end - from_start
377
+ to_length = to_end - to_start
378
+ case tag
379
+ when :replace
380
+ from_tags << "^" * from_length
381
+ to_tags << "^" * to_length
382
+ when :delete
383
+ from_tags << "-" * from_length
384
+ when :insert
385
+ to_tags << "+" * to_length
386
+ when :equal
387
+ from_tags << " " * from_length
388
+ to_tags << " " * to_length
389
+ else
390
+ raise "unknown tag: #{tag}"
391
+ end
392
+ end
393
+ format_diff_point(from_line, to_line, from_tags, to_tags)
394
+ end
395
+
396
+ def format_diff_point(from_line, to_line, from_tags, to_tags)
397
+ common = [n_leading_characters(from_line, ?\t),
398
+ n_leading_characters(to_line, ?\t)].min
399
+ common = [common, n_leading_characters(from_tags[0, common], " "[0])].min
400
+ from_tags = from_tags[common..-1].rstrip
401
+ to_tags = to_tags[common..-1].rstrip
402
+
403
+ result = tag_deleted([from_line])
404
+ unless from_tags.empty?
405
+ result.concat(tag_difference(["#{"\t" * common}#{from_tags}"]))
406
+ end
407
+ result.concat(tag_inserted([to_line]))
408
+ unless to_tags.empty?
409
+ result.concat(tag_difference(["#{"\t" * common}#{to_tags}"]))
410
+ end
411
+ result
412
+ end
413
+
414
+ def n_leading_characters(string, character)
415
+ n = 0
416
+ while string[n] == character
417
+ n += 1
418
+ end
419
+ n
420
+ end
421
+
422
+ def space_character?(character)
423
+ [" "[0], "\t"[0]].include?(character)
424
+ end
425
+ end
426
+
427
+ class UnifiedDiffer < Differ
428
+ def diff(options={})
429
+ groups = SequenceMatcher.new(@from, @to).grouped_operations
430
+ return [] if groups.empty?
431
+ return [] if same_content?(groups)
432
+
433
+ show_context = options[:show_context]
434
+ show_context = true if show_context.nil?
435
+ result = ["--- #{options[:from_label]}".rstrip,
436
+ "+++ #{options[:to_label]}".rstrip]
437
+ groups.each do |operations|
438
+ result << format_summary(operations, show_context)
439
+ operations.each do |args|
440
+ operation_tag, from_start, from_end, to_start, to_end = args
441
+ case operation_tag
442
+ when :replace
443
+ result.concat(tag("-", @from[from_start...from_end]))
444
+ result.concat(tag("+", @to[to_start...to_end]))
445
+ when :delete
446
+ result.concat(tag("-", @from[from_start...from_end]))
447
+ when :insert
448
+ result.concat(tag("+", @to[to_start...to_end]))
449
+ when :equal
450
+ result.concat(tag(" ", @from[from_start...from_end]))
451
+ end
452
+ end
453
+ end
454
+ result
455
+ end
456
+
457
+ private
458
+ def same_content?(groups)
459
+ return false if groups.size != 1
460
+ group = groups[0]
461
+ return false if group.size != 1
462
+ tag, from_start, from_end, to_start, to_end = group[0]
463
+
464
+ tag == :equal and [from_start, from_end] == [to_start, to_end]
465
+ end
466
+
467
+ def format_summary(operations, show_context)
468
+ _, first_from_start, _, first_to_start, _ = operations[0]
469
+ _, _, last_from_end, _, last_to_end = operations[-1]
470
+ summary = "@@ -%d,%d +%d,%d @@" % [first_from_start + 1,
471
+ last_from_end - first_from_start,
472
+ first_to_start + 1,
473
+ last_to_end - first_to_start,]
474
+ if show_context
475
+ interesting_line = find_interesting_line(first_from_start,
476
+ first_to_start,
477
+ :define_line?)
478
+ summary << " #{interesting_line}" if interesting_line
479
+ end
480
+ summary
481
+ end
482
+
483
+ def find_interesting_line(from_start, to_start, predicate)
484
+ from_index = from_start
485
+ to_index = to_start
486
+ while from_index >= 0 or to_index >= 0
487
+ [@from[from_index], @to[to_index]].each do |line|
488
+ return line if line and send(predicate, line)
489
+ end
490
+
491
+ from_index -= 1
492
+ to_index -= 1
493
+ end
494
+ nil
495
+ end
496
+
497
+ def define_line?(line)
498
+ /\A(?:[_a-zA-Z$]|\s*(?:class|module|def)\b)/ =~ line
499
+ end
500
+ end
501
+
502
+ module_function
503
+ def readable(from, to, options={})
504
+ diff(ReadableDiffer, from, to, options)
505
+ end
506
+
507
+ def unified(from, to, options={})
508
+ diff(UnifiedDiffer, from, to, options)
509
+ end
510
+
511
+ def diff(differ_class, from, to, options={})
512
+ differ = differ_class.new(from.split(/\r?\n/), to.split(/\r?\n/))
513
+ differ.diff(options).join("\n")
514
+ end
515
+ end
516
+ end
@@ -0,0 +1,79 @@
1
+ module Test
2
+ module Unit
3
+ class TestResult
4
+ attr_reader :notifications
5
+
6
+ alias_method(:initialize_without_notifications, :initialize)
7
+ def initialize
8
+ initialize_without_notifications
9
+ @notifications = []
10
+ end
11
+
12
+ def add_notification(notification)
13
+ @notifications << notification
14
+ notify_listeners(FAULT, notification)
15
+ notify_listeners(CHANGED, self)
16
+ end
17
+
18
+ def notification_count
19
+ @notifications.size
20
+ end
21
+
22
+ alias_method(:to_s_without_notifications, :to_s)
23
+ def to_s
24
+ to_s_without_notifications + ", #{notification_count} notifications"
25
+ end
26
+ end
27
+
28
+ class Notification
29
+ include Util::BacktraceFilter
30
+ attr_reader :test_name, :location, :message
31
+
32
+ SINGLE_CHARACTER = 'N'
33
+
34
+ # Creates a new Notification with the given location and
35
+ # message.
36
+ def initialize(test_name, location, message)
37
+ @test_name = test_name
38
+ @location = location
39
+ @message = message
40
+ end
41
+
42
+ # Returns a single character representation of a notification.
43
+ def single_character_display
44
+ SINGLE_CHARACTER
45
+ end
46
+
47
+ # Returns a brief version of the error description.
48
+ def short_display
49
+ "#@test_name: #{@message.split("\n")[0]}"
50
+ end
51
+
52
+ # Returns a verbose version of the error description.
53
+ def long_display
54
+ location_display = filter_backtrace(location)[0]
55
+ location_display = location_display.sub(/\A(.+:\d+).*/, ' [\\1]')
56
+ "Notification:\n#{@test_name}#{location_display}:\n#{@message}"
57
+ end
58
+
59
+ # Overridden to return long_display.
60
+ def to_s
61
+ long_display
62
+ end
63
+ end
64
+
65
+ class NotifiedError < StandardError
66
+ end
67
+
68
+ module AssertionsWithNotify
69
+ def notify(message)
70
+ notification = Notification.new(name, caller[0, 1], message)
71
+ @_result.add_notification(notification)
72
+ end
73
+ end
74
+
75
+ class TestCase
76
+ include AssertionsWithNotify
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,96 @@
1
+ module Test
2
+ module Unit
3
+ class TestResult
4
+ attr_reader :omissions
5
+
6
+ alias_method(:initialize_without_omissions, :initialize)
7
+ def initialize
8
+ initialize_without_omissions
9
+ @omissions = []
10
+ end
11
+
12
+ def add_omission(omission)
13
+ @omissions << omission
14
+ notify_listeners(FAULT, omission)
15
+ notify_listeners(CHANGED, self)
16
+ end
17
+
18
+ def omission_count
19
+ @omissions.size
20
+ end
21
+
22
+ alias_method(:to_s_without_omissions, :to_s)
23
+ def to_s
24
+ to_s_without_omissions + ", #{omission_count} omissions"
25
+ end
26
+ end
27
+
28
+ class Omission
29
+ include Util::BacktraceFilter
30
+ attr_reader :test_name, :location, :message
31
+
32
+ SINGLE_CHARACTER = 'O'
33
+
34
+ # Creates a new Omission with the given location and
35
+ # message.
36
+ def initialize(test_name, location, message)
37
+ @test_name = test_name
38
+ @location = location
39
+ @message = message
40
+ end
41
+
42
+ # Returns a single character representation of a omission.
43
+ def single_character_display
44
+ SINGLE_CHARACTER
45
+ end
46
+
47
+ # Returns a brief version of the error description.
48
+ def short_display
49
+ "#@test_name: #{@message.split("\n")[0]}"
50
+ end
51
+
52
+ # Returns a verbose version of the error description.
53
+ def long_display
54
+ backtrace = filter_backtrace(location).join("\n")
55
+ "Omission:\n#{@test_name}\n#{@message}\n#{backtrace}"
56
+ end
57
+
58
+ # Overridden to return long_display.
59
+ def to_s
60
+ long_display
61
+ end
62
+ end
63
+
64
+ class OmittedError < StandardError
65
+ end
66
+
67
+ module AssertionsWithOmit
68
+ def omit(message="Omitted", &block)
69
+ if block_given?
70
+ begin
71
+ yield
72
+ rescue Exception
73
+ raise OmittedError, message, $!.backtrace
74
+ end
75
+ flunk("Omission block should not be passed: #{message}")
76
+ else
77
+ raise OmittedError.new(message)
78
+ end
79
+ end
80
+ end
81
+
82
+ class TestCase
83
+ include AssertionsWithOmit
84
+
85
+ alias_method(:add_error_without_omission, :add_error)
86
+ def add_error(exception)
87
+ if exception.is_a?(OmittedError)
88
+ omission = Omission.new(name, exception.backtrace, exception.message)
89
+ @_result.add_omission(omission)
90
+ else
91
+ add_error_without_omission(exception)
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end