mspec 1.5.11 → 1.5.12

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.
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