arkenstone-open 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/codacy-analysis.yml +46 -0
  3. data/.gitignore +19 -0
  4. data/.rubocop.yml +5 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +16 -0
  7. data/Gemfile +21 -0
  8. data/Gemfile.lock +101 -0
  9. data/LICENSE.txt +11 -0
  10. data/README.md +87 -0
  11. data/Rakefile +36 -0
  12. data/arkenstone.gemspec +27 -0
  13. data/lib/arkenstone/associations/resources.rb +76 -0
  14. data/lib/arkenstone/associations.rb +389 -0
  15. data/lib/arkenstone/document.rb +289 -0
  16. data/lib/arkenstone/enumerable/query_list.rb +20 -0
  17. data/lib/arkenstone/errors/no_url_error.rb +14 -0
  18. data/lib/arkenstone/helpers.rb +18 -0
  19. data/lib/arkenstone/network/env.rb +19 -0
  20. data/lib/arkenstone/network/hook.rb +74 -0
  21. data/lib/arkenstone/network/network.rb +72 -0
  22. data/lib/arkenstone/query_builder.rb +84 -0
  23. data/lib/arkenstone/queryable.rb +38 -0
  24. data/lib/arkenstone/timestamps.rb +25 -0
  25. data/lib/arkenstone/validation/validation_error.rb +34 -0
  26. data/lib/arkenstone/validation/validations.rb +192 -0
  27. data/lib/arkenstone/version.rb +5 -0
  28. data/lib/arkenstone.rb +22 -0
  29. data/test/associations/test_document_overrides.rb +50 -0
  30. data/test/associations/test_has_and_belongs_to_many.rb +80 -0
  31. data/test/dummy/app/models/association.rb +35 -0
  32. data/test/dummy/app/models/superuser.rb +8 -0
  33. data/test/dummy/app/models/user.rb +10 -0
  34. data/test/spec_helper.rb +16 -0
  35. data/test/test_arkenstone.rb +354 -0
  36. data/test/test_arkenstone_hook_inheritance.rb +39 -0
  37. data/test/test_associations.rb +327 -0
  38. data/test/test_enumerables.rb +36 -0
  39. data/test/test_environment.rb +14 -0
  40. data/test/test_helpers.rb +18 -0
  41. data/test/test_hooks.rb +104 -0
  42. data/test/test_query_builder.rb +163 -0
  43. data/test/test_queryable.rb +59 -0
  44. data/test/test_validations.rb +197 -0
  45. metadata +133 -0
