remarkable_rails 3.1.0 → 3.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,28 @@
1
+ * mock_models now creates a second class method to be used on the index action [#71]
2
+ In other words, mock_models :project will create:
3
+
4
+ def self.mock_project
5
+ proc { mock_project }
6
+ end
7
+
8
+ # This was added to be used on index actions
9
+ def self.mock_projects
10
+ proc { [ mock_project ] }
11
+ end
12
+
13
+ def mock_project(stubs={})
14
+ @project ||= mock_model(Project, stubs)
15
+ end
16
+
17
+ * Allow multiple args to be given to :with in expects. If you need to verify that
18
+ an array is being sent, you need to send an array inside another array [#70]
19
+
20
+ * Allow procs or blocks to be given to respond_with_body and respond_with :body [#67]
21
+
22
+ * Allow ordered to be given to macro stubs as option [#66]
23
+
24
+ * Allow multiple methods to be given to expects [#65]
25
+
1
26
  # v3.1
2
27
 
3
28
  * Ensure set_cookies and set_session work with arrays [#55]
@@ -56,12 +56,27 @@ module Remarkable
56
56
  # This also works in the rspec way:
57
57
  #
58
58
  # it { should assign_to(:project).with_stubs }
59
- # it { should render_tempalte('show').with_expectations }
59
+ # it { should render_template('show').with_expectations }
60
+ #
61
+ # == Attention!
62
+ #
63
+ # If you need to check that an array is being sent to a method, you need to
64
+ # give an array inside another array, for example:
65
+ #
66
+ # expects :comment_ids=, :on => Post, :with => [1,2,3]
67
+ #
68
+ # Is the same as:
69
+ #
70
+ # Post.comment_ids = (1, 2, 3)
71
+ #
72
+ # And it won't work. The right way to handle this is:
73
+ #
74
+ # expects :comment_ids=, :on => Post, :with => [[1,2,3]]
60
75
  #
61
76
  # == mock_models
62
77
  #
63
78
  # You don't have to play with proc all the time. You can call mock_models which
64
- # creates a class method that simply returns a proc and a instance method that
79
+ # creates two class methods that simply returns a proc and a instance method that
65
80
  # do the actual mock.
66
81
  #
67
82
  # describe ProjectsController do
@@ -71,6 +86,11 @@ module Remarkable
71
86
  #
72
87
  # def self.mock_project
73
88
  # proc { mock_project }
89
+ # end
90
+ #
91
+ # # To be used on index actions
92
+ # def self.mock_projects
93
+ # proc { [mock_project] }
74
94
  # end
75
95
  #
76
96
  # def mock_project(stubs={})
@@ -180,8 +200,9 @@ module Remarkable
180
200
  module ClassMethods
181
201
 
182
202
  # Creates a chain that will be evaluated as stub or expectation. The
183
- # first parameter is the method expected. Also, a block can be given
184
- # to calculate the returned value. See examples below.
203
+ # first parameter is the method expected. You can also specify multiple
204
+ # methods to stub and give a block to calculate the returned value. See
205
+ # examples below.
185
206
  #
186
207
  # == Options
187
208
  #
@@ -195,18 +216,26 @@ module Remarkable
195
216
  # required.
196
217
  #
197
218
  # * <tt>:times</tt> - The number of times the object will receive the
198
- # method. Used only in expectations and when not given, defaults to 1.
219
+ # method. Used only in expectations and when not given, defaults to 1.
220
+ #
221
+ # * <tt>:ordered</tt> - When true specifies that expectations should
222
+ # be received in order.
199
223
  #
200
224
  # == Example
201
225
  #
202
226
  # expects :new, :on => Project, :returns => :mock_project, :times => 2
203
227
  #
228
+ # expects :new, :find, :on => Project, :returns => :mock_project
229
+ #
204
230
  # expects :human_attribute_name, :on => Project, :with => :title do |attr|
205
231
  # attr.to_s.humanize
206
232
  # end
207
233
  #
208
234
  def expects(*args, &block)
209
- write_inheritable_array(:expects_chain, [args << block])
235
+ options = args.extract_options!
236
+ args.each do |arg|
237
+ write_inheritable_array(:expects_chain, [ [ arg, options, block] ])
238
+ end
210
239
  end
211
240
 
212
241
  # The mime type of the request. The value given will be called transformed
@@ -396,15 +425,20 @@ module Remarkable
396
425
  # mock_models :project
397
426
  # end
398
427
  #
399
- # Will create a class and instance mock method for you:
428
+ # Will create one instance and two class mock methods for you:
400
429
  #
401
430
  # def self.mock_project
402
431
  # proc { mock_project }
432
+ # end
433
+ #
434
+ # # To be used on index actions
435
+ # def self.mock_projects
436
+ # proc { [ mock_project ] }
403
437
  # end
404
438
  #
405
439
  # def mock_project(stubs={})
406
440
  # @project ||= mock_model(Project, stubs)
407
- # end
441
+ # end
408
442
  #
409
443
  # If you want to create just the instance method, you can give
410
444
  # :class_method => false as option.
@@ -413,12 +447,14 @@ module Remarkable
413
447
  options = models.extract_options!
414
448
  options = { :class_method => true }.merge(options)
415
449
 
416
- models.each do |model|
450
+ models.each do |model|
451
+ model = model.to_s
417
452
  self.class_eval <<-METHOD
418
- #{"def self.mock_#{model}; proc { mock_#{model} }; end" if options[:class_method]}
453
+ #{"def self.mock_#{model}; proc { mock_#{model} }; end" if options[:class_method]}
454
+ #{"def self.mock_#{model.pluralize}; proc { [ mock_#{model} ] }; end" if options[:class_method]}
419
455
 
420
456
  def mock_#{model}(stubs={})
421
- @#{model} ||= mock_model(#{model.to_s.classify}, stubs)
457
+ @#{model} ||= mock_model(#{model.classify}, stubs)
422
458
  end
423
459
  METHOD
424
460
  end
@@ -433,19 +469,22 @@ module Remarkable
433
469
  def evaluate_expectation_chain(use_expectations=true) #:nodoc:
434
470
  return if self.expects_chain.nil?
435
471
 
436
- self.expects_chain.each do |method, default_options, block|
437
- options = default_options.dup
438
-
439
- # Those are used both in expectations and stubs
440
- object = evaluate_value(options.delete(:on))
441
- return_value = evaluate_value(options.delete(:returns))
442
-
472
+ self.expects_chain.each do |method, options, block|
473
+ object = evaluate_value(options[:on])
443
474
  raise ScriptError, "You have to give me :on as an option when calling :expects." if object.nil?
444
475
 
445
476
  if use_expectations
446
- chain = object.should_receive(method)
447
- chain = chain.with(evaluate_value(options.delete(:with))) if options.key?(:with)
448
- chain = chain.exactly(options.delete(:times) || 1).times
477
+ chain = object.should_receive(method)
478
+
479
+ if options.key?(:with)
480
+ with = evaluate_value(options[:with])
481
+ chain = chain.with(*with)
482
+ end
483
+
484
+ times = options[:times] || 1
485
+ chain = chain.exactly(times).times
486
+
487
+ chain = chain.ordered if options[:ordered]
449
488
  else
450
489
  chain = object.stub!(method)
451
490
  end
@@ -453,6 +492,7 @@ module Remarkable
453
492
  chain = if block
454
493
  chain.and_return(&block)
455
494
  else
495
+ return_value = evaluate_value(options[:returns])
456
496
  chain.and_return(return_value)
457
497
  end
458
498
  end
@@ -122,23 +122,26 @@ module Remarkable
122
122
  # Extensions check does not work in Rails 2.1.x.
123
123
  #
124
124
  def render_template(*args, &block)
125
- options = args.extract_options!
126
- RenderTemplateMatcher.new(options.merge(:template => args.first), &block).spec(self)
125
+ options = args.extract_options!
126
+ options.merge!(:template => args.first)
127
+ RenderTemplateMatcher.new(options, &block).spec(self)
127
128
  end
128
129
 
129
130
  # This is just a shortcut for render_template :layout => layout. It's also
130
131
  # used for Shoulda compatibility. Check render_template for more information.
131
132
  #
132
133
  def render_with_layout(*args, &block)
133
- options = args.extract_options!
134
- RenderTemplateMatcher.new(options.merge(:layout => args.first), &block).spec(self)
134
+ options = args.extract_options!
135
+ options.merge!(:layout => args.first)
136
+ RenderTemplateMatcher.new(options, &block).spec(self)
135
137
  end
136
138
 
137
139
  # This is just a shortcut for render_template :layout => nil. It's also
138
140
  # used for Shoulda compatibility. Check render_template for more information.
139
141
  #
140
- def render_without_layout(options={}, &block)
141
- RenderTemplateMatcher.new(options.merge(:layout => nil), &block).spec(self)
142
+ def render_without_layout(options={}, &block)
143
+ options.merge!(:layout => nil)
144
+ RenderTemplateMatcher.new(options, &block).spec(self)
142
145
  end
143
146
 
144
147
  end
@@ -2,7 +2,7 @@ module Remarkable
2
2
  module ActionController
3
3
  module Matchers
4
4
  class RespondWithMatcher < Remarkable::ActionController::Base #:nodoc:
5
- arguments
5
+ arguments :block => true
6
6
 
7
7
  optional :with, :body, :content_type
8
8
 
@@ -11,7 +11,7 @@ module Remarkable
11
11
  @controller = @spec.instance_variable_get('@controller')
12
12
  end
13
13
 
14
- before_assert :evaluate_content_type
14
+ before_assert :evaluate_content_type, :evaluate_body
15
15
 
16
16
  assertions :status_matches?, :body_matches?, :content_type_matches?
17
17
 
@@ -45,7 +45,6 @@ module Remarkable
45
45
  assert_contains(@response.content_type, @options[:content_type])
46
46
  end
47
47
 
48
- # Evaluate content_type before assertions to have nice descriptions
49
48
  def evaluate_content_type
50
49
  return unless @options.key?(:content_type)
51
50
 
@@ -57,6 +56,14 @@ module Remarkable
57
56
  else
58
57
  @options[:content_type].to_s
59
58
  end
59
+ end
60
+
61
+ def evaluate_body
62
+ if @options.key?(:body) || @block
63
+ value = @options.key?(:body) ? @options[:body] : @block
64
+ value = @spec.instance_eval(&value) if value.is_a?(Proc)
65
+ @options[:body] = value
66
+ end
60
67
  end
61
68
 
62
69
  def interpolation_options
@@ -98,16 +105,20 @@ module Remarkable
98
105
  # it { should respond_with(300..399).content_type(Mime::XML) }
99
106
  #
100
107
  def respond_with(*args, &block)
101
- options = args.extract_options!
102
- RespondWithMatcher.new(options.merge(:with => args.first), &block).spec(self)
108
+ options = args.extract_options!
109
+ options.merge!(:with => args.first)
110
+ RespondWithMatcher.new(options, &block).spec(self)
103
111
  end
104
112
 
105
113
  # This is just a shortcut for respond_with :body => body. Check respond_with
106
114
  # for more information.
107
115
  #
108
116
  def respond_with_body(*args, &block)
109
- options = args.extract_options!
110
- RespondWithMatcher.new(options.merge(:body => args.first), &block).spec(self)
117
+ options = args.extract_options!
118
+ # Since body can be also given as block, only merge if any arguments was
119
+ # actually sent.
120
+ options.merge!(:body => args.first) unless args.empty?
121
+ RespondWithMatcher.new(options, &block).spec(self)
111
122
  end
112
123
 
113
124
  # This is just a shortcut for respond_with :content_type => content_type.
@@ -115,8 +126,9 @@ module Remarkable
115
126
  # information.
116
127
  #
117
128
  def respond_with_content_type(*args, &block)
118
- options = args.extract_options!
119
- RespondWithMatcher.new(options.merge(:content_type => args.first), &block).spec(self)
129
+ options = args.extract_options!
130
+ options.merge!(:content_type => args.first)
131
+ RespondWithMatcher.new(options, &block).spec(self)
120
132
  end
121
133
 
122
134
  end
@@ -10,15 +10,22 @@ describe 'MacroStubs' do
10
10
  def current_id; '37'; end
11
11
 
12
12
  describe 'mock_models' do
13
- before(:each) do
14
- self.class.metaclass.send(:undef_method, :mock_project) if self.class.respond_to?(:mock_project)
15
- self.class.send(:undef_method, :mock_project) if self.respond_to?(:mock_project)
13
+ before(:each) do
14
+ self.class.metaclass.send(:undef_method, :mock_projects) if self.class.respond_to?(:mock_projects)
15
+ self.class.metaclass.send(:undef_method, :mock_project) if self.class.respond_to?(:mock_project)
16
+ self.class.send(:undef_method, :mock_project) if self.respond_to?(:mock_project)
16
17
  end
17
18
 
18
- it 'should create a class mock method' do
19
+ it 'should create a class singular mock method' do
19
20
  self.class.respond_to?(:mock_project).should be_false
20
21
  self.class.mock_models :project
21
22
  self.class.respond_to?(:mock_project).should be_true
23
+ end
24
+
25
+ it 'should create a class plural mock method' do
26
+ self.class.respond_to?(:mock_projects).should be_false
27
+ self.class.mock_models :project
28
+ self.class.respond_to?(:mock_projects).should be_true
22
29
  end
23
30
 
24
31
  it 'should create an instance mock method' do
@@ -35,18 +42,66 @@ describe 'MacroStubs' do
35
42
  self.respond_to?(:mock_project).should be_true
36
43
  end
37
44
 
38
- it 'should create procs which evals to mocks dynamically' do
45
+ it 'should create procs which evals to a mock dynamically' do
39
46
  proc = self.class.mock_task
40
47
  proc.should be_kind_of(Proc)
41
48
 
42
- self.instance_variable_get('@task').should be_nil
43
- instance_eval(&proc)
44
- self.instance_variable_get('@task').should_not be_nil
49
+ @task.should be_nil
50
+ instance_eval(&proc).should == mock_task
51
+ @task.should_not be_nil
52
+ end
53
+
54
+ it 'should create procs which evals to an array of mocks dynamically' do
55
+ proc = self.class.mock_tasks
56
+ proc.should be_kind_of(Proc)
57
+
58
+ @task.should be_nil
59
+ instance_eval(&proc).should == [ mock_task ]
60
+ @task.should == mock_task
45
61
  end
62
+ end
63
+
64
+ describe 'failures' do
65
+ expects :find, :on => Task, :with => proc{ current_id }, :returns => mock_task
66
+ expects :max, :min, :count, :on => Task, :ordered => true
67
+
68
+ get :show, :id => 37
69
+
70
+ it 'should fail if expectation is not met' do
71
+ self.stub!(:current_id).and_return("42")
72
+
73
+ lambda {
74
+ run_action!(true)
75
+ }.should raise_error(Spec::Mocks::MockExpectationError, /expected :find with \("42"\) but received it with \("37"\)/)
76
+ end
77
+
78
+ it 'should fail if expectations are received out of order' do
79
+ lambda {
80
+ run_action!(true)
81
+ }.should raise_error(Spec::Mocks::MockExpectationError, /received :count out of order/)
82
+ end
83
+
84
+ it 'should splat an array given to with' do
85
+ self.stub!(:current_id).and_return([1, 2, 3])
86
+ run_expectations!
87
+
88
+ lambda {
89
+ Task.find([1,2,3])
90
+ }.should raise_error(Spec::Mocks::MockExpectationError, /expected :find with \(1\, 2\, 3\) but received it with \(\[1\, 2\, 3\]\)/)
91
+
92
+ lambda {
93
+ Task.find(1, 2, 3)
94
+ }.should_not raise_error
95
+ end
96
+
97
+ after(:each) do
98
+ teardown_mocks_for_rspec
99
+ end
46
100
  end
47
101
 
48
102
  describe 'when extending describe group behavior' do
49
- expects :find, :on => Task, :with => proc{ current_id }, :returns => mock_task
103
+ expects :find, :on => Task, :with => proc{ current_id }, :returns => mock_task
104
+ expects :count, :max, :min, :on => Task
50
105
 
51
106
  get :show, :id => 37
52
107
  params :special_task_id => 42
@@ -89,8 +144,8 @@ describe 'MacroStubs' do
89
144
  it 'should run expectations without performing an action' do
90
145
  self.should_receive(:current_id).once.and_return('37')
91
146
  run_expectations!
92
- @controller.send(:performed?).should_not be_true
93
- Task.find('37') # Execute expectations by hand
147
+ @controller.send(:performed?).should_not be_true
148
+ get :show, :id => '37' # Execute the action to match expectations
94
149
  end
95
150
 
96
151
  it 'should run action with stubs' do
@@ -77,7 +77,9 @@ describe 'respond_with' do
77
77
  before(:each) { build_response { respond_to{ |format| format.xml { render :xml => [].to_xml } } } }
78
78
 
79
79
  it { should respond_with_body(%{<?xml version="1.0" encoding="UTF-8"?>\n<nil-classes type="array"/>\n}) }
80
- it { should respond_with_body(/xml/) }
80
+ it { should respond_with_body(/xml/) }
81
+ it { should respond_with_body{/xml/} }
82
+ it { should respond_with_body proc{/xml/} }
81
83
  it { should_not respond_with_body('html') }
82
84
  it { should_not respond_with_body(/html/) }
83
85
  end
@@ -11,7 +11,12 @@ class TasksController < ApplicationController
11
11
  end
12
12
 
13
13
  def show
14
- @task = Task.find(params[:id])
14
+ @task = Task.find(params[:id])
15
+
16
+ # Multiple expects
17
+ Task.count
18
+ Task.max
19
+ Task.min
15
20
 
16
21
  respond_to do |format|
17
22
  format.html { render :text => 'show' }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: remarkable_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.0
4
+ version: 3.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carlos Brando
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-05-04 00:00:00 +02:00
13
+ date: 2009-05-13 00:00:00 +02:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -31,7 +31,7 @@ dependencies:
31
31
  requirements:
32
32
  - - ">="
33
33
  - !ruby/object:Gem::Version
34
- version: 3.1.0
34
+ version: 3.1.1
35
35
  version:
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: remarkable_activerecord
@@ -41,7 +41,7 @@ dependencies:
41
41
  requirements:
42
42
  - - ">="
43
43
  - !ruby/object:Gem::Version
44
- version: 3.1.0
44
+ version: 3.1.1
45
45
  version:
46
46
  description: "Remarkable Rails: collection of matchers and macros with I18n for Rails"
47
47
  email: