mspec 1.5.11 → 1.5.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/Rakefile +1 -1
  2. data/lib/mspec/commands/mspec-ci.rb +1 -0
  3. data/lib/mspec/commands/mspec-run.rb +1 -0
  4. data/lib/mspec/commands/mspec-tag.rb +1 -0
  5. data/lib/mspec/helpers.rb +4 -0
  6. data/lib/mspec/helpers/ducktype.rb +33 -0
  7. data/lib/mspec/helpers/enumerator_class.rb +9 -0
  8. data/lib/mspec/helpers/environment.rb +10 -1
  9. data/lib/mspec/helpers/hash.rb +27 -0
  10. data/lib/mspec/helpers/io.rb +4 -0
  11. data/lib/mspec/helpers/metaclass.rb +7 -0
  12. data/lib/mspec/matchers.rb +5 -0
  13. data/lib/mspec/matchers/have_class_variable.rb +12 -0
  14. data/lib/mspec/matchers/have_constant.rb +6 -24
  15. data/lib/mspec/matchers/have_instance_variable.rb +12 -0
  16. data/lib/mspec/matchers/have_protected_instance_method.rb +24 -0
  17. data/lib/mspec/matchers/have_public_instance_method.rb +24 -0
  18. data/lib/mspec/matchers/stringsymboladapter.rb +1 -1
  19. data/lib/mspec/matchers/variable.rb +28 -0
  20. data/lib/mspec/mocks/mock.rb +70 -47
  21. data/lib/mspec/mocks/object.rb +4 -0
  22. data/lib/mspec/mocks/proxy.rb +17 -3
  23. data/lib/mspec/runner.rb +1 -0
  24. data/lib/mspec/runner/exception.rb +4 -3
  25. data/lib/mspec/utils/options.rb +10 -2
  26. data/lib/mspec/version.rb +1 -1
  27. data/spec/commands/mkspec_spec.rb +1 -1
  28. data/spec/commands/mspec_ci_spec.rb +5 -0
  29. data/spec/commands/mspec_run_spec.rb +5 -0
  30. data/spec/commands/mspec_spec.rb +2 -2
  31. data/spec/commands/mspec_tag_spec.rb +5 -0
  32. data/spec/expectations/should.rb +1 -0
  33. data/spec/helpers/ducktype_spec.rb +44 -0
  34. data/spec/helpers/enumerator_class_spec.rb +19 -0
  35. data/spec/helpers/hash_spec.rb +30 -0
  36. data/spec/helpers/io_spec.rb +5 -0
  37. data/spec/matchers/have_class_variable_spec.rb +75 -0
  38. data/spec/matchers/have_instance_variable_spec.rb +75 -0
  39. data/spec/matchers/have_protected_instance_method_spec.rb +57 -0
  40. data/spec/matchers/have_public_instance_method_spec.rb +53 -0
  41. data/spec/matchers/stringsymboladapter_spec.rb +8 -10
  42. data/spec/mocks/mock_spec.rb +5 -5
  43. data/spec/runner/exception_spec.rb +17 -10
  44. data/spec/utils/options_spec.rb +26 -0
  45. 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-3-30}
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 ]
@@ -42,6 +42,7 @@ class MSpecCI < MSpecScript
42
42
  options.action_filters
43
43
 
44
44
  options.doc "\n Help!"
45
+ options.debug
45
46
  options.version MSpec::VERSION
46
47
  options.help
47
48
 
@@ -53,6 +53,7 @@ class MSpecRun < MSpecScript
53
53
  options.action_filters
54
54
 
55
55
  options.doc "\n Help!"
56
+ options.debug
56
57
  options.version MSpec::VERSION
57
58
  options.help
58
59
 
@@ -72,6 +72,7 @@ class MSpecTag < MSpecScript
72
72
  end
73
73
 
74
74
  options.doc "\n Help!"
75
+ options.debug
75
76
  options.version MSpec::VERSION
