mcmire-shoulda-matchers 2.5.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 (164) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.travis.yml +32 -0
  4. data/.yardopts +7 -0
  5. data/Appraisals +45 -0
  6. data/CONTRIBUTING.md +41 -0
  7. data/Gemfile +31 -0
  8. data/Gemfile.lock +166 -0
  9. data/MIT-LICENSE +22 -0
  10. data/NEWS.md +299 -0
  11. data/README.md +163 -0
  12. data/Rakefile +116 -0
  13. data/doc_config/gh-pages/index.html.erb +9 -0
  14. data/doc_config/yard/setup.rb +22 -0
  15. data/doc_config/yard/templates/default/fulldoc/html/css/bootstrap.css +5967 -0
  16. data/doc_config/yard/templates/default/fulldoc/html/css/full_list.css +12 -0
  17. data/doc_config/yard/templates/default/fulldoc/html/css/global.css +45 -0
  18. data/doc_config/yard/templates/default/fulldoc/html/css/solarized.css +69 -0
  19. data/doc_config/yard/templates/default/fulldoc/html/css/style.css +283 -0
  20. data/doc_config/yard/templates/default/fulldoc/html/full_list.erb +32 -0
  21. data/doc_config/yard/templates/default/fulldoc/html/full_list_class.erb +1 -0
  22. data/doc_config/yard/templates/default/fulldoc/html/full_list_method.erb +8 -0
  23. data/doc_config/yard/templates/default/fulldoc/html/js/app.js +300 -0
  24. data/doc_config/yard/templates/default/fulldoc/html/js/full_list.js +1 -0
  25. data/doc_config/yard/templates/default/fulldoc/html/js/jquery.stickyheaders.js +289 -0
  26. data/doc_config/yard/templates/default/fulldoc/html/js/underscore.min.js +6 -0
  27. data/doc_config/yard/templates/default/fulldoc/html/setup.rb +8 -0
  28. data/doc_config/yard/templates/default/layout/html/breadcrumb.erb +14 -0
  29. data/doc_config/yard/templates/default/layout/html/fonts.erb +1 -0
  30. data/doc_config/yard/templates/default/layout/html/layout.erb +23 -0
  31. data/doc_config/yard/templates/default/layout/html/search.erb +13 -0
  32. data/doc_config/yard/templates/default/layout/html/setup.rb +8 -0
  33. data/doc_config/yard/templates/default/method_details/html/source.erb +10 -0
  34. data/doc_config/yard/templates/default/module/html/box_info.erb +31 -0
  35. data/features/rails_integration.feature +113 -0
  36. data/features/step_definitions/rails_steps.rb +162 -0
  37. data/features/support/env.rb +5 -0
  38. data/gemfiles/3.0.gemfile +24 -0
  39. data/gemfiles/3.0.gemfile.lock +150 -0
  40. data/gemfiles/3.1.gemfile +27 -0
  41. data/gemfiles/3.1.gemfile.lock +173 -0
  42. data/gemfiles/3.2.gemfile +27 -0
  43. data/gemfiles/3.2.gemfile.lock +171 -0
  44. data/gemfiles/4.0.0.gemfile +28 -0
  45. data/gemfiles/4.0.0.gemfile.lock +172 -0
  46. data/gemfiles/4.0.1.gemfile +28 -0
  47. data/gemfiles/4.0.1.gemfile.lock +172 -0
  48. data/lib/shoulda-matchers.rb +1 -0
  49. data/lib/shoulda/matchers.rb +11 -0
  50. data/lib/shoulda/matchers/action_controller.rb +17 -0
  51. data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +64 -0
  52. data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +97 -0
  53. data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +81 -0
  54. data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +117 -0
  55. data/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +114 -0
  56. data/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +154 -0
  57. data/lib/shoulda/matchers/action_controller/route_matcher.rb +116 -0
  58. data/lib/shoulda/matchers/action_controller/route_params.rb +48 -0
  59. data/lib/shoulda/matchers/action_controller/set_session_matcher.rb +164 -0
  60. data/lib/shoulda/matchers/action_controller/set_the_flash_matcher.rb +296 -0
  61. data/lib/shoulda/matchers/active_model.rb +30 -0
  62. data/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +167 -0
  63. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +314 -0
  64. data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +46 -0
  65. data/lib/shoulda/matchers/active_model/ensure_exclusion_of_matcher.rb +160 -0
  66. data/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb +417 -0
  67. data/lib/shoulda/matchers/active_model/ensure_length_of_matcher.rb +337 -0
  68. data/lib/shoulda/matchers/active_model/errors.rb +10 -0
  69. data/lib/shoulda/matchers/active_model/exception_message_finder.rb +58 -0
  70. data/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +92 -0
  71. data/lib/shoulda/matchers/active_model/helpers.rb +46 -0
  72. data/lib/shoulda/matchers/active_model/numericality_matchers.rb +9 -0
  73. data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +75 -0
  74. data/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb +27 -0
  75. data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +41 -0
  76. data/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb +27 -0
  77. data/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb +26 -0
  78. data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +112 -0
  79. data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +77 -0
  80. data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +121 -0
  81. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +380 -0
  82. data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +89 -0
  83. data/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb +372 -0
  84. data/lib/shoulda/matchers/active_model/validation_matcher.rb +97 -0
  85. data/lib/shoulda/matchers/active_model/validation_message_finder.rb +69 -0
  86. data/lib/shoulda/matchers/active_record.rb +22 -0
  87. data/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +204 -0
  88. data/lib/shoulda/matchers/active_record/association_matcher.rb +901 -0
  89. data/lib/shoulda/matchers/active_record/association_matchers.rb +9 -0
  90. data/lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb +41 -0
  91. data/lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb +41 -0
  92. data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +81 -0
  93. data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +65 -0
  94. data/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +94 -0
  95. data/lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb +41 -0
  96. data/lib/shoulda/matchers/active_record/association_matchers/source_matcher.rb +41 -0
  97. data/lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb +63 -0
  98. data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +261 -0
  99. data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +149 -0
  100. data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +72 -0
  101. data/lib/shoulda/matchers/active_record/serialize_matcher.rb +181 -0
  102. data/lib/shoulda/matchers/assertion_error.rb +19 -0
  103. data/lib/shoulda/matchers/error.rb +6 -0
  104. data/lib/shoulda/matchers/integrations/rspec.rb +20 -0
  105. data/lib/shoulda/matchers/integrations/test_unit.rb +30 -0
  106. data/lib/shoulda/matchers/rails_shim.rb +50 -0
  107. data/lib/shoulda/matchers/version.rb +6 -0
  108. data/lib/shoulda/matchers/warn.rb +8 -0
  109. data/shoulda-matchers.gemspec +23 -0
  110. data/spec/shoulda/matchers/action_controller/filter_param_matcher_spec.rb +22 -0
  111. data/spec/shoulda/matchers/action_controller/redirect_to_matcher_spec.rb +42 -0
  112. data/spec/shoulda/matchers/action_controller/render_template_matcher_spec.rb +78 -0
  113. data/spec/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb +63 -0
  114. data/spec/shoulda/matchers/action_controller/rescue_from_matcher_spec.rb +63 -0
  115. data/spec/shoulda/matchers/action_controller/respond_with_matcher_spec.rb +31 -0
  116. data/spec/shoulda/matchers/action_controller/route_matcher_spec.rb +70 -0
  117. data/spec/shoulda/matchers/action_controller/route_params_spec.rb +30 -0
  118. data/spec/shoulda/matchers/action_controller/set_session_matcher_spec.rb +51 -0
  119. data/spec/shoulda/matchers/action_controller/set_the_flash_matcher_spec.rb +153 -0
  120. data/spec/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb +111 -0
  121. data/spec/shoulda/matchers/active_model/allow_value_matcher_spec.rb +170 -0
  122. data/spec/shoulda/matchers/active_model/disallow_value_matcher_spec.rb +81 -0
  123. data/spec/shoulda/matchers/active_model/ensure_exclusion_of_matcher_spec.rb +95 -0
  124. data/spec/shoulda/matchers/active_model/ensure_inclusion_of_matcher_spec.rb +320 -0
  125. data/spec/shoulda/matchers/active_model/ensure_length_of_matcher_spec.rb +166 -0
  126. data/spec/shoulda/matchers/active_model/exception_message_finder_spec.rb +111 -0
  127. data/spec/shoulda/matchers/active_model/have_secure_password_matcher_spec.rb +20 -0
  128. data/spec/shoulda/matchers/active_model/helpers_spec.rb +158 -0
  129. data/spec/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb +169 -0
  130. data/spec/shoulda/matchers/active_model/numericality_matchers/even_number_matcher_spec.rb +59 -0
  131. data/spec/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher_spec.rb +59 -0
  132. data/spec/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher_spec.rb +57 -0
  133. data/spec/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb +139 -0
  134. data/spec/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +41 -0
  135. data/spec/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb +47 -0
  136. data/spec/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +331 -0
  137. data/spec/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +180 -0
  138. data/spec/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb +398 -0
  139. data/spec/shoulda/matchers/active_model/validation_message_finder_spec.rb +127 -0
  140. data/spec/shoulda/matchers/active_record/accept_nested_attributes_for_matcher_spec.rb +107 -0
  141. data/spec/shoulda/matchers/active_record/association_matcher_spec.rb +860 -0
  142. data/spec/shoulda/matchers/active_record/association_matchers/model_reflection_spec.rb +247 -0
  143. data/spec/shoulda/matchers/active_record/have_db_column_matcher_spec.rb +111 -0
  144. data/spec/shoulda/matchers/active_record/have_db_index_matcher_spec.rb +78 -0
  145. data/spec/shoulda/matchers/active_record/have_readonly_attributes_matcher_spec.rb +41 -0
  146. data/spec/shoulda/matchers/active_record/serialize_matcher_spec.rb +86 -0
  147. data/spec/spec_helper.rb +26 -0
  148. data/spec/support/active_model_versions.rb +13 -0
  149. data/spec/support/active_resource_builder.rb +29 -0
  150. data/spec/support/activemodel_helpers.rb +19 -0
  151. data/spec/support/capture_helpers.rb +19 -0
  152. data/spec/support/class_builder.rb +42 -0
  153. data/spec/support/controller_builder.rb +74 -0
  154. data/spec/support/fail_with_message_including_matcher.rb +33 -0
  155. data/spec/support/fail_with_message_matcher.rb +32 -0
  156. data/spec/support/i18n_faker.rb +10 -0
  157. data/spec/support/mailer_builder.rb +10 -0
  158. data/spec/support/model_builder.rb +81 -0
  159. data/spec/support/rails_versions.rb +18 -0
  160. data/spec/support/shared_examples/numerical_submatcher.rb +19 -0
  161. data/spec/support/shared_examples/numerical_type_submatcher.rb +17 -0
  162. data/spec/support/test_application.rb +120 -0
  163. data/yard.watchr +5 -0
  164. metadata +281 -0
