shoulda-matchers 2.8.0 → 3.0.0.rc1

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 (171) hide show
  1. checksums.yaml +4 -4
  2. data/.hound_config/ruby.yml +7 -0
  3. data/.travis.yml +11 -54
  4. data/Appraisals +45 -100
  5. data/CONTRIBUTING.md +51 -7
  6. data/Gemfile +7 -19
  7. data/Gemfile.lock +60 -134
  8. data/Guardfile +5 -0
  9. data/NEWS.md +203 -0
  10. data/README.md +95 -50
  11. data/Rakefile +1 -0
  12. data/doc_config/yard/templates/default/layout/html/setup.rb +1 -1
  13. data/gemfiles/4.0.0.gemfile +10 -7
  14. data/gemfiles/4.0.0.gemfile.lock +103 -79
  15. data/gemfiles/4.0.1.gemfile +10 -7
  16. data/gemfiles/4.0.1.gemfile.lock +109 -83
  17. data/gemfiles/4.1.gemfile +10 -7
  18. data/gemfiles/4.1.gemfile.lock +109 -85
  19. data/gemfiles/4.2.gemfile +10 -9
  20. data/gemfiles/4.2.gemfile.lock +86 -78
  21. data/lib/shoulda/matchers.rb +13 -18
  22. data/lib/shoulda/matchers/action_controller.rb +4 -1
  23. data/lib/shoulda/matchers/action_controller/flash_store.rb +95 -0
  24. data/lib/shoulda/matchers/action_controller/{strong_parameters_matcher.rb → permit_matcher.rb} +147 -30
  25. data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +1 -1
  26. data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +1 -1
  27. data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +1 -1
  28. data/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +1 -1
  29. data/lib/shoulda/matchers/action_controller/route_matcher.rb +5 -1
  30. data/lib/shoulda/matchers/action_controller/route_params.rb +15 -6
  31. data/lib/shoulda/matchers/action_controller/session_store.rb +34 -0
  32. data/lib/shoulda/matchers/action_controller/set_flash_matcher.rb +30 -136
  33. data/lib/shoulda/matchers/action_controller/set_session_matcher.rb +28 -109
  34. data/lib/shoulda/matchers/action_controller/set_session_or_flash_matcher.rb +103 -0
  35. data/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +1 -12
  36. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +79 -10
  37. data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +10 -0
  38. data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +21 -0
  39. data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +24 -0
  40. data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +22 -5
  41. data/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +29 -10
  42. data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +27 -10
  43. data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +27 -12
  44. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +56 -20
  45. data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +3 -11
  46. data/lib/shoulda/matchers/active_model/validation_message_finder.rb +65 -0
  47. data/lib/shoulda/matchers/active_record/association_matcher.rb +40 -6
  48. data/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb +21 -7
  49. data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +11 -40
  50. data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +1 -1
  51. data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +2 -6
  52. data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +137 -22
  53. data/lib/shoulda/matchers/configuration.rb +20 -0
  54. data/lib/shoulda/matchers/doublespeak.rb +11 -1
  55. data/lib/shoulda/matchers/doublespeak/double.rb +29 -11
  56. data/lib/shoulda/matchers/doublespeak/double_collection.rb +4 -3
  57. data/lib/shoulda/matchers/doublespeak/method_call.rb +35 -0
  58. data/lib/shoulda/matchers/doublespeak/object_double.rb +7 -2
  59. data/lib/shoulda/matchers/doublespeak/proxy_implementation.rb +4 -3
  60. data/lib/shoulda/matchers/doublespeak/stub_implementation.rb +3 -3
  61. data/lib/shoulda/matchers/doublespeak/world.rb +21 -1
  62. data/lib/shoulda/matchers/integrations.rb +43 -0
  63. data/lib/shoulda/matchers/integrations/configuration.rb +68 -0
  64. data/lib/shoulda/matchers/integrations/configuration_error.rb +9 -0
  65. data/lib/shoulda/matchers/integrations/inclusion.rb +20 -0
  66. data/lib/shoulda/matchers/integrations/libraries.rb +15 -0
  67. data/lib/shoulda/matchers/integrations/libraries/action_controller.rb +31 -0
  68. data/lib/shoulda/matchers/integrations/libraries/active_model.rb +26 -0
  69. data/lib/shoulda/matchers/integrations/libraries/active_record.rb +26 -0
  70. data/lib/shoulda/matchers/integrations/libraries/missing_library.rb +19 -0
  71. data/lib/shoulda/matchers/integrations/libraries/rails.rb +30 -0
  72. data/lib/shoulda/matchers/integrations/rails.rb +12 -0
  73. data/lib/shoulda/matchers/integrations/registry.rb +28 -0
  74. data/lib/shoulda/matchers/integrations/test_frameworks.rb +16 -0
  75. data/lib/shoulda/matchers/integrations/test_frameworks/active_support_test_case.rb +37 -0
  76. data/lib/shoulda/matchers/integrations/test_frameworks/minitest_4.rb +36 -0
  77. data/lib/shoulda/matchers/integrations/test_frameworks/minitest_5.rb +37 -0
  78. data/lib/shoulda/matchers/integrations/test_frameworks/missing_test_framework.rb +40 -0
  79. data/lib/shoulda/matchers/integrations/test_frameworks/rspec.rb +29 -0
  80. data/lib/shoulda/matchers/integrations/test_frameworks/test_unit.rb +36 -0
  81. data/lib/shoulda/matchers/rails_shim.rb +0 -40
  82. data/lib/shoulda/matchers/version.rb +1 -1
  83. data/script/SUPPORTED_VERSIONS +1 -1
  84. data/script/update_gems_in_all_appraisals +14 -0
  85. data/shoulda-matchers.gemspec +2 -2
  86. data/spec/acceptance/active_model_integration_spec.rb +4 -1
  87. data/spec/acceptance/independent_matchers_spec.rb +6 -6
  88. data/spec/acceptance/multiple_libraries_integration_spec.rb +52 -0
  89. data/spec/acceptance/rails_integration_spec.rb +15 -5
  90. data/spec/acceptance_spec_helper.rb +8 -0
  91. data/spec/doublespeak_spec_helper.rb +14 -0
  92. data/spec/support/acceptance/adds_shoulda_matchers_to_project.rb +110 -0
  93. data/spec/support/acceptance/helpers.rb +2 -0
  94. data/spec/support/acceptance/helpers/base_helpers.rb +6 -1
  95. data/spec/support/acceptance/helpers/command_helpers.rb +6 -2
  96. data/spec/support/acceptance/helpers/minitest_helpers.rb +0 -8
  97. data/spec/support/acceptance/helpers/n_unit_helpers.rb +25 -0
  98. data/spec/support/acceptance/helpers/rspec_helpers.rb +2 -0
  99. data/spec/support/acceptance/helpers/step_helpers.rb +13 -19
  100. data/spec/support/acceptance/matchers/have_output.rb +1 -1
  101. data/spec/support/tests/bundle.rb +1 -1
  102. data/spec/support/tests/command_runner.rb +25 -13
  103. data/spec/support/tests/current_bundle.rb +47 -0
  104. data/spec/support/tests/database.rb +28 -0
  105. data/spec/support/tests/database_adapters/postgresql.rb +25 -0
  106. data/spec/support/tests/database_adapters/sqlite3.rb +26 -0
  107. data/spec/support/tests/database_configuration.rb +33 -0
  108. data/spec/support/tests/database_configuration_registry.rb +28 -0
  109. data/spec/support/tests/filesystem.rb +25 -2
  110. data/spec/support/unit/helpers/active_record_versions.rb +12 -0
  111. data/spec/support/unit/helpers/class_builder.rb +6 -2
  112. data/spec/support/unit/helpers/column_type_helpers.rb +26 -0
  113. data/spec/support/unit/helpers/controller_builder.rb +0 -28
  114. data/spec/support/unit/helpers/database_helpers.rb +18 -0
  115. data/spec/support/unit/helpers/model_builder.rb +38 -6
  116. data/spec/support/unit/helpers/rails_versions.rb +2 -2
  117. data/spec/support/unit/matchers/fail_with_message_including_matcher.rb +9 -8
  118. data/spec/support/unit/matchers/fail_with_message_matcher.rb +1 -1
  119. data/spec/support/unit/rails_application.rb +29 -13
  120. data/spec/support/unit/record_validating_confirmation_builder.rb +1 -2
  121. data/spec/support/unit/shared_examples/set_session_or_flash.rb +355 -0
  122. data/spec/unit/shoulda/matchers/action_controller/permit_matcher_spec.rb +433 -0
  123. data/spec/unit/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb +1 -5
  124. data/spec/unit/shoulda/matchers/action_controller/route_matcher_spec.rb +37 -0
  125. data/spec/unit/shoulda/matchers/action_controller/set_flash_matcher_spec.rb +23 -147
  126. data/spec/unit/shoulda/matchers/action_controller/set_session_matcher_spec.rb +8 -285
  127. data/spec/unit/shoulda/matchers/action_controller/set_session_or_flash_matcher_spec.rb +562 -0
  128. data/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb +81 -14
  129. data/spec/unit/shoulda/matchers/active_model/disallow_value_matcher_spec.rb +16 -8
  130. data/spec/unit/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb +101 -9
  131. data/spec/unit/shoulda/matchers/active_model/numericality_matchers/even_number_matcher_spec.rb +39 -1
  132. data/spec/unit/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher_spec.rb +39 -1
  133. data/spec/unit/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher_spec.rb +39 -0
  134. data/spec/unit/shoulda/matchers/active_model/validate_exclusion_of_matcher_spec.rb +0 -17
  135. data/spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb +0 -17
  136. data/spec/unit/shoulda/matchers/active_model/validate_length_of_matcher_spec.rb +0 -17
  137. data/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +838 -271
  138. data/spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +0 -19
  139. data/spec/unit/shoulda/matchers/active_record/association_matcher_spec.rb +93 -0
  140. data/spec/unit/shoulda/matchers/active_record/association_matchers/model_reflection_spec.rb +3 -3
  141. data/spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb +25 -0
  142. data/spec/unit/shoulda/matchers/active_record/validate_uniqueness_of_matcher_spec.rb +905 -0
  143. data/spec/unit/shoulda/matchers/doublespeak/double_collection_spec.rb +17 -11
  144. data/spec/unit/shoulda/matchers/doublespeak/double_implementation_registry_spec.rb +1 -1
  145. data/spec/unit/shoulda/matchers/doublespeak/double_spec.rb +144 -43
  146. data/spec/unit/shoulda/matchers/doublespeak/object_double_spec.rb +1 -1
  147. data/spec/unit/shoulda/matchers/doublespeak/proxy_implementation_spec.rb +36 -11
  148. data/spec/unit/shoulda/matchers/doublespeak/stub_implementation_spec.rb +29 -16
  149. data/spec/unit/shoulda/matchers/doublespeak/world_spec.rb +8 -5
  150. data/spec/unit/shoulda/matchers/doublespeak_spec.rb +1 -1
  151. data/spec/unit_spec_helper.rb +15 -14
  152. data/spec/warnings_spy.rb +1 -1
  153. metadata +68 -29
  154. data/docs.watchr +0 -5
  155. data/gemfiles/3.0.gemfile +0 -26
  156. data/gemfiles/3.0.gemfile.lock +0 -173
  157. data/gemfiles/3.1.gemfile +0 -32
  158. data/gemfiles/3.1.gemfile.lock +0 -212
  159. data/gemfiles/3.1_1.9.2.gemfile +0 -32
  160. data/gemfiles/3.1_1.9.2.gemfile.lock +0 -212
  161. data/gemfiles/3.2.gemfile +0 -33
  162. data/gemfiles/3.2.gemfile.lock +0 -212
  163. data/gemfiles/3.2_1.9.2.gemfile +0 -31
  164. data/gemfiles/3.2_1.9.2.gemfile.lock +0 -207
  165. data/lib/shoulda/matchers/assertion_error.rb +0 -27
  166. data/lib/shoulda/matchers/doublespeak/structs.rb +0 -10
  167. data/lib/shoulda/matchers/integrations/nunit_test_case_detection.rb +0 -39
  168. data/lib/shoulda/matchers/integrations/rspec.rb +0 -19
  169. data/lib/shoulda/matchers/integrations/test_unit.rb +0 -34
  170. data/spec/unit/shoulda/matchers/action_controller/strong_parameters_matcher_spec.rb +0 -331
  171. data/spec/unit/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb +0 -564
