|
157 | 157 | end |
158 | 158 |
|
159 | 159 | # Match an arbitrary field of a response to a given value. |
160 | | -RSpec::Matchers.define :match_response do |expected_pairs, test| |
| 160 | +RSpec::Matchers.define :match_response do |pairs, test| |
161 | 161 |
|
162 | 162 | match do |response| |
163 | | - mismatched_values(sanitize_pairs(expected_pairs), test, response).empty? |
| 163 | + pairs = sanitize_pairs(pairs) |
| 164 | + compare_pairs(pairs, response, test).empty? |
164 | 165 | end |
165 | 166 |
|
166 | 167 | failure_message do |response| |
167 | | - "the pair/value #{mismatched_values(sanitize_pairs(expected_pairs), test, response)}" + |
168 | | - " does not match the pair/value in the response #{response}" |
| 168 | + "the actual response pair/value(s) #{@mismatched_pairs}" + |
| 169 | + " does not match the pair/value(s) in the response #{response}" |
169 | 170 | end |
170 | 171 |
|
171 | 172 | def sanitize_pairs(expected_pairs) |
172 | 173 | # sql test returns results at '$body' key. See sql/translate.yml |
173 | 174 | @pairs ||= expected_pairs['$body'] ? expected_pairs['$body'] : expected_pairs |
174 | 175 | end |
175 | 176 |
|
176 | | - def mismatched_values(pairs, test, response) |
177 | | - @mismatched_values ||= begin |
178 | | - if pairs.is_a?(String) |
179 | | - # Must return an empty list if there are no mismatched values |
180 | | - compare_string_response(pairs, response) ? [] : [ pairs ] |
181 | | - else |
182 | | - compare_hash(pairs, response, test) |
183 | | - end |
| 177 | + def compare_pairs(expected_pairs, response, test) |
| 178 | + @mismatched_pairs = {} |
| 179 | + if expected_pairs.is_a?(String) |
| 180 | + @mismatched_pairs = expected_pairs unless compare_string_response(expected_pairs, response) |
| 181 | + else |
| 182 | + compare_hash(expected_pairs, response, test) |
184 | 183 | end |
| 184 | + @mismatched_pairs |
185 | 185 | end |
186 | 186 |
|
187 | | - def compare_hash(expected_keys_values, response, test) |
188 | | - expected_keys_values.reject do |expected_key, expected_value| |
| 187 | + def compare_hash(expected_pairs, actual_hash, test) |
| 188 | + expected_pairs.each do |expected_key, expected_value| |
189 | 189 | # Select the values that don't match, used for the failure message. |
190 | 190 |
|
191 | | - if expected_value.is_a?(Hash) |
192 | | - compare_hash(response[expected_key], expected_value, test) |
193 | | - elsif expected_value.is_a?(String) |
194 | | - split_key = TestFile::Test.split_and_parse_key(expected_key).collect do |k| |
195 | | - test.get_cached_value(k) |
| 191 | + # Find the value to compare in the response |
| 192 | + split_key = TestFile::Test.split_and_parse_key(expected_key).collect do |k| |
| 193 | + # Sometimes the expected *key* is a cached value from a previous request. |
| 194 | + test.get_cached_value(k) |
| 195 | + end |
| 196 | + actual_value = TestFile::Test.find_value_in_document(split_key, actual_hash) |
| 197 | + # Sometimes the key includes dots. See watcher/put_watch/60_put_watch_with_action_condition.yml |
| 198 | + actual_value = TestFile::Test.find_value_in_document(expected_key, actual_hash) if actual_value.nil? |
| 199 | + |
| 200 | + # Sometimes the expected *value* is a cached value from a previous request. |
| 201 | + # See test api_key/10_basic.yml |
| 202 | + expected_value = test.get_cached_value(expected_value) |
| 203 | + |
| 204 | + case expected_value |
| 205 | + when Hash |
| 206 | + compare_hash(expected_value, actual_value, test) |
| 207 | + when Array |
| 208 | + unless compare_array(expected_value, actual_value, test, actual_hash) |
| 209 | + @mismatched_pairs.merge!(expected_key => expected_value) |
196 | 210 | end |
197 | | - actual_value = TestFile::Test.find_value_in_document(split_key, response) |
198 | | - |
199 | | - # Sometimes the expected value is a cached value from a previous request. |
200 | | - # See test api_key/10_basic.yml |
201 | | - expected_value = test.get_cached_value(expected_value) |
202 | | - |
203 | | - # When you must match a regex. For example: |
204 | | - # match: {task: '/.+:\d+/'} |
205 | | - if expected_value.is_a?(String) && expected_value[0] == "/" && expected_value[-1] == "/" |
206 | | - /#{expected_value.tr("/", "")}/ =~ actual_value |
207 | | - elsif expected_key == '' |
208 | | - expected_value == response |
209 | | - else |
210 | | - actual_value == expected_value |
| 211 | + when String |
| 212 | + unless compare_string(expected_value, actual_value, test, actual_hash) |
| 213 | + @mismatched_pairs.merge!(expected_key => expected_value) |
| 214 | + end |
| 215 | + else |
| 216 | + unless expected_value == actual_value |
| 217 | + @mismatched_pairs.merge!(expected_key => expected_value) |
211 | 218 | end |
212 | 219 | end |
213 | 220 | end |
214 | 221 | end |
215 | 222 |
|
| 223 | + def compare_string(expected, actual_value, test, response) |
| 224 | + # When you must match a regex. For example: |
| 225 | + # match: {task: '/.+:\d+/'} |
| 226 | + if expected[0] == "/" && expected[-1] == "/" |
| 227 | + /#{expected.tr("/", "")}/ =~ actual_value |
| 228 | + elsif expected == '' |
| 229 | + actual_value == response |
| 230 | + else |
| 231 | + expected == actual_value |
| 232 | + end |
| 233 | + end |
| 234 | + |
| 235 | + def compare_array(expected, actual, test, response) |
| 236 | + expected.each_with_index do |value, i| |
| 237 | + case value |
| 238 | + when Hash |
| 239 | + return false unless compare_hash(value, actual[i], test) |
| 240 | + when Array |
| 241 | + return false unless compare_array(value, actual[i], test, response) |
| 242 | + when String |
| 243 | + return false unless compare_string(value, actual[i], test, response) |
| 244 | + end |
| 245 | + end |
| 246 | + end |
| 247 | + |
216 | 248 | def compare_string_response(expected_string, response) |
217 | 249 | regexp = Regexp.new(expected_string.strip[1..-2], Regexp::EXTENDED|Regexp::MULTILINE) |
218 | 250 | regexp =~ response |
|
0 commit comments