ssickles-tire 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. data/.gitignore +14 -0
  2. data/.travis.yml +13 -0
  3. data/Gemfile +4 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.markdown +760 -0
  6. data/Rakefile +78 -0
  7. data/examples/rails-application-template.rb +249 -0
  8. data/examples/tire-dsl.rb +876 -0
  9. data/lib/tire.rb +52 -0
  10. data/lib/tire/alias.rb +296 -0
  11. data/lib/tire/configuration.rb +30 -0
  12. data/lib/tire/dsl.rb +43 -0
  13. data/lib/tire/http/client.rb +62 -0
  14. data/lib/tire/http/clients/curb.rb +61 -0
  15. data/lib/tire/http/response.rb +27 -0
  16. data/lib/tire/index.rb +345 -0
  17. data/lib/tire/logger.rb +60 -0
  18. data/lib/tire/model/callbacks.rb +40 -0
  19. data/lib/tire/model/import.rb +26 -0
  20. data/lib/tire/model/indexing.rb +128 -0
  21. data/lib/tire/model/naming.rb +100 -0
  22. data/lib/tire/model/percolate.rb +99 -0
  23. data/lib/tire/model/persistence.rb +72 -0
  24. data/lib/tire/model/persistence/attributes.rb +143 -0
  25. data/lib/tire/model/persistence/finders.rb +66 -0
  26. data/lib/tire/model/persistence/storage.rb +71 -0
  27. data/lib/tire/model/search.rb +305 -0
  28. data/lib/tire/results/collection.rb +114 -0
  29. data/lib/tire/results/item.rb +83 -0
  30. data/lib/tire/results/pagination.rb +54 -0
  31. data/lib/tire/rubyext/hash.rb +8 -0
  32. data/lib/tire/rubyext/ruby_1_8.rb +54 -0
  33. data/lib/tire/rubyext/symbol.rb +11 -0
  34. data/lib/tire/search.rb +160 -0
  35. data/lib/tire/search/facet.rb +70 -0
  36. data/lib/tire/search/filter.rb +28 -0
  37. data/lib/tire/search/highlight.rb +37 -0
  38. data/lib/tire/search/query.rb +151 -0
  39. data/lib/tire/search/scan.rb +114 -0
  40. data/lib/tire/search/sort.rb +25 -0
  41. data/lib/tire/tasks.rb +135 -0
  42. data/lib/tire/utils.rb +17 -0
  43. data/lib/tire/version.rb +22 -0
  44. data/test/fixtures/articles/1.json +1 -0
  45. data/test/fixtures/articles/2.json +1 -0
  46. data/test/fixtures/articles/3.json +1 -0
  47. data/test/fixtures/articles/4.json +1 -0
  48. data/test/fixtures/articles/5.json +1 -0
  49. data/test/integration/active_model_indexing_test.rb +51 -0
  50. data/test/integration/active_model_searchable_test.rb +114 -0
  51. data/test/integration/active_record_searchable_test.rb +446 -0
  52. data/test/integration/boolean_queries_test.rb +43 -0
  53. data/test/integration/count_test.rb +34 -0
  54. data/test/integration/custom_score_queries_test.rb +88 -0
  55. data/test/integration/dsl_search_test.rb +22 -0
  56. data/test/integration/explanation_test.rb +44 -0
  57. data/test/integration/facets_test.rb +232 -0
  58. data/test/integration/filtered_queries_test.rb +66 -0
  59. data/test/integration/filters_test.rb +63 -0
  60. data/test/integration/fuzzy_queries_test.rb +20 -0
  61. data/test/integration/highlight_test.rb +64 -0
  62. data/test/integration/index_aliases_test.rb +122 -0
  63. data/test/integration/index_mapping_test.rb +43 -0
  64. data/test/integration/index_store_test.rb +96 -0
  65. data/test/integration/mongoid_searchable_test.rb +309 -0
  66. data/test/integration/percolator_test.rb +111 -0
  67. data/test/integration/persistent_model_test.rb +117 -0
  68. data/test/integration/query_return_version_test.rb +70 -0
  69. data/test/integration/query_string_test.rb +52 -0
  70. data/test/integration/range_queries_test.rb +36 -0
  71. data/test/integration/reindex_test.rb +46 -0
  72. data/test/integration/results_test.rb +39 -0
  73. data/test/integration/scan_test.rb +56 -0
  74. data/test/integration/sort_test.rb +36 -0
  75. data/test/integration/text_query_test.rb +39 -0
  76. data/test/models/active_model_article.rb +31 -0
  77. data/test/models/active_model_article_with_callbacks.rb +49 -0
  78. data/test/models/active_model_article_with_custom_document_type.rb +7 -0
  79. data/test/models/active_model_article_with_custom_index_name.rb +7 -0
  80. data/test/models/active_record_models.rb +122 -0
  81. data/test/models/article.rb +15 -0
  82. data/test/models/mongoid_models.rb +97 -0
  83. data/test/models/persistent_article.rb +11 -0
  84. data/test/models/persistent_article_in_namespace.rb +12 -0
  85. data/test/models/persistent_article_with_casting.rb +28 -0
  86. data/test/models/persistent_article_with_defaults.rb +11 -0
  87. data/test/models/persistent_articles_with_custom_index_name.rb +10 -0
  88. data/test/models/supermodel_article.rb +17 -0
  89. data/test/models/validated_model.rb +11 -0
  90. data/test/test_helper.rb +88 -0
  91. data/test/unit/active_model_lint_test.rb +17 -0
  92. data/test/unit/configuration_test.rb +74 -0
  93. data/test/unit/http_client_test.rb +76 -0
  94. data/test/unit/http_response_test.rb +49 -0
  95. data/test/unit/index_alias_test.rb +275 -0
  96. data/test/unit/index_test.rb +841 -0
  97. data/test/unit/logger_test.rb +125 -0
  98. data/test/unit/model_callbacks_test.rb +116 -0
  99. data/test/unit/model_import_test.rb +71 -0
  100. data/test/unit/model_persistence_test.rb +516 -0
  101. data/test/unit/model_search_test.rb +899 -0
  102. data/test/unit/results_collection_test.rb +281 -0
  103. data/test/unit/results_item_test.rb +155 -0
  104. data/test/unit/rubyext_test.rb +60 -0
  105. data/test/unit/search_facet_test.rb +153 -0
  106. data/test/unit/search_filter_test.rb +42 -0
  107. data/test/unit/search_highlight_test.rb +46 -0
  108. data/test/unit/search_query_test.rb +242 -0
  109. data/test/unit/search_scan_test.rb +113 -0
  110. data/test/unit/search_sort_test.rb +50 -0
  111. data/test/unit/search_test.rb +455 -0
  112. data/test/unit/tire_test.rb +126 -0
  113. data/tire.gemspec +85 -0
  114. metadata +506 -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,155 @@
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', :author => { :name => 'Kafka' }
19
+ end
20
+
21
+ should "be initialized with a Hash or Hash like object" do
22
+ assert_raise(ArgumentError) { Results::Item.new('FUUUUUUU') }
23
+
24
+ assert_nothing_raised do
25
+ d = Results::Item.new(:id => 1)
26
+ assert_instance_of Results::Item, d
27
+ end
28
+
29
+ assert_nothing_raised do
30
+ class AlmostHash < Hash; end
31
+ d = Results::Item.new(AlmostHash.new(:id => 1))
32
+ end
33
+ end
34
+
35
+ should "have an 'id' method" do
36
+ a = Results::Item.new(:_id => 1)
37
+ b = Results::Item.new(:id => 1)
38
+ assert_equal 1, a.id
39
+ assert_equal 1, b.id
40
+ end
41
+
42
+ should "have a 'type' method" do
43
+ a = Results::Item.new(:_type => 'foo')
44
+ b = Results::Item.new(:type => 'foo')
45
+ assert_equal 'foo', a.type
46
+ assert_equal 'foo', b.type
47
+ end
48
+
49
+ should "respond to :to_indexed_json" do
50
+ assert_respond_to Results::Item.new, :to_indexed_json
51
+ end
52
+
53
+ should "retrieve simple values from underlying hash" do
54
+ assert_equal 'Test', @document[:title]
55
+ end
56
+
57
+ should "retrieve hash values from underlying hash" do
58
+ assert_equal 'Kafka', @document[:author][:name]
59
+ end
60
+
61
+ should "allow to retrieve value by methods" do
62
+ assert_not_nil @document.title
63
+ assert_equal 'Test', @document.title
64
+ end
65
+
66
+ should "return nil for non-existing keys/methods" do
67
+ assert_nothing_raised { @document.whatever }
68
+ assert_nil @document.whatever
69
+ end
70
+
71
+ should "not care about symbols or strings in keys" do
72
+ @document = Results::Item.new 'title' => 'Test'
73
+ assert_not_nil @document.title
74
+ assert_equal 'Test', @document.title
75
+ end
76
+
77
+ should "not care about symbols or strings in composite keys" do
78
+ @document = Results::Item.new :highlight => { 'name.ngrams' => 'abc' }
79
+
80
+ assert_not_nil @document.highlight['name.ngrams']
81
+ assert_equal 'abc', @document.highlight['name.ngrams']
82
+ assert_equal @document.highlight['name.ngrams'], @document.highlight['name.ngrams'.to_sym]
83
+ end
84
+
85
+ should "allow to retrieve values from nested hashes" do
86
+ assert_not_nil @document.author.name
87
+ assert_equal 'Kafka', @document.author.name
88
+ end
89
+
90
+ should "wrap arrays" do
91
+ @document = Results::Item.new :stats => [1, 2, 3]
92
+ assert_equal [1, 2, 3], @document.stats
93
+ end
94
+
95
+ should "wrap hashes in arrays" do
96
+ @document = Results::Item.new :comments => [{:title => 'one'}, {:title => 'two'}]
97
+ assert_equal 2, @document.comments.size
98
+ assert_instance_of Results::Item, @document.comments.first
99
+ assert_equal 'one', @document.comments.first.title
100
+ assert_equal 'two', @document.comments.last.title
101
+ end
102
+
103
+ should "be an Item instance" do
104
+ assert_instance_of Tire::Results::Item, @document
105
+ end
106
+
107
+ should "be convertible to hash" do
108
+ assert_instance_of Hash, @document.to_hash
109
+ end
110
+
111
+ should "be inspectable" do
112
+ assert_match /<Item title|Item author/, @document.inspect
113
+ end
114
+
115
+ context "within Rails" do
116
+
117
+ setup do
118
+ module ::Rails
119
+ end
120
+
121
+ class ::FakeRailsModel
122
+ extend ActiveModel::Naming
123
+ include ActiveModel::Conversion
124
+ def self.find(id, options); new; end
125
+ end
126
+
127
+ @document = Results::Item.new :id => 1, :_type => 'fake_rails_model', :title => 'Test'
128
+ end
129
+
130
+ should "be an instance of model, based on _type" do
131
+ assert_equal FakeRailsModel, @document.class
132
+ end
133
+
134
+ should "be inspectable with masquerade" do
135
+ assert_match /<Item \(FakeRailsModel\)/, @document.inspect
136
+ end
137
+
138
+ should "return proper singular and plural forms" do
139
+ assert_equal 'fake_rails_model', ActiveModel::Naming.singular(@document)
140
+ assert_equal 'fake_rails_models', ActiveModel::Naming.plural(@document)
141
+ end
142
+
143
+ should "instantiate itself for deep hashes, not a Ruby class corresponding to type" do
144
+ document = Results::Item.new :_type => 'my_model', :title => 'Test', :author => { :name => 'John' }
145
+
146
+ assert_equal Tire::Results::Item, document.class
147
+ end
148
+
149
+ end
150
+
151
+ end
152
+
153
+ end
154
+
155
+ end
@@ -0,0 +1,60 @@
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
+ end
59
+
60
+ end