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
|
require 'mspec/expectations/expectations'
require 'mspec/runner/actions/timer'
require 'mspec/runner/actions/tally'
if ENV['CHECK_LEAKS']
require 'mspec/runner/actions/leakchecker'
require 'mspec/runner/actions/constants_leak_checker'
end
class DottedFormatter
attr_reader :exceptions, :timer, :tally
def initialize(out=nil)
@exception = @failure = false
@exceptions = []
@count = 0 # For subclasses
if out.nil?
@out = $stdout
else
@out = File.open out, "w"
end
@current_state = nil
end
# Creates the +TimerAction+ and +TallyAction+ instances and
# registers them. Registers +self+ for the +:exception+,
# +:before+, +:after+, and +:finish+ actions.
def register
(@timer = TimerAction.new).register
(@tally = TallyAction.new).register
if ENV['CHECK_LEAKS']
save = ENV['CHECK_LEAKS'] == 'save'
LeakCheckerAction.new.register
ConstantsLeakCheckerAction.new(save).register
end
@counter = @tally.counter
MSpec.register :exception, self
MSpec.register :before, self
MSpec.register :after, self
MSpec.register :finish, self
MSpec.register :abort, self
end
def abort
if @current_state
puts "\naborting example: #{@current_state.description}"
end
end
# Returns true if any exception is raised while running
# an example. This flag is reset before each example
# is evaluated.
def exception?
@exception
end
# Returns true if all exceptions during the evaluation
# of an example are failures rather than errors. See
# <tt>ExceptionState#failure</tt>. This flag is reset
# before each example is evaluated.
def failure?
@failure
end
# Callback for the MSpec :before event. Resets the
# +#exception?+ and +#failure+ flags.
def before(state=nil)
@current_state = state
@failure = @exception = false
end
# Callback for the MSpec :exception event. Stores the
# +ExceptionState+ object to generate the list of backtraces
# after all the specs are run. Also updates the internal
# +#exception?+ and +#failure?+ flags.
def exception(exception)
@count += 1
@failure = @exception ? @failure && exception.failure? : exception.failure?
@exception = true
@exceptions << exception
end
# Callback for the MSpec :after event. Prints an indicator
# for the result of evaluating this example as follows:
# . = No failure or error
# F = An SpecExpectationNotMetError was raised
# E = Any exception other than SpecExpectationNotMetError
def after(state = nil)
@current_state = nil
unless exception?
print "."
else
print failure? ? "F" : "E"
end
end
# Callback for the MSpec :start event. Calls :after event.
def start
after
end
# Callback for the MSpec :unload event. Calls :after event.
def unload
after
end
# Callback for the MSpec :finish event. Prints a description
# and backtrace for every exception that occurred while
# evaluating the examples.
def finish
print "\n"
count = 0
@exceptions.each do |exc|
count += 1
print_exception(exc, count)
end
print "\n#{@timer.format}\n\n#{@tally.format}\n"
end
def print_exception(exc, count)
outcome = exc.failure? ? "FAILED" : "ERROR"
print "\n#{count})\n#{exc.description} #{outcome}\n"
print exc.message, "\n"
print exc.backtrace, "\n"
end
# A convenience method to allow printing to different outputs.
def print(*args)
@out.print(*args)
@out.flush
end
end
|