load_balanced_tire 0.1
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.
- data/.gitignore +14 -0
- data/.travis.yml +29 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +20 -0
- data/README.markdown +760 -0
- data/Rakefile +78 -0
- data/examples/rails-application-template.rb +249 -0
- data/examples/tire-dsl.rb +876 -0
- data/lib/tire.rb +55 -0
- data/lib/tire/alias.rb +296 -0
- data/lib/tire/configuration.rb +30 -0
- data/lib/tire/dsl.rb +43 -0
- data/lib/tire/http/client.rb +62 -0
- data/lib/tire/http/clients/curb.rb +61 -0
- data/lib/tire/http/clients/faraday.rb +71 -0
- data/lib/tire/http/response.rb +27 -0
- data/lib/tire/index.rb +361 -0
- data/lib/tire/logger.rb +60 -0
- data/lib/tire/model/callbacks.rb +40 -0
- data/lib/tire/model/import.rb +26 -0
- data/lib/tire/model/indexing.rb +128 -0
- data/lib/tire/model/naming.rb +100 -0
- data/lib/tire/model/percolate.rb +99 -0
- data/lib/tire/model/persistence.rb +71 -0
- data/lib/tire/model/persistence/attributes.rb +143 -0
- data/lib/tire/model/persistence/finders.rb +66 -0
- data/lib/tire/model/persistence/storage.rb +69 -0
- data/lib/tire/model/search.rb +307 -0
- data/lib/tire/results/collection.rb +114 -0
- data/lib/tire/results/item.rb +86 -0
- data/lib/tire/results/pagination.rb +54 -0
- data/lib/tire/rubyext/hash.rb +8 -0
- data/lib/tire/rubyext/ruby_1_8.rb +7 -0
- data/lib/tire/rubyext/symbol.rb +11 -0
- data/lib/tire/search.rb +188 -0
- data/lib/tire/search/facet.rb +74 -0
- data/lib/tire/search/filter.rb +28 -0
- data/lib/tire/search/highlight.rb +37 -0
- data/lib/tire/search/query.rb +186 -0
- data/lib/tire/search/scan.rb +114 -0
- data/lib/tire/search/script_field.rb +23 -0
- data/lib/tire/search/sort.rb +25 -0
- data/lib/tire/tasks.rb +135 -0
- data/lib/tire/utils.rb +17 -0
- data/lib/tire/version.rb +22 -0
- data/test/fixtures/articles/1.json +1 -0
- data/test/fixtures/articles/2.json +1 -0
- data/test/fixtures/articles/3.json +1 -0
- data/test/fixtures/articles/4.json +1 -0
- data/test/fixtures/articles/5.json +1 -0
- data/test/integration/active_model_indexing_test.rb +51 -0
- data/test/integration/active_model_searchable_test.rb +114 -0
- data/test/integration/active_record_searchable_test.rb +446 -0
- data/test/integration/boolean_queries_test.rb +43 -0
- data/test/integration/count_test.rb +34 -0
- data/test/integration/custom_score_queries_test.rb +88 -0
- data/test/integration/dis_max_queries_test.rb +68 -0
- data/test/integration/dsl_search_test.rb +22 -0
- data/test/integration/explanation_test.rb +44 -0
- data/test/integration/facets_test.rb +259 -0
- data/test/integration/filtered_queries_test.rb +66 -0
- data/test/integration/filters_test.rb +63 -0
- data/test/integration/fuzzy_queries_test.rb +20 -0
- data/test/integration/highlight_test.rb +64 -0
- data/test/integration/index_aliases_test.rb +122 -0
- data/test/integration/index_mapping_test.rb +43 -0
- data/test/integration/index_store_test.rb +96 -0
- data/test/integration/index_update_document_test.rb +111 -0
- data/test/integration/mongoid_searchable_test.rb +309 -0
- data/test/integration/percolator_test.rb +111 -0
- data/test/integration/persistent_model_test.rb +130 -0
- data/test/integration/prefix_query_test.rb +43 -0
- data/test/integration/query_return_version_test.rb +70 -0
- data/test/integration/query_string_test.rb +52 -0
- data/test/integration/range_queries_test.rb +36 -0
- data/test/integration/reindex_test.rb +46 -0
- data/test/integration/results_test.rb +39 -0
- data/test/integration/scan_test.rb +56 -0
- data/test/integration/script_fields_test.rb +38 -0
- data/test/integration/sort_test.rb +36 -0
- data/test/integration/text_query_test.rb +39 -0
- data/test/models/active_model_article.rb +31 -0
- data/test/models/active_model_article_with_callbacks.rb +49 -0
- data/test/models/active_model_article_with_custom_document_type.rb +7 -0
- data/test/models/active_model_article_with_custom_index_name.rb +7 -0
- data/test/models/active_record_models.rb +122 -0
- data/test/models/article.rb +15 -0
- data/test/models/mongoid_models.rb +97 -0
- data/test/models/persistent_article.rb +11 -0
- data/test/models/persistent_article_in_namespace.rb +12 -0
- data/test/models/persistent_article_with_casting.rb +28 -0
- data/test/models/persistent_article_with_defaults.rb +11 -0
- data/test/models/persistent_articles_with_custom_index_name.rb +10 -0
- data/test/models/supermodel_article.rb +17 -0
- data/test/models/validated_model.rb +11 -0
- data/test/test_helper.rb +93 -0
- data/test/unit/active_model_lint_test.rb +17 -0
- data/test/unit/configuration_test.rb +74 -0
- data/test/unit/http_client_test.rb +76 -0
- data/test/unit/http_response_test.rb +49 -0
- data/test/unit/index_alias_test.rb +275 -0
- data/test/unit/index_test.rb +894 -0
- data/test/unit/logger_test.rb +125 -0
- data/test/unit/model_callbacks_test.rb +116 -0
- data/test/unit/model_import_test.rb +71 -0
- data/test/unit/model_persistence_test.rb +528 -0
- data/test/unit/model_search_test.rb +913 -0
- data/test/unit/results_collection_test.rb +281 -0
- data/test/unit/results_item_test.rb +162 -0
- data/test/unit/rubyext_test.rb +66 -0
- data/test/unit/search_facet_test.rb +153 -0
- data/test/unit/search_filter_test.rb +42 -0
- data/test/unit/search_highlight_test.rb +46 -0
- data/test/unit/search_query_test.rb +301 -0
- data/test/unit/search_scan_test.rb +113 -0
- data/test/unit/search_script_field_test.rb +26 -0
- data/test/unit/search_sort_test.rb +50 -0
- data/test/unit/search_test.rb +499 -0
- data/test/unit/tire_test.rb +126 -0
- data/tire.gemspec +90 -0
- metadata +549 -0
@@ -0,0 +1,281 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Tire
|
4
|
+
|
5
|
+
class ResultsCollectionTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
context "Collection" do
|
8
|
+
setup do
|
9
|
+
begin; Object.send(:remove_const, :Rails); rescue; end
|
10
|
+
Configuration.reset
|
11
|
+
@default_response = { 'hits' => { 'hits' => [{'_id' => 1, '_score' => 1, '_source' => {:title => 'Test'}},
|
12
|
+
{'_id' => 2},
|
13
|
+
{'_id' => 3}] } }
|
14
|
+
end
|
15
|
+
|
16
|
+
should "be iterable" do
|
17
|
+
assert_respond_to Results::Collection.new(@default_response), :each
|
18
|
+
assert_respond_to Results::Collection.new(@default_response), :size
|
19
|
+
assert_nothing_raised do
|
20
|
+
Results::Collection.new(@default_response).each { |item| item.id + 1 }
|
21
|
+
Results::Collection.new(@default_response).map { |item| item.id + 1 }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
should "have size/length" do
|
26
|
+
assert_equal 3, Results::Collection.new(@default_response).size
|
27
|
+
assert_equal 3, Results::Collection.new(@default_response).length
|
28
|
+
end
|
29
|
+
|
30
|
+
should "allow access to items" do
|
31
|
+
assert_not_nil Results::Collection.new(@default_response)[1]
|
32
|
+
assert_equal 2, Results::Collection.new(@default_response)[1][:id]
|
33
|
+
end
|
34
|
+
|
35
|
+
should "be initialized with parsed json" do
|
36
|
+
assert_nothing_raised do
|
37
|
+
collection = Results::Collection.new( @default_response )
|
38
|
+
assert_equal 3, collection.results.count
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
should "be populated lazily" do
|
43
|
+
collection = Results::Collection.new(@default_response)
|
44
|
+
assert_nil collection.instance_variable_get(:@results)
|
45
|
+
end
|
46
|
+
|
47
|
+
should "store passed options" do
|
48
|
+
collection = Results::Collection.new( @default_response, :per_page => 20, :page => 2 )
|
49
|
+
assert_equal 20, collection.options[:per_page]
|
50
|
+
assert_equal 2, collection.options[:page]
|
51
|
+
end
|
52
|
+
|
53
|
+
should "be will_paginate compatible" do
|
54
|
+
collection = Results::Collection.new(@default_response)
|
55
|
+
%w(total_pages offset current_page per_page total_entries).each do |method|
|
56
|
+
assert_respond_to collection, method
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
should "be kaminari compatible" do
|
61
|
+
collection = Results::Collection.new(@default_response)
|
62
|
+
%w(limit_value total_count num_pages offset_value).each do |method|
|
63
|
+
assert_respond_to collection, method
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "wrapping results" do
|
68
|
+
|
69
|
+
setup do
|
70
|
+
@response = { 'hits' => { 'hits' => [ { '_id' => 1, '_score' => 0.5, '_index' => 'testing', '_type' => 'article', '_source' => { :title => 'Test', :body => 'Lorem' } } ] } }
|
71
|
+
end
|
72
|
+
|
73
|
+
should "wrap hits in Item by default" do
|
74
|
+
document = Results::Collection.new(@response).first
|
75
|
+
assert_kind_of Results::Item, document
|
76
|
+
assert_equal 'Test', document.title
|
77
|
+
end
|
78
|
+
|
79
|
+
should "NOT allow access to raw underlying Hash in Item" do
|
80
|
+
document = Results::Collection.new(@response).first
|
81
|
+
assert_nil document[:_source]
|
82
|
+
assert_nil document['_source']
|
83
|
+
end
|
84
|
+
|
85
|
+
should "allow wrapping hits in a Hash" do
|
86
|
+
Configuration.wrapper(Hash)
|
87
|
+
|
88
|
+
document = Results::Collection.new(@response).first
|
89
|
+
assert_kind_of Hash, document
|
90
|
+
assert_raise(NoMethodError) { document.title }
|
91
|
+
assert_equal 'Test', document['_source'][:title]
|
92
|
+
end
|
93
|
+
|
94
|
+
should "allow wrapping hits in custom class" do
|
95
|
+
Configuration.wrapper(Article)
|
96
|
+
|
97
|
+
article = Results::Collection.new(@response).first
|
98
|
+
assert_kind_of Article, article
|
99
|
+
assert_equal 'Test', article.title
|
100
|
+
end
|
101
|
+
|
102
|
+
should "return score" do
|
103
|
+
document = Results::Collection.new(@response).first
|
104
|
+
assert_equal 0.5, document._score
|
105
|
+
end
|
106
|
+
|
107
|
+
should "return id" do
|
108
|
+
document = Results::Collection.new(@response).first
|
109
|
+
assert_equal 1, document.id
|
110
|
+
end
|
111
|
+
|
112
|
+
should "return index" do
|
113
|
+
document = Results::Collection.new(@response).first
|
114
|
+
assert_equal "testing", document._index
|
115
|
+
end
|
116
|
+
|
117
|
+
should "return type" do
|
118
|
+
document = Results::Collection.new(@response).first
|
119
|
+
assert_equal "article", document._type
|
120
|
+
end
|
121
|
+
|
122
|
+
should "properly decode type" do
|
123
|
+
@response = { 'hits' => { 'hits' => [ { '_id' => 1, '_type' => 'foo%2Fbar' } ] } }
|
124
|
+
document = Results::Collection.new(@response).first
|
125
|
+
assert_equal "foo/bar", document._type
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
context "wrapping results with selected fields" do
|
131
|
+
# When limiting fields from _source to return ES returns them prefixed, not as "real" Hashes.
|
132
|
+
# Underlying issue: https://github.com/karmi/tire/pull/31#issuecomment-1340967
|
133
|
+
#
|
134
|
+
setup do
|
135
|
+
Configuration.reset
|
136
|
+
@default_response = { 'hits' => { 'hits' =>
|
137
|
+
[ { '_id' => 1, '_score' => 0.5, '_index' => 'testing', '_type' => 'article',
|
138
|
+
'fields' => {
|
139
|
+
'title' => 'Knee Deep in JSON',
|
140
|
+
'crazy.field' => 'CRAAAAZY!',
|
141
|
+
'_source.artist' => {
|
142
|
+
'name' => 'Elastiq',
|
143
|
+
'meta' => {
|
144
|
+
'favorited' => 1000,
|
145
|
+
'url' => 'http://first.fm/abc123/xyz567'
|
146
|
+
}
|
147
|
+
},
|
148
|
+
'_source.track.info.duration' => {
|
149
|
+
'minutes' => 3
|
150
|
+
}
|
151
|
+
} } ] } }
|
152
|
+
collection = Results::Collection.new(@default_response)
|
153
|
+
@item = collection.first
|
154
|
+
end
|
155
|
+
|
156
|
+
should "return fields from the first level" do
|
157
|
+
assert_equal 'Knee Deep in JSON', @item.title
|
158
|
+
end
|
159
|
+
|
160
|
+
should "return fields from the _source prefixed and nested fields" do
|
161
|
+
assert_equal 'Elastiq', @item.artist.name
|
162
|
+
assert_equal 1000, @item.artist.meta.favorited
|
163
|
+
assert_equal 3, @item.track.info.duration.minutes
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
context "while paginating results" do
|
169
|
+
|
170
|
+
setup do
|
171
|
+
@default_response = { 'hits' => { 'hits' => [{'_id' => 1, '_score' => 1, '_source' => {:title => 'Test'}},
|
172
|
+
{'_id' => 2},
|
173
|
+
{'_id' => 3},
|
174
|
+
{'_id' => 4}],
|
175
|
+
'total' => 4 },
|
176
|
+
'took' => 1 }
|
177
|
+
@collection = Results::Collection.new( @default_response, :per_page => 1, :page => 2 )
|
178
|
+
end
|
179
|
+
|
180
|
+
should "return total entries" do
|
181
|
+
assert_equal 4, @collection.total
|
182
|
+
assert_equal 4, @collection.total_entries
|
183
|
+
end
|
184
|
+
|
185
|
+
should "return total pages" do
|
186
|
+
assert_equal 4, @collection.total_pages
|
187
|
+
@collection = Results::Collection.new( @default_response, :per_page => 2, :page => 2 )
|
188
|
+
assert_equal 2, @collection.total_pages
|
189
|
+
@collection = Results::Collection.new( @default_response, :per_page => 3, :page => 2 )
|
190
|
+
assert_equal 2, @collection.total_pages
|
191
|
+
end
|
192
|
+
|
193
|
+
should "return total pages when per_page option not set" do
|
194
|
+
collection = Results::Collection.new( @default_response, :page => 1 )
|
195
|
+
assert_equal 1, collection.total_pages
|
196
|
+
end
|
197
|
+
|
198
|
+
should "return current page" do
|
199
|
+
assert_equal 2, @collection.current_page
|
200
|
+
end
|
201
|
+
|
202
|
+
should "return current page for empty result" do
|
203
|
+
collection = Results::Collection.new( { 'hits' => { 'hits' => [], 'total' => 0 } } )
|
204
|
+
assert_equal 1, collection.current_page
|
205
|
+
end
|
206
|
+
|
207
|
+
should "return previous page" do
|
208
|
+
assert_equal 1, @collection.previous_page
|
209
|
+
end
|
210
|
+
|
211
|
+
should "return next page" do
|
212
|
+
assert_equal 3, @collection.next_page
|
213
|
+
end
|
214
|
+
|
215
|
+
end
|
216
|
+
|
217
|
+
context "with eager loading" do
|
218
|
+
setup do
|
219
|
+
@response = { 'hits' => { 'hits' => [ {'_id' => 1, '_type' => 'active_record_article'},
|
220
|
+
{'_id' => 2, '_type' => 'active_record_article'},
|
221
|
+
{'_id' => 3, '_type' => 'active_record_article'}] } }
|
222
|
+
ActiveRecordArticle.stubs(:inspect).returns("<ActiveRecordArticle>")
|
223
|
+
end
|
224
|
+
|
225
|
+
should "load the records via model find method from database" do
|
226
|
+
ActiveRecordArticle.expects(:find).with([1,2,3]).
|
227
|
+
returns([ Results::Item.new(:id => 3),
|
228
|
+
Results::Item.new(:id => 1),
|
229
|
+
Results::Item.new(:id => 2) ])
|
230
|
+
Results::Collection.new(@response, :load => true).results
|
231
|
+
end
|
232
|
+
|
233
|
+
should "pass the :load option Hash to model find metod" do
|
234
|
+
ActiveRecordArticle.expects(:find).with([1,2,3], :include => 'comments').
|
235
|
+
returns([ Results::Item.new(:id => 3),
|
236
|
+
Results::Item.new(:id => 1),
|
237
|
+
Results::Item.new(:id => 2) ])
|
238
|
+
Results::Collection.new(@response, :load => { :include => 'comments' }).results
|
239
|
+
end
|
240
|
+
|
241
|
+
should "preserve the order of records returned from search" do
|
242
|
+
ActiveRecordArticle.expects(:find).with([1,2,3]).
|
243
|
+
returns([ Results::Item.new(:id => 3),
|
244
|
+
Results::Item.new(:id => 1),
|
245
|
+
Results::Item.new(:id => 2) ])
|
246
|
+
assert_equal [1,2,3], Results::Collection.new(@response, :load => true).results.map(&:id)
|
247
|
+
end
|
248
|
+
|
249
|
+
should "raise error when model class cannot be inferred from _type" do
|
250
|
+
assert_raise(NameError) do
|
251
|
+
response = { 'hits' => { 'hits' => [ {'_id' => 1, '_type' => 'hic_sunt_leones'}] } }
|
252
|
+
Results::Collection.new(response, :load => true).results
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
should "raise error when _type is missing" do
|
257
|
+
assert_raise(NoMethodError) do
|
258
|
+
response = { 'hits' => { 'hits' => [ {'_id' => 1}] } }
|
259
|
+
Results::Collection.new(response, :load => true).results
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
should "return empty array for empty hits" do
|
264
|
+
response = { 'hits' => {
|
265
|
+
'hits' => [],
|
266
|
+
'total' => 4
|
267
|
+
},
|
268
|
+
'took' => 1 }
|
269
|
+
@collection = Results::Collection.new( response, :load => true )
|
270
|
+
assert @collection.empty?, 'Collection should be empty'
|
271
|
+
assert @collection.results.empty?, 'Collection results should be empty'
|
272
|
+
assert_equal 0, @collection.size
|
273
|
+
end
|
274
|
+
|
275
|
+
end
|
276
|
+
|
277
|
+
end
|
278
|
+
|
279
|
+
end
|
280
|
+
|
281
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Tire
|
4
|
+
class ResultsItemTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
# ActiveModel compatibility tests
|
7
|
+
#
|
8
|
+
def setup
|
9
|
+
super
|
10
|
+
begin; Object.send(:remove_const, :Rails); rescue; end
|
11
|
+
@model = Results::Item.new :title => 'Test'
|
12
|
+
end
|
13
|
+
include ActiveModel::Lint::Tests
|
14
|
+
|
15
|
+
context "Item" do
|
16
|
+
|
17
|
+
setup do
|
18
|
+
@document = Results::Item.new :title => 'Test',
|
19
|
+
:author => { :name => 'Kafka' },
|
20
|
+
:awards => { :best_fiction => { :year => '1925' } }
|
21
|
+
end
|
22
|
+
|
23
|
+
should "be initialized with a Hash or Hash like object" do
|
24
|
+
assert_raise(ArgumentError) { Results::Item.new('FUUUUUUU') }
|
25
|
+
|
26
|
+
assert_nothing_raised do
|
27
|
+
d = Results::Item.new(:id => 1)
|
28
|
+
assert_instance_of Results::Item, d
|
29
|
+
end
|
30
|
+
|
31
|
+
assert_nothing_raised do
|
32
|
+
class AlmostHash < Hash; end
|
33
|
+
d = Results::Item.new(AlmostHash.new(:id => 1))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
should "have an 'id' method" do
|
38
|
+
a = Results::Item.new(:_id => 1)
|
39
|
+
b = Results::Item.new(:id => 1)
|
40
|
+
assert_equal 1, a.id
|
41
|
+
assert_equal 1, b.id
|
42
|
+
end
|
43
|
+
|
44
|
+
should "have a 'type' method" do
|
45
|
+
a = Results::Item.new(:_type => 'foo')
|
46
|
+
b = Results::Item.new(:type => 'foo')
|
47
|
+
assert_equal 'foo', a.type
|
48
|
+
assert_equal 'foo', b.type
|
49
|
+
end
|
50
|
+
|
51
|
+
should "respond to :to_indexed_json" do
|
52
|
+
assert_respond_to Results::Item.new, :to_indexed_json
|
53
|
+
end
|
54
|
+
|
55
|
+
should "retrieve simple values from underlying hash" do
|
56
|
+
assert_equal 'Test', @document[:title]
|
57
|
+
end
|
58
|
+
|
59
|
+
should "retrieve hash values from underlying hash" do
|
60
|
+
assert_equal 'Kafka', @document[:author][:name]
|
61
|
+
end
|
62
|
+
|
63
|
+
should "allow to retrieve value by methods" do
|
64
|
+
assert_not_nil @document.title
|
65
|
+
assert_equal 'Test', @document.title
|
66
|
+
end
|
67
|
+
|
68
|
+
should "return nil for non-existing keys/methods" do
|
69
|
+
assert_nothing_raised { @document.whatever }
|
70
|
+
assert_nil @document.whatever
|
71
|
+
end
|
72
|
+
|
73
|
+
should "not care about symbols or strings in keys" do
|
74
|
+
@document = Results::Item.new 'title' => 'Test'
|
75
|
+
assert_not_nil @document.title
|
76
|
+
assert_equal 'Test', @document.title
|
77
|
+
end
|
78
|
+
|
79
|
+
should "not care about symbols or strings in composite keys" do
|
80
|
+
@document = Results::Item.new :highlight => { 'name.ngrams' => 'abc' }
|
81
|
+
|
82
|
+
assert_not_nil @document.highlight['name.ngrams']
|
83
|
+
assert_equal 'abc', @document.highlight['name.ngrams']
|
84
|
+
assert_equal @document.highlight['name.ngrams'], @document.highlight['name.ngrams'.to_sym]
|
85
|
+
end
|
86
|
+
|
87
|
+
should "allow to retrieve values from nested hashes" do
|
88
|
+
assert_not_nil @document.author.name
|
89
|
+
assert_equal 'Kafka', @document.author.name
|
90
|
+
end
|
91
|
+
|
92
|
+
should "wrap arrays" do
|
93
|
+
@document = Results::Item.new :stats => [1, 2, 3]
|
94
|
+
assert_equal [1, 2, 3], @document.stats
|
95
|
+
end
|
96
|
+
|
97
|
+
should "wrap hashes in arrays" do
|
98
|
+
@document = Results::Item.new :comments => [{:title => 'one'}, {:title => 'two'}]
|
99
|
+
assert_equal 2, @document.comments.size
|
100
|
+
assert_instance_of Results::Item, @document.comments.first
|
101
|
+
assert_equal 'one', @document.comments.first.title
|
102
|
+
assert_equal 'two', @document.comments.last.title
|
103
|
+
end
|
104
|
+
|
105
|
+
should "be an Item instance" do
|
106
|
+
assert_instance_of Tire::Results::Item, @document
|
107
|
+
end
|
108
|
+
|
109
|
+
should "be convertible to hash" do
|
110
|
+
assert_instance_of Hash, @document.to_hash
|
111
|
+
assert_instance_of Hash, @document.to_hash[:author]
|
112
|
+
assert_instance_of Hash, @document.to_hash[:awards][:best_fiction]
|
113
|
+
|
114
|
+
assert_equal 'Kafka', @document.to_hash[:author][:name]
|
115
|
+
assert_equal '1925', @document.to_hash[:awards][:best_fiction][:year]
|
116
|
+
end
|
117
|
+
|
118
|
+
should "be inspectable" do
|
119
|
+
assert_match /<Item .* title|Item .* author/, @document.inspect
|
120
|
+
end
|
121
|
+
|
122
|
+
context "within Rails" do
|
123
|
+
|
124
|
+
setup do
|
125
|
+
module ::Rails
|
126
|
+
end
|
127
|
+
|
128
|
+
class ::FakeRailsModel
|
129
|
+
extend ActiveModel::Naming
|
130
|
+
include ActiveModel::Conversion
|
131
|
+
def self.find(id, options); new; end
|
132
|
+
end
|
133
|
+
|
134
|
+
@document = Results::Item.new :id => 1, :_type => 'fake_rails_model', :title => 'Test'
|
135
|
+
end
|
136
|
+
|
137
|
+
should "be an instance of model, based on _type" do
|
138
|
+
assert_equal FakeRailsModel, @document.class
|
139
|
+
end
|
140
|
+
|
141
|
+
should "be inspectable with masquerade" do
|
142
|
+
assert_match /<Item \(FakeRailsModel\)/, @document.inspect
|
143
|
+
end
|
144
|
+
|
145
|
+
should "return proper singular and plural forms" do
|
146
|
+
assert_equal 'fake_rails_model', ActiveModel::Naming.singular(@document)
|
147
|
+
assert_equal 'fake_rails_models', ActiveModel::Naming.plural(@document)
|
148
|
+
end
|
149
|
+
|
150
|
+
should "instantiate itself for deep hashes, not a Ruby class corresponding to type" do
|
151
|
+
document = Results::Item.new :_type => 'my_model', :title => 'Test', :author => { :name => 'John' }
|
152
|
+
|
153
|
+
assert_equal Tire::Results::Item, document.class
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Tire
|
4
|
+
|
5
|
+
class RubyCoreExtensionsTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
context "Hash" do
|
8
|
+
|
9
|
+
context "with no to_json method provided" do
|
10
|
+
|
11
|
+
setup do
|
12
|
+
@hash = { :one => 1}
|
13
|
+
# Undefine the `to_json` method...
|
14
|
+
::Hash.class_eval { remove_method(:to_json) rescue nil }
|
15
|
+
# ... and reload the extension, so it's added
|
16
|
+
load 'tire/rubyext/hash.rb'
|
17
|
+
end
|
18
|
+
|
19
|
+
should "have its own to_json method" do
|
20
|
+
assert_respond_to( @hash, :to_json )
|
21
|
+
assert_equal '{"one":1}', @hash.to_json
|
22
|
+
end
|
23
|
+
|
24
|
+
should "allow to pass options to to_json for compatibility" do
|
25
|
+
assert_nothing_raised do
|
26
|
+
assert_equal '{"one":1}', @hash.to_json({})
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
should "have a to_json method from a JSON serialization library" do
|
33
|
+
assert_respond_to( {}, :to_json )
|
34
|
+
assert_equal '{"one":1}', { :one => 1}.to_json
|
35
|
+
end
|
36
|
+
|
37
|
+
should "have to_indexed_json method doing the same as to_json" do
|
38
|
+
[{}, { 1 => 2 }, { 3 => 4, 5 => 6 }, { nil => [7,8,9] }].each do |h|
|
39
|
+
assert_equal MultiJson.decode(h.to_json), MultiJson.decode(h.to_indexed_json)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
should "properly serialize Time into JSON" do
|
44
|
+
json = { :time => Time.mktime(2011, 01, 01, 11, 00).to_json }.to_json
|
45
|
+
assert_match /"2011-01-01T11:00:00.*"/, MultiJson.decode(json)['time']
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
context "Array" do
|
51
|
+
|
52
|
+
should "encode itself to JSON" do
|
53
|
+
assert_equal '["one","two"]', ['one','two'].to_json
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
context "Ruby Test::Unit" do
|
59
|
+
should "actually return true from assert..." do
|
60
|
+
assert_equal true, assert(true)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|