shoulda 2.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.
Files changed (104) hide show
  1. data/CONTRIBUTION_GUIDELINES.rdoc +12 -0
  2. data/MIT-LICENSE +22 -0
  3. data/README.rdoc +132 -0
  4. data/Rakefile +72 -0
  5. data/bin/convert_to_should_syntax +42 -0
  6. data/lib/shoulda.rb +16 -0
  7. data/lib/shoulda/action_mailer.rb +10 -0
  8. data/lib/shoulda/action_mailer/assertions.rb +39 -0
  9. data/lib/shoulda/active_record.rb +12 -0
  10. data/lib/shoulda/active_record/assertions.rb +85 -0
  11. data/lib/shoulda/active_record/macros.rb +703 -0
  12. data/lib/shoulda/assertions.rb +45 -0
  13. data/lib/shoulda/context.rb +309 -0
  14. data/lib/shoulda/controller.rb +30 -0
  15. data/lib/shoulda/controller/formats/html.rb +201 -0
  16. data/lib/shoulda/controller/formats/xml.rb +170 -0
  17. data/lib/shoulda/controller/helpers.rb +64 -0
  18. data/lib/shoulda/controller/macros.rb +287 -0
  19. data/lib/shoulda/controller/resource_options.rb +236 -0
  20. data/lib/shoulda/controller/routing.rb +0 -0
  21. data/lib/shoulda/controller/routing/macros.rb +0 -0
  22. data/lib/shoulda/helpers.rb +10 -0
  23. data/lib/shoulda/macros.rb +80 -0
  24. data/lib/shoulda/private_helpers.rb +22 -0
  25. data/lib/shoulda/proc_extensions.rb +14 -0
  26. data/lib/shoulda/rails.rb +19 -0
  27. data/lib/shoulda/tasks.rb +3 -0
  28. data/lib/shoulda/tasks/list_tests.rake +24 -0
  29. data/lib/shoulda/tasks/yaml_to_shoulda.rake +28 -0
  30. data/test/README +36 -0
  31. data/test/fixtures/addresses.yml +3 -0
  32. data/test/fixtures/friendships.yml +0 -0
  33. data/test/fixtures/posts.yml +5 -0
  34. data/test/fixtures/products.yml +0 -0
  35. data/test/fixtures/taggings.yml +0 -0
  36. data/test/fixtures/tags.yml +9 -0
  37. data/test/fixtures/users.yml +6 -0
  38. data/test/functional/posts_controller_test.rb +104 -0
  39. data/test/functional/users_controller_test.rb +36 -0
  40. data/test/other/context_test.rb +145 -0
  41. data/test/other/convert_to_should_syntax_test.rb +63 -0
  42. data/test/other/helpers_test.rb +183 -0
  43. data/test/other/private_helpers_test.rb +34 -0
  44. data/test/other/should_test.rb +266 -0
  45. data/test/rails_root/app/controllers/application.rb +25 -0
  46. data/test/rails_root/app/controllers/posts_controller.rb +85 -0
  47. data/test/rails_root/app/controllers/users_controller.rb +81 -0
  48. data/test/rails_root/app/helpers/application_helper.rb +3 -0
  49. data/test/rails_root/app/helpers/posts_helper.rb +2 -0
  50. data/test/rails_root/app/helpers/users_helper.rb +2 -0
  51. data/test/rails_root/app/models/address.rb +7 -0
  52. data/test/rails_root/app/models/dog.rb +5 -0
  53. data/test/rails_root/app/models/flea.rb +3 -0
  54. data/test/rails_root/app/models/friendship.rb +4 -0
  55. data/test/rails_root/app/models/post.rb +12 -0
  56. data/test/rails_root/app/models/product.rb +12 -0
  57. data/test/rails_root/app/models/tag.rb +8 -0
  58. data/test/rails_root/app/models/tagging.rb +4 -0
  59. data/test/rails_root/app/models/user.rb +28 -0
  60. data/test/rails_root/app/views/layouts/posts.rhtml +17 -0
  61. data/test/rails_root/app/views/layouts/users.rhtml +17 -0
  62. data/test/rails_root/app/views/posts/edit.rhtml +27 -0
  63. data/test/rails_root/app/views/posts/index.rhtml +25 -0
  64. data/test/rails_root/app/views/posts/new.rhtml +26 -0
  65. data/test/rails_root/app/views/posts/show.rhtml +18 -0
  66. data/test/rails_root/app/views/users/edit.rhtml +22 -0
  67. data/test/rails_root/app/views/users/index.rhtml +22 -0
  68. data/test/rails_root/app/views/users/new.rhtml +21 -0
  69. data/test/rails_root/app/views/users/show.rhtml +13 -0
  70. data/test/rails_root/config/boot.rb +109 -0
  71. data/test/rails_root/config/database.yml +4 -0
  72. data/test/rails_root/config/environment.rb +14 -0
  73. data/test/rails_root/config/environments/sqlite3.rb +0 -0
  74. data/test/rails_root/config/initializers/new_rails_defaults.rb +15 -0
  75. data/test/rails_root/config/initializers/shoulda.rb +8 -0
  76. data/test/rails_root/config/routes.rb +6 -0
  77. data/test/rails_root/db/migrate/001_create_users.rb +18 -0
  78. data/test/rails_root/db/migrate/002_create_posts.rb +13 -0
  79. data/test/rails_root/db/migrate/003_create_taggings.rb +12 -0
  80. data/test/rails_root/db/migrate/004_create_tags.rb +11 -0
  81. data/test/rails_root/db/migrate/005_create_dogs.rb +12 -0
  82. data/test/rails_root/db/migrate/006_create_addresses.rb +14 -0
  83. data/test/rails_root/db/migrate/007_create_fleas.rb +11 -0
  84. data/test/rails_root/db/migrate/008_create_dogs_fleas.rb +12 -0
  85. data/test/rails_root/db/migrate/009_create_products.rb +17 -0
  86. data/test/rails_root/db/migrate/010_create_friendships.rb +14 -0
  87. data/test/rails_root/db/schema.rb +0 -0
  88. data/test/rails_root/log/sqlite3.log +0 -0
  89. data/test/rails_root/public/404.html +30 -0
  90. data/test/rails_root/public/422.html +30 -0
  91. data/test/rails_root/public/500.html +30 -0
  92. data/test/rails_root/script/console +3 -0
  93. data/test/rails_root/script/generate +3 -0
  94. data/test/test_helper.rb +33 -0
  95. data/test/unit/address_test.rb +10 -0
  96. data/test/unit/dog_test.rb +7 -0
  97. data/test/unit/flea_test.rb +6 -0
  98. data/test/unit/friendship_test.rb +6 -0
  99. data/test/unit/post_test.rb +15 -0
  100. data/test/unit/product_test.rb +27 -0
  101. data/test/unit/tag_test.rb +14 -0
  102. data/test/unit/tagging_test.rb +6 -0
  103. data/test/unit/user_test.rb +52 -0
  104. metadata +170 -0
