mspec 1.5.11 → 1.5.12
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/lib/mspec/commands/mspec-ci.rb +1 -0
- data/lib/mspec/commands/mspec-run.rb +1 -0
- data/lib/mspec/commands/mspec-tag.rb +1 -0
- data/lib/mspec/helpers.rb +4 -0
- data/lib/mspec/helpers/ducktype.rb +33 -0
- data/lib/mspec/helpers/enumerator_class.rb +9 -0
- data/lib/mspec/helpers/environment.rb +10 -1
- data/lib/mspec/helpers/hash.rb +27 -0
- data/lib/mspec/helpers/io.rb +4 -0
- data/lib/mspec/helpers/metaclass.rb +7 -0
- data/lib/mspec/matchers.rb +5 -0
- data/lib/mspec/matchers/have_class_variable.rb +12 -0
- data/lib/mspec/matchers/have_constant.rb +6 -24
- data/lib/mspec/matchers/have_instance_variable.rb +12 -0
- data/lib/mspec/matchers/have_protected_instance_method.rb +24 -0
- data/lib/mspec/matchers/have_public_instance_method.rb +24 -0
- data/lib/mspec/matchers/stringsymboladapter.rb +1 -1
- data/lib/mspec/matchers/variable.rb +28 -0
- data/lib/mspec/mocks/mock.rb +70 -47
- data/lib/mspec/mocks/object.rb +4 -0
- data/lib/mspec/mocks/proxy.rb +17 -3
- data/lib/mspec/runner.rb +1 -0
- data/lib/mspec/runner/exception.rb +4 -3
- data/lib/mspec/utils/options.rb +10 -2
- data/lib/mspec/version.rb +1 -1
- data/spec/commands/mkspec_spec.rb +1 -1
- data/spec/commands/mspec_ci_spec.rb +5 -0
- data/spec/commands/mspec_run_spec.rb +5 -0
- data/spec/commands/mspec_spec.rb +2 -2
- data/spec/commands/mspec_tag_spec.rb +5 -0
- data/spec/expectations/should.rb +1 -0
- data/spec/helpers/ducktype_spec.rb +44 -0
- data/spec/helpers/enumerator_class_spec.rb +19 -0
- data/spec/helpers/hash_spec.rb +30 -0
- data/spec/helpers/io_spec.rb +5 -0
- data/spec/matchers/have_class_variable_spec.rb +75 -0
- data/spec/matchers/have_instance_variable_spec.rb +75 -0
- data/spec/matchers/have_protected_instance_method_spec.rb +57 -0
- data/spec/matchers/have_public_instance_method_spec.rb +53 -0
- data/spec/matchers/stringsymboladapter_spec.rb +8 -10
- data/spec/mocks/mock_spec.rb +5 -5
- data/spec/runner/exception_spec.rb +17 -10
- data/spec/utils/options_spec.rb +26 -0
- metadata +18 -2
data/Rakefile
CHANGED
@@ -18,7 +18,7 @@ spec = Gem::Specification.new do |s|
|
|
18
18
|
|
19
19
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
20
20
|
s.authors = ["Brian Ford"]
|
21
|
-
s.date = %q{2009-
|
21
|
+
s.date = %q{2009-6-8}
|
22
22
|
s.email = %q{bford@engineyard.com}
|
23
23
|
s.has_rdoc = true
|
24
24
|
s.extra_rdoc_files = %w[ README LICENSE ]
|
data/lib/mspec/helpers.rb
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
require 'mspec/helpers/argv'
|
2
2
|
require 'mspec/helpers/bignum'
|
3
3
|
require 'mspec/helpers/const_lookup'
|
4
|
+
require 'mspec/helpers/ducktype'
|
5
|
+
require 'mspec/helpers/enumerator_class'
|
4
6
|
require 'mspec/helpers/environment'
|
5
7
|
require 'mspec/helpers/fixture'
|
6
8
|
require 'mspec/helpers/flunk'
|
9
|
+
require 'mspec/helpers/hash'
|
7
10
|
require 'mspec/helpers/io'
|
8
11
|
require 'mspec/helpers/language_version'
|
12
|
+
require 'mspec/helpers/metaclass'
|
9
13
|
require 'mspec/helpers/ruby_exe'
|
10
14
|
require 'mspec/helpers/scratch'
|
11
15
|
require 'mspec/helpers/tmp'
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class Object
|
2
|
+
def responds_to(sym)
|
3
|
+
metaclass.class_eval <<-END
|
4
|
+
def respond_to?(sym, include_private=false)
|
5
|
+
sym.to_sym == #{sym.to_sym.inspect} ? true : super
|
6
|
+
end
|
7
|
+
END
|
8
|
+
end
|
9
|
+
|
10
|
+
def does_not_respond_to(sym)
|
11
|
+
metaclass.class_eval <<-END
|
12
|
+
def respond_to?(sym, include_private=false)
|
13
|
+
sym.to_sym == #{sym.to_sym.inspect} ? false : super
|
14
|
+
end
|
15
|
+
END
|
16
|
+
end
|
17
|
+
|
18
|
+
def undefine(sym)
|
19
|
+
metaclass.class_eval <<-END
|
20
|
+
undef_method #{sym.to_sym.inspect}
|
21
|
+
END
|
22
|
+
end
|
23
|
+
|
24
|
+
def fake!(sym, value=nil)
|
25
|
+
responds_to sym
|
26
|
+
|
27
|
+
metaclass.class_eval <<-END
|
28
|
+
def method_missing(sym, *args)
|
29
|
+
return #{value.inspect} if sym.to_sym == #{sym.to_sym.inspect}
|
30
|
+
end
|
31
|
+
END
|
32
|
+
end
|
33
|
+
end
|
@@ -11,13 +11,22 @@ class Object
|
|
11
11
|
env
|
12
12
|
end
|
13
13
|
|
14
|
+
def windows_env_echo(var)
|
15
|
+
`cmd.exe /C ECHO %#{var}%`.strip
|
16
|
+
end
|
17
|
+
|
14
18
|
def username
|
15
19
|
user = ""
|
16
20
|
if SpecGuard.windows?
|
17
|
-
user =
|
21
|
+
user = windows_env_echo('USERNAME')
|
18
22
|
else
|
19
23
|
user = `whoami`.strip
|
20
24
|
end
|
21
25
|
user
|
22
26
|
end
|
27
|
+
|
28
|
+
def home_directory
|
29
|
+
return ENV['HOME'] unless SpecGuard.windows?
|
30
|
+
windows_env_echo('HOMEDRIVE') + windows_env_echo('HOMEPATH')
|
31
|
+
end
|
23
32
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class Object
|
2
|
+
# The following helpers provide a level of indirection for running the specs
|
3
|
+
# against a Hash implementation that has a different name than Hash.
|
4
|
+
|
5
|
+
# Returns the Hash class.
|
6
|
+
unless method_defined?(:hash_class)
|
7
|
+
def hash_class
|
8
|
+
Hash
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Returns a new instance of hash_class.
|
13
|
+
def new_hash(*args, &block)
|
14
|
+
if block
|
15
|
+
hash_class.new(&block)
|
16
|
+
elsif args.size == 1
|
17
|
+
value = args.first
|
18
|
+
if value.is_a?(Hash) or value.is_a?(hash_class)
|
19
|
+
hash_class[value]
|
20
|
+
else
|
21
|
+
hash_class.new value
|
22
|
+
end
|
23
|
+
else
|
24
|
+
hash_class[*args]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/mspec/helpers/io.rb
CHANGED
data/lib/mspec/matchers.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'mspec/matchers/base'
|
2
|
+
require 'mspec/matchers/be_an_instance_of'
|
2
3
|
require 'mspec/matchers/be_ancestor_of'
|
3
4
|
require 'mspec/matchers/be_close'
|
4
5
|
require 'mspec/matchers/be_empty'
|
@@ -12,9 +13,13 @@ require 'mspec/matchers/equal'
|
|
12
13
|
require 'mspec/matchers/equal_element'
|
13
14
|
require 'mspec/matchers/equal_utf16'
|
14
15
|
require 'mspec/matchers/have_constant'
|
16
|
+
require 'mspec/matchers/have_class_variable'
|
15
17
|
require 'mspec/matchers/have_instance_method'
|
18
|
+
require 'mspec/matchers/have_instance_variable'
|
16
19
|
require 'mspec/matchers/have_method'
|
17
20
|
require 'mspec/matchers/have_private_instance_method'
|
21
|
+
require 'mspec/matchers/have_protected_instance_method'
|
22
|
+
require 'mspec/matchers/have_public_instance_method'
|
18
23
|
require 'mspec/matchers/include'
|
19
24
|
require 'mspec/matchers/match_yaml'
|
20
25
|
require 'mspec/matchers/raise_error'
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'mspec/matchers/variable'
|
2
|
+
|
3
|
+
class HaveClassVariableMatcher < VariableMatcher
|
4
|
+
self.variables_method = :class_variables
|
5
|
+
self.description = 'class variable'
|
6
|
+
end
|
7
|
+
|
8
|
+
class Object
|
9
|
+
def have_class_variable(variable)
|
10
|
+
HaveClassVariableMatcher.new(variable)
|
11
|
+
end
|
12
|
+
end
|
@@ -1,30 +1,12 @@
|
|
1
|
-
require 'mspec/matchers/
|
1
|
+
require 'mspec/matchers/variable'
|
2
2
|
|
3
|
-
class HaveConstantMatcher
|
4
|
-
|
5
|
-
|
6
|
-
def initialize(name)
|
7
|
-
@name = convert_name name
|
8
|
-
end
|
9
|
-
|
10
|
-
def matches?(mod)
|
11
|
-
@mod = mod
|
12
|
-
@mod.constants.include? @name
|
13
|
-
end
|
14
|
-
|
15
|
-
def failure_message
|
16
|
-
["Expected #{@mod} to have constant '#{@name.to_s}'",
|
17
|
-
"but it does not"]
|
18
|
-
end
|
19
|
-
|
20
|
-
def negative_failure_message
|
21
|
-
["Expected #{@mod} NOT to have constant '#{@name.to_s}'",
|
22
|
-
"but it does"]
|
23
|
-
end
|
3
|
+
class HaveConstantMatcher < VariableMatcher
|
4
|
+
self.variables_method = :constants
|
5
|
+
self.description = 'constant'
|
24
6
|
end
|
25
7
|
|
26
8
|
class Object
|
27
|
-
def have_constant(
|
28
|
-
HaveConstantMatcher.new
|
9
|
+
def have_constant(variable)
|
10
|
+
HaveConstantMatcher.new(variable)
|
29
11
|
end
|
30
12
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'mspec/matchers/variable'
|
2
|
+
|
3
|
+
class HaveInstanceVariableMatcher < VariableMatcher
|
4
|
+
self.variables_method = :instance_variables
|
5
|
+
self.description = 'instance variable'
|
6
|
+
end
|
7
|
+
|
8
|
+
class Object
|
9
|
+
def have_instance_variable(variable)
|
10
|
+
HaveInstanceVariableMatcher.new(variable)
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'mspec/matchers/method'
|
2
|
+
|
3
|
+
class HaveProtectedInstanceMethodMatcher < MethodMatcher
|
4
|
+
def matches?(mod)
|
5
|
+
@mod = mod
|
6
|
+
mod.protected_instance_methods(@include_super).include? @method
|
7
|
+
end
|
8
|
+
|
9
|
+
def failure_message
|
10
|
+
["Expected #{@mod} to have protected instance method '#{@method.to_s}'",
|
11
|
+
"but it does not"]
|
12
|
+
end
|
13
|
+
|
14
|
+
def negative_failure_message
|
15
|
+
["Expected #{@mod} NOT to have protected instance method '#{@method.to_s}'",
|
16
|
+
"but it does"]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Object
|
21
|
+
def have_protected_instance_method(method, include_super=true)
|
22
|
+
HaveProtectedInstanceMethodMatcher.new method, include_super
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'mspec/matchers/method'
|
2
|
+
|
3
|
+
class HavePublicInstanceMethodMatcher < MethodMatcher
|
4
|
+
def matches?(mod)
|
5
|
+
@mod = mod
|
6
|
+
mod.public_instance_methods(@include_super).include? @method
|
7
|
+
end
|
8
|
+
|
9
|
+
def failure_message
|
10
|
+
["Expected #{@mod} to have public instance method '#{@method.to_s}'",
|
11
|
+
"but it does not"]
|
12
|
+
end
|
13
|
+
|
14
|
+
def negative_failure_message
|
15
|
+
["Expected #{@mod} NOT to have public instance method '#{@method.to_s}'",
|
16
|
+
"but it does"]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Object
|
21
|
+
def have_public_instance_method(method, include_super=true)
|
22
|
+
HavePublicInstanceMethodMatcher.new method, include_super
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'mspec/matchers/stringsymboladapter'
|
2
|
+
|
3
|
+
class VariableMatcher
|
4
|
+
include StringSymbolAdapter
|
5
|
+
|
6
|
+
class << self
|
7
|
+
attr_accessor :variables_method, :description
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(variable)
|
11
|
+
@variable = convert_name(variable)
|
12
|
+
end
|
13
|
+
|
14
|
+
def matches?(object)
|
15
|
+
@object = object
|
16
|
+
@object.send(self.class.variables_method).include? @variable
|
17
|
+
end
|
18
|
+
|
19
|
+
def failure_message
|
20
|
+
["Expected #{@object} to have #{self.class.description} '#{@variable}'",
|
21
|
+
"but it does not"]
|
22
|
+
end
|
23
|
+
|
24
|
+
def negative_failure_message
|
25
|
+
["Expected #{@object} NOT to have #{self.class.description} '#{@variable}'",
|
26
|
+
"but it does"]
|
27
|
+
end
|
28
|
+
end
|
data/lib/mspec/mocks/mock.rb
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
require 'mspec/expectations/expectations'
|
2
|
+
require 'mspec/helpers/metaclass'
|
2
3
|
|
3
4
|
module Mock
|
4
5
|
def self.reset
|
5
|
-
@mocks = @stubs = nil
|
6
|
+
@mocks = @stubs = @objects = nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.objects
|
10
|
+
@objects ||= {}
|
6
11
|
end
|
7
12
|
|
8
13
|
def self.mocks
|
@@ -14,23 +19,38 @@ module Mock
|
|
14
19
|
end
|
15
20
|
|
16
21
|
def self.replaced_name(obj, sym)
|
17
|
-
:"
|
22
|
+
:"__mspec_#{obj.__id__}_#{sym}__"
|
18
23
|
end
|
19
24
|
|
20
25
|
def self.replaced_key(obj, sym)
|
21
|
-
[replaced_name(obj, sym),
|
26
|
+
[replaced_name(obj, sym), sym]
|
22
27
|
end
|
23
28
|
|
24
|
-
def self.
|
25
|
-
!!
|
29
|
+
def self.has_key?(keys, sym)
|
30
|
+
!!keys.find { |k| k.first == sym }
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.replaced?(sym)
|
34
|
+
has_key?(mocks.keys, sym) or has_key?(stubs.keys, sym)
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.mock_respond_to?(obj, sym)
|
38
|
+
name = replaced_name(obj, :respond_to?)
|
39
|
+
if replaced? name
|
40
|
+
obj.__send__ name, sym
|
41
|
+
else
|
42
|
+
obj.respond_to? sym
|
43
|
+
end
|
26
44
|
end
|
27
45
|
|
28
46
|
def self.install_method(obj, sym, type=nil)
|
29
|
-
meta =
|
47
|
+
meta = obj.metaclass
|
30
48
|
|
31
49
|
key = replaced_key obj, sym
|
32
|
-
|
33
|
-
|
50
|
+
sym = sym.to_sym
|
51
|
+
|
52
|
+
if (sym == :respond_to? or mock_respond_to?(obj, sym)) and !replaced?(key.first)
|
53
|
+
meta.__send__ :alias_method, key.first, sym
|
34
54
|
end
|
35
55
|
|
36
56
|
meta.class_eval <<-END
|
@@ -51,6 +71,7 @@ module Mock
|
|
51
71
|
else
|
52
72
|
mocks[key] << proxy
|
53
73
|
end
|
74
|
+
objects[key] = obj
|
54
75
|
|
55
76
|
proxy
|
56
77
|
end
|
@@ -61,7 +82,7 @@ module Mock
|
|
61
82
|
|
62
83
|
def self.verify_count
|
63
84
|
mocks.each do |key, proxies|
|
64
|
-
|
85
|
+
obj = objects[key]
|
65
86
|
proxies.each do |proxy|
|
66
87
|
qualifier, count = proxy.count
|
67
88
|
pass = case qualifier
|
@@ -78,7 +99,7 @@ module Mock
|
|
78
99
|
end
|
79
100
|
unless pass
|
80
101
|
SpecExpectation.fail_with(
|
81
|
-
"Mock '#{name_or_inspect obj}' expected to receive '#{
|
102
|
+
"Mock '#{name_or_inspect obj}' expected to receive '#{key.last}' " \
|
82
103
|
"#{qualifier.to_s.sub('_', ' ')} #{count} times",
|
83
104
|
"but received it #{proxy.calls} times")
|
84
105
|
end
|
@@ -88,50 +109,51 @@ module Mock
|
|
88
109
|
|
89
110
|
def self.verify_call(obj, sym, *args, &block)
|
90
111
|
compare = *args
|
91
|
-
if
|
112
|
+
if (behaves_like_ruby_1_9 = *[])
|
92
113
|
compare = compare.first if compare.length <= 1
|
93
114
|
end
|
94
115
|
|
95
116
|
key = replaced_key obj, sym
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
117
|
+
[mocks, stubs].each do |proxies|
|
118
|
+
proxies[key].each do |proxy|
|
119
|
+
pass = case proxy.arguments
|
120
|
+
when :any_args
|
121
|
+
true
|
122
|
+
when :no_args
|
123
|
+
compare.nil?
|
124
|
+
else
|
125
|
+
proxy.arguments == compare
|
126
|
+
end
|
106
127
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
128
|
+
if proxy.yielding?
|
129
|
+
if block
|
130
|
+
proxy.yielding.each do |args_to_yield|
|
131
|
+
if block.arity == -1 || block.arity == args_to_yield.size
|
132
|
+
block.call(*args_to_yield)
|
133
|
+
else
|
134
|
+
SpecExpectation.fail_with(
|
135
|
+
"Mock '#{name_or_inspect obj}' asked to yield " \
|
136
|
+
"|#{proxy.yielding.join(', ')}| on #{sym}\n",
|
137
|
+
"but a block with arity #{block.arity} was passed")
|
138
|
+
end
|
117
139
|
end
|
140
|
+
else
|
141
|
+
SpecExpectation.fail_with(
|
142
|
+
"Mock '#{name_or_inspect obj}' asked to yield " \
|
143
|
+
"|[#{proxy.yielding.join('], [')}]| on #{sym}\n",
|
144
|
+
"but no block was passed")
|
118
145
|
end
|
119
|
-
else
|
120
|
-
SpecExpectation.fail_with(
|
121
|
-
"Mock '#{name_or_inspect obj}' asked to yield " \
|
122
|
-
"|[#{proxy.yielding.join('], [')}]| on #{sym}\n",
|
123
|
-
"but no block was passed")
|
124
146
|
end
|
125
|
-
end
|
126
147
|
|
127
|
-
|
128
|
-
|
129
|
-
|
148
|
+
if pass
|
149
|
+
proxy.called
|
150
|
+
return proxy.returning
|
151
|
+
end
|
130
152
|
end
|
131
153
|
end
|
132
154
|
|
133
155
|
if sym.to_sym == :respond_to?
|
134
|
-
|
156
|
+
mock_respond_to? obj, compare
|
135
157
|
else
|
136
158
|
SpecExpectation.fail_with("Mock '#{name_or_inspect obj}': method #{sym}\n",
|
137
159
|
"called with unexpected arguments (#{Array(compare).join(' ')})")
|
@@ -139,15 +161,16 @@ module Mock
|
|
139
161
|
end
|
140
162
|
|
141
163
|
def self.cleanup
|
142
|
-
|
143
|
-
|
144
|
-
|
164
|
+
objects.each do |key, obj|
|
165
|
+
replaced = key.first
|
166
|
+
sym = key.last
|
167
|
+
meta = obj.metaclass
|
145
168
|
|
146
|
-
if meta.instance_methods.map { |x| x.to_sym }.include?(replaced
|
147
|
-
meta.__send__ :alias_method, sym
|
169
|
+
if meta.instance_methods.map { |x| x.to_sym }.include?(replaced)
|
170
|
+
meta.__send__ :alias_method, sym, replaced
|
148
171
|
meta.__send__ :remove_method, replaced
|
149
172
|
else
|
150
|
-
meta.__send__ :remove_method, sym
|
173
|
+
meta.__send__ :remove_method, sym
|
151
174
|
end
|
152
175
|
end
|
153
176
|
reset
|