superdupe 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/README.markdown +10 -0
  2. data/lib/superdupe/active_resource_extensions.rb +161 -0
  3. data/lib/superdupe/attribute_template.rb +71 -0
  4. data/lib/superdupe/cucumber_hooks.rb +16 -0
  5. data/lib/superdupe/custom_mocks.rb +116 -0
  6. data/lib/superdupe/database.rb +69 -0
  7. data/lib/superdupe/dupe.rb +534 -0
  8. data/lib/superdupe/hash_pruner.rb +37 -0
  9. data/lib/superdupe/log.rb +38 -0
  10. data/lib/superdupe/mock.rb +127 -0
  11. data/lib/superdupe/model.rb +59 -0
  12. data/lib/superdupe/network.rb +56 -0
  13. data/lib/superdupe/record.rb +42 -0
  14. data/lib/superdupe/rest_validation.rb +16 -0
  15. data/lib/superdupe/schema.rb +52 -0
  16. data/lib/superdupe/sequence.rb +20 -0
  17. data/lib/superdupe/singular_plural_detection.rb +9 -0
  18. data/lib/superdupe/string.rb +7 -0
  19. data/lib/superdupe/symbol.rb +3 -0
  20. data/lib/superdupe.rb +20 -0
  21. data/rails_generators/dupe/dupe_generator.rb +20 -0
  22. data/rails_generators/dupe/templates/custom_mocks.rb +4 -0
  23. data/rails_generators/dupe/templates/definitions.rb +9 -0
  24. data/rails_generators/dupe/templates/load_dupe.rb +9 -0
  25. data/spec/lib_specs/active_resource_extensions_spec.rb +141 -0
  26. data/spec/lib_specs/attribute_template_spec.rb +173 -0
  27. data/spec/lib_specs/database_spec.rb +163 -0
  28. data/spec/lib_specs/dupe_spec.rb +522 -0
  29. data/spec/lib_specs/hash_pruner_spec.rb +73 -0
  30. data/spec/lib_specs/log_spec.rb +78 -0
  31. data/spec/lib_specs/logged_request_spec.rb +22 -0
  32. data/spec/lib_specs/mock_definitions_spec.rb +58 -0
  33. data/spec/lib_specs/mock_spec.rb +194 -0
  34. data/spec/lib_specs/model_spec.rb +95 -0
  35. data/spec/lib_specs/network_spec.rb +130 -0
  36. data/spec/lib_specs/record_spec.rb +70 -0
  37. data/spec/lib_specs/rest_validation_spec.rb +17 -0
  38. data/spec/lib_specs/schema_spec.rb +109 -0
  39. data/spec/lib_specs/sequence_spec.rb +39 -0
  40. data/spec/lib_specs/string_spec.rb +31 -0
  41. data/spec/lib_specs/symbol_spec.rb +17 -0
  42. data/spec/spec_helper.rb +8 -0
  43. 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