@@ -16,7 +16,7 @@ module UnitTests
16
16
  @actual = ex.message
17
17
  end
18
18
 
19
- @actual && @actual == expected
19
+ @actual && @actual == expected.sub(/\n\z/, '')
20
20
  end
21
21
 
22
22
  def failure_message
@@ -1,18 +1,26 @@
1
+ require_relative '../tests/bundle'
1
2
  require_relative '../tests/command_runner'
3
+ require_relative '../tests/database'
2
4
  require_relative '../tests/filesystem'
3
- require_relative '../tests/bundle'
5
+
6
+ require 'yaml'
4
7
 
5
8
  module UnitTests
6
9
  class RailsApplication
7
10
  def initialize
8
11
  @fs = Tests::Filesystem.new
9
12
  @bundle = Tests::Bundle.new
13
+ @database = Tests::Database.instance
10
14
  end
11
15
 
12
16
  def create
13
17
  fs.clean
14
18
  generate
15
- fs.within_project { install_gems }
19
+
20
+ fs.within_project do
21
+ install_gems
22
+ remove_unwanted_gems
23
+ end
16
24
  end
17
25
 
18
26
  def load
@@ -51,7 +59,7 @@ module UnitTests
51
59
 
52
60
  protected
53
61
 
54
- attr_reader :fs, :shell, :bundle
62
+ attr_reader :fs, :shell, :bundle, :database
55
63
 
