mspec 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +22 -0
- data/README +101 -0
- data/Rakefile +44 -0
- data/bin/mkspec +7 -0
- data/bin/mspec +7 -0
- data/bin/mspec-ci +8 -0
- data/bin/mspec-run +8 -0
- data/bin/mspec-tag +8 -0
- data/lib/mspec.rb +6 -0
- data/lib/mspec/commands/mkspec.rb +147 -0
- data/lib/mspec/commands/mspec-ci.rb +71 -0
- data/lib/mspec/commands/mspec-run.rb +80 -0
- data/lib/mspec/commands/mspec-tag.rb +87 -0
- data/lib/mspec/commands/mspec.rb +143 -0
- data/lib/mspec/expectations.rb +2 -0
- data/lib/mspec/expectations/expectations.rb +12 -0
- data/lib/mspec/expectations/should.rb +23 -0
- data/lib/mspec/guards.rb +13 -0
- data/lib/mspec/guards/bug.rb +27 -0
- data/lib/mspec/guards/compliance.rb +18 -0
- data/lib/mspec/guards/conflict.rb +16 -0
- data/lib/mspec/guards/endian.rb +40 -0
- data/lib/mspec/guards/extensions.rb +12 -0
- data/lib/mspec/guards/guard.rb +120 -0
- data/lib/mspec/guards/noncompliance.rb +12 -0
- data/lib/mspec/guards/platform.rb +38 -0
- data/lib/mspec/guards/quarantine.rb +15 -0
- data/lib/mspec/guards/runner.rb +30 -0
- data/lib/mspec/guards/superuser.rb +15 -0
- data/lib/mspec/guards/support.rb +12 -0
- data/lib/mspec/guards/version.rb +40 -0
- data/lib/mspec/helpers.rb +6 -0
- data/lib/mspec/helpers/bignum.rb +5 -0
- data/lib/mspec/helpers/const_lookup.rb +5 -0
- data/lib/mspec/helpers/flunk.rb +5 -0
- data/lib/mspec/helpers/io.rb +13 -0
- data/lib/mspec/helpers/scratch.rb +17 -0
- data/lib/mspec/helpers/tmp.rb +32 -0
- data/lib/mspec/matchers.rb +16 -0
- data/lib/mspec/matchers/base.rb +95 -0
- data/lib/mspec/matchers/be_ancestor_of.rb +24 -0
- data/lib/mspec/matchers/be_close.rb +27 -0
- data/lib/mspec/matchers/be_empty.rb +20 -0
- data/lib/mspec/matchers/be_false.rb +20 -0
- data/lib/mspec/matchers/be_kind_of.rb +24 -0
- data/lib/mspec/matchers/be_nil.rb +20 -0
- data/lib/mspec/matchers/be_true.rb +20 -0
- data/lib/mspec/matchers/complain.rb +56 -0
- data/lib/mspec/matchers/eql.rb +26 -0
- data/lib/mspec/matchers/equal.rb +26 -0
- data/lib/mspec/matchers/equal_utf16.rb +34 -0
- data/lib/mspec/matchers/include.rb +32 -0
- data/lib/mspec/matchers/output.rb +67 -0
- data/lib/mspec/matchers/output_to_fd.rb +71 -0
- data/lib/mspec/matchers/raise_error.rb +48 -0
- data/lib/mspec/mocks.rb +3 -0
- data/lib/mspec/mocks/mock.rb +123 -0
- data/lib/mspec/mocks/object.rb +28 -0
- data/lib/mspec/mocks/proxy.rb +112 -0
- data/lib/mspec/runner.rb +13 -0
- data/lib/mspec/runner/actions.rb +6 -0
- data/lib/mspec/runner/actions/debug.rb +17 -0
- data/lib/mspec/runner/actions/filter.rb +40 -0
- data/lib/mspec/runner/actions/gdb.rb +17 -0
- data/lib/mspec/runner/actions/tag.rb +97 -0
- data/lib/mspec/runner/actions/tally.rb +80 -0
- data/lib/mspec/runner/actions/timer.rb +22 -0
- data/lib/mspec/runner/filters.rb +4 -0
- data/lib/mspec/runner/filters/match.rb +22 -0
- data/lib/mspec/runner/filters/profile.rb +54 -0
- data/lib/mspec/runner/filters/regexp.rb +7 -0
- data/lib/mspec/runner/filters/tag.rb +29 -0
- data/lib/mspec/runner/formatters.rb +7 -0
- data/lib/mspec/runner/formatters/dotted.rb +81 -0
- data/lib/mspec/runner/formatters/html.rb +87 -0
- data/lib/mspec/runner/formatters/specdoc.rb +27 -0
- data/lib/mspec/runner/formatters/spinner.rb +89 -0
- data/lib/mspec/runner/formatters/summary.rb +8 -0
- data/lib/mspec/runner/formatters/unit.rb +25 -0
- data/lib/mspec/runner/formatters/yaml.rb +43 -0
- data/lib/mspec/runner/mspec.rb +232 -0
- data/lib/mspec/runner/object.rb +20 -0
- data/lib/mspec/runner/shared.rb +12 -0
- data/lib/mspec/runner/state.rb +116 -0
- data/lib/mspec/runner/tag.rb +20 -0
- data/lib/mspec/utils/name_map.rb +130 -0
- data/lib/mspec/utils/options.rb +344 -0
- data/lib/mspec/utils/script.rb +77 -0
- data/lib/mspec/version.rb +3 -0
- data/spec/commands/mkspec_spec.rb +321 -0
- data/spec/commands/mspec_ci_spec.rb +139 -0
- data/spec/commands/mspec_run_spec.rb +146 -0
- data/spec/commands/mspec_spec.rb +359 -0
- data/spec/commands/mspec_tag_spec.rb +131 -0
- data/spec/expectations/expectations_spec.rb +16 -0
- data/spec/expectations/should_spec.rb +99 -0
- data/spec/guards/bug_spec.rb +137 -0
- data/spec/guards/compliance_spec.rb +70 -0
- data/spec/guards/conflict_spec.rb +20 -0
- data/spec/guards/endian_spec.rb +42 -0
- data/spec/guards/extensions_spec.rb +36 -0
- data/spec/guards/guard_spec.rb +355 -0
- data/spec/guards/noncompliance_spec.rb +36 -0
- data/spec/guards/platform_spec.rb +84 -0
- data/spec/guards/quarantine_spec.rb +19 -0
- data/spec/guards/runner_spec.rb +75 -0
- data/spec/guards/superuser_spec.rb +22 -0
- data/spec/guards/support_spec.rb +22 -0
- data/spec/guards/version_spec.rb +133 -0
- data/spec/helpers/bignum_spec.rb +11 -0
- data/spec/helpers/const_lookup_spec.rb +19 -0
- data/spec/helpers/flunk_spec.rb +15 -0
- data/spec/helpers/io_spec.rb +34 -0
- data/spec/helpers/scratch_spec.rb +22 -0
- data/spec/helpers/tmp_spec.rb +72 -0
- data/spec/matchers/base_spec.rb +180 -0
- data/spec/matchers/be_ancestor_of_spec.rb +28 -0
- data/spec/matchers/be_close_spec.rb +46 -0
- data/spec/matchers/be_empty_spec.rb +26 -0
- data/spec/matchers/be_false_spec.rb +28 -0
- data/spec/matchers/be_kind_of_spec.rb +29 -0
- data/spec/matchers/be_nil_spec.rb +27 -0
- data/spec/matchers/be_true_spec.rb +28 -0
- data/spec/matchers/complain_spec.rb +52 -0
- data/spec/matchers/eql_spec.rb +33 -0
- data/spec/matchers/equal_spec.rb +33 -0
- data/spec/matchers/equal_utf16_spec.rb +47 -0
- data/spec/matchers/include_spec.rb +37 -0
- data/spec/matchers/output_spec.rb +74 -0
- data/spec/matchers/output_to_fd_spec.rb +33 -0
- data/spec/matchers/raise_error_spec.rb +56 -0
- data/spec/mocks/mock_spec.rb +272 -0
- data/spec/mocks/proxy_spec.rb +259 -0
- data/spec/runner/actions/debug_spec.rb +61 -0
- data/spec/runner/actions/filter_spec.rb +84 -0
- data/spec/runner/actions/gdb_spec.rb +61 -0
- data/spec/runner/actions/tag_spec.rb +253 -0
- data/spec/runner/actions/tally_spec.rb +107 -0
- data/spec/runner/actions/timer_spec.rb +42 -0
- data/spec/runner/filters/a.yaml +4 -0
- data/spec/runner/filters/b.yaml +11 -0
- data/spec/runner/filters/match_spec.rb +44 -0
- data/spec/runner/filters/profile_spec.rb +117 -0
- data/spec/runner/filters/regexp_spec.rb +13 -0
- data/spec/runner/filters/tag_spec.rb +77 -0
- data/spec/runner/formatters/dotted_spec.rb +184 -0
- data/spec/runner/formatters/html_spec.rb +191 -0
- data/spec/runner/formatters/specdoc_spec.rb +57 -0
- data/spec/runner/formatters/spinner_spec.rb +78 -0
- data/spec/runner/formatters/summary_spec.rb +29 -0
- data/spec/runner/formatters/unit_spec.rb +71 -0
- data/spec/runner/formatters/yaml_spec.rb +123 -0
- data/spec/runner/mspec_spec.rb +393 -0
- data/spec/runner/shared_spec.rb +41 -0
- data/spec/runner/state_spec.rb +535 -0
- data/spec/runner/tag_spec.rb +93 -0
- data/spec/runner/tags.txt +3 -0
- data/spec/spec_helper.rb +46 -0
- data/spec/utils/name_map_spec.rb +178 -0
- data/spec/utils/options_spec.rb +862 -0
- data/spec/utils/script_spec.rb +240 -0
- metadata +217 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
class RaiseErrorMatcher
|
|
2
|
+
def initialize(exception, message, &block)
|
|
3
|
+
@exception = exception
|
|
4
|
+
@message = message
|
|
5
|
+
@block = block
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def matches?(proc)
|
|
9
|
+
proc.call
|
|
10
|
+
return false
|
|
11
|
+
rescue Exception => @actual
|
|
12
|
+
return false unless @exception === @actual
|
|
13
|
+
if @message then
|
|
14
|
+
case @message
|
|
15
|
+
when String then
|
|
16
|
+
return false if @message != @actual.message
|
|
17
|
+
when Regexp then
|
|
18
|
+
return false if @message !~ @actual.message
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
@block[@actual] if @block
|
|
23
|
+
|
|
24
|
+
return true
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def failure_message
|
|
28
|
+
message = ["Expected #{@exception}#{%[ (#{@message})] if @message}"]
|
|
29
|
+
|
|
30
|
+
if @actual then
|
|
31
|
+
message << "but got #{@actual.class}#{%[ (#{@actual.message})] if @actual.message}"
|
|
32
|
+
else
|
|
33
|
+
message << "but no exception was raised"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
message
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def negative_failure_message
|
|
40
|
+
["Expected to not get #{@exception}#{%[ (#{@message})] if @message}", ""]
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
class Object
|
|
45
|
+
def raise_error(exception=Exception, message=nil, &block)
|
|
46
|
+
RaiseErrorMatcher.new(exception, message, &block)
|
|
47
|
+
end
|
|
48
|
+
end
|
data/lib/mspec/mocks.rb
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
require 'mspec/expectations/expectations'
|
|
2
|
+
|
|
3
|
+
module Mock
|
|
4
|
+
def self.reset
|
|
5
|
+
@expects = nil
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def self.expects
|
|
9
|
+
@expects ||= Hash.new { |h,k| h[k] = [] }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.replaced_name(sym)
|
|
13
|
+
:"__ms_#{sym}__"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.install_method(obj, sym, type = :mock)
|
|
17
|
+
meta = class << obj; self; end
|
|
18
|
+
|
|
19
|
+
if (sym.to_sym == :respond_to? or obj.respond_to?(sym)) and !meta.instance_methods.include?(replaced_name(sym).to_s)
|
|
20
|
+
meta.__send__ :alias_method, replaced_name(sym), sym.to_sym
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
meta.class_eval <<-END
|
|
24
|
+
def #{sym}(*args, &block)
|
|
25
|
+
Mock.verify_call self, :#{sym}, *args, &block
|
|
26
|
+
end
|
|
27
|
+
END
|
|
28
|
+
|
|
29
|
+
MSpec.actions :expectation, MSpec.current.state
|
|
30
|
+
|
|
31
|
+
proxy = MockProxy.new
|
|
32
|
+
|
|
33
|
+
if type == :stub
|
|
34
|
+
expects[[obj, sym]] << proxy
|
|
35
|
+
proxy.at_least(0)
|
|
36
|
+
else
|
|
37
|
+
expects[[obj, sym]].unshift proxy
|
|
38
|
+
proxy.exactly(1)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.verify_count
|
|
43
|
+
expects.each do |key, proxies|
|
|
44
|
+
obj, sym = key.first, key.last
|
|
45
|
+
|
|
46
|
+
proxies.each do |proxy|
|
|
47
|
+
qualifier, count = proxy.count
|
|
48
|
+
pass = case qualifier
|
|
49
|
+
when :at_least
|
|
50
|
+
proxy.calls >= count
|
|
51
|
+
when :at_most
|
|
52
|
+
proxy.calls <= count
|
|
53
|
+
when :exactly
|
|
54
|
+
proxy.calls == count
|
|
55
|
+
else
|
|
56
|
+
false
|
|
57
|
+
end
|
|
58
|
+
unless pass
|
|
59
|
+
Expectation.fail_with("Mock #{obj.inspect}\nexpected to receive #{sym} #{qualifier.to_s.sub('_', ' ')} #{count} times",
|
|
60
|
+
"but received it #{proxy.calls} times")
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def self.verify_call(obj, sym, *args, &block)
|
|
67
|
+
compare = *args
|
|
68
|
+
|
|
69
|
+
expects[[obj, sym]].each do |proxy|
|
|
70
|
+
pass = case proxy.arguments
|
|
71
|
+
when :any_args
|
|
72
|
+
true
|
|
73
|
+
when :no_args
|
|
74
|
+
compare.nil?
|
|
75
|
+
else
|
|
76
|
+
proxy.arguments == compare
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
if proxy.yielding?
|
|
80
|
+
if block
|
|
81
|
+
proxy.yielding.each do |args_to_yield|
|
|
82
|
+
if block.arity == -1 || block.arity == args_to_yield.size
|
|
83
|
+
block.call(*args_to_yield)
|
|
84
|
+
else
|
|
85
|
+
Expectation.fail_with("Mock #{obj.inspect} asked to yield |#{proxy.yielding.join(', ')}| on #{sym}\n",
|
|
86
|
+
"but a block with arity #{block.arity} was passed")
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
else
|
|
90
|
+
Expectation.fail_with("Mock #{obj.inspect} asked to yield |[#{proxy.yielding.join('], [')}]| on #{sym}\n",
|
|
91
|
+
"but no block was passed")
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
if pass
|
|
96
|
+
proxy.called
|
|
97
|
+
return proxy.returning
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
if sym.to_sym == :respond_to?
|
|
102
|
+
return obj.__send__(replaced_name(sym), compare)
|
|
103
|
+
else
|
|
104
|
+
Expectation.fail_with("Mock #{obj.inspect}: method #{sym}\n",
|
|
105
|
+
"called with unexpected arguments (#{Array(compare).join(' ')})")
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def self.cleanup
|
|
110
|
+
expects.keys.each do |obj, sym|
|
|
111
|
+
meta = class << obj; self; end
|
|
112
|
+
|
|
113
|
+
replaced = replaced_name(sym)
|
|
114
|
+
if meta.instance_methods.include?(replaced.to_s)
|
|
115
|
+
meta.__send__ :alias_method, sym.to_sym, replaced
|
|
116
|
+
meta.__send__ :remove_method, replaced
|
|
117
|
+
else
|
|
118
|
+
meta.__send__ :remove_method, sym.to_sym
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
reset
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'mspec/mocks/proxy'
|
|
2
|
+
|
|
3
|
+
class MockObject
|
|
4
|
+
def initialize(name)
|
|
5
|
+
@name = name
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class Object
|
|
10
|
+
def stub!(sym)
|
|
11
|
+
Mock.install_method self, sym, :stub
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def should_receive(sym)
|
|
15
|
+
Mock.install_method self, sym
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def should_not_receive(sym)
|
|
19
|
+
proxy = Mock.install_method self, sym
|
|
20
|
+
proxy.exactly(0).times
|
|
21
|
+
# return nil so that further chained calls will raise
|
|
22
|
+
nil
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def mock(name)
|
|
26
|
+
MockObject.new(name)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
class MockProxy
|
|
2
|
+
def initialize
|
|
3
|
+
@multiple_returns = nil
|
|
4
|
+
@returning = nil
|
|
5
|
+
@yielding = []
|
|
6
|
+
@arguments = :any_args
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def count
|
|
10
|
+
@count ||= [:exactly, 0]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def arguments
|
|
14
|
+
@arguments
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def returning
|
|
18
|
+
if @multiple_returns
|
|
19
|
+
if @returning.size == 1
|
|
20
|
+
@multiple_returns = false
|
|
21
|
+
return @returning = @returning.shift
|
|
22
|
+
end
|
|
23
|
+
return @returning.shift
|
|
24
|
+
end
|
|
25
|
+
@returning
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def times
|
|
29
|
+
self
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def calls
|
|
33
|
+
@calls ||= 0
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def called
|
|
37
|
+
@calls = calls + 1
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def exactly(n)
|
|
41
|
+
@count = [:exactly, n_times(n)]
|
|
42
|
+
self
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def at_least(n)
|
|
46
|
+
@count = [:at_least, n_times(n)]
|
|
47
|
+
self
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def at_most(n)
|
|
51
|
+
@count = [:at_most, n_times(n)]
|
|
52
|
+
self
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def once
|
|
56
|
+
exactly 1
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def twice
|
|
60
|
+
exactly 2
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def any_number_of_times
|
|
64
|
+
at_least 0
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def with(*args)
|
|
68
|
+
raise ArgumentError, "you must specify the expected arguments" if args.empty?
|
|
69
|
+
@arguments = *args
|
|
70
|
+
self
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def and_return(*args)
|
|
74
|
+
case args.size
|
|
75
|
+
when 0
|
|
76
|
+
@returning = nil
|
|
77
|
+
when 1
|
|
78
|
+
@returning = args[0]
|
|
79
|
+
else
|
|
80
|
+
@multiple_returns = true
|
|
81
|
+
@returning = args
|
|
82
|
+
count[1] = args.size if count[1] < args.size
|
|
83
|
+
end
|
|
84
|
+
self
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def and_yield(*args)
|
|
88
|
+
@yielding << args
|
|
89
|
+
self
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def yielding
|
|
93
|
+
@yielding
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def yielding?
|
|
97
|
+
!@yielding.empty?
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
private
|
|
101
|
+
|
|
102
|
+
def n_times(n)
|
|
103
|
+
case n
|
|
104
|
+
when :once
|
|
105
|
+
1
|
|
106
|
+
when :twice
|
|
107
|
+
2
|
|
108
|
+
else
|
|
109
|
+
Integer n
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
data/lib/mspec/runner.rb
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'mspec/mocks'
|
|
2
|
+
require 'mspec/runner/mspec'
|
|
3
|
+
require 'mspec/runner/object'
|
|
4
|
+
require 'mspec/runner/formatters'
|
|
5
|
+
require 'mspec/runner/actions'
|
|
6
|
+
require 'mspec/runner/filters'
|
|
7
|
+
require 'mspec/runner/shared'
|
|
8
|
+
require 'mspec/runner/tag'
|
|
9
|
+
|
|
10
|
+
def $stderr.write(str)
|
|
11
|
+
# The 'useless use of' warnings are a crime against OO.
|
|
12
|
+
str =~ /useless use of/ ? nil : super
|
|
13
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require 'mspec/runner/actions/filter'
|
|
2
|
+
|
|
3
|
+
class DebugAction < ActionFilter
|
|
4
|
+
def before(state)
|
|
5
|
+
Kernel.debugger if self === state.description
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def register
|
|
9
|
+
super
|
|
10
|
+
MSpec.register :before, self
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def unregister
|
|
14
|
+
super
|
|
15
|
+
MSpec.unregister :before, self
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require 'mspec/runner/filters/match'
|
|
2
|
+
|
|
3
|
+
# ActionFilter is a base class for actions that are triggered by
|
|
4
|
+
# specs that match the filter. The filter may be specified by
|
|
5
|
+
# strings that match spec descriptions or by tags for strings
|
|
6
|
+
# that match spec descriptions.
|
|
7
|
+
#
|
|
8
|
+
# Unlike TagFilter and RegexpFilter, ActionFilter instances do
|
|
9
|
+
# not affect the specs that are run. The filter is only used to
|
|
10
|
+
# trigger the action.
|
|
11
|
+
|
|
12
|
+
class ActionFilter
|
|
13
|
+
def initialize(tags=nil, descs=nil)
|
|
14
|
+
@tags = Array(tags)
|
|
15
|
+
descs = Array(descs)
|
|
16
|
+
@sfilter = MatchFilter.new(nil, *descs) unless descs.empty?
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def ===(string)
|
|
20
|
+
@sfilter === string or @tfilter === string
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def load
|
|
24
|
+
@tfilter = nil
|
|
25
|
+
return if @tags.empty?
|
|
26
|
+
|
|
27
|
+
desc = MSpec.read_tags(*@tags).map { |t| t.description }
|
|
28
|
+
return if desc.empty?
|
|
29
|
+
|
|
30
|
+
@tfilter = MatchFilter.new(nil, *desc)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def register
|
|
34
|
+
MSpec.register :load, self
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def unregister
|
|
38
|
+
MSpec.unregister :load, self
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require 'mspec/runner/actions/filter'
|
|
2
|
+
|
|
3
|
+
class GdbAction < ActionFilter
|
|
4
|
+
def before(state)
|
|
5
|
+
Kernel.yield_gdb(true) if self === state.description
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def register
|
|
9
|
+
super
|
|
10
|
+
MSpec.register :before, self
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def unregister
|
|
14
|
+
super
|
|
15
|
+
MSpec.unregister :before, self
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
require 'mspec/runner/actions/filter'
|
|
2
|
+
|
|
3
|
+
# TagAction - Write tagged spec description string to a
|
|
4
|
+
# tag file associated with each spec file.
|
|
5
|
+
#
|
|
6
|
+
# The action is triggered by specs whose descriptions
|
|
7
|
+
# match the filter created with 'tags' and/or 'desc'
|
|
8
|
+
#
|
|
9
|
+
# The action fires in the :after event, after the spec
|
|
10
|
+
# had been run. The action fires if the outcome of
|
|
11
|
+
# running the spec matches 'outcome'.
|
|
12
|
+
#
|
|
13
|
+
# The arguments are:
|
|
14
|
+
#
|
|
15
|
+
# action: :add, :del
|
|
16
|
+
# outcome: :pass, :fail, :all
|
|
17
|
+
# tag: the tag to create/delete
|
|
18
|
+
# comment: the comment to create
|
|
19
|
+
# tags: zero or more tags to get matching
|
|
20
|
+
# spec description strings from
|
|
21
|
+
# desc: zero or more strings to match the
|
|
22
|
+
# spec description strings
|
|
23
|
+
|
|
24
|
+
class TagAction < ActionFilter
|
|
25
|
+
def initialize(action, outcome, tag, comment, tags=nil, descs=nil)
|
|
26
|
+
super tags, descs
|
|
27
|
+
@action = action
|
|
28
|
+
@outcome = outcome
|
|
29
|
+
@tag = tag
|
|
30
|
+
@comment = comment
|
|
31
|
+
@report = []
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def ===(string)
|
|
35
|
+
return true unless @sfilter or @tfilter
|
|
36
|
+
@sfilter === string or @tfilter === string
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def after(state)
|
|
40
|
+
if self === state.description and outcome? state
|
|
41
|
+
tag = SpecTag.new
|
|
42
|
+
tag.tag = @tag
|
|
43
|
+
tag.comment = @comment
|
|
44
|
+
tag.description = state.description
|
|
45
|
+
|
|
46
|
+
case @action
|
|
47
|
+
when :add
|
|
48
|
+
changed = MSpec.write_tag tag
|
|
49
|
+
when :del
|
|
50
|
+
changed = MSpec.delete_tag tag
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
@report << state.description if changed
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def outcome?(state)
|
|
58
|
+
@outcome == :all or
|
|
59
|
+
(@outcome == :pass and not state.exception?) or
|
|
60
|
+
(@outcome == :fail and state.exception?)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def report
|
|
64
|
+
@report.join("\n") + "\n"
|
|
65
|
+
end
|
|
66
|
+
private :report
|
|
67
|
+
|
|
68
|
+
def finish
|
|
69
|
+
case @action
|
|
70
|
+
when :add
|
|
71
|
+
if @report.empty?
|
|
72
|
+
print "\nTagAction: no specs were tagged with '#{@tag}'\n"
|
|
73
|
+
else
|
|
74
|
+
print "\nTagAction: specs tagged with '#{@tag}':\n\n"
|
|
75
|
+
print report
|
|
76
|
+
end
|
|
77
|
+
when :del
|
|
78
|
+
if @report.empty?
|
|
79
|
+
print "\nTagAction: no tags '#{@tag}' were deleted\n"
|
|
80
|
+
else
|
|
81
|
+
print "\nTagAction: tag '#{@tag}' deleted for specs:\n\n"
|
|
82
|
+
print report
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def register
|
|
88
|
+
super
|
|
89
|
+
MSpec.register :after, self
|
|
90
|
+
MSpec.register :finish, self
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def unregister
|
|
94
|
+
super
|
|
95
|
+
MSpec.unregister :after, self
|
|
96
|
+
end
|
|
97
|
+
end
|