76
77
  options.help
77
78
 
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
@@ -0,0 +1,9 @@
1
+ class Object
2
+
3
+ # Returns the Enumerator class (either Enumerator or Enumerable::Enumerator)
4
+ # depending of the version.
5
+ #
6
+ def enumerator_class
7
+ SpecVersion.new(RUBY_VERSION) < "1.9" ? Enumerable::Enumerator : Enumerator
8
+ end
9
+ 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 = `cmd.exe /C ECHO %USERNAME%`.strip
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
@@ -11,6 +11,10 @@ class IOStub < String
11
11
  write(str.collect { |s| s.to_s.chomp }.concat([nil]).join("\n"))
12
12
  end
13
13
 
14
+ def printf(format, *args)
15
+ self << sprintf(format, *args)
16
+ end
17
+
14
18
  def flush
15
19
  self
16
20
  end
@@ -0,0 +1,7 @@
1
+ class Object
2
+ unless method_defined? :metaclass
3
+ def metaclass
4
+ class << self; self; end
5
+ end
6
+ end
7
+ end
@@ -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/stringsymboladapter'
1
+ require 'mspec/matchers/variable'
2
2
 
3
- class HaveConstantMatcher
4
- include StringSymbolAdapter
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(name)
28
- HaveConstantMatcher.new name
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
@@ -3,6 +3,6 @@ require 'mspec/utils/version'
3
3
  module StringSymbolAdapter
4
4
  def convert_name(name)
5
5
  version = SpecVersion.new(RUBY_VERSION) <=> "1.9"
6
- version < 0 ? name.to_s : name
6
+ version < 0 ? name.to_s : name.to_sym
7
7
  end
8
8
  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
@@ -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
- :"__ms_#{obj.__id__}_#{sym}__"
22
+ :"__mspec_#{obj.__id__}_#{sym}__"
18
23
  end
19
24
 
20
25
  def self.replaced_key(obj, sym)
21
- [replaced_name(obj, sym), obj, sym]
26
+ [replaced_name(obj, sym), sym]
22
27
  end
23
28
 
24
- def self.replaced?(key)
25
- !!(mocks.keys + stubs.keys).find { |k| k.first == key.first }
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 = class << obj; self; end
47
+ meta = obj.metaclass
30
48
 
31
49
  key = replaced_key obj, sym
32
- if (sym.to_sym == :respond_to? or obj.respond_to?(sym)) and !replaced?(key)
33
- meta.__send__ :alias_method, key.first, sym.to_sym
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
- replaced, obj, sym = *key
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 '#{sym}' " \
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 RUBY_VERSION >= '1.9'
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
- proxies = mocks[key] + stubs[key]
97
- proxies.each do |proxy|
98
- pass = case proxy.arguments
99
- when :any_args
100
- true
101
- when :no_args
102
- compare.nil?
103
- else
104
- proxy.arguments == compare
105
- end
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
- if proxy.yielding?
108
- if block
109
- proxy.yielding.each do |args_to_yield|
110
- if block.arity == -1 || block.arity == args_to_yield.size
111
- block.call(*args_to_yield)
112
- else
113
- SpecExpectation.fail_with(
114
- "Mock '#{name_or_inspect obj}' asked to yield " \
115
- "|#{proxy.yielding.join(', ')}| on #{sym}\n",
116
- "but a block with arity #{block.arity} was passed")
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
- if pass
128
- proxy.called
129
- return proxy.returning
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
- return obj.__send__(replaced_name(obj, sym), compare)
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
- symbols = mocks.keys + stubs.keys
143
- symbols.uniq.each do |replaced, obj, sym|
144
- meta = class << obj; self; end
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.to_sym)
147
- meta.__send__ :alias_method, sym.to_sym, replaced
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.to_sym
173
+ meta.__send__ :remove_method, sym
151
174
  end
152
175
  end
153
176
  reset