@@ -0,0 +1,170 @@
1
+ module ThoughtBot # :nodoc:
2
+ module Shoulda # :nodoc:
3
+ module Controller # :nodoc:
4
+ module XML
5
+ def self.included(other) #:nodoc:
6
+ other.class_eval do
7
+ extend ThoughtBot::Shoulda::Controller::XML::ClassMethods
8
+ end
9
+ end
10
+
11
+ module ClassMethods
12
+ # Macro that creates a test asserting that the controller responded with an XML content-type
13
+ # and that the XML contains +<name/>+ as the root element.
14
+ def should_respond_with_xml_for(name = nil)
15
+ should "have ContentType set to 'application/xml'" do
16
+ assert_xml_response
17
+ end
18
+
19
+ if name
20
+ should "return <#{name}/> as the root element" do
21
+ body = @response.body.first(100).map {|l| " #{l}"}
22
+ assert_select name.to_s.dasherize, 1, "Body:\n#{body}...\nDoes not have <#{name}/> as the root element."
23
+ end
24
+ end
25
+ end
26
+ alias should_respond_with_xml should_respond_with_xml_for
27
+
28
+ protected
29
+
30
+ def make_show_xml_tests(res) # :nodoc:
31
+ context "on GET to #{controller_name_from_class}#show as xml" do
32
+ setup do
33
+ request_xml
34
+ record = get_existing_record(res)
35
+ parent_params = make_parent_params(res, record)
36
+ get :show, parent_params.merge({ res.identifier => record.to_param })
37
+ end
38
+
39
+ if res.denied.actions.include?(:show)
40
+ should_not_assign_to res.object
41
+ should_respond_with 401
42
+ else
43
+ should_assign_to res.object
44
+ should_respond_with :success
45
+ should_respond_with_xml_for res.object
46
+ end
47
+ end
48
+ end
49
+
50
+ def make_edit_xml_tests(res) # :nodoc:
51
+ # XML doesn't need an :edit action
52
+ end
53
+
54
+ def make_new_xml_tests(res) # :nodoc:
55
+ # XML doesn't need a :new action
56
+ end
57
+
58
+ def make_index_xml_tests(res) # :nodoc:
59
+ context "on GET to #{controller_name_from_class}#index as xml" do
60
+ setup do
61
+ request_xml
62
+ parent_params = make_parent_params(res)
63
+ get(:index, parent_params)
64
+ end
65
+
66
+ if res.denied.actions.include?(:index)
67
+ should_not_assign_to res.object.to_s.pluralize
68
+ should_respond_with 401
69
+ else
70
+ should_respond_with :success
71
+ should_respond_with_xml_for res.object.to_s.pluralize
72
+ should_assign_to res.object.to_s.pluralize
73
+ end
74
+ end
75
+ end
76
+
77
+ def make_destroy_xml_tests(res) # :nodoc:
78
+ context "on DELETE to #{controller_name_from_class}#destroy as xml" do
79
+ setup do
80
+ request_xml
81
+ @record = get_existing_record(res)
82
+ parent_params = make_parent_params(res, @record)
83
+ delete :destroy, parent_params.merge({ res.identifier => @record.to_param })
84
+ end
85
+
86
+ if res.denied.actions.include?(:destroy)
87
+ should_respond_with 401
88
+
89
+ should "not destroy record" do
90
+ assert @record.reload
91
+ end
92
+ else
93
+ should "destroy record" do
94
+ assert_raises(::ActiveRecord::RecordNotFound, "@#{res.object} was not destroyed.") do
95
+ @record.reload
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+
102
+ def make_create_xml_tests(res) # :nodoc:
103
+ context "on POST to #{controller_name_from_class}#create as xml" do
104
+ setup do
105
+ request_xml
106
+ parent_params = make_parent_params(res)
107
+ @count = res.klass.count
108
+ post :create, parent_params.merge(res.object => res.create.params)
109
+ end
110
+
111
+ if res.denied.actions.include?(:create)
112
+ should_respond_with 401
113
+ should_not_assign_to res.object
114
+
115
+ should "not create new record" do
116
+ assert_equal @count, res.klass.count
117
+ end
118
+ else
119
+ should_assign_to res.object
120
+
121
+ should "not have errors on @#{res.object}" do
122
+ assert_equal [], pretty_error_messages(assigns(res.object)), "@#{res.object} has errors:"
123
+ end
124
+ end
125
+ end
126
+ end
127
+
128
+ def make_update_xml_tests(res) # :nodoc:
129
+ context "on PUT to #{controller_name_from_class}#update as xml" do
130
+ setup do
131
+ request_xml
132
+ @record = get_existing_record(res)
133
+ parent_params = make_parent_params(res, @record)
134
+ put :update, parent_params.merge(res.identifier => @record.to_param, res.object => res.update.params)
135
+ end
136
+
137
+ if res.denied.actions.include?(:update)
138
+ should_not_assign_to res.object
139
+ should_respond_with 401
140
+ else
141
+ should_assign_to res.object
142
+
143
+ should "not have errors on @#{res.object}" do
144
+ assert_equal [], assigns(res.object).errors.full_messages, "@#{res.object} has errors:"
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
150
+
151
+ # Sets the next request's format to 'application/xml'
152
+ def request_xml
153
+ @request.accept = "application/xml"
154
+ end
155
+
156
+ # Asserts that the controller's response was 'application/xml'
157
+ def assert_xml_response
158
+ content_type = (@response.headers["Content-Type"] || @response.headers["type"]).to_s
159
+ regex = %r{\bapplication/xml\b}
160
+
161
+ msg = "Content Type '#{content_type.inspect}' doesn't match '#{regex.inspect}'\n"
162
+ msg += "Body: #{@response.body.first(100).chomp} ..."
163
+
164
+ assert_match regex, content_type, msg
165
+ end
166
+
167
+ end
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,64 @@
1
+ module ThoughtBot # :nodoc:
2
+ module Shoulda # :nodoc:
3
+ module Controller # :nodoc:
4
+ module Helpers # :nodoc:
5
+ private # :enddoc:
6
+
7
+ SPECIAL_INSTANCE_VARIABLES = %w{
8
+ _cookies
9
+ _flash
10
+ _headers
11
+ _params
12
+ _request
13
+ _response
14
+ _session
15
+ action_name
16
+ before_filter_chain_aborted
17
+ cookies
18
+ flash
19
+ headers
20
+ ignore_missing_templates
21
+ logger
22
+ params
23
+ request
24
+ request_origin
25
+ response
26
+ session
27
+ template
28
+ template_class
29
+ template_root
30
+ url
31
+ variables_added
32
+ }.map(&:to_s)
33
+
34
+ def instantiate_variables_from_assigns(*names, &blk)
35
+ old = {}
36
+ names = (@response.template.assigns.keys - SPECIAL_INSTANCE_VARIABLES) if names.empty?
37
+ names.each do |name|
38
+ old[name] = instance_variable_get("@#{name}")
39
+ instance_variable_set("@#{name}", assigns(name.to_sym))
40
+ end
41
+ blk.call
42
+ names.each do |name|
43
+ instance_variable_set("@#{name}", old[name])
44
+ end
45
+ end
46
+
47
+ def get_existing_record(res) # :nodoc:
48
+ returning(instance_variable_get("@#{res.object}")) do |record|
49
+ assert(record, "This test requires you to set @#{res.object} in your setup block")
50
+ end
51
+ end
52
+
53
+ def make_parent_params(resource, record = nil, parent_names = nil) # :nodoc:
54
+ parent_names ||= resource.parents.reverse
55
+ return {} if parent_names == [] # Base case
56
+ parent_name = parent_names.shift
57
+ parent = record ? record.send(parent_name) : parent_name.to_s.classify.constantize.find(:first)
58
+
59
+ { :"#{parent_name}_id" => parent.to_param }.merge(make_parent_params(resource, parent, parent_names))
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,287 @@
1
+ module ThoughtBot # :nodoc:
2
+ module Shoulda # :nodoc:
3
+ module Controller # :nodoc:
4
+ # = Macro test helpers for your controllers
5
+ #
6
+ # By using the macro helpers you can quickly and easily create concise and easy to read test suites.
7
+ #
8
+ # This code segment:
9
+ # context "on GET to :show for first record" do
10
+ # setup do
11
+ # get :show, :id => 1
12
+ # end
13
+ #
14
+ # should_assign_to :user
15
+ # should_respond_with :success
16
+ # should_render_template :show
17
+ # should_not_set_the_flash
18
+ #
19
+ # should "do something else really cool" do
20
+ # assert_equal 1, assigns(:user).id
21
+ # end
22
+ # end
23
+ #
24
+ # Would produce 5 tests for the +show+ action
25
+ #
26
+ # Furthermore, the should_be_restful helper will create an entire set of tests which will verify that your
27
+ # controller responds restfully to a variety of requested formats.
28
+ module Macros
29
+ # :section: should_be_restful
30
+ # Generates a full suite of tests for a restful controller.
31
+ #
32
+ # The following definition will generate tests for the +index+, +show+, +new+,
33
+ # +edit+, +create+, +update+ and +destroy+ actions, in both +html+ and +xml+ formats:
34
+ #
35
+ # should_be_restful do |resource|
36
+ # resource.parent = :user
37
+ #
38
+ # resource.create.params = { :title => "first post", :body => 'blah blah blah'}
39
+ # resource.update.params = { :title => "changed" }
40
+ # end
41
+ #
42
+ # This generates about 40 tests, all of the format:
43
+ # "on GET to :show should assign @user."
44
+ # "on GET to :show should not set the flash."
45
+ # "on GET to :show should render 'show' template."
46
+ # "on GET to :show should respond with success."
47
+ # "on GET to :show as xml should assign @user."
48
+ # "on GET to :show as xml should have ContentType set to 'application/xml'."
49
+ # "on GET to :show as xml should respond with success."
50
+ # "on GET to :show as xml should return <user/> as the root element."
51
+ # The +resource+ parameter passed into the block is a ResourceOptions object, and
52
+ # is used to configure the tests for the details of your resources.
53
+ #
54
+ def should_be_restful(&blk) # :yields: resource
55
+ resource = ResourceOptions.new
56
+ blk.call(resource)
57
+ resource.normalize!(self)
58
+
59
+ resource.formats.each do |format|
60
+ resource.actions.each do |action|
61
+ if self.respond_to? :"make_#{action}_#{format}_tests"
62
+ self.send(:"make_#{action}_#{format}_tests", resource)
63
+ else
64
+ should "test #{action} #{format}" do
65
+ flunk "Test for #{action} as #{format} not implemented"
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ # :section: Test macros
73
+ # Macro that creates a test asserting that the flash contains the given value.
74
+ # val can be a String, a Regex, or nil (indicating that the flash should not be set)
75
+ #
76
+ # Example:
77
+ #
78
+ # should_set_the_flash_to "Thank you for placing this order."
79
+ # should_set_the_flash_to /created/i
80
+ # should_set_the_flash_to nil
81
+ def should_set_the_flash_to(val)
82
+ if val
83
+ should "have #{val.inspect} in the flash" do
84
+ assert_contains flash.values, val, ", Flash: #{flash.inspect}"
85
+ end
86
+ else
87
+ should "not set the flash" do
88
+ assert_equal({}, flash, "Flash was set to:\n#{flash.inspect}")
89
+ end
90
+ end
91
+ end
92
+
93
+ # Macro that creates a test asserting that the flash is empty. Same as
94
+ # @should_set_the_flash_to nil@
95
+ def should_not_set_the_flash
96
+ should_set_the_flash_to nil
97
+ end
98
+
99
+ # Macro that creates a test asserting that the controller assigned to
100
+ # each of the named instance variable(s).
101
+ #
102
+ # Options:
103
+ # * <tt>:class</tt> - The expected class of the instance variable being checked.
104
+ # * <tt>:equals</tt> - A string which is evaluated and compared for equality with
105
+ # the instance variable being checked.
106
+ #
107
+ # Example:
108
+ #
109
+ # should_assign_to :user, :posts
110
+ # should_assign_to :user, :class => User
111
+ # should_assign_to :user, :equals => '@user'
112
+ def should_assign_to(*names)
113
+ opts = names.extract_options!
114
+ names.each do |name|
115
+ test_name = "assign @#{name}"
116
+ test_name << " as class #{opts[:class]}" if opts[:class]
117
+ test_name << " which is equal to #{opts[:equals]}" if opts[:equals]
118
+ should test_name do
119
+ assigned_value = assigns(name.to_sym)
120
+ assert assigned_value, "The action isn't assigning to @#{name}"
121
+ assert_kind_of opts[:class], assigned_value if opts[:class]
122
+ if opts[:equals]
123
+ instantiate_variables_from_assigns do
124
+ expected_value = eval(opts[:equals], self.send(:binding), __FILE__, __LINE__)
125
+ assert_equal expected_value, assigned_value,
126
+ "Instance variable @#{name} expected to be #{expected_value}" +
127
+ " but was #{assigned_value}"
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
133
+
134
+ # Macro that creates a test asserting that the controller did not assign to
135
+ # any of the named instance variable(s).
136
+ #
137
+ # Example:
138
+ #
139
+ # should_not_assign_to :user, :posts
140
+ def should_not_assign_to(*names)
141
+ names.each do |name|
142
+ should "not assign to @#{name}" do
143
+ assert !assigns(name.to_sym), "@#{name} was visible"
144
+ end
145
+ end
146
+ end
147
+
148
+ # Macro that creates a test asserting that the controller responded with a 'response' status code.
149
+ # Example:
150
+ #
151
+ # should_respond_with :success
152
+ def should_respond_with(response)
153
+ should "respond with #{response}" do
154
+ assert_response response
155
+ end
156
+ end
157
+
158
+ # Macro that creates a test asserting that the response content type was 'content_type'.
159
+ # Example:
160
+ #
161
+ # should_respond_with_content_type 'application/rss+xml'
162
+ def should_respond_with_content_type(content_type)
163
+ should "respond with content type of #{content_type}" do
164
+ content_type = Mime::EXTENSION_LOOKUP[content_type.to_s].to_s if content_type.is_a? Symbol
165
+ if content_type.is_a? Regexp
166
+ assert_match content_type, @response.content_type, "Expected to match #{content_type} but was actually #{@response.content_type}"
167
+ else
168
+ assert_equal content_type, @response.content_type, "Expected #{content_type} but was actually #{@response.content_type}"
169
+ end
170
+ end
171
+ end
172
+
173
+ # Macro that creates a test asserting that a value returned from the session is correct.
174
+ # The given string is evaled to produce the resulting redirect path. All of the instance variables
175
+ # set by the controller are available to the evaled string.
176
+ # Example:
177
+ #
178
+ # should_return_from_session :user_id, '@user.id'
179
+ # should_return_from_session :message, '"Free stuff"'
180
+ def should_return_from_session(key, expected)
181
+ should "return the correct value from the session for key #{key}" do
182
+ instantiate_variables_from_assigns do
183
+ expected_value = eval(expected, self.send(:binding), __FILE__, __LINE__)
184
+ assert_equal expected_value, session[key], "Expected #{expected_value.inspect} but was #{session[key]}"
185
+ end
186
+ end
187
+ end
188
+
189
+ # Macro that creates a test asserting that the controller rendered the given template.
190
+ # Example:
191
+ #
192
+ # should_render_template :new
193
+ def should_render_template(template)
194
+ should "render template #{template.inspect}" do
195
+ assert_template template.to_s
196
+ end
197
+ end
198
+
199
+ # Macro that creates a test asserting that the controller rendered with the given layout.
200
+ # Example:
201
+ #
202
+ # should_render_with_layout 'special'
203
+ def should_render_with_layout(expected_layout = 'application')
204
+ if expected_layout
205
+ should "render with #{expected_layout} layout" do
206
+ response_layout = @response.layout.blank? ? "" : @response.layout.split('/').last
207
+ assert_equal expected_layout,
208
+ response_layout,
209
+ "Expected to render with layout #{expected_layout} but was rendered with #{response_layout}"
210
+ end
211
+ else
212
+ should "render without layout" do
213
+ assert_nil @response.layout,
214
+ "Expected no layout, but was rendered using #{@response.layout}"
215
+ end
216
+ end
217
+ end
218
+
219
+ # Macro that creates a test asserting that the controller rendered without a layout.
220
+ # Same as @should_render_with_layout false@
221
+ def should_render_without_layout
222
+ should_render_with_layout nil
223
+ end
224
+
225
+ # Macro that creates a test asserting that the controller returned a redirect to the given path.
226
+ # The given string is evaled to produce the resulting redirect path. All of the instance variables
227
+ # set by the controller are available to the evaled string.
228
+ # Example:
229
+ #
230
+ # should_redirect_to '"/"'
231
+ # should_redirect_to "users_url(@user)"
232
+ def should_redirect_to(url)
233
+ should "redirect to #{url.inspect}" do
234
+ instantiate_variables_from_assigns do
235
+ assert_redirected_to eval(url, self.send(:binding), __FILE__, __LINE__)
236
+ end
237
+ end
238
+ end
239
+
240
+ # Macro that creates a test asserting that the rendered view contains a <form> element.
241
+ def should_render_a_form
242
+ should "display a form" do
243
+ assert_select "form", true, "The template doesn't contain a <form> element"
244
+ end
245
+ end
246
+
247
+ # Macro that creates a routing test. It tries to use the given HTTP
248
+ # +method+ on the given +path+, and asserts that it routes to the
249
+ # given +options+.
250
+ #
251
+ # If you don't specify a :controller, it will try to guess the controller
252
+ # based on the current test.
253
+ #
254
+ # +to_param+ is called on the +options+ given.
255
+ #
256
+ # Examples:
257
+ #
258
+ # should_route :get, '/posts', :action => :index
259
+ # should_route :post, '/posts', :controller => :posts, :action => :create
260
+ # should_route :get, '/posts/1', :action => :show, :id => 1
261
+ # should_route :put, '/posts/1', :action => :update, :id => "1"
262
+ # should_route :delete, '/posts/1', :action => :destroy, :id => 1
263
+ # should_route :get, '/posts/new', :action => :new
264
+ #
265
+ def should_route(method, path, options)
266
+ unless options[:controller]
267
+ options[:controller] = self.name.gsub(/ControllerTest$/, '').tableize
268
+ end
269
+ options[:controller] = options[:controller].to_s
270
+ options[:action] = options[:action].to_s
271
+
272
+ populated_path = path.dup
273
+ options.each do |key, value|
274
+ options[key] = value.to_param if value.respond_to? :to_param
275
+ populated_path.gsub!(key.inspect, value.to_s)
276
+ end
277
+
278
+ should_name = "route #{method.to_s.upcase} #{populated_path} to/from #{options.inspect}"
279
+
280
+ should should_name do
281
+ assert_routing({:method => method, :path => populated_path}, options)
282
+ end
283
+ end
284
+ end
285
+ end
286
+ end
287
+ end