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.
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