superdupe 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|