56
64
  private
57
65
 
@@ -66,6 +74,7 @@ module UnitTests
66
74
  def generate
67
75
  rails_new
68
76
  fix_available_locales_warning
77
+ write_database_configuration
69
78
  end
70
79
 
71
80
  def rails_new
@@ -75,17 +84,17 @@ module UnitTests
75
84
  def fix_available_locales_warning
76
85
  # See here for more on this:
77
86
  # http://stackoverflow.com/questions/20361428/rails-i18n-validation-deprecation-warning
78
-
79
- filename = 'config/application.rb'
80
-
81
- lines = fs.read(filename).split("\n")
82
- lines.insert(-3, <<EOT)
87
+ fs.transform('config/application.rb') do |lines|
88
+ lines.insert(-3, <<-EOT)
83
89
  if I18n.respond_to?(:enforce_available_locales=)
84
90
  I18n.enforce_available_locales = false
85
91
  end
86
- EOT
92
+ EOT
93
+ end
94
+ end
87
95
 
88
- fs.write(filename, lines.join("\n"))
96
+ def write_database_configuration
97
+ YAML.dump(database.config.to_hash, fs.open('config/database.yml', 'w'))
89
98
  end
90
99
 
91
100
  def load_environment
@@ -93,15 +102,22 @@ EOT
93
102
  end