@@ -0,0 +1,117 @@
1
+ module Shoulda
2
+ module Matchers
3
+ module ActionController
4
+ # The `render_with_layout` matcher tests that an action is rendered with
5
+ # a certain layout.
6
+ #
7
+ # class PostsController < ApplicationController
8
+ # def show
9
+ # render layout: 'posts'
10
+ # end
11
+ # end
12
+ #
13
+ # # RSpec
14
+ # describe PostsController do
15
+ # describe 'GET #show' do
16
+ # before { get :show }
17
+ #
18
+ # it { should render_with_layout('posts') }
19
+ # end
20
+ # end
21
+ #
22
+ # # Test::Unit
23
+ # class PostsControllerTest < ActionController::TestCase
24
+ # context 'GET #show' do
25
+ # setup { get :show }
26
+ #
27
+ # should render_with_layout('posts')
28
+ # end
29
+ # end
30
+ #
31
+ # @return [RenderWithLayoutMatcher]
32
+ #
33
+ def render_with_layout(expected_layout = nil)
34
+ RenderWithLayoutMatcher.new(expected_layout).in_context(self)
35
+ end
36
+
37
+ # @private
38
+ class RenderWithLayoutMatcher
39
+ def initialize(expected_layout)
40
+ unless expected_layout.nil?
41
+ @expected_layout = expected_layout.to_s
42
+ end
43
+ end
44
+
45
+ # Used to provide access to layouts recorded by
46
+ # ActionController::TemplateAssertions in Rails 3
47
+ def in_context(context)
48
+ @context = context
49
+ self
50
+ end
51
+
52
+ def matches?(controller)
53
+ @controller = controller
54
+ rendered_with_layout? && rendered_with_expected_layout?
55
+ end
56
+
57
+ def failure_message
58
+ "Expected #{expectation}, but #{result}"
59
+ end
60
+ alias failure_message_for_should failure_message
61
+
62
+ def failure_message_when_negated
63
+ "Did not expect #{expectation}, but #{result}"
64
+ end
65
+ alias failure_message_for_should_not failure_message_when_negated
66
+
67
+ def description
68
+ description = 'render with '
69
+ if @expected_layout.nil?
70
+ description << 'a layout'
71
+ else
72
+ description << "the #{@expected_layout.inspect} layout"
73
+ end
74
+ description
75
+ end
76
+
77
+ private
78
+
79
+ def rendered_with_layout?
80
+ !rendered_layouts.empty?
81
+ end
82
+
83
+ def rendered_with_expected_layout?
84
+ if @expected_layout.nil?
85
+ true
86
+ else
87
+ rendered_layouts.include?(@expected_layout)
88
+ end
89
+ end
90
+
91
+ def rendered_layouts
92
+ recorded_layouts.keys.compact.map { |layout| layout.sub(%r{^layouts/}, '') }
93
+ end
94
+
95
+ def recorded_layouts
96
+ if @context
97
+ @context.instance_variable_get(Shoulda::Matchers::RailsShim.layouts_ivar)
98
+ else
99
+ {}
100
+ end
101
+ end
102
+
103
+ def expectation
104
+ "to #{description}"
105
+ end
106
+
107
+ def result
108
+ if rendered_with_layout?
109
+ 'rendered with ' + rendered_layouts.map(&:inspect).join(', ')
110
+ else
111
+ 'rendered without a layout'
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,114 @@
1
+ module Shoulda
2
+ module Matchers
3
+ module ActionController
4
+ # The `rescue_from` matcher tests usage of the `rescue_from` macro. It
5
+ # asserts that an exception and method are present in the list of
6
+ # exception handlers, and that the handler method exists.
7
+ #
8
+ # class ApplicationController < ActionController::Base
9
+ # rescue_from ActiveRecord::RecordNotFound, with: :handle_not_found
10
+ #
11
+ # private
12
+ #
13
+ # def handle_not_found
14
+ # # ...
15
+ # end
16
+ # end
17
+ #
18
+ # # RSpec
19
+ # describe ApplicationController do
20
+ # it do
21
+ # should rescue_from(ActiveRecord::RecordNotFound).
22
+ # with(:handle_not_found)
23
+ # end
24
+ # end
25
+ #
26
+ # # Test::Unit
27
+ # class ApplicationControllerTest < ActionController::TestCase
28
+ # should rescue_from(ActiveRecord::RecordNotFound).
29
+ # with(:handle_not_found)
30
+ # end
31
+ #
32
+ # @return [RescueFromMatcher]
33
+ #
34
+ def rescue_from(exception)
35
+ RescueFromMatcher.new exception
36
+ end
37
+
38
+ # @private
39
+ class RescueFromMatcher
40
+ def initialize(exception)
41
+ @exception = exception
42
+ end
43
+
44
+ def with(method)
45
+ @expected_method = method
46
+ self
47
+ end
48
+
49
+ def matches?(controller)
50
+ @controller = controller
51
+ rescues_from_exception? && method_name_matches? && handler_exists?
52
+ end
53
+
54
+ def description
55
+ description = "rescues from #{exception}"
56
+ description << " with ##{expected_method}" if expected_method
57
+ description
58
+ end
59
+
60
+ def failure_message
61
+ "Expected #{expectation}"
62
+ end
63
+ alias failure_message_for_should failure_message
64
+
65
+ def failure_message_when_negated
66
+ "Did not expect #{expectation}"
67
+ end
68
+ alias failure_message_for_should_not failure_message_when_negated
69
+
70
+ private
71
+
72
+ attr_reader :controller, :exception, :expected_method, :handlers
73
+
74
+ def expectation
75
+ expectation = "#{controller} to rescue from #{exception}"
76
+
77
+ if expected_method && !method_name_matches?
78
+ expectation << " with ##{expected_method}"
79
+ end
80
+
81
+ unless handler_exists?
82
+ expectation << " but #{controller} does not respond to #{expected_method}"
83
+ end
84
+ expectation
85
+ end
86
+
87
+ def rescues_from_exception?
88
+ @handlers = controller.rescue_handlers.select do |handler|
89
+ handler.first == exception.to_s
90
+ end
91
+ handlers.any?
92
+ end
93
+
94
+ def method_name_matches?
95
+ if expected_method.present?
96
+ handlers.any? do |handler|
97
+ handler.last == expected_method
98
+ end
99
+ else
100
+ true
101
+ end
102
+ end
103
+
104
+ def handler_exists?
105
+ if expected_method.present?
106
+ controller.respond_to? expected_method
107
+ else
108
+ true
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,154 @@
1
+ module Shoulda
2
+ module Matchers
3
+ module ActionController
4
+ # The `respond_with` matcher tests that an action responds with a certain
5
+ # status code.
6
+ #
7
+ # You can specify that the status should be a number:
8
+ #
9
+ # class PostsController < ApplicationController
10
+ # def index
11
+ # render status: 403
12
+ # end
13
+ # end
14
+ #
15
+ # # RSpec
16
+ # describe PostsController do
17
+ # describe 'GET #index' do
18
+ # before { get :index }
19
+ #
20
+ # it { should respond_with(403) }
21
+ # end
22
+ # end
23
+ #
24
+ # # Test::Unit
25
+ # class PostsControllerTest < ActionController::TestCase
26
+ # context 'GET #index' do
27
+ # setup { get :index }
28
+ #
29
+ # should respond_with(403)
30
+ # end
31
+ # end
32
+ #
33
+ # You can specify that the status should be within a range of numbers:
34
+ #
35
+ # class PostsController < ApplicationController
36
+ # def destroy
37
+ # render status: 508
38
+ # end
39
+ # end
40
+ #
41
+ # # RSpec
42
+ # describe PostsController do
43
+ # describe 'DELETE #destroy' do
44
+ # before { delete :destroy }
45
+ #
46
+ # it { should respond_with(500..600) }
47
+ # end
48
+ # end
49
+ #
50
+ # # Test::Unit
51
+ # class PostsControllerTest < ActionController::TestCase
52
+ # context 'DELETE #destroy' do
53
+ # setup { delete :destroy }
54
+ #
55
+ # should respond_with(500..600)
56
+ # end
57
+ # end
58
+ #
59
+ # Finally, you can specify that the status should be a symbol:
60
+ #
61
+ # class PostsController < ApplicationController
62
+ # def show
63
+ # render status: :locked
64
+ # end
65
+ # end
66
+ #
67
+ # # RSpec
68
+ # describe PostsController do
69
+ # describe 'GET #show' do
70
+ # before { get :show }
71
+ #
72
+ # it { should respond_with(:locked) }
73
+ # end
74
+ # end
75
+ #
76
+ # # Test::Unit
77
+ # class PostsControllerTest < ActionController::TestCase
78
+ # context 'GET #show' do
79
+ # setup { get :show }
80
+ #
81
+ # should respond_with(:locked)
82
+ # end
83
+ # end
84
+ #
85
+ # @return [RespondWithMatcher]
86
+ #
87
+ def respond_with(status)
88
+ RespondWithMatcher.new(status)
89
+ end
90
+
91
+ # @private
92
+ class RespondWithMatcher
93
+ def initialize(status)
94
+ @status = symbol_to_status_code(status)
95
+ end
96
+
97
+ def matches?(controller)
98
+ @controller = controller
99
+ correct_status_code? || correct_status_code_range?
100
+ end
101
+
102
+ def failure_message
103
+ "Expected #{expectation}"
104
+ end
105
+ alias failure_message_for_should failure_message
106
+
107
+ def failure_message_when_negated
108
+ "Did not expect #{expectation}"
109
+ end
110
+ alias failure_message_for_should_not failure_message_when_negated
111
+
112
+ def description
113
+ "respond with #{@status}"
114
+ end
115
+
116
+ protected
117
+
118
+ def correct_status_code?
119
+ response_code == @status
120
+ end
121
+
122
+ def correct_status_code_range?
123
+ @status.is_a?(Range) &&
124
+ @status.include?(response_code)
125
+ end
126
+
127
+ def response_code
128
+ @controller.response.response_code
129
+ end
130
+
131
+ def symbol_to_status_code(potential_symbol)
132
+ case potential_symbol
133
+ when :success then 200
134
+ when :redirect then 300..399
135
+ when :missing then 404
136
+ when :error then 500..599
137
+ when Symbol
138
+ if defined?(::Rack::Utils::SYMBOL_TO_STATUS_CODE)
139
+ ::Rack::Utils::SYMBOL_TO_STATUS_CODE[potential_symbol]
140
+ else
141
+ ::ActionController::Base::SYMBOL_TO_STATUS_CODE[potential_symbol]
142
+ end
143
+ else
144
+ potential_symbol
145
+ end
146
+ end
147
+
148
+ def expectation
149
+ "response to be a #{@status}, but was #{response_code}"
150
+ end
151
+ end
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,116 @@
1
+ module Shoulda
2
+ module Matchers
3
+ module ActionController
4
+ # The `route` matcher tests that a route resolves to a controller,
5
+ # action, and params; and that the controller, action, and params
6
+ # generates the same route. For an RSpec suite, this is like using a
7
+ # combination of `route_to` and `be_routable`. For a Test::Unit suite, it
8
+ # provides a more expressive syntax over `assert_routing`.
9
+ #
10
+ # Given these routes:
11
+ #
12
+ # My::Application.routes.draw do
13
+ # get '/posts', controller: 'posts', action: 'index'
14
+ # get '/posts/:id' => 'posts#show'
15
+ # end
16
+ #
17
+ # You can choose to keep your routing tests under the test file for one
18
+ # controller:
19
+ #
20
+ # class PostsController < ApplicationController
21
+ # # ...
22
+ # end
23
+ #
24
+ # # RSpec
25
+ # describe PostsController do
26
+ # it { should route(:get, '/posts').to(action: :index) }
27
+ # it { should route(:get, '/posts/1').to(action: :show, id: 1) }
28
+ # end
29
+ #
30
+ # # Test::Unit
31
+ # class PostsControllerTest < ActionController::TestCase
32
+ # should route(:get, '/posts').to(action: 'index')
33
+ # should route(:get, '/posts/1').to(action: :show, id: 1)
34
+ # end
35
+ #
36
+ # Or if you like, you can keep all of your routing tests in one file.
37
+ # Just be sure to always specify a controller as `route` won't be able to
38
+ # figure it out otherwise:
39
+ #
40
+ # # RSpec
41
+ # describe 'Routing' do
42
+ # it { should route(:get, '/posts').to(controller: :posts, action: :index) }
43
+ # it { should route(:get, '/posts/1').to('posts#show', id: 1) }
44
+ # end
45
+ #
46
+ # # Test::Unit
47
+ # class RoutesTest < ActionController::IntegrationTest
48
+ # should route(:get, '/posts').to(controller: :posts, action: :index)
49
+ # should route(:get, '/posts/1').to('posts#show', id: 1)
50
+ # end
51
+ #
52
+ # @return [RouteMatcher]
53
+ #
54
+ def route(method, path)
55
+ RouteMatcher.new(method, path, self)
56
+ end
57
+
58
+ # @private
59
+ class RouteMatcher
60
+ def initialize(method, path, context)
61
+ @method = method
62
+ @path = path
63
+ @context = context
64
+ end
65
+
66
+ attr_reader :failure_message, :failure_message_when_negated
67
+
68
+ alias failure_message_for_should failure_message
69
+ alias failure_message_for_should_not failure_message_when_negated
70
+
71
+ def to(*args)
72
+ @params = RouteParams.new(args).normalize
73
+ self
74
+ end
75
+
76
+ def in_context(context)
77
+ @context = context
78
+ self
79
+ end
80
+
81
+ def matches?(controller)
82
+ guess_controller!(controller)
83
+ route_recognized?
84
+ end
85
+
86
+ def description
87
+ "route #{@method.to_s.upcase} #{@path} to/from #{@params.inspect}"
88
+ end
89
+
90
+ private
91
+
92
+ def guess_controller!(controller)
93
+ @params[:controller] ||= controller.controller_path
94
+ end
95
+
96
+
97
+ def route_recognized?
98
+ begin
99
+ @context.__send__(:assert_routing,
100
+ { method: @method, path: @path },
101
+ @params)
102
+
103
+ @failure_message_when_negated = "Didn't expect to #{description}"
104
+ true
105
+ rescue ::ActionController::RoutingError => error
106
+ @failure_message = error.message
107
+ false
108
+ rescue Shoulda::Matchers::AssertionError => error
109
+ @failure_message = error.message
110
+ false
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end