superdupe 0.4.0
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/README.markdown +10 -0
- data/lib/superdupe/active_resource_extensions.rb +161 -0
- data/lib/superdupe/attribute_template.rb +71 -0
- data/lib/superdupe/cucumber_hooks.rb +16 -0
- data/lib/superdupe/custom_mocks.rb +116 -0
- data/lib/superdupe/database.rb +69 -0
- data/lib/superdupe/dupe.rb +534 -0
- data/lib/superdupe/hash_pruner.rb +37 -0
- data/lib/superdupe/log.rb +38 -0
- data/lib/superdupe/mock.rb +127 -0
- data/lib/superdupe/model.rb +59 -0
- data/lib/superdupe/network.rb +56 -0
- data/lib/superdupe/record.rb +42 -0
- data/lib/superdupe/rest_validation.rb +16 -0
- data/lib/superdupe/schema.rb +52 -0
- data/lib/superdupe/sequence.rb +20 -0
- data/lib/superdupe/singular_plural_detection.rb +9 -0
- data/lib/superdupe/string.rb +7 -0
- data/lib/superdupe/symbol.rb +3 -0
- data/lib/superdupe.rb +20 -0
- data/rails_generators/dupe/dupe_generator.rb +20 -0
- data/rails_generators/dupe/templates/custom_mocks.rb +4 -0
- data/rails_generators/dupe/templates/definitions.rb +9 -0
- data/rails_generators/dupe/templates/load_dupe.rb +9 -0
- data/spec/lib_specs/active_resource_extensions_spec.rb +141 -0
- data/spec/lib_specs/attribute_template_spec.rb +173 -0
- data/spec/lib_specs/database_spec.rb +163 -0
- data/spec/lib_specs/dupe_spec.rb +522 -0
- data/spec/lib_specs/hash_pruner_spec.rb +73 -0
- data/spec/lib_specs/log_spec.rb +78 -0
- data/spec/lib_specs/logged_request_spec.rb +22 -0
- data/spec/lib_specs/mock_definitions_spec.rb +58 -0
- data/spec/lib_specs/mock_spec.rb +194 -0
- data/spec/lib_specs/model_spec.rb +95 -0
- data/spec/lib_specs/network_spec.rb +130 -0
- data/spec/lib_specs/record_spec.rb +70 -0
- data/spec/lib_specs/rest_validation_spec.rb +17 -0
- data/spec/lib_specs/schema_spec.rb +109 -0
- data/spec/lib_specs/sequence_spec.rb +39 -0
- data/spec/lib_specs/string_spec.rb +31 -0
- data/spec/lib_specs/symbol_spec.rb +17 -0
- data/spec/spec_helper.rb +8 -0
- metadata +142 -0
@@ -0,0 +1,522 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Dupe do
|
4
|
+
before do
|
5
|
+
Dupe.reset
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "#sequences" do
|
9
|
+
it "should be empty on initialization" do
|
10
|
+
Dupe.sequences.should == {}
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#sequence" do
|
15
|
+
it "should require a sequence name and a block" do
|
16
|
+
proc {Dupe.sequence}.should raise_error(ArgumentError)
|
17
|
+
proc {Dupe.sequence :name}.should_not raise_error
|
18
|
+
proc {Dupe.sequence(:name) {}}.should raise_error(ArgumentError, "Your block must accept a single parameter")
|
19
|
+
proc {Dupe.sequence(:name) {|n| n}}.should_not raise_error
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should store the sequence in a sequences hash" do
|
23
|
+
Dupe.sequences.should be_empty
|
24
|
+
|
25
|
+
Dupe.sequence :email do |n|
|
26
|
+
"email-#{n}@address.com"
|
27
|
+
end
|
28
|
+
|
29
|
+
Dupe.sequences.should_not be_empty
|
30
|
+
Dupe.sequences.keys.include?(:email).should == true
|
31
|
+
Dupe.sequences[:email].should be_kind_of(Sequence)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#next" do
|
36
|
+
it "should require a sequence name" do
|
37
|
+
Dupe.sequence :email do |n|
|
38
|
+
"email-#{n}@address.com"
|
39
|
+
end
|
40
|
+
|
41
|
+
proc {Dupe.next}.should raise_error(ArgumentError)
|
42
|
+
proc {Dupe.next :title}.should raise_error(ArgumentError, 'Unknown sequence ":title"')
|
43
|
+
Dupe.next(:email).should == "email-1@address.com"
|
44
|
+
Dupe.next(:email).should == "email-2@address.com"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "reset" do
|
49
|
+
it "should call reset_models, reset_database, and reset_network" do
|
50
|
+
Dupe.should_receive(:reset_models).once
|
51
|
+
Dupe.should_receive(:reset_database).once
|
52
|
+
Dupe.should_receive(:reset_network).once
|
53
|
+
Dupe.should_receive(:reset_sequences).once
|
54
|
+
Dupe.reset
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "reset_sequences" do
|
59
|
+
it "should reset the sequences to an empty hash" do
|
60
|
+
Dupe.sequences.should == {}
|
61
|
+
Dupe.sequence :email do |n|
|
62
|
+
n
|
63
|
+
end
|
64
|
+
Dupe.sequences.should_not be_empty
|
65
|
+
Dupe.reset_sequences
|
66
|
+
Dupe.sequences.should == {}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "reset_models" do
|
71
|
+
it "should reset @models to an empty hash" do
|
72
|
+
Dupe.models.length.should == 0
|
73
|
+
Dupe.define :book do |attrs|
|
74
|
+
attrs.title
|
75
|
+
attrs.author
|
76
|
+
end
|
77
|
+
Dupe.models.length.should == 1
|
78
|
+
Dupe.reset_models
|
79
|
+
Dupe.models.should == {}
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "reset_database" do
|
84
|
+
it "should clear out the database" do
|
85
|
+
Dupe.define :book
|
86
|
+
Dupe.define :author
|
87
|
+
Dupe.database.tables.length.should == 2
|
88
|
+
Dupe.reset_database
|
89
|
+
Dupe.database.tables.should be_empty
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "reset_network" do
|
94
|
+
it "should clear out the network" do
|
95
|
+
Dupe.create :book
|
96
|
+
Dupe.network.mocks.values.inject(false) {|b,v| b || !v.empty?}.should == true
|
97
|
+
Dupe.network.mocks[:get].should_not be_empty
|
98
|
+
Dupe.reset_network
|
99
|
+
Dupe.network.mocks.values.inject(false) {|b,v| b || !v.empty?}.should == false
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "define" do
|
104
|
+
|
105
|
+
# Dupe.define :model_name
|
106
|
+
it "should accept a single symbol parameter" do
|
107
|
+
proc {
|
108
|
+
Dupe.define :book
|
109
|
+
}.should_not raise_error
|
110
|
+
end
|
111
|
+
|
112
|
+
# Dupe.define :model_name do |attrs|
|
113
|
+
# attrs.attr1 'Default Value'
|
114
|
+
# attrs.attr2 do |value|
|
115
|
+
# 'transformed value'
|
116
|
+
# end
|
117
|
+
# end
|
118
|
+
it "should accept a symbol plus a block (that accepts a single parameter)" do
|
119
|
+
proc {
|
120
|
+
Dupe.define :book do
|
121
|
+
end
|
122
|
+
}.should raise_error(
|
123
|
+
ArgumentError,
|
124
|
+
"Unknown Dupe.define parameter format. Please consult the API" +
|
125
|
+
" for information on how to use Dupe.define"
|
126
|
+
)
|
127
|
+
|
128
|
+
proc {
|
129
|
+
Dupe.define :book do |attrs|
|
130
|
+
attrs.author 'Anon'
|
131
|
+
attrs.title 'Untitled'
|
132
|
+
end
|
133
|
+
}.should_not raise_error
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should create a model and a schema with the desired definition" do
|
137
|
+
Dupe.define :book do |attrs|
|
138
|
+
attrs.author 'Anon'
|
139
|
+
attrs.genre do
|
140
|
+
'Unknown' + rand(2).to_s
|
141
|
+
end
|
142
|
+
attrs.title 'Untitled' do |value|
|
143
|
+
"transformed #{value}"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
Dupe.models.length.should == 1
|
148
|
+
Dupe.models[:book].schema.attribute_templates[:author].name.should == :author
|
149
|
+
Dupe.models[:book].schema.attribute_templates[:author].default.should == 'Anon'
|
150
|
+
Dupe.models[:book].schema.attribute_templates[:title].name.should == :title
|
151
|
+
Dupe.models[:book].schema.attribute_templates[:title].default.should == 'Untitled'
|
152
|
+
Dupe.models[:book].schema.attribute_templates[:title].transformer.should be_kind_of(Proc)
|
153
|
+
Dupe.models[:book].schema.attribute_templates[:title].transformer.call('value').should == 'transformed value'
|
154
|
+
Dupe.models[:book].schema.attribute_templates[:genre].name.should == :genre
|
155
|
+
Dupe.models[:book].schema.attribute_templates[:genre].transformer.should be_nil
|
156
|
+
Dupe.models[:book].schema.attribute_templates[:genre].default.should be_kind_of(Proc)
|
157
|
+
Dupe.models[:book].schema.attribute_templates[:genre].default.call.should match(/^Unknown\d$/)
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should add a table to the database" do
|
161
|
+
Dupe.database.tables.length.should == 0
|
162
|
+
Dupe.database.tables[:book].should be_nil
|
163
|
+
Dupe.define :book
|
164
|
+
Dupe.database.tables.length.should == 1
|
165
|
+
Dupe.database.tables[:book].should_not be_nil
|
166
|
+
Dupe.database.tables[:book].should == []
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should add find(:all) and find(<id>) mocks to the network" do
|
170
|
+
Dupe.network.mocks[:get].should be_empty
|
171
|
+
Dupe.create :book
|
172
|
+
Dupe.network.mocks[:get].should_not be_empty
|
173
|
+
Dupe.network.mocks[:get].length.should == 2
|
174
|
+
|
175
|
+
find_all_mock = Dupe.network.mocks[:get].first
|
176
|
+
find_all_mock.class.should == Dupe::Network::GetMock
|
177
|
+
find_all_mock.url_pattern.should == %r{^/books\.xml$}
|
178
|
+
find_all_mock.mocked_response('/books.xml').should == Dupe.find(:books).to_xml(:root => 'books')
|
179
|
+
|
180
|
+
find_one_mock = Dupe.network.mocks[:get].last
|
181
|
+
find_one_mock.class.should == Dupe::Network::GetMock
|
182
|
+
find_one_mock.url_pattern.should == %r{^/books/(\d+)\.xml$}
|
183
|
+
find_one_mock.mocked_response('/books/1.xml').should == Dupe.find(:book).to_xml(:root => 'book')
|
184
|
+
end
|
185
|
+
|
186
|
+
it "should add a POST (create resource) mock to the network" do
|
187
|
+
Dupe.network.mocks[:post].should be_empty
|
188
|
+
Dupe.define :book
|
189
|
+
Dupe.network.mocks[:post].should_not be_empty
|
190
|
+
Dupe.network.mocks[:post].length.should == 1
|
191
|
+
|
192
|
+
post_mock = Dupe.network.mocks[:post].first
|
193
|
+
post_mock.class.should == Dupe::Network::PostMock
|
194
|
+
post_mock.url_pattern.should == %r{^/books\.xml$}
|
195
|
+
resp, url = post_mock.mocked_response('/books.xml', {:title => "Rooby"})
|
196
|
+
resp.should == Dupe.find(:book).to_xml(:root => 'book')
|
197
|
+
url.should == "/books/1.xml"
|
198
|
+
end
|
199
|
+
|
200
|
+
it "should add a PUT (update resource) mock to the network" do
|
201
|
+
Dupe.network.mocks[:put].should be_empty
|
202
|
+
book = Dupe.create :book, :title => 'Rooby!'
|
203
|
+
Dupe.network.mocks[:put].should_not be_empty
|
204
|
+
Dupe.network.mocks[:put].length.should == 1
|
205
|
+
|
206
|
+
put_mock = Dupe.network.mocks[:put].first
|
207
|
+
put_mock.class.should == Dupe::Network::PutMock
|
208
|
+
put_mock.url_pattern.should == %r{^/books/(\d+)\.xml$}
|
209
|
+
resp, url = put_mock.mocked_response('/books/1.xml', {:title => "Rails!"})
|
210
|
+
resp.should == nil
|
211
|
+
url.should == "/books/1.xml"
|
212
|
+
book.title.should == "Rails!"
|
213
|
+
end
|
214
|
+
|
215
|
+
it "should add a DELETE mock to the network" do
|
216
|
+
Dupe.network.mocks[:delete].should be_empty
|
217
|
+
book = Dupe.create :book, :title => 'Rooby!'
|
218
|
+
Dupe.network.mocks[:delete].should_not be_empty
|
219
|
+
Dupe.network.mocks[:delete].length.should == 1
|
220
|
+
|
221
|
+
delete_mock = Dupe.network.mocks[:delete].first
|
222
|
+
delete_mock.class.should == Dupe::Network::DeleteMock
|
223
|
+
delete_mock.url_pattern.should == %r{^/books/(\d+)\.xml$}
|
224
|
+
end
|
225
|
+
|
226
|
+
|
227
|
+
it "should honor ActiveResource site prefix's for the find(:all) and find(<id>) mocks" do
|
228
|
+
Dupe.network.mocks[:get].should be_empty
|
229
|
+
class Author < ActiveResource::Base; self.site='http://somewhere.com/book_services'; end
|
230
|
+
Dupe.create :author
|
231
|
+
Dupe.network.mocks[:get].should_not be_empty
|
232
|
+
Dupe.network.mocks[:get].length.should == 2
|
233
|
+
|
234
|
+
find_all_mock = Dupe.network.mocks[:get].first
|
235
|
+
find_all_mock.class.should == Dupe::Network::GetMock
|
236
|
+
find_all_mock.url_pattern.should == %r{^/book_services/authors\.xml$}
|
237
|
+
find_all_mock.mocked_response('/book_services/authors.xml').should == Dupe.find(:authors).to_xml(:root => 'authors')
|
238
|
+
|
239
|
+
find_one_mock = Dupe.network.mocks[:get].last
|
240
|
+
find_one_mock.class.should == Dupe::Network::GetMock
|
241
|
+
find_one_mock.url_pattern.should == %r{^/book_services/authors/(\d+)\.xml$}
|
242
|
+
find_one_mock.mocked_response('/book_services/authors/1.xml').should == Dupe.find(:author).to_xml(:root => 'author')
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
describe "create" do
|
247
|
+
it "should require a model name parameter" do
|
248
|
+
proc {Dupe.create}.should raise_error(ArgumentError)
|
249
|
+
proc {Dupe.create :book}.should_not raise_error(ArgumentError)
|
250
|
+
end
|
251
|
+
|
252
|
+
it "should create a model if one doesn't already exist" do
|
253
|
+
Dupe.models.should be_empty
|
254
|
+
Dupe.create :book
|
255
|
+
Dupe.models.should_not be_empty
|
256
|
+
Dupe.models[:book].should_not be_nil
|
257
|
+
Dupe.models[:book].name.should == :book
|
258
|
+
end
|
259
|
+
|
260
|
+
it "should be smart enough to singularize the model name before lookup/create" do
|
261
|
+
Dupe.define :book
|
262
|
+
Dupe.models.should_not be_empty
|
263
|
+
Dupe.models.length.should == 1
|
264
|
+
Dupe.models[:book].should_not be_nil
|
265
|
+
Dupe.create :books
|
266
|
+
Dupe.models.length.should == 1
|
267
|
+
Dupe.models[:books].should be_nil
|
268
|
+
Dupe.models[:book].should_not be_nil
|
269
|
+
Dupe.create :authors
|
270
|
+
Dupe.models.length.should == 2
|
271
|
+
Dupe.models[:author].should_not be_nil
|
272
|
+
Dupe.models[:author].name.should == :author
|
273
|
+
Dupe.models[:authors].should be_nil
|
274
|
+
end
|
275
|
+
|
276
|
+
it "should create (and return) a database record if passed a single hash" do
|
277
|
+
Dupe.define :book
|
278
|
+
Dupe.database.tables[:book].should be_empty
|
279
|
+
@book = Dupe.create :book, :title => 'test'
|
280
|
+
Dupe.database.tables[:book].should_not be_empty
|
281
|
+
Dupe.database.tables[:book].length.should == 1
|
282
|
+
Dupe.database.tables[:book].first.should == @book
|
283
|
+
end
|
284
|
+
|
285
|
+
it "should create several records if passed an array of hashes (and return an array of the records created)" do
|
286
|
+
Dupe.define :book
|
287
|
+
Dupe.database.tables[:book].should be_empty
|
288
|
+
@books = Dupe.create :books, [{:title => 'Book 1'}, {:title => 'Book 2'}]
|
289
|
+
Dupe.database.tables[:book].should_not be_empty
|
290
|
+
Dupe.database.tables[:book].length.should == 2
|
291
|
+
Dupe.database.tables[:book].first.should == @books.first
|
292
|
+
Dupe.database.tables[:book].last.should == @books.last
|
293
|
+
end
|
294
|
+
|
295
|
+
it "should symbolize hash keys to keep from duplicating column names" do
|
296
|
+
b = Dupe.create :book, 'title' => 'War And Peace', :title => 'War And Peace'
|
297
|
+
b.title.should == 'War And Peace'
|
298
|
+
b[:title].should == 'War And Peace'
|
299
|
+
b['title'].should == nil
|
300
|
+
|
301
|
+
bs = Dupe.create :books, [{:test => 2, 'test' => 2}, {:test => 4, 'test' => 4}]
|
302
|
+
bs.first.test.should == 2
|
303
|
+
bs.first[:test].should == 2
|
304
|
+
bs.first['test'].should == nil
|
305
|
+
bs.last.test.should == 4
|
306
|
+
bs.last[:test].should == 4
|
307
|
+
bs.last['test'].should == nil
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
describe "create resources with unique attributes" do
|
312
|
+
before do
|
313
|
+
Dupe.define :book do |book|
|
314
|
+
book.uniquify :title, :author, :genre
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
it "should uniquify the appropriate columns if they don't already have values" do
|
319
|
+
b = Dupe.create :book
|
320
|
+
b.title.should == "book 1 title"
|
321
|
+
b.author.should == "book 1 author"
|
322
|
+
b.genre.should == "book 1 genre"
|
323
|
+
|
324
|
+
b = Dupe.create :book, :title => 'Rooby Rocks', :isbn => 1
|
325
|
+
b.title.should == 'Rooby Rocks'
|
326
|
+
b.author.should == "book 2 author"
|
327
|
+
b.genre.should == "book 2 genre"
|
328
|
+
b.isbn.should == 1
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
describe "create resources that have an after_create callback" do
|
333
|
+
before do
|
334
|
+
Dupe.define :book do |book|
|
335
|
+
book.uniquify :title, :author, :genre
|
336
|
+
|
337
|
+
book.after_create do |b|
|
338
|
+
b.label = b.title.downcase.gsub(/\ +/, '-') unless b.label
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
it "should create a label based on the title if a label is passed in during the create call" do
|
344
|
+
b = Dupe.create :book, :title => 'Testing Testing'
|
345
|
+
b.label.should == 'testing-testing'
|
346
|
+
b = Dupe.create :book, :title => 'Testing Testing', :label => 'testbook'
|
347
|
+
b.label.should == 'testbook'
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
describe "find" do
|
352
|
+
before do
|
353
|
+
Dupe.define :book
|
354
|
+
@book = Dupe.create :book
|
355
|
+
end
|
356
|
+
|
357
|
+
it "should require a model name parameter" do
|
358
|
+
proc { Dupe.find }.should raise_error(ArgumentError)
|
359
|
+
end
|
360
|
+
|
361
|
+
it "should require the model to exist" do
|
362
|
+
proc { Dupe.find :unknown_models }.should raise_error(Dupe::Database::TableDoesNotExistError)
|
363
|
+
end
|
364
|
+
|
365
|
+
it "should return an array if you ask for a plural model (e.g., Dupe.find :books)" do
|
366
|
+
result = Dupe.find :books
|
367
|
+
result.should be_kind_of(Array)
|
368
|
+
result.should_not be_empty
|
369
|
+
result.length.should == 1
|
370
|
+
result.first.should == @book
|
371
|
+
end
|
372
|
+
|
373
|
+
it "should return a single record (or nil) if you ask for a singular model (e.g., Dupe.find :book)" do
|
374
|
+
result = Dupe.find :book
|
375
|
+
result.should be_kind_of(Dupe::Database::Record)
|
376
|
+
result.should == @book
|
377
|
+
|
378
|
+
result = Dupe.find(:book) {|b| false}
|
379
|
+
result.should be_nil
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
describe "debug" do
|
384
|
+
it "should default to false" do
|
385
|
+
Dupe.debug.should == false
|
386
|
+
end
|
387
|
+
|
388
|
+
it "should allow you to set it to true" do
|
389
|
+
Dupe.debug = true
|
390
|
+
Dupe.debug.should == true
|
391
|
+
end
|
392
|
+
|
393
|
+
it "should persist across a Dupe.reset" do
|
394
|
+
Dupe.debug = true
|
395
|
+
Dupe.debug.should == true
|
396
|
+
Dupe.reset
|
397
|
+
Dupe.debug.should == true
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
describe "stub" do
|
402
|
+
it ": when called with only a count and a model_name, it should generate that many blank (id-only) records" do
|
403
|
+
Dupe.database.tables[:author].should be_nil
|
404
|
+
authors = Dupe.stub 20, :authors
|
405
|
+
authors.length.should == 20
|
406
|
+
Dupe.database.tables[:author].length.should == 20
|
407
|
+
authors.collect(&:id).should == (1..20).to_a
|
408
|
+
end
|
409
|
+
|
410
|
+
it "should accept procs on stubs" do
|
411
|
+
Dupe.database.tables[:author].should be_nil
|
412
|
+
authors =
|
413
|
+
Dupe.stub(
|
414
|
+
2,
|
415
|
+
:authors,
|
416
|
+
:like => {
|
417
|
+
:name => proc {|n| "Author #{n}"},
|
418
|
+
:bio => proc {|n| "Author #{n}'s bio"}
|
419
|
+
}
|
420
|
+
)
|
421
|
+
authors.first.name.should == "Author 1"
|
422
|
+
authors.first.bio.should == "Author 1's bio"
|
423
|
+
authors.last.name.should == "Author 2"
|
424
|
+
authors.last.bio.should == "Author 2's bio"
|
425
|
+
Dupe.database.tables[:author].length.should == 2
|
426
|
+
end
|
427
|
+
|
428
|
+
it "shouldn't care if the model_name is singular or plural" do
|
429
|
+
Dupe.database.tables.should be_empty
|
430
|
+
Dupe.stub 5, :author
|
431
|
+
Dupe.database.tables.should_not be_empty
|
432
|
+
Dupe.database.tables.length.should == 1
|
433
|
+
Dupe.database.tables[:author].length.should == 5
|
434
|
+
Dupe.stub 5, :authors
|
435
|
+
Dupe.database.tables[:author].length.should == 10
|
436
|
+
Dupe.database.tables.length.should == 1
|
437
|
+
end
|
438
|
+
end
|
439
|
+
|
440
|
+
describe "find_or_create" do
|
441
|
+
it "should require a model name" do
|
442
|
+
proc { Dupe.find_or_create }.should raise_error(ArgumentError)
|
443
|
+
end
|
444
|
+
|
445
|
+
it "should find a result if one exists" do
|
446
|
+
b = Dupe.create :book, :title => 'Rooby', :serial_number => 21345
|
447
|
+
found_book = Dupe.find_or_create :book, :title => 'Rooby', :serial_number => 21345
|
448
|
+
b.should === found_book
|
449
|
+
|
450
|
+
g = Dupe.create :genre, :name => 'Science Fiction', :label => 'sci-fi'
|
451
|
+
found_genre = Dupe.find_or_create :genre, :name => 'Science Fiction', :label => 'sci-fi'
|
452
|
+
g.should === found_genre
|
453
|
+
end
|
454
|
+
|
455
|
+
it "should create a result if one does not exist" do
|
456
|
+
Dupe.database.tables.should be_empty
|
457
|
+
author = Dupe.find_or_create :author, :name => 'Matt Parker', :age => 27, :label => 'matt-parker'
|
458
|
+
Dupe.database.tables.should_not be_empty
|
459
|
+
author.should === (Dupe.find(:author) {|a| a.label == 'matt-parker' && a.age == 27})
|
460
|
+
end
|
461
|
+
|
462
|
+
it "should return an array of results if passed a plural model name" do
|
463
|
+
books = Dupe.stub 20, :books, :like => { :title => proc {|n| "book ##{n} title"} }
|
464
|
+
bs = Dupe.find_or_create :books
|
465
|
+
books.should == bs
|
466
|
+
end
|
467
|
+
|
468
|
+
it "should create and return an array of results if passed a plural model name for which no matching records exist" do
|
469
|
+
Dupe.database.tables.should be_empty
|
470
|
+
books = Dupe.find_or_create :books, :author => 'test'
|
471
|
+
Dupe.database.tables.length.should == 1
|
472
|
+
books.should be_kind_of(Array)
|
473
|
+
books.should == Dupe.find(:books)
|
474
|
+
end
|
475
|
+
|
476
|
+
end
|
477
|
+
|
478
|
+
describe "creating resources should not change definitions (regression test)" do
|
479
|
+
before do
|
480
|
+
Dupe.define :book do |book|
|
481
|
+
book.authors []
|
482
|
+
book.genre do
|
483
|
+
Dupe.find_or_create :genre, :name => 'Sci-fi'
|
484
|
+
end
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
488
|
+
it "should not add a record to the definition when the default value is an array" do
|
489
|
+
b = Dupe.create :book
|
490
|
+
a = Dupe.create :author
|
491
|
+
b.authors << a
|
492
|
+
b.authors.include?(a).should be_true
|
493
|
+
b2 = Dupe.create :book
|
494
|
+
b2.authors.should be_empty
|
495
|
+
end
|
496
|
+
|
497
|
+
it "should not dupe the value returned by a lazy attribute" do
|
498
|
+
b = Dupe.create :book
|
499
|
+
b2 = Dupe.create :book
|
500
|
+
b.genre.should == b2.genre
|
501
|
+
b.genre.name = 'Science Fiction'
|
502
|
+
b2.genre.name.should == 'Science Fiction'
|
503
|
+
end
|
504
|
+
end
|
505
|
+
|
506
|
+
describe "##delete" do
|
507
|
+
it "should remove any resources that match the conditions provided in the block" do
|
508
|
+
Dupe.stub 10, :authors
|
509
|
+
Dupe.find(:authors).length.should == 10
|
510
|
+
Dupe.delete :author
|
511
|
+
Dupe.find(:authors).length.should == 9
|
512
|
+
Dupe.delete :authors
|
513
|
+
Dupe.find(:authors).length.should == 0
|
514
|
+
Dupe.create :author, :name => 'CS Lewis'
|
515
|
+
Dupe.create :author, :name => 'Robert Lewis Stevenson'
|
516
|
+
Dupe.create :author, :name => 'Frank Herbert'
|
517
|
+
Dupe.delete(:author) {|a| a.name.match /Lewis/}
|
518
|
+
Dupe.find(:authors).length.should == 1
|
519
|
+
Dupe.find(:authors).first.name.should == 'Frank Herbert'
|
520
|
+
end
|
521
|
+
end
|
522
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe HashPruner do
|
4
|
+
describe "#prune" do
|
5
|
+
it "should nil out any repeated hashes" do
|
6
|
+
clarke = {:name => "Arthur C. Clarke"}
|
7
|
+
heinlein = {:name => "Robert Heinlein"}
|
8
|
+
sci_fi = {:name => "Science Fiction", :authors => [clarke, heinlein]}
|
9
|
+
clarke[:genre] = sci_fi
|
10
|
+
odyssey = {:name => "2001", :genre => sci_fi, :author => clarke}
|
11
|
+
hoag = {:name => "the unpleasant profession", :genre => sci_fi, :author => heinlein}
|
12
|
+
clarke[:books] = [odyssey]
|
13
|
+
heinlein[:books] = [hoag]
|
14
|
+
|
15
|
+
HashPruner.prune(clarke).should ==
|
16
|
+
{
|
17
|
+
:name=>"Arthur C. Clarke",
|
18
|
+
:genre => {
|
19
|
+
:name => "Science Fiction",
|
20
|
+
:authors => [
|
21
|
+
{
|
22
|
+
:name=>"Arthur C. Clarke"
|
23
|
+
},
|
24
|
+
{
|
25
|
+
:name=>"Robert Heinlein",
|
26
|
+
:books=> [
|
27
|
+
{
|
28
|
+
:name => "the unpleasant profession",
|
29
|
+
:genre => {
|
30
|
+
:name => "Science Fiction"
|
31
|
+
},
|
32
|
+
:author => {
|
33
|
+
:name => "Robert Heinlein"
|
34
|
+
}
|
35
|
+
}
|
36
|
+
]
|
37
|
+
}
|
38
|
+
]
|
39
|
+
},
|
40
|
+
:books=> [
|
41
|
+
{
|
42
|
+
:name => "2001",
|
43
|
+
:genre => {
|
44
|
+
:name => "Science Fiction",
|
45
|
+
:authors => [
|
46
|
+
{
|
47
|
+
:name => "Arthur C. Clarke"
|
48
|
+
},
|
49
|
+
{
|
50
|
+
:name=>"Robert Heinlein",
|
51
|
+
:books=> [
|
52
|
+
{
|
53
|
+
:name => "the unpleasant profession",
|
54
|
+
:genre => {
|
55
|
+
:name => "Science Fiction"
|
56
|
+
},
|
57
|
+
:author => {
|
58
|
+
:name => "Robert Heinlein"
|
59
|
+
}
|
60
|
+
}
|
61
|
+
]
|
62
|
+
}
|
63
|
+
]
|
64
|
+
},
|
65
|
+
:author => {
|
66
|
+
:name => "Arthur C. Clarke"
|
67
|
+
}
|
68
|
+
}
|
69
|
+
]
|
70
|
+
}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Dupe::Network::Log do
|
4
|
+
before do
|
5
|
+
Dupe.reset
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "##new" do
|
9
|
+
it "should initialize the request entries to an empty array" do
|
10
|
+
log = Dupe::Network::Log.new
|
11
|
+
log.requests.should == []
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#add_request" do
|
16
|
+
before do
|
17
|
+
@log = Dupe::Network::Log.new
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should require a valid HTTP verb" do
|
21
|
+
proc {
|
22
|
+
@log.add_request :invalid_http_verb, '/some_url'
|
23
|
+
}.should raise_error(Dupe::Network::UnknownRestVerbError)
|
24
|
+
proc {
|
25
|
+
Dupe::Network::VERBS.each do |verb|
|
26
|
+
@log.add_request verb, '/some_url'
|
27
|
+
end
|
28
|
+
}.should_not raise_error
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should require a url" do
|
32
|
+
proc {
|
33
|
+
@log.add_request :get
|
34
|
+
}.should raise_error(ArgumentError)
|
35
|
+
proc {
|
36
|
+
@log.add_request :get, '/a_url'
|
37
|
+
}.should_not raise_error
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should add a Dupe::Network::Log::MockedRequest to requests" do
|
41
|
+
@log.requests.should be_empty
|
42
|
+
path = '/translate?q=hola&from=spanish&to=english'
|
43
|
+
response_body = 'hello'
|
44
|
+
@log.add_request :get, path, response_body
|
45
|
+
@log.requests.should_not be_empty
|
46
|
+
@log.requests.length.should == 1
|
47
|
+
logged_request = @log.requests.first
|
48
|
+
logged_request.should be_kind_of(Dupe::Network::Log::Request)
|
49
|
+
logged_request.verb.should == :get
|
50
|
+
logged_request.path.should == path
|
51
|
+
logged_request.response_body.should == response_body
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "#pretty_print" do
|
56
|
+
before do
|
57
|
+
@log = Dupe::Network::Log.new
|
58
|
+
@log.add_request :get, '/knock-knock', "who's there?"
|
59
|
+
end
|
60
|
+
it "should return a formatted list of mocked requests" do
|
61
|
+
@log.pretty_print.should ==
|
62
|
+
"Logged Requests:\n" +
|
63
|
+
" Request: GET /knock-knock\n" +
|
64
|
+
" Response:\n" +
|
65
|
+
" who's there?\n\n"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "#reset" do
|
70
|
+
it "should clear out all logged requests" do
|
71
|
+
@log = Dupe::Network::Log.new
|
72
|
+
@log.add_request :get, '/knock-knock', "who's there?"
|
73
|
+
@log.requests.should_not be_empty
|
74
|
+
@log.reset
|
75
|
+
@log.requests.should be_empty
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Dupe::Network::Log::Request do
|
4
|
+
describe "##new" do
|
5
|
+
it "should set the verb, url, and response_body" do
|
6
|
+
r = Dupe::Network::Log::Request.new :get, "/knock-knock", "who's there?"
|
7
|
+
r.verb.should == :get
|
8
|
+
r.path.should == "/knock-knock"
|
9
|
+
r.response_body.should == "who's there?"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "#pretty_print" do
|
14
|
+
it "should show the request type, request path, and request response" do
|
15
|
+
r = Dupe::Network::Log::Request.new :get, "/knock-knock", "who's there?"
|
16
|
+
r.pretty_print.should ==
|
17
|
+
"Request: GET /knock-knock\n" +
|
18
|
+
"Response:\n" +
|
19
|
+
" who's there?"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|