94
103
 
95
104
  def run_migrations
96
- ActiveRecord::Migration.verbose = false
97
- ActiveRecord::Migrator.migrate(migrations_directory)
105
+ fs.within_project do
106
+ run_command! 'bundle exec rake db:drop db:create db:migrate'
107
+ end
98
108
  end
99
109
 
100
110
  def install_gems
101
111
  bundle.install_gems
102
112
  end
103
113
 
104
- private
114
+ def remove_unwanted_gems
115
+ bundle.updating do
116
+ bundle.remove_gem 'debugger'
117
+ bundle.remove_gem 'byebug'
118
+ bundle.remove_gem 'web-console'
119
+ end
120
+ end
105
121
 
106
122
  def run_command!(*args)
107
123
  Tests::CommandRunner.run!(*args)
@@ -34,8 +34,7 @@ module UnitTests
34
34
  end
35
35
 
36
36
  def attribute_that_receives_error
37
- Shoulda::Matchers::RailsShim.
38
- validates_confirmation_of_error_attribute(self)
37
+ confirmation_attribute
39
38
  end
40
39
 
41
40
  protected
@@ -0,0 +1,355 @@
1
+ shared_examples_for 'set session or flash matcher' do
2
+ context 'without any qualifiers' do
3
+ it 'produces the right description' do
4
+ expected_description = "should set any key in #{store_name}"
5
+ matcher = set_store
6
+
7
+ expect(matcher.description).to eq expected_description
8
+ end
9
+
10
+ context 'in the positive' do
11
+ context 'if the store is not empty' do
12
+ it 'accepts' do
13
+ controller = controller_with_store('any key' => 'any value')
14
+ expect(controller).to set_store
15
+ end
16
+ end
17
+
18
+ context 'if the store is empty' do
19
+ it 'rejects' do
20
+ controller = controller_with_empty_store
21
+ expect(controller).not_to set_store
22
+ end
23
+
24
+ it 'produces the correct failure message' do
25
+ controller = controller_with_empty_store
26
+ expected_message = %<Expected #{controller.class} to set any key in #{store_name}, but it did not>
27
+
28
+ expect { expect(controller).to set_store }.
29
+ to fail_with_message(expected_message)
30
+ end
31
+ end
32
+ end
33
+
34
+ context 'in the negative' do
35
+ context 'if the given key is present in the store' do
36
+ it 'produces the correct failure message' do
37
+ controller = controller_with_store('any key' => 'any value')
38
+ expected_message = %<Expected #{controller.class} not to set any key in #{store_name}, but it did>
39
+ assertion = proc do
40
+ expect(controller).not_to set_store
41
+ end
42
+
43
+ expect(&assertion).to fail_with_message(expected_message)
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ context 'with #[]' do
50
+ it 'produces the right description' do
51
+ matcher = set_store['the key']
52
+ expected_description = %<should set #{store_name}["the key"]>
53
+
54
+ expect(matcher.description).to eq expected_description
55
+ end
56
+
57
+ context 'in the positive' do
58
+ context 'if the given key is present in the store' do
59
+ it 'accepts' do
60
+ controller = controller_with_store('the key' => 'any value')
61
+ expect(controller).to set_store['the key']
62
+ end
63
+ end
64
+
65
+ context 'if the given key is not present in the store' do
66
+ it 'rejects' do
67
+ controller = controller_with_empty_store
68
+ expect(controller).not_to set_store['the key']
69
+ end
70
+
71
+ it 'produces the correct failure message' do
72
+ controller = controller_with_empty_store
73
+ expected_message = %<Expected #{controller.class} to set #{store_name}["the key"], but it did not>
74
+ assertion = proc do
75
+ expect(controller).to set_store['the key']
76
+ end
77
+
78
+ expect(&assertion).to fail_with_message(expected_message)
79
+ end
80
+ end
81
+ end
82
+
83
+ context 'in the negative' do
84
+ context 'if the given key is present in the store' do
85
+ it 'produces the correct failure message' do
86
+ controller = controller_with_store('the key' => 'any value')
87
+ expected_message = %<Expected #{controller.class} not to set #{store_name}["the key"], but it did>
88
+ assertion = proc do
89
+ expect(controller).not_to set_store['the key']
90
+ end
91
+
92
+ expect(&assertion).to fail_with_message(expected_message)
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+ context 'with #to' do
99
+ context 'given a static value' do
100
+ it 'produces the right description' do
101
+ matcher = set_store.to('the value')
102
+ expected_description = %<should set any key in #{store_name} to "the value">
103
+
104
+ expect(matcher.description).to eq expected_description
105
+ end
106
+
107
+ context 'in the positive' do
108
+ context 'if the given value is present in the store' do
109
+ it 'accepts' do
110
+ controller = controller_with_store('any key' => 'the value')
111
+ expect(controller).to set_store.to('the value')
112
+ end
113
+
114
+ it 'accepts given a value of nil' do
115
+ controller = controller_with_store('any key' => nil)
116
+ expect(controller).to set_store.to(nil)
117
+ end
118
+
119
+ it 'accepts given a value of false' do
120
+ controller = controller_with_store('any key' => false)
121
+ expect(controller).to set_store.to(false)
122
+ end
123
+ end
124
+
125
+ context 'if the given value is not present in the store' do
126
+ it 'rejects' do
127
+ controller = controller_with_empty_store
128
+ expect(controller).not_to set_store.to('the value')
129
+ end
130
+
131
+ it 'rejects checking for nil' do
132
+ controller = controller_with_empty_store
133
+ expect(controller).not_to set_store.to(nil)
134
+ end
135
+
136
+ it 'produces the correct failure message' do
137
+ controller = controller_with_empty_store
138
+ expected_message = %<Expected #{controller.class} to set any key in #{store_name} to "the value", but it did not>
139
+ assertion = proc do
140
+ expect(controller).to set_store.to('the value')
141
+ end
142
+
143
+ expect(&assertion).to fail_with_message(expected_message)
144
+ end
145
+ end
146
+ end
147
+
148
+ context 'in the negative' do
149
+ context 'if the given value is present in the store' do
150
+ it 'produces the correct failure message' do
151
+ controller = controller_with_store('any key' => 'the value')
152
+ expected_message = %<Expected #{controller.class} not to set any key in #{store_name} to "the value", but it did>
153
+ assertion = proc do
154
+ expect(controller).not_to set_store.to('the value')
155
+ end
156
+
157
+ expect(&assertion).to fail_with_message(expected_message)
158
+ end
159
+ end
160
+ end
161
+ end
162
+
163
+ context 'given a regexp' do
164
+ it 'produces the right description' do
165
+ matcher = set_store.to(/value/)
166
+ expected_description = %<should set any key in #{store_name} to a value matching /value/>
167
+
168
+ expect(matcher.description).to eq expected_description
169
+ end
170
+
171
+ context 'in the positive' do
172
+ context 'if the given value is present in the store' do
173
+ it 'accepts' do
174
+ controller = controller_with_store('any key' => 'the value')
175
+ expect(controller).to set_store.to(/value/)
176
+ end
177
+
178
+ it 'accepts given a value of nil' do
179
+ controller = controller_with_store('any key' => nil)
180
+ expect(controller).to set_store.to(nil)
181
+ end
182
+
183
+ it 'accepts given a value of false' do
184
+ controller = controller_with_store('any key' => false)
185
+ expect(controller).to set_store.to(false)
186
+ end
187
+ end
188
+
189
+ context 'if the given value is not present in the store' do
190
+ it 'rejects' do
191
+ controller = controller_with_empty_store
192
+ expect(controller).not_to set_store.to(/value/)
193
+ end
194
+
195
+ it 'produces the correct failure message' do
196
+ controller = controller_with_empty_store
197
+ expected_message = %<Expected #{controller.class} to set any key in #{store_name} to a value matching /value/, but it did not>
198
+ assertion = proc do
199
+ expect(controller).to set_store.to(/value/)
200
+ end
201
+
202
+ expect(&assertion).to fail_with_message(expected_message)
203
+ end
204
+ end
205
+ end
206
+
207
+ context 'in the negative' do
208
+ context 'if the given value is present in the store' do
209
+ it 'produces the correct failure message' do
210
+ controller = controller_with_store('any key' => 'the value')
211
+ expected_message = %<Expected #{controller.class} not to set any key in #{store_name} to a value matching /value/, but it did>
212
+ assertion = proc do
213
+ expect(controller).not_to set_store.to(/value/)
214
+ end
215
+
216
+ expect(&assertion).to fail_with_message(expected_message)
217
+ end
218
+ end
219
+ end
220
+ end
221
+ end
222
+
223
+ context 'with #[] + #to' do
224
+ context 'given a static value' do
225
+ it 'produces the right description' do
226
+ expected_description = %<should set #{store_name}["the key"] to "the value">
227
+ matcher = set_store['the key'].to('the value')
228
+
229
+ expect(matcher.description).to eq expected_description
230
+ end
231
+
232
+ context 'in the positive' do
233
+ context 'if the given value is present in the store' do
234
+ it 'accepts' do
235
+ controller = controller_with_store('the key' => 'the value')
236
+ expect(controller).to set_store['the key'].to('the value')
237
+ end
238
+ end
239
+
240
+ context 'if the given value is not present in the store' do
241
+ it 'rejects' do
242
+ controller = controller_with_empty_store
243
+ expect(controller).not_to set_store['the key'].to('the value')
244
+ end
245
+
246
+ it 'produces the correct failure message' do
247
+ controller = controller_with_empty_store
248
+ expected_message = %<Expected #{controller.class} to set #{store_name}["the key"] to "the value", but it did not>
249
+ assertion = proc do
250
+ expect(controller).to set_store['the key'].to('the value')
251
+ end
252
+
253
+ expect(&assertion).to fail_with_message(expected_message)
254
+ end
255
+ end
256
+ end
257
+
258
+ context 'in the negative' do
259
+ context 'if the given value is present in the store' do
260
+ it 'produces the correct failure message' do
261
+ controller = controller_with_store('the key' => 'the value')
262
+ expected_message = %<Expected #{controller.class} not to set #{store_name}["the key"] to "the value", but it did>
263
+ assertion = proc do
264
+ expect(controller).not_to set_store['the key'].to('the value')
265
+ end
266
+
267
+ expect(&assertion).to fail_with_message(expected_message)
268
+ end
269
+ end
270
+ end
271
+ end
272
+
273
+ context 'given a dynamic value' do
274
+ it 'produces the right description' do
275
+ context = double('context', method_in_context: 'the value')
276
+ matcher = set_store['the key'].
277
+ in_context(context).
278
+ to { method_in_context }
279
+ expected_description = %<should set #{store_name}["the key"] to "the value">
280
+
281
+ expect(matcher.description).to eq expected_description
282
+ end
283
+
284
+ context 'in the positive' do
285
+ context 'if the value evaluated in the context is present in the store' do
286
+ it 'accepts' do
287
+ controller = controller_with_store('the key' => 'the value')
288
+ context = double('context', method_in_context: 'the value')
289
+
290
+ expect(controller).to set_store['the key'].
291
+ in_context(context).
292
+ to { method_in_context }
293
+ end
294
+ end
295
+
296
+ context 'if the value evaluated in the context is not present in the store' do
297
+ it 'rejects' do
298
+ controller = controller_with_empty_store
299
+ context = double('context', method_in_context: 'the value')
300
+
301
+ expect(controller).not_to set_store['the key'].
302
+ in_context(context).
303
+ to { method_in_context }
304
+ end
305
+
306
+ it 'produces the correct failure message' do
307
+ controller = controller_with_empty_store
308
+ context = double('context', method_in_context: 'the value')
309
+ expected_message = %<Expected #{controller.class} to set #{store_name}["the key"] to "the value", but it did not>
310
+ assertion = proc do
311
+ expect(controller).to set_store['the key'].
312
+ in_context(context).
313
+ to { method_in_context }
314
+ end
315
+
316
+ expect(&assertion).to fail_with_message(expected_message)
317
+ end
318
+ end
319
+ end
320
+
321
+ context 'in the negative' do
322
+ context 'if the value evaluated in the context is present in the store' do
323
+ it 'produces the correct failure message' do
324
+ context = double('context', method_in_context: 'the value')
325
+ controller = controller_with_store('the key' => 'the value')
326
+ expected_message = %<Expected #{controller.class} not to set #{store_name}["the key"] to "the value", but it did>
327
+ assertion = proc do
328
+ expect(controller).not_to set_store['the key'].
329
+ in_context(context).
330
+ to { method_in_context }
331
+ end
332
+
333
+ expect(&assertion).to fail_with_message(expected_message)
334
+ end
335
+ end
336
+ end
337
+ end
338
+ end
339
+
340
+ def controller_with_empty_store
341
+ build_fake_response
342
+ end
343
+
344
+ def controller_with_store(store_contents)
345
+ context = self
346
+
347
+ build_fake_response do
348
+ store = context.store_within(self)
349
+
350
+ store_contents.each do |key, value|
351
+ store[key] = value
352
+ end
353
+ end
354
+ end
355
+ end