mspec 1.1.1 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/lib/mspec/runner/actions/tag.rb +41 -7
- data/lib/mspec/runner/actions/tally.rb +16 -7
- data/lib/mspec/runner/{state.rb → context.rb} +22 -54
- data/lib/mspec/runner/example.rb +37 -0
- data/lib/mspec/runner/exception.rb +39 -0
- data/lib/mspec/runner/formatters/dotted.rb +61 -45
- data/lib/mspec/runner/formatters/html.rb +16 -22
- data/lib/mspec/runner/formatters/specdoc.rb +24 -11
- data/lib/mspec/runner/formatters/spinner.rb +20 -10
- data/lib/mspec/runner/formatters/summary.rb +4 -1
- data/lib/mspec/runner/formatters/unit.rb +5 -9
- data/lib/mspec/runner/formatters/yaml.rb +11 -10
- data/lib/mspec/runner/mspec.rb +15 -16
- data/lib/mspec/version.rb +1 -1
- data/spec/runner/actions/debug_spec.rb +2 -2
- data/spec/runner/actions/gdb_spec.rb +2 -2
- data/spec/runner/actions/tag_spec.rb +76 -22
- data/spec/runner/actions/tally_spec.rb +26 -6
- data/spec/runner/{state_spec.rb → context_spec.rb} +80 -167
- data/spec/runner/example_spec.rb +96 -0
- data/spec/runner/exception_spec.rb +110 -0
- data/spec/runner/formatters/dotted_spec.rb +117 -27
- data/spec/runner/formatters/html_spec.rb +44 -21
- data/spec/runner/formatters/specdoc_spec.rb +52 -12
- data/spec/runner/formatters/spinner_spec.rb +2 -2
- data/spec/runner/formatters/summary_spec.rb +7 -11
- data/spec/runner/formatters/unit_spec.rb +12 -11
- data/spec/runner/formatters/yaml_spec.rb +7 -6
- data/spec/runner/mspec_spec.rb +28 -29
- metadata +7 -3
data/Rakefile
CHANGED
@@ -29,15 +29,35 @@ class TagAction < ActionFilter
|
|
29
29
|
@tag = tag
|
30
30
|
@comment = comment
|
31
31
|
@report = []
|
32
|
+
@exception = false
|
32
33
|
end
|
33
34
|
|
35
|
+
# Returns true if there are no _tag_ or _description_ filters. This
|
36
|
+
# means that a TagAction matches any example by default. Otherwise,
|
37
|
+
# returns true if either the _tag_ or the _description_ filter
|
38
|
+
# matches +string+.
|
34
39
|
def ===(string)
|
35
40
|
return true unless @sfilter or @tfilter
|
36
41
|
@sfilter === string or @tfilter === string
|
37
42
|
end
|
38
43
|
|
44
|
+
# Callback for the MSpec :before event. Resets the +#exception?+
|
45
|
+
# flag to false.
|
46
|
+
def before(state)
|
47
|
+
@exception = false
|
48
|
+
end
|
49
|
+
|
50
|
+
# Callback for the MSpec :exception event. Sets the +#exception?+
|
51
|
+
# flag.
|
52
|
+
def exception(exception)
|
53
|
+
@exception = exception
|
54
|
+
end
|
55
|
+
|
56
|
+
# Callback for the MSpec :after event. Performs the tag action
|
57
|
+
# depending on the type of action and the outcome of evaluating
|
58
|
+
# the example. See +TagAction+ for a description of the actions.
|
39
59
|
def after(state)
|
40
|
-
if self === state.description and outcome?
|
60
|
+
if self === state.description and outcome?
|
41
61
|
tag = SpecTag.new
|
42
62
|
tag.tag = @tag
|
43
63
|
tag.comment = @comment
|
@@ -54,10 +74,19 @@ class TagAction < ActionFilter
|
|
54
74
|
end
|
55
75
|
end
|
56
76
|
|
57
|
-
|
77
|
+
# Returns true if the result of evaluating the example matches
|
78
|
+
# the _outcome_ registered for this tag action. See +TagAction+
|
79
|
+
# for a description of the _outcome_ types.
|
80
|
+
def outcome?
|
58
81
|
@outcome == :all or
|
59
|
-
(@outcome == :pass and not
|
60
|
-
(@outcome == :fail and
|
82
|
+
(@outcome == :pass and not exception?) or
|
83
|
+
(@outcome == :fail and exception?)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Returns true if an exception was raised while evaluating the
|
87
|
+
# current example.
|
88
|
+
def exception?
|
89
|
+
!!@exception
|
61
90
|
end
|
62
91
|
|
63
92
|
def report
|
@@ -65,6 +94,8 @@ class TagAction < ActionFilter
|
|
65
94
|
end
|
66
95
|
private :report
|
67
96
|
|
97
|
+
# Callback for the MSpec :finish event. Prints the actions
|
98
|
+
# performed while evaluating the examples.
|
68
99
|
def finish
|
69
100
|
case @action
|
70
101
|
when :add
|
@@ -86,12 +117,15 @@ class TagAction < ActionFilter
|
|
86
117
|
|
87
118
|
def register
|
88
119
|
super
|
89
|
-
MSpec.register :
|
90
|
-
MSpec.register :
|
120
|
+
MSpec.register :exception, self
|
121
|
+
MSpec.register :after, self
|
122
|
+
MSpec.register :finish, self
|
91
123
|
end
|
92
124
|
|
93
125
|
def unregister
|
94
126
|
super
|
95
|
-
MSpec.unregister :
|
127
|
+
MSpec.unregister :exception, self
|
128
|
+
MSpec.unregister :after, self
|
129
|
+
MSpec.unregister :finish, self
|
96
130
|
end
|
97
131
|
end
|
@@ -48,14 +48,16 @@ class TallyAction
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def register
|
51
|
-
MSpec.register :load,
|
52
|
-
MSpec.register :
|
51
|
+
MSpec.register :load, self
|
52
|
+
MSpec.register :exception, self
|
53
|
+
MSpec.register :after, self
|
53
54
|
MSpec.register :expectation, self
|
54
55
|
end
|
55
56
|
|
56
57
|
def unregister
|
57
|
-
MSpec.unregister :load,
|
58
|
-
MSpec.unregister :
|
58
|
+
MSpec.unregister :load, self
|
59
|
+
MSpec.unregister :exception, self
|
60
|
+
MSpec.unregister :after, self
|
59
61
|
MSpec.unregister :expectation, self
|
60
62
|
end
|
61
63
|
|
@@ -63,15 +65,22 @@ class TallyAction
|
|
63
65
|
@counter.files!
|
64
66
|
end
|
65
67
|
|
68
|
+
# Callback for the MSpec :expectation event. Increments the
|
69
|
+
# tally of expectations (e.g. #should, #should_receive, etc.).
|
66
70
|
def expectation(state)
|
67
71
|
@counter.expectations!
|
68
72
|
end
|
69
73
|
|
74
|
+
# Callback for the MSpec :exception event. Increments the
|
75
|
+
# tally of errors and failures.
|
76
|
+
def exception(exception)
|
77
|
+
exception.failure? ? @counter.failures! : @counter.errors!
|
78
|
+
end
|
79
|
+
|
80
|
+
# Callback for the MSpec :after event. Increments the tally
|
81
|
+
# of examples.
|
70
82
|
def after(state)
|
71
83
|
@counter.examples!
|
72
|
-
state.exceptions.each do |msg, exc|
|
73
|
-
state.failure?(exc) ? @counter.failures! : @counter.errors!
|
74
|
-
end
|
75
84
|
end
|
76
85
|
|
77
86
|
def format
|
@@ -1,6 +1,18 @@
|
|
1
1
|
require 'mspec/runner/mspec'
|
2
|
-
|
3
|
-
|
2
|
+
require 'mspec/runner/example'
|
3
|
+
|
4
|
+
# Holds the state of the +describe+ block that is being
|
5
|
+
# evaluated. Every example (i.e. +it+ block) is evaluated
|
6
|
+
# in a context, which may include state set up in <tt>before
|
7
|
+
# :each</tt> or <tt>before :all</tt> blocks.
|
8
|
+
#
|
9
|
+
#--
|
10
|
+
# A note on naming: this is named _ContextState_ rather
|
11
|
+
# than _DescribeState_ because +describe+ is the keyword
|
12
|
+
# in the DSL for refering to the context in which an example
|
13
|
+
# is evaluated, just as +it+ refers to the example itself.
|
14
|
+
#++
|
15
|
+
class ContextState
|
4
16
|
def initialize
|
5
17
|
@start = []
|
6
18
|
@before = []
|
@@ -32,7 +44,7 @@ class RunState
|
|
32
44
|
end
|
33
45
|
|
34
46
|
def it(desc, &block)
|
35
|
-
state =
|
47
|
+
state = ExampleState.new @describe, desc
|
36
48
|
@spec << [desc, block, state] unless state.filtered?
|
37
49
|
end
|
38
50
|
|
@@ -42,8 +54,8 @@ class RunState
|
|
42
54
|
end
|
43
55
|
|
44
56
|
def protect(what, blocks, check=true)
|
45
|
-
return if check and MSpec.pretend_mode?
|
46
|
-
Array(blocks).
|
57
|
+
return false if check and MSpec.pretend_mode?
|
58
|
+
Array(blocks).all? { |block| MSpec.protect what, &block }
|
47
59
|
end
|
48
60
|
|
49
61
|
def process
|
@@ -56,10 +68,11 @@ class RunState
|
|
56
68
|
@spec.each do |desc, spec, state|
|
57
69
|
@state = state
|
58
70
|
MSpec.actions :before, state
|
59
|
-
protect
|
60
|
-
|
61
|
-
|
62
|
-
|
71
|
+
if protect("before :each", @before)
|
72
|
+
protect nil, spec
|
73
|
+
protect "after :each", @after
|
74
|
+
protect "Mock.verify_count", lambda { Mock.verify_count }
|
75
|
+
end
|
63
76
|
protect "Mock.cleanup", lambda { Mock.cleanup }
|
64
77
|
MSpec.actions :after, state
|
65
78
|
@state = nil
|
@@ -69,48 +82,3 @@ class RunState
|
|
69
82
|
end
|
70
83
|
end
|
71
84
|
|
72
|
-
class SpecState
|
73
|
-
def initialize(describe, it)
|
74
|
-
@describe = describe
|
75
|
-
@it = it
|
76
|
-
@unfiltered = nil
|
77
|
-
end
|
78
|
-
|
79
|
-
def describe
|
80
|
-
@describe
|
81
|
-
end
|
82
|
-
|
83
|
-
def it
|
84
|
-
@it
|
85
|
-
end
|
86
|
-
|
87
|
-
def description
|
88
|
-
@description ||= "#{@describe} #{@it}"
|
89
|
-
end
|
90
|
-
|
91
|
-
def exceptions
|
92
|
-
@exceptions ||= []
|
93
|
-
end
|
94
|
-
|
95
|
-
def exception?
|
96
|
-
not exceptions.empty?
|
97
|
-
end
|
98
|
-
|
99
|
-
def unfiltered?
|
100
|
-
unless @unfiltered
|
101
|
-
incl = MSpec.retrieve(:include) || []
|
102
|
-
excl = MSpec.retrieve(:exclude) || []
|
103
|
-
@unfiltered = incl.empty? || incl.any? { |f| f === description }
|
104
|
-
@unfiltered &&= excl.empty? || !excl.any? { |f| f === description }
|
105
|
-
end
|
106
|
-
@unfiltered
|
107
|
-
end
|
108
|
-
|
109
|
-
def filtered?
|
110
|
-
not unfiltered?
|
111
|
-
end
|
112
|
-
|
113
|
-
def failure?(exception)
|
114
|
-
exception.is_a?(ExpectationNotMetError)
|
115
|
-
end
|
116
|
-
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'mspec/runner/mspec'
|
2
|
+
|
3
|
+
# Holds some of the state of the example (i.e. +it+ block) that is
|
4
|
+
# being evaluated. See also +ContextState+.
|
5
|
+
class ExampleState
|
6
|
+
def initialize(describe, it)
|
7
|
+
@describe = describe
|
8
|
+
@it = it
|
9
|
+
@unfiltered = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def describe
|
13
|
+
@describe
|
14
|
+
end
|
15
|
+
|
16
|
+
def it
|
17
|
+
@it
|
18
|
+
end
|
19
|
+
|
20
|
+
def description
|
21
|
+
@description ||= "#{@describe} #{@it}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def unfiltered?
|
25
|
+
unless @unfiltered
|
26
|
+
incl = MSpec.retrieve(:include) || []
|
27
|
+
excl = MSpec.retrieve(:exclude) || []
|
28
|
+
@unfiltered = incl.empty? || incl.any? { |f| f === description }
|
29
|
+
@unfiltered &&= excl.empty? || !excl.any? { |f| f === description }
|
30
|
+
end
|
31
|
+
@unfiltered
|
32
|
+
end
|
33
|
+
|
34
|
+
def filtered?
|
35
|
+
not unfiltered?
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class ExceptionState
|
2
|
+
attr_reader :description, :describe, :it, :exception
|
3
|
+
|
4
|
+
def initialize(state, location, exception)
|
5
|
+
@exception = exception
|
6
|
+
|
7
|
+
@description = location ? "An exception occurred during: #{location}" : ""
|
8
|
+
if state
|
9
|
+
@description << "\n" unless @description.empty?
|
10
|
+
@description << state.description
|
11
|
+
@describe = state.describe
|
12
|
+
@it = state.it
|
13
|
+
else
|
14
|
+
@describe = @it = ""
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def failure?
|
19
|
+
@exception.is_a? ExpectationNotMetError
|
20
|
+
end
|
21
|
+
|
22
|
+
def message
|
23
|
+
if @exception.message.empty?
|
24
|
+
"<No message>"
|
25
|
+
elsif @exception.class == ExpectationNotMetError
|
26
|
+
@exception.message
|
27
|
+
else
|
28
|
+
"#{@exception.class}: #{@exception.message}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def backtrace
|
33
|
+
begin
|
34
|
+
return @exception.awesome_backtrace.show
|
35
|
+
rescue Exception
|
36
|
+
return @exception.backtrace && @exception.backtrace.join("\n")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -3,10 +3,12 @@ require 'mspec/runner/actions/timer'
|
|
3
3
|
require 'mspec/runner/actions/tally'
|
4
4
|
|
5
5
|
class DottedFormatter
|
6
|
-
attr_reader :timer, :tally
|
6
|
+
attr_reader :exceptions, :timer, :tally
|
7
7
|
|
8
8
|
def initialize(out=nil)
|
9
|
-
@
|
9
|
+
@exception = @failure = false
|
10
|
+
@exceptions = []
|
11
|
+
@count = 0
|
10
12
|
if out.nil?
|
11
13
|
@out = $stdout
|
12
14
|
else
|
@@ -14,68 +16,82 @@ class DottedFormatter
|
|
14
16
|
end
|
15
17
|
end
|
16
18
|
|
19
|
+
# Creates the +TimerAction+ and +TallyAction+ instances and
|
20
|
+
# registers them. Registers +self+ for the +:exception+,
|
21
|
+
# +:before+, +:after+, and +:finish+ actions.
|
17
22
|
def register
|
18
|
-
@timer = TimerAction.new
|
19
|
-
@
|
20
|
-
@tally = TallyAction.new
|
21
|
-
@tally.register
|
23
|
+
(@timer = TimerAction.new).register
|
24
|
+
(@tally = TallyAction.new).register
|
22
25
|
@counter = @tally.counter
|
23
26
|
|
24
|
-
MSpec.register :
|
25
|
-
MSpec.register :
|
27
|
+
MSpec.register :exception, self
|
28
|
+
MSpec.register :before, self
|
29
|
+
MSpec.register :after, self
|
30
|
+
MSpec.register :finish, self
|
26
31
|
end
|
27
32
|
|
33
|
+
# Returns true if any exception is raised while running
|
34
|
+
# an example. This flag is reset before each example
|
35
|
+
# is evaluated.
|
36
|
+
def exception?
|
37
|
+
@exception
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns true if all exceptions during the evaluation
|
41
|
+
# of an example are failures rather than errors. See
|
42
|
+
# <tt>ExceptionState#failure</tt>. This flag is reset
|
43
|
+
# before each example is evaluated.
|
44
|
+
def failure?
|
45
|
+
@failure
|
46
|
+
end
|
47
|
+
|
48
|
+
# Callback for the MSpec :before event. Resets the
|
49
|
+
# +#exception?+ and +#failure+ flags.
|
50
|
+
def before(state)
|
51
|
+
@failure = @exception = false
|
52
|
+
end
|
53
|
+
|
54
|
+
# Callback for the MSpec :exception event. Stores the
|
55
|
+
# +ExceptionState+ object to generate the list of backtraces
|
56
|
+
# after all the specs are run. Also updates the internal
|
57
|
+
# +#exception?+ and +#failure?+ flags.
|
58
|
+
def exception(exception)
|
59
|
+
@count += 1
|
60
|
+
@failure = @exception ? @failure && exception.failure? : exception.failure?
|
61
|
+
@exception = true
|
62
|
+
@exceptions << exception
|
63
|
+
end
|
64
|
+
|
65
|
+
# Callback for the MSpec :after event. Prints an indicator
|
66
|
+
# for the result of evaluating this example as follows:
|
67
|
+
# . = No failure or error
|
68
|
+
# F = An ExpectationNotMetError was raised
|
69
|
+
# E = Any exception other than ExpectationNotMetError
|
28
70
|
def after(state)
|
29
|
-
unless
|
71
|
+
unless exception?
|
30
72
|
print "."
|
31
73
|
else
|
32
|
-
|
33
|
-
print failure?(state) ? "F" : "E"
|
74
|
+
print failure? ? "F" : "E"
|
34
75
|
end
|
35
76
|
end
|
36
77
|
|
78
|
+
# Callback for the MSpec :finish event. Prints a description
|
79
|
+
# and backtrace for every exception that occurred while
|
80
|
+
# evaluating the examples.
|
37
81
|
def finish
|
38
82
|
print "\n"
|
39
83
|
count = 0
|
40
|
-
@
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
print message(exc)
|
46
|
-
print "\n"
|
47
|
-
print backtrace(exc)
|
48
|
-
print "\n"
|
49
|
-
end
|
84
|
+
@exceptions.each do |exc|
|
85
|
+
outcome = exc.failure? ? "FAILED" : "ERROR"
|
86
|
+
print "\n#{count += 1})\n#{exc.description} #{outcome}\n"
|
87
|
+
print exc.message, "\n"
|
88
|
+
print exc.backtrace, "\n"
|
50
89
|
end
|
51
90
|
print "\n#{@timer.format}\n\n#{@tally.format}\n"
|
52
91
|
end
|
53
92
|
|
93
|
+
# A convenience method to allow printing to different outputs.
|
54
94
|
def print(*args)
|
55
95
|
@out.print(*args)
|
56
96
|
end
|
57
|
-
|
58
|
-
def message(exc)
|
59
|
-
if exc.message.empty?
|
60
|
-
"<No message>"
|
61
|
-
elsif exc.class == ExpectationNotMetError
|
62
|
-
exc.message
|
63
|
-
else
|
64
|
-
"#{exc.class}: #{exc.message}"
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def failure?(state)
|
69
|
-
state.exceptions.all? { |msg, exc| state.failure?(exc) }
|
70
|
-
end
|
71
|
-
private :failure?
|
72
|
-
|
73
|
-
def backtrace(exc)
|
74
|
-
begin
|
75
|
-
return exc.awesome_backtrace.show
|
76
|
-
rescue Exception
|
77
|
-
return exc.backtrace && exc.backtrace.join("\n")
|
78
|
-
end
|
79
|
-
end
|
80
|
-
private :backtrace
|
81
97
|
end
|