@@ -0,0 +1,327 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ class AssociationsTest < Test::Unit::TestCase
6
+ def setup
7
+ @model = AssociatedUser.new
8
+ @model.id = 100
9
+ @dummy_things = [{ 'id' => 100, 'name' => 'test' }, { 'id' => 200, 'name' => 'dummy data' }]
10
+
11
+ stub_request(:get, "#{AssociatedUser.arkenstone_url}100/things").to_return do |_req|
12
+ { body: @dummy_things.to_json }
13
+ end
14
+
15
+ stub_request(:get, "#{AssociatedUser.arkenstone_url}100/roles").to_return(body: '')
16
+
17
+ @dummy_resource = { 'id' => 50, 'name' => 'Resource 1' }
18
+ stub_request(:get, "#{AssociatedUser.arkenstone_url}100/resource").to_return do |_req|
19
+ if @dummy_resource.nil?
20
+ { status: 200 }
21
+ else
22
+ { body: @dummy_resource.to_json }
23
+ end
24
+ end
25
+ end
26
+
27
+ def test_associations_dont_clobber_existing_methods
28
+ AssociatedUser.add_association_method 'test_method' do
29
+ 'replaced'
30
+ end
31
+ model = AssociatedUser.new
32
+ assert(model.test_method == 'on AssociatedUser')
33
+ # model = UserWithMethods.new
34
+ # assert(model.things == 'on UserWithMethods')
35
+ end
36
+
37
+ def test_has_many_creates_child_array
38
+ assert(AssociatedUser.method_defined?(:things))
39
+ assert(@model.things.nil? == false)
40
+ assert(@model.things != [])
41
+ assert(@model.things.count == 2)
42
+
43
+ assert(@model.roles == [])
44
+ end
45
+
46
+ def test_has_many_creates_cached_method
47
+ assert(AssociatedUser.method_defined?(:cached_things))
48
+ assert(@model.cached_things.count == 2)
49
+ end
50
+
51
+ def test_has_many_creates_add_child
52
+ stub_request(:post, "#{AssociatedUser.arkenstone_url}100/things").to_return do |_req|
53
+ @dummy_things << { 'id' => 500, 'name' => 'new thing' }
54
+ { status: 200 }
55
+ end
56
+ assert(AssociatedUser.method_defined?(:add_thing))
57
+ new_thing = Thing.new
58
+ new_thing.name = 'new thing'
59
+ new_thing.id = 500
60
+ @model.add_thing new_thing
61
+ assert(@model.cached_things.count == 3)
62
+ end
63
+
64
+ def test_has_many_creates_remove_child
65
+ stub_request(:delete, "#{AssociatedUser.arkenstone_url}100/things/100").to_return do |_req|
66
+ @dummy_things = [{ 'id' => 200, 'name' => 'dummy data' }]
67
+ { status: 200 }
68
+ end
69
+
70
+ assert(AssociatedUser.method_defined?(:remove_thing))
71
+ bad_thing = Thing.new
72
+ bad_thing.id = 100
73
+ @model.remove_thing bad_thing
74
+ assert(@model.cached_things.count == 1)
75
+ assert(@model.cached_things[0].id == 200)
76
+ end
77
+
78
+ def test_has_one_creates_a_cached_object
79
+ assert(AssociatedUser.method_defined?('cached_resource'))
80
+ assert(!@model.cached_resource.nil?)
81
+ end
82
+
83
+ def test_has_one_creates_a_uncached_object
84
+ assert(AssociatedUser.method_defined?('resource'))
85
+ assert(@model.resource.id == 50)
86
+ end
87
+
88
+ def test_has_one_creates_a_setter
89
+ new_values = { id: 75, name: 'new resource' }
90
+ stub_request(:post, "#{AssociatedUser.arkenstone_url}100/resource").to_return(body: '')
91
+
92
+ assert(AssociatedUser.method_defined?('resource='))
93
+ new_resource = Resource.build new_values
94
+ @model.resource = new_resource
95
+ @dummy_resource = new_resource
96
+ assert(@model.resource.id == 75)
97
+ end
98
+
99
+ def test_has_one_can_delete_an_association
100
+ stub_request(:delete, "#{AssociatedUser.arkenstone_url}100/resource/50").to_return(status: 200)
101
+ @model.resource = nil
102
+ @dummy_resource = nil
103
+ assert(@model.resource.nil?)
104
+ end
105
+
106
+ def test_associations_uses_the_same_namespace
107
+ eval %(
108
+ module Foo
109
+ class Bar
110
+ include Arkenstone::Document
111
+ end
112
+
113
+ class MyClass
114
+ include Arkenstone::Document
115
+ url "http://example.com/myclasses/"
116
+
117
+ attributes :id, :name
118
+
119
+ has_many :bars
120
+ end
121
+ end
122
+ )
123
+ stub_request(:get, "#{Foo::MyClass.arkenstone_url}100/bars").to_return(body: '')
124
+ model = Foo::MyClass.new
125
+ model.id = 100
126
+ result = model.bars
127
+ assert(!result.nil?)
128
+ end
129
+
130
+ def test_assoications_handles_405
131
+ eval %(
132
+ module Foo
133
+ class Bar
134
+ include Arkenstone::Document
135
+ end
136
+
137
+ class MyClass
138
+ include Arkenstone::Document
139
+ url "http://example.com/myclasses/"
140
+
141
+ attributes :id, :name
142
+
143
+ has_one :bar
144
+ end
145
+ end
146
+ )
147
+ stub_request(:get, "#{Foo::MyClass.arkenstone_url}100/bar").to_return(status: '405', body: 'ERROR')
148
+ model = Foo::MyClass.new
149
+ model.id = 100
150
+ result = model.bar
151
+ assert(result == [])
152
+ end
153
+
154
+ def test_belongs_to_association
155
+ eval %(
156
+ module Foo
157
+ class Bar
158
+ include Arkenstone::Document
159
+ url 'http://example.com/bar'
160
+
161
+ attributes :id
162
+ belongs_to :freezer
163
+ end
164
+
165
+ class Freezer
166
+ include Arkenstone::Document
167
+ url 'http://example.com/freezer'
168
+
169
+ attributes :id, :age
170
+ has_many :bars
171
+ end
172
+ end
173
+ )
174
+
175
+ stub_request(:post, "#{Foo::Freezer.arkenstone_url}/").to_return(status: '200', body: { id: 1 }.to_json)
176
+ stub_request(:post, "#{Foo::Bar.arkenstone_url}/").to_return(status: '200', body: { id: 1, freezer_id: 1 }.to_json)
177
+
178
+ freezer = Foo::Freezer.create({ age: 30 })
179
+ bar = Foo::Bar.create({ freezer: })
180
+
181
+ stub_request(:get, "#{Foo::Freezer.arkenstone_url}/1").to_return(status: 200, body: freezer.to_json)
182
+
183
+ assert_equal(freezer.id, bar.freezer_id)
184
+ assert_equal(freezer.to_json, bar.freezer.to_json)
185
+ assert_equal(bar.cached_freezer.id, freezer.id)
186
+ end
187
+
188
+ def test_has_and_belongs_to_many
189
+ # Pending Test
190
+
191
+ return true
192
+ eval %(
193
+ module Foo
194
+ class Bar
195
+ include Arkenstone::Document
196
+ url 'http://example.com/bar'
197
+
198
+ attributes :id
199
+ has_and_belongs_to_many :freezers
200
+ end
201
+
202
+ class Freezer
203
+ include Arkenstone::Document
204
+ url 'http://example.com/freezer'
205
+
206
+ attributes :id, :age
207
+ has_and_belongs_to_many :bars
208
+ end
209
+ end
210
+ )
211
+
212
+ stub_request(:post, "#{Foo::Freezer.arkenstone_url}/").to_return(status: '200',
213
+ body: {
214
+ id: 1, bar_ids: []
215
+ }.to_json)
216
+ stub_request(:post, "#{Foo::Bar.arkenstone_url}/").to_return(status: '200',
217
+ body: {
218
+ id: 1, freezer_ids: [1]
219
+ }.to_json)
220
+
221
+ freezer = Foo::Freezer.create({ age: 30 })
222
+ bar = Foo::Bar.create({ freezers: [freezer] })
223
+
224
+ stub_request(:get, "#{Foo::Freezer.arkenstone_url}/1").to_return(status: 200,
225
+ body: freezer.merge({ bar_ids: [bar.id] }).to_json)
226
+ stub_request(:get, "#{Foo::Bar.arkenstone_url}/1").to_return(status: 200,
227
+ body: bar.merge({ freezer_ids: [freezer.id] }).to_json)
228
+
229
+ assert(bar.freezer_ids.include?(freezer.id))
230
+ assert(freezer.bar_ids.include?(bar.id))
231
+
232
+ freezer = Foo::Freezer.find(1)
233
+ bar = Foo::Bar.find(1)
234
+
235
+ assert_equal(1, freezer.bars.length)
236
+ assert_equal(1, bar.freezers.length)
237
+
238
+ found_freezer = bar.freezers.first
239
+ found_bar = freezer.bars.first
240
+
241
+ assert_equal(freezer.to_json, found_freezer.to_json)
242
+ assert_equal(bar.to_json, found_bar.to_json)
243
+ end
244
+
245
+ def test_handles_nested_json
246
+ eval %(
247
+ module Foo
248
+ class Bar
249
+ include Arkenstone::Document
250
+ url 'http://example.com/bar'
251
+
252
+ attributes :id
253
+ belongs_to :freezer
254
+ end
255
+
256
+ class Freezer
257
+ include Arkenstone::Document
258
+ url 'http://example.com/freezer'
259
+
260
+ attributes :id, :age
261
+ has_many :bars
262
+ end
263
+ end
264
+ )
265
+
266
+ stub_request(:post, "#{Foo::Freezer.arkenstone_url}/").to_return(status: '200', body: { id: 1 }.to_json)
267
+ stub_request(:post, "#{Foo::Bar.arkenstone_url}/").to_return(status: '200', body: { id: 1, freezer_id: 1 }.to_json)
268
+
269
+ freezer = Foo::Freezer.create({ age: 30 })
270
+ bar = Foo::Bar.create({ freezer: })
271
+
272
+ stub_request(:get, "#{Foo::Freezer.arkenstone_url}/1").to_return(status: 200,
273
+ body: {
274
+ id: 1, age: 30, bars: [{ id: 1 }]
275
+ }.to_json)
276
+ stub_request(:get, "#{Foo::Freezer.arkenstone_url}/1/bars").to_return(status: 200, body: [{ id: 1 }].to_json)
277
+
278
+ freezer = Foo::Freezer.find(freezer.id)
279
+
280
+ assert(freezer.bars)
281
+ assert(freezer.bar_ids)
282
+ assert(freezer.bar_ids.include?(bar.id))
283
+ end
284
+
285
+ def test_allows_custom_url
286
+ eval %(
287
+ class Tool
288
+ include Arkenstone::Document
289
+ attributes :name
290
+ url 'http://example.com/tools'
291
+ end
292
+
293
+ class Garage
294
+ include Arkenstone::Document
295
+ attributes :address
296
+ url 'http://example.com/garages'
297
+
298
+ has_many :tools, model_name: 'derps'
299
+ end
300
+ )
301
+ stub_request(:get,
302
+ "#{Garage.arkenstone_url}/10/derps").to_return(body: [{ name: 'test' }, { name: 'other' }].to_json)
303
+ g = Garage.new
304
+ g.id = 10
305
+ tools = g.tools
306
+ assert_equal(2, tools.count)
307
+ end
308
+
309
+ def test_has_many_custom_class
310
+ eval %(
311
+ class Organization
312
+ include Arkenstone::Document
313
+ attributes :name
314
+ url 'http://example.com/organizations'
315
+
316
+ has_many :child_organizations, class_name: :organization, model_name: 'descendents'
317
+ end
318
+ )
319
+ url = "#{Organization.arkenstone_url}/10/descendents"
320
+ children = [{ name: 'child 1' }, { name: 'child 2' }]
321
+ stub_request(:get, url).to_return(body: children.to_json)
322
+ parent = Organization.new
323
+ parent.id = 10
324
+ child_orgs = parent.child_organizations
325
+ assert_equal(2, child_orgs.count)
326
+ end
327
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ class EnumerableTests < Test::Unit::TestCase
6
+ def test_json_returns_attributes_of_elements
7
+ eval %(
8
+ class EnumerableElement
9
+ include Arkenstone::Document
10
+
11
+ attributes :name, :id
12
+ end
13
+ )
14
+ dummy = EnumerableElement.new
15
+ dummy.name = 'test'
16
+ dummy.id = 100
17
+
18
+ dummy2 = EnumerableElement.new
19
+ dummy2.name = 'test2'
20
+ dummy2.id = 101
21
+
22
+ list = Arkenstone::QueryList.new [dummy, dummy2]
23
+ result = list.to_json
24
+ assert_equal(result, '[{"name":"test","id":100},{"name":"test2","id":101}]')
25
+ end
26
+
27
+ def test_initialize_takes_array
28
+ list = Arkenstone::QueryList.new [10, 20]
29
+ assert_equal([10, 20], list)
30
+ end
31
+
32
+ def test_initialize_takes_element
33
+ list = Arkenstone::QueryList.new 'test'
34
+ assert_equal ['test'], list
35
+ end
36
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ class ArkenstoneEnvTest < Test::Unit::TestCase
6
+ def setup
7
+ @env = Arkenstone::Environment.new url: 'http://example.com', verb: :get
8
+ end
9
+
10
+ def test_env_takes_hash_to_init
11
+ assert(@env.url == 'http://example.com')
12
+ assert(@env.verb == :get)
13
+ end
14
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ class HelpersTest < Test::Unit::TestCase
6
+ def test_full_url
7
+ eval %(
8
+ class FooTest
9
+ include Arkenstone::Document
10
+ include Arkenstone::Helpers
11
+
12
+ url 'http://example.com'
13
+ end
14
+ )
15
+
16
+ assert_equal('http://example.com/', FooTest.full_url(FooTest.arkenstone_url))
17
+ end
18
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ class RequestHook < Arkenstone::Hook
6
+ attr_accessor :called
7
+
8
+ def before_request(_req)
9
+ @called = true
10
+ end
11
+ end
12
+
13
+ class ResponseHook < Arkenstone::Hook
14
+ attr_accessor :called
15
+
16
+ def after_complete(_resp)
17
+ @called = true
18
+ end
19
+ end
20
+
21
+ class ArkenstoneHookTest < Test::Unit::TestCase
22
+ def test_hook_called_before_request
23
+ request_hook = RequestHook.new
24
+ User.add_hook request_hook
25
+ assert(User.arkenstone_hooks.count == 1)
26
+ stub_request(:get, "#{User.arkenstone_url}1").to_return(body: '{}')
27
+ User.find(1)
28
+ assert(request_hook.called, 'hook was not called')
29
+ end
30
+
31
+ def test_hook_called_after_complete
32
+ resp_hook = ResponseHook.new
33
+ User.add_hook resp_hook
34
+ stub_request(:get, "#{User.arkenstone_url}1").to_return(body: '{}')
35
+ User.find(1)
36
+ assert(resp_hook.called, 'response hook was not called')
37
+ end
38
+
39
+ def test_has_hooks
40
+ eval %(
41
+ class BaseThing
42
+ include Arkenstone::Document
43
+ add_hook RequestHook.new
44
+ end
45
+ )
46
+ assert_equal(true, Arkenstone::Hook.has_hooks?(BaseThing))
47
+ end
48
+
49
+ def test_has_hooks_via_inheritance
50
+ eval %(
51
+ class BaseThing
52
+ include Arkenstone::Document
53
+ add_hook RequestHook.new
54
+ end
55
+
56
+ class ChildThing < BaseThing
57
+ inherit_hooks
58
+ end
59
+
60
+ )
61
+ assert_equal(true, Arkenstone::Hook.has_hooks?(ChildThing))
62
+ end
63
+
64
+ def test_has_hooks_negative
65
+ eval %(
66
+ class NoHooks
67
+ end
68
+ )
69
+ assert_equal(false, Arkenstone::Hook.has_hooks?(NoHooks))
70
+ end
71
+
72
+ def test_all_hooks_for_class_verifies_inherit_hooks
73
+ eval %(
74
+ class BaseThing
75
+ include Arkenstone::Document
76
+ add_hook ResponseHook.new
77
+ end
78
+
79
+ class ChildThing < BaseThing
80
+ add_hook RequestHook.new
81
+ end
82
+ )
83
+ assert_equal(1, Arkenstone::Hook.all_hooks_for_class(ChildThing).count)
84
+ end
85
+
86
+ def test_all_hooks_for_class_walks_the_inheritance_chain
87
+ eval %(
88
+ class BaseBaseThing
89
+ include Arkenstone::Document
90
+ add_hook ResponseHook.new
91
+ end
92
+
93
+ class DerpChildThing < BaseBaseThing
94
+ add_hook RequestHook.new
95
+ inherit_hooks
96
+ end
97
+ )
98
+ assert_equal(2, Arkenstone::Hook.all_hooks_for_class(DerpChildThing).count)
99
+ end
100
+
101
+ def teardown
102
+ User.arkenstone_hooks = []
103
+ end
104
+ end
@@ -0,0 +1,163 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ class QueryBuilderTest < Test::Unit::TestCase
6
+ def setup
7
+ @builder = Arkenstone::QueryBuilder.new
8
+ end
9
+
10
+ def test_build_find_with_one_param
11
+ json = @builder.build do
12
+ {
13
+ foo: 'foo'
14
+ }
15
+ end
16
+
17
+ assert_equal '{"foo":"foo"}', json
18
+ end
19
+
20
+ def test_build_find_in
21
+ json = @builder.build do
22
+ {
23
+ foo: _in(%w[foo bar])
24
+ }
25
+ end
26
+ assert_equal '{"foo":{"$in":["foo","bar"]}}', json
27
+ end
28
+
29
+ def test_query_find_comparison
30
+ json = @builder.build do
31
+ {
32
+ foo: _gt(500)
33
+ }
34
+ end
35
+ assert_equal '{"foo":{"$gt":500}}', json
36
+ end
37
+
38
+ def test_query_complex_find
39
+ json = @builder.build do
40
+ {
41
+ foo: 'foo',
42
+ bar: _in(%w[foo bar]),
43
+ baz: _gt(400)
44
+ }
45
+ end
46
+ assert_equal '{"foo":"foo","bar":{"$in":["foo","bar"]},"baz":{"$gt":400}}', json
47
+ end
48
+
49
+ def test_query_and
50
+ json = @builder.build do
51
+ _and(
52
+ { foo: 'foo' },
53
+ { bar: 'bar' }
54
+ )
55
+ end
56
+ assert_equal '{"$and":[{"foo":"foo"},{"bar":"bar"}]}', json
57
+ end
58
+
59
+ def test_query_and_with_gt
60
+ json = @builder.build do
61
+ _and(
62
+ { foo: _gt(200) },
63
+ { foo: _lt(300) }
64
+ )
65
+ end
66
+ assert_equal '{"$and":[{"foo":{"$gt":200}},{"foo":{"$lt":300}}]}', json
67
+ end
68
+
69
+ def test_include
70
+ json = @builder.build do
71
+ _include %w[Foo Bar]
72
+ {
73
+ foo: 'foo'
74
+ }
75
+ end
76
+ assert_equal '{"$include":["Foo","Bar"],"foo":"foo"}', json
77
+ end
78
+
79
+ def test_limit
80
+ json = @builder.build do
81
+ _limit 5
82
+ {
83
+ foo: 'foo'
84
+ }
85
+ end
86
+ assert_equal '{"$limit":5,"foo":"foo"}', json
87
+ end
88
+
89
+ def test_complex_include_with_booleans
90
+ json = @builder.build do
91
+ _include %w[DocDataElement Document]
92
+ _or(
93
+ _and(
94
+ { 'DocDataElement.Name' => 'AccountNumber' },
95
+ { 'Value' => '123456' }
96
+ ),
97
+ _and(
98
+ { 'DocDataElement.Name' => 'Zip' },
99
+ { 'Value' => '55555' }
100
+ )
101
+ )
102
+ end
103
+ assert_equal '{"$include":["DocDataElement","Document"],"$or":[{"$and":[{"DocDataElement.Name":"AccountNumber"},{"Value":"123456"}]},{"$and":[{"DocDataElement.Name":"Zip"},{"Value":"55555"}]}]}',
104
+ json
105
+ end
106
+
107
+ def test_query_not
108
+ json = @builder.build do
109
+ _or(
110
+ _and(
111
+ { foo: _gt(200) },
112
+ { bar: 'bar' }
113
+ ),
114
+ _not(
115
+ { baz: 'derp' }
116
+ )
117
+ )
118
+ end
119
+ assert_equal '{"$or":[{"$and":[{"foo":{"$gt":200}},{"bar":"bar"}]},{"$not":[{"baz":"derp"}]}]}', json
120
+ end
121
+
122
+ def test_query_or
123
+ json = @builder.build do
124
+ _or(
125
+ { foo: _gt(200) },
126
+ { bar: 'bar' }
127
+ )
128
+ end
129
+ assert_equal '{"$or":[{"foo":{"$gt":200}},{"bar":"bar"}]}', json
130
+ end
131
+
132
+ def test_query_complex_and
133
+ json = @builder.build do
134
+ _or(
135
+ _and(
136
+ { foo: _gt(200) },
137
+ { bar: 'bar' }
138
+ ),
139
+ _and(
140
+ { derp: 'derp' }
141
+ )
142
+ )
143
+ end
144
+ assert_equal '{"$or":[{"$and":[{"foo":{"$gt":200}},{"bar":"bar"}]},{"$and":[{"derp":"derp"}]}]}', json
145
+ end
146
+
147
+ def test_query_is_idempotent
148
+ json = @builder.build do
149
+ _and(
150
+ { foo: _gt(200) },
151
+ { bar: 'bar' }
152
+ )
153
+ end
154
+ assert_equal '{"$and":[{"foo":{"$gt":200}},{"bar":"bar"}]}', json
155
+ json = @builder.build do
156
+ _and(
157
+ { foo: _gt(200) },
158
+ { derp: 'derp derp' }
159
+ )
160
+ end
161
+ assert_equal '{"$and":[{"foo":{"$gt":200}},{"derp":"derp derp"}]}', json
162
+ end
163
+ end