sunspot_matchers_testunit 1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +27 -0
- data/MIT-LICENSE +21 -0
- data/README.markdown +238 -0
- data/Rakefile +11 -0
- data/lib/sunspot_matchers_testunit.rb +2 -0
- data/lib/sunspot_matchers_testunit/matchers.rb +317 -0
- data/lib/sunspot_matchers_testunit/sunspot_session_spy.rb +112 -0
- data/lib/sunspot_matchers_testunit/version.rb +3 -0
- data/sunspot_matchers_testunit.gemspec +21 -0
- data/test/sunspot_matchers_testunit_test.rb +702 -0
- metadata +121 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
sunspot_matchers_testunit (1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: http://rubygems.org/
|
8
|
+
specs:
|
9
|
+
builder (3.0.0)
|
10
|
+
escape (0.0.4)
|
11
|
+
pr_geohash (1.0.0)
|
12
|
+
rake (0.8.7)
|
13
|
+
rsolr (0.12.1)
|
14
|
+
builder (>= 2.1.2)
|
15
|
+
sunspot (1.2.1)
|
16
|
+
escape (= 0.0.4)
|
17
|
+
pr_geohash (~> 1.0)
|
18
|
+
rsolr (= 0.12.1)
|
19
|
+
|
20
|
+
PLATFORMS
|
21
|
+
ruby
|
22
|
+
|
23
|
+
DEPENDENCIES
|
24
|
+
bundler (>= 1.0.0)
|
25
|
+
rake
|
26
|
+
sunspot (~> 1.2.1)
|
27
|
+
sunspot_matchers_testunit!
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2011 Joseph Palermo, Pivotal Labs, Inc.
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE
|
data/README.markdown
ADDED
@@ -0,0 +1,238 @@
|
|
1
|
+
# Sunspot Matchers
|
2
|
+
|
3
|
+
[Sunspot](http://outoftime.github.com/sunspot/) is a great Ruby library for constructing searches against Solr. However,
|
4
|
+
because of the way the Sunspot DSL is constructed, it can be difficult to do simple assertions about your searches
|
5
|
+
without doing full integration tests.
|
6
|
+
|
7
|
+
The goal of these matchers are to make it easier to unit test search logic without having to construct the individual
|
8
|
+
fixture scenarios inside of Solr and then actually perform a search against Solr.
|
9
|
+
|
10
|
+
This is a direct port of the excellent [Sunspot Matchers](http://github.com/pivotal/sunspot_matchers) library by Joseph
|
11
|
+
Palermo, rewritten for use with Test::Unit.
|
12
|
+
|
13
|
+
# Installation
|
14
|
+
|
15
|
+
You will need to replace the Sunspot Session object with the spy provided. You can do this globally by putting the
|
16
|
+
following in a setup block or your test_helper.
|
17
|
+
|
18
|
+
def setup
|
19
|
+
Sunspot.session = SunspotMatchers::SunspotSessionSpy.new(Sunspot.session)
|
20
|
+
end
|
21
|
+
|
22
|
+
Keep in mind, this will prevent any test from actually hitting Solr, so if you have integration tests, you'll either
|
23
|
+
need to be more careful which tests you replace the session for, or you'll need to restore the original session before
|
24
|
+
those tests
|
25
|
+
|
26
|
+
Sunspot.session = Sunspot.session.original_session
|
27
|
+
|
28
|
+
You will also need to include the matchers in your tests. Again, this can be done globally in your test_helper.
|
29
|
+
|
30
|
+
require 'sunspot_matchers_testunit'
|
31
|
+
include SunspotMatchersTestunit
|
32
|
+
|
33
|
+
Alternately, you could include them into individual tests if needed.
|
34
|
+
|
35
|
+
# Matchers
|
36
|
+
|
37
|
+
## assert_is_search_for
|
38
|
+
|
39
|
+
If you perform a search against your Post model, you could write this assertion:
|
40
|
+
|
41
|
+
`assert_is_search_for Sunspot.session, Post`
|
42
|
+
|
43
|
+
Individual searches are stored in an array, so if you perform multiple, you'll have to match against them manually. Without
|
44
|
+
an explicit search specified, it will use the last one.
|
45
|
+
|
46
|
+
`assert_is_search_for Sunspot.session.searches.first, Post`
|
47
|
+
|
48
|
+
## assert_has_search_params
|
49
|
+
|
50
|
+
This is where the bulk of the functionality lies. There are seven types of search matches you can perform: `keywords`,
|
51
|
+
`with`, `without`, `paginate`, `order_by`, `facet`, and `boost`.
|
52
|
+
|
53
|
+
In all of the examples below, the arguments fully match the search terms. This is not expected or required. You can
|
54
|
+
have a dozen `with` restrictions on a search and still write an expectation on a single one of them.
|
55
|
+
|
56
|
+
Negative expectations also work correctly. `assert_has_no_search_params` will fail if the search actually includes the
|
57
|
+
provided arguments.
|
58
|
+
|
59
|
+
With all matchers, you can specify a `Proc` as the second argument, and perform multi statement expectations inside the
|
60
|
+
Proc. Keep in mind, that only the search type specified in the first argument will actually be checked. So if you specify
|
61
|
+
`keywords` and `with` restrictions in the same Proc, but you said `assert_has_search_params Sunspot.session, :keywords, ...`
|
62
|
+
the `with` restrictions are simply ignored.
|
63
|
+
|
64
|
+
### wildcard matching
|
65
|
+
|
66
|
+
keywords, with, without, and order_by support wildcard expectations using the `any_param` parameter:
|
67
|
+
|
68
|
+
Sunspot.search(Post) do
|
69
|
+
with :blog_id, 4
|
70
|
+
order_by :blog_id, :desc
|
71
|
+
end
|
72
|
+
|
73
|
+
assert_has_search_params Sunspot.session, [ :with, :blog_id, any_param ]
|
74
|
+
assert_has_search_params Sunspot.session, [ :order_by, :blog_id, any_param ]
|
75
|
+
assert_has_search_params Sunspot.session, [ :order_by, any_param ]
|
76
|
+
assert_has_no_search_params Sunspot.session, [ :order_by, :category_ids, any_param ]
|
77
|
+
|
78
|
+
### :keywords
|
79
|
+
|
80
|
+
You can match against a keyword search:
|
81
|
+
|
82
|
+
Sunspot.search(Post) do
|
83
|
+
keywords 'great pizza'
|
84
|
+
end
|
85
|
+
|
86
|
+
assert_has_search_params Sunspot.session, [ :keywords, 'great pizza' ]
|
87
|
+
|
88
|
+
### :with
|
89
|
+
|
90
|
+
You can match against a with restriction:
|
91
|
+
|
92
|
+
Sunspot.search(Post) do
|
93
|
+
with :author_name, 'Mark Twain'
|
94
|
+
end
|
95
|
+
|
96
|
+
assert_has_search_params Sunspot.session, [ :with, :author_name, 'Mark Twain' ]
|
97
|
+
|
98
|
+
Complex conditions can be matched by using a Proc instead of a value. Be aware that order does matter, not for
|
99
|
+
the actual results that would come out of Solr, but the matcher will fail of the order of `with` restrictions is
|
100
|
+
different.
|
101
|
+
|
102
|
+
Sunspot.search(Post) do
|
103
|
+
any_of do
|
104
|
+
with :category_ids, 1
|
105
|
+
with :category_ids, 2
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
assert_has_search_params Sunspot.session, [ :with, Proc.new {
|
110
|
+
any_of do
|
111
|
+
with :category_ids, 1
|
112
|
+
with :category_ids, 2
|
113
|
+
end
|
114
|
+
} ]
|
115
|
+
|
116
|
+
### :without
|
117
|
+
|
118
|
+
Without is nearly identical to with:
|
119
|
+
|
120
|
+
Sunspot.search(Post) do
|
121
|
+
without :author_name, 'Mark Twain'
|
122
|
+
end
|
123
|
+
|
124
|
+
assert_has_search_params Sunspot.session, [ :without, :author_name, 'Mark Twain' ]
|
125
|
+
|
126
|
+
### :paginate
|
127
|
+
|
128
|
+
You can also specify only page or per_page, both are not required.
|
129
|
+
|
130
|
+
Sunspot.search(Post) do
|
131
|
+
paginate :page => 3, :per_page => 15
|
132
|
+
end
|
133
|
+
|
134
|
+
assert_has_search_params Sunspot.session, [ :paginate, :page => 3, :per_page => 15 ]
|
135
|
+
|
136
|
+
### :order_by
|
137
|
+
|
138
|
+
Expectations on multiple orderings are supported using using the Proc format mentioned above.
|
139
|
+
|
140
|
+
Sunspot.search(Post) do
|
141
|
+
order_by :published_at, :desc
|
142
|
+
end
|
143
|
+
|
144
|
+
assert_has_search_params Sunspot.session, [ :order_by, :published_at, :desc ]
|
145
|
+
|
146
|
+
### :facet
|
147
|
+
|
148
|
+
Standard faceting expectation:
|
149
|
+
|
150
|
+
Sunspot.search(Post) do
|
151
|
+
facet :category_ids
|
152
|
+
end
|
153
|
+
|
154
|
+
assert_has_search_params Sunspot.session, [ :facet, :category_ids ]
|
155
|
+
|
156
|
+
Faceting where a query is excluded:
|
157
|
+
|
158
|
+
Sunspot.search(Post) do
|
159
|
+
category_filter = with(:category_ids, 2)
|
160
|
+
facet(:category_ids, :exclude => category_filter)
|
161
|
+
end
|
162
|
+
|
163
|
+
assert_has_search_params Sunspot.session, [ :facet, Proc.new {
|
164
|
+
category_filter = with(:category_ids, 2)
|
165
|
+
facet(:category_ids, :exclude => category_filter)
|
166
|
+
} ]
|
167
|
+
|
168
|
+
Query faceting:
|
169
|
+
|
170
|
+
Sunspot.search(Post) do
|
171
|
+
facet(:average_rating) do
|
172
|
+
row(1.0..2.0) do
|
173
|
+
with(:average_rating, 1.0..2.0)
|
174
|
+
end
|
175
|
+
row(2.0..3.0) do
|
176
|
+
with(:average_rating, 2.0..3.0)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
assert_has_search_params Sunspot.session, [ :facet, Proc.new {
|
182
|
+
facet(:average_rating) do
|
183
|
+
row(1.0..2.0) do
|
184
|
+
with(:average_rating, 1.0..2.0)
|
185
|
+
end
|
186
|
+
row(2.0..3.0) do
|
187
|
+
with(:average_rating, 2.0..3.0)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
} ]
|
191
|
+
|
192
|
+
### :boost
|
193
|
+
|
194
|
+
Field boost matching:
|
195
|
+
|
196
|
+
Sunspot.search(Post) do
|
197
|
+
keywords 'great pizza' do
|
198
|
+
boost_fields :body => 2.0
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
assert_has_search_params Sunspot.session, [ :boost, Proc.new {
|
203
|
+
keywords 'great pizza' do
|
204
|
+
boost_fields :body => 2.0
|
205
|
+
end
|
206
|
+
} ]
|
207
|
+
|
208
|
+
Boost query matching:
|
209
|
+
|
210
|
+
Sunspot.search(Post) do
|
211
|
+
keywords 'great pizza' do
|
212
|
+
boost(2.0) do
|
213
|
+
with :blog_id, 4
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
assert_has_search_params Sunspot.session, [ :boost, Proc.new {
|
219
|
+
keywords 'great pizza' do
|
220
|
+
boost(2.0) do
|
221
|
+
with :blog_id, 4
|
222
|
+
end
|
223
|
+
end
|
224
|
+
} ]
|
225
|
+
|
226
|
+
Boost function matching:
|
227
|
+
|
228
|
+
Sunspot.search(Post) do
|
229
|
+
keywords 'great pizza' do
|
230
|
+
boost(function { sum(:average_rating, product(:popularity, 10)) })
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
assert_has_search_params Sunspot.session, [ :boost, Proc.new {
|
235
|
+
keywords 'great pizza' do
|
236
|
+
boost(function { sum(:average_rating, product(:popularity, 10)) })
|
237
|
+
end
|
238
|
+
} ]
|
data/Rakefile
ADDED
@@ -0,0 +1,317 @@
|
|
1
|
+
require 'test/unit/assertions'
|
2
|
+
|
3
|
+
module SunspotMatchersTestunit
|
4
|
+
class BaseMatcher
|
5
|
+
attr_accessor :args
|
6
|
+
|
7
|
+
def initialize(session, args)
|
8
|
+
@session = session
|
9
|
+
@args = args
|
10
|
+
build_comparison_search
|
11
|
+
end
|
12
|
+
|
13
|
+
def build_comparison_search
|
14
|
+
@comparison_search = if(@args.last.is_a?(Proc))
|
15
|
+
SunspotMatchersTestunit::SunspotSessionSpy.new(@session).build_search(search_types, &args.last)
|
16
|
+
else
|
17
|
+
SunspotMatchersTestunit::SunspotSessionSpy.new(@session).build_search(search_types) do
|
18
|
+
send(search_method, *args)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def search_tuple
|
24
|
+
search_tuple = @session.is_a?(Array) ? @session : @session.searches.last
|
25
|
+
raise 'no search found' unless search_tuple
|
26
|
+
search_tuple
|
27
|
+
end
|
28
|
+
|
29
|
+
def actual_search
|
30
|
+
search_tuple.last
|
31
|
+
end
|
32
|
+
|
33
|
+
def search_types
|
34
|
+
search_tuple.first
|
35
|
+
end
|
36
|
+
|
37
|
+
def wildcard?
|
38
|
+
@args && @args.last == any_param
|
39
|
+
end
|
40
|
+
|
41
|
+
def field
|
42
|
+
@args && @args.first
|
43
|
+
end
|
44
|
+
|
45
|
+
def query_params_for_search(search)
|
46
|
+
search.instance_variable_get(:@query).to_params
|
47
|
+
end
|
48
|
+
|
49
|
+
def actual_params
|
50
|
+
@actual_params ||= query_params_for_search(actual_search)
|
51
|
+
end
|
52
|
+
|
53
|
+
def comparison_params
|
54
|
+
@comparison_params ||= query_params_for_search(@comparison_search)
|
55
|
+
end
|
56
|
+
|
57
|
+
def match?
|
58
|
+
differences.empty?
|
59
|
+
end
|
60
|
+
|
61
|
+
def missing_param_error_message
|
62
|
+
missing_params = differences
|
63
|
+
actual_values = missing_params.keys.collect {|key| "#{key} => #{actual_params[key]}"}
|
64
|
+
missing_values = missing_params.collect{ |key, value| "#{key} => #{value}"}
|
65
|
+
"expected search params: #{actual_values.join(' and ')} to match expected: #{missing_values.join(' and ')}"
|
66
|
+
end
|
67
|
+
|
68
|
+
def unexpected_match_error_message
|
69
|
+
actual_values = keys_to_compare.collect {|key| "#{key} => #{actual_params[key]}"}
|
70
|
+
comparison_values = keys_to_compare.collect {|key| "#{key} => #{comparison_params[key]}"}
|
71
|
+
"expected search params: #{actual_values.join(' and ')} NOT to match expected: #{comparison_values.join(' and ')}"
|
72
|
+
end
|
73
|
+
|
74
|
+
def differences
|
75
|
+
keys_to_compare.inject({}) do |hsh, key|
|
76
|
+
result = compare_key(key)
|
77
|
+
hsh[key] = result unless result.empty?
|
78
|
+
hsh
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def compare_key(key)
|
83
|
+
if(actual_params[key].is_a?(Array) || comparison_params[key].is_a?(Array))
|
84
|
+
compare_multi_value(actual_params[key], comparison_params[key])
|
85
|
+
else
|
86
|
+
compare_single_value(actual_params[key], comparison_matcher_for_key(key))
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def comparison_matcher_for_key(key)
|
91
|
+
if wildcard? && wildcard_matcher_for_keys.has_key?(key)
|
92
|
+
wildcard_matcher_for_keys[key]
|
93
|
+
else
|
94
|
+
comparison_params[key]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def compare_single_value(actual, comparison)
|
99
|
+
if comparison.is_a?(Regexp)
|
100
|
+
return [] if comparison =~ actual
|
101
|
+
return [comparison.source]
|
102
|
+
end
|
103
|
+
return [comparison] unless actual == comparison
|
104
|
+
[]
|
105
|
+
end
|
106
|
+
|
107
|
+
def compare_multi_value(actual, comparison)
|
108
|
+
filter_values(comparison).reject do |value|
|
109
|
+
next false unless actual
|
110
|
+
value_matcher = Regexp.new(Regexp.escape(value))
|
111
|
+
actual.any?{ |actual_value| actual_value =~ value_matcher }
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def filter_values(values)
|
116
|
+
return values unless wildcard?
|
117
|
+
field_matcher = Regexp.new(field.to_s)
|
118
|
+
values.select{ |value| field_matcher =~ value }.collect{|value| value.gsub(/:.*/, '')}
|
119
|
+
end
|
120
|
+
|
121
|
+
def wildcard_matcher_for_keys
|
122
|
+
{}
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
class HaveSearchParams
|
127
|
+
include Test::Unit::Assertions
|
128
|
+
|
129
|
+
def initialize(session, method, *args)
|
130
|
+
@session = session
|
131
|
+
@method = method
|
132
|
+
@args = args
|
133
|
+
end
|
134
|
+
|
135
|
+
def get_matcher
|
136
|
+
matcher_class = case @method
|
137
|
+
when :with
|
138
|
+
WithMatcher
|
139
|
+
when :without
|
140
|
+
WithoutMatcher
|
141
|
+
when :keywords
|
142
|
+
KeywordsMatcher
|
143
|
+
when :boost
|
144
|
+
BoostMatcher
|
145
|
+
when :facet
|
146
|
+
FacetMatcher
|
147
|
+
when :order_by
|
148
|
+
OrderByMatcher
|
149
|
+
when :paginate
|
150
|
+
PaginationMatcher
|
151
|
+
end
|
152
|
+
matcher_class.new(@session, @args)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def assert_has_search_params(session, method_and_args)
|
157
|
+
method, *args = method_and_args
|
158
|
+
matcher = HaveSearchParams.new(session, method, *args).get_matcher
|
159
|
+
assert matcher.match?, matcher.missing_param_error_message
|
160
|
+
end
|
161
|
+
|
162
|
+
def assert_has_no_search_params(session, method_and_args)
|
163
|
+
method, *args = method_and_args
|
164
|
+
matcher = HaveSearchParams.new(session, method, *args).get_matcher
|
165
|
+
assert !matcher.match?, matcher.unexpected_match_error_message
|
166
|
+
end
|
167
|
+
|
168
|
+
class WithMatcher < BaseMatcher
|
169
|
+
def search_method
|
170
|
+
:with
|
171
|
+
end
|
172
|
+
|
173
|
+
def keys_to_compare
|
174
|
+
[:fq]
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
class WithoutMatcher < BaseMatcher
|
179
|
+
def search_method
|
180
|
+
:without
|
181
|
+
end
|
182
|
+
|
183
|
+
def keys_to_compare
|
184
|
+
[:fq]
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
class KeywordsMatcher < BaseMatcher
|
189
|
+
def search_method
|
190
|
+
:keywords
|
191
|
+
end
|
192
|
+
|
193
|
+
def keys_to_compare
|
194
|
+
[:q, :qf]
|
195
|
+
end
|
196
|
+
|
197
|
+
def wildcard_matcher_for_keys
|
198
|
+
{:q => /./, :qf => /./}
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
class BoostMatcher < BaseMatcher
|
203
|
+
def search_method
|
204
|
+
:boost
|
205
|
+
end
|
206
|
+
|
207
|
+
|
208
|
+
def keys_to_compare
|
209
|
+
[:qf, :bq, :bf]
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
class FacetMatcher < BaseMatcher
|
214
|
+
def search_method
|
215
|
+
:facet
|
216
|
+
end
|
217
|
+
|
218
|
+
def keys_to_compare
|
219
|
+
comparison_params.keys.select {|key| /facet/ =~ key.to_s}
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
class OrderByMatcher < BaseMatcher
|
224
|
+
def search_method
|
225
|
+
:order_by
|
226
|
+
end
|
227
|
+
|
228
|
+
def keys_to_compare
|
229
|
+
[:sort]
|
230
|
+
end
|
231
|
+
|
232
|
+
def wildcard_matcher_for_keys
|
233
|
+
return {:sort => /./} if field_wildcard?
|
234
|
+
param = comparison_params[:sort]
|
235
|
+
regex = Regexp.new(param.gsub(any_param, '.*'))
|
236
|
+
{:sort => regex}
|
237
|
+
end
|
238
|
+
|
239
|
+
def field_wildcard?
|
240
|
+
@args.first == any_param
|
241
|
+
end
|
242
|
+
|
243
|
+
def direction_wildcard?
|
244
|
+
@args.length == 2 && @args.last == any_param
|
245
|
+
end
|
246
|
+
|
247
|
+
def args
|
248
|
+
return @args unless direction_wildcard?
|
249
|
+
@args[0...-1] + [:asc]
|
250
|
+
end
|
251
|
+
|
252
|
+
def build_comparison_search
|
253
|
+
if field_wildcard?
|
254
|
+
@comparison_params = {:sort => any_param}
|
255
|
+
elsif direction_wildcard?
|
256
|
+
super
|
257
|
+
@comparison_params = comparison_params
|
258
|
+
@comparison_params[:sort].gsub!("asc", any_param)
|
259
|
+
else
|
260
|
+
super
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
class PaginationMatcher < BaseMatcher
|
266
|
+
def search_method
|
267
|
+
:paginate
|
268
|
+
end
|
269
|
+
|
270
|
+
def keys_to_compare
|
271
|
+
[:rows, :start]
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
class BeASearchFor
|
276
|
+
def initialize(session, expected_class)
|
277
|
+
@session = session
|
278
|
+
@expected_class = expected_class
|
279
|
+
end
|
280
|
+
|
281
|
+
def match?
|
282
|
+
search_types.include?(@expected_class)
|
283
|
+
end
|
284
|
+
|
285
|
+
def search_tuple
|
286
|
+
search_tuple = @session.is_a?(Array) ? @session : @session.searches.last
|
287
|
+
raise 'no search found' unless search_tuple
|
288
|
+
search_tuple
|
289
|
+
end
|
290
|
+
|
291
|
+
def search_types
|
292
|
+
search_tuple.first
|
293
|
+
end
|
294
|
+
|
295
|
+
def failure_message_for_should
|
296
|
+
"expected search class: #{search_types.join(' and ')} to match expected class: #{@expected_class}"
|
297
|
+
end
|
298
|
+
|
299
|
+
def failure_message_for_should_not
|
300
|
+
"expected search class: #{search_types.join(' and ')} NOT to match expected class: #{@expected_class}"
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
def assert_is_search_for(session, expected_class)
|
305
|
+
matcher = BeASearchFor.new(session, expected_class)
|
306
|
+
assert matcher.match?, matcher.failure_message_for_should
|
307
|
+
end
|
308
|
+
|
309
|
+
def assert_is_not_search_for(session, expected_class)
|
310
|
+
matcher = BeASearchFor.new(session, expected_class)
|
311
|
+
assert !matcher.match?, matcher.failure_message_for_should_not
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
def any_param
|
316
|
+
"ANY_PARAM"
|
317
|
+
end
|