eloqua 1.1.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 (72) hide show
  1. data/.gitignore +11 -0
  2. data/.yardopts +2 -0
  3. data/CHANGELOG.md +23 -0
  4. data/Gemfile +3 -0
  5. data/Gemfile.lock +81 -0
  6. data/LICENSE +21 -0
  7. data/README.md +245 -0
  8. data/Rakefile +13 -0
  9. data/TODO.md +8 -0
  10. data/eloqua.gemspec +32 -0
  11. data/eloqua_initializer.tpl.rb +3 -0
  12. data/lib/eloqua.rb +51 -0
  13. data/lib/eloqua/api.rb +119 -0
  14. data/lib/eloqua/api/action.rb +41 -0
  15. data/lib/eloqua/api/service.rb +240 -0
  16. data/lib/eloqua/asset.rb +31 -0
  17. data/lib/eloqua/builder/templates.rb +31 -0
  18. data/lib/eloqua/builder/xml.rb +129 -0
  19. data/lib/eloqua/entity.rb +72 -0
  20. data/lib/eloqua/exceptions.rb +5 -0
  21. data/lib/eloqua/helper/attribute_map.rb +78 -0
  22. data/lib/eloqua/query.rb +291 -0
  23. data/lib/eloqua/remote_object.rb +274 -0
  24. data/lib/eloqua/version.rb +3 -0
  25. data/lib/eloqua/wsdl/action.wsdl +1 -0
  26. data/lib/eloqua/wsdl/data.wsdl +1 -0
  27. data/lib/eloqua/wsdl/email.wsdl +1 -0
  28. data/lib/eloqua/wsdl/service.wsdl +1 -0
  29. data/lib/tasks/test.rake +24 -0
  30. data/rspec.watchr +74 -0
  31. data/spec/fixtures/add_group_member/success.xml +18 -0
  32. data/spec/fixtures/create/contact_duplicate.xml +30 -0
  33. data/spec/fixtures/create/contact_success.xml +25 -0
  34. data/spec/fixtures/create_asset/failure.xml +30 -0
  35. data/spec/fixtures/create_asset/group_success.xml +25 -0
  36. data/spec/fixtures/delete_asset/access_deny.xml +31 -0
  37. data/spec/fixtures/describe_asset/success.xml +72 -0
  38. data/spec/fixtures/describe_asset_type/success.xml +23 -0
  39. data/spec/fixtures/describe_entity/success.xml +54 -0
  40. data/spec/fixtures/describe_entity_type/success.xml +45 -0
  41. data/spec/fixtures/get_member_count_in_step_by_status/success.xml +15 -0
  42. data/spec/fixtures/list_asset_types/success.xml +28 -0
  43. data/spec/fixtures/list_entity_types/success.xml +21 -0
  44. data/spec/fixtures/list_group_membership/success.xml +25 -0
  45. data/spec/fixtures/list_members_in_step_by_status/success.xml +15 -0
  46. data/spec/fixtures/query/contact_email_one.xml +38 -0
  47. data/spec/fixtures/query/contact_email_two.xml +56 -0
  48. data/spec/fixtures/query/contact_missing.xml +19 -0
  49. data/spec/fixtures/query/fault.xml +43 -0
  50. data/spec/fixtures/remove_group_member/success.xml +18 -0
  51. data/spec/fixtures/retrieve/contact_missing.xml +17 -0
  52. data/spec/fixtures/retrieve/contact_multiple.xml +3460 -0
  53. data/spec/fixtures/retrieve/contact_single.xml +38 -0
  54. data/spec/fixtures/retrieve_asset/failure.xml +17 -0
  55. data/spec/fixtures/retrieve_asset/success.xml +50 -0
  56. data/spec/fixtures/update/contact_success.xml +26 -0
  57. data/spec/lib/eloqua/api/action_spec.rb +36 -0
  58. data/spec/lib/eloqua/api/service_spec.rb +498 -0
  59. data/spec/lib/eloqua/api_spec.rb +133 -0
  60. data/spec/lib/eloqua/asset_spec.rb +63 -0
  61. data/spec/lib/eloqua/builder/templates_spec.rb +68 -0
  62. data/spec/lib/eloqua/builder/xml_spec.rb +254 -0
  63. data/spec/lib/eloqua/entity_spec.rb +224 -0
  64. data/spec/lib/eloqua/helper/attribute_map_spec.rb +14 -0
  65. data/spec/lib/eloqua/query_spec.rb +596 -0
  66. data/spec/lib/eloqua/remote_object_spec.rb +742 -0
  67. data/spec/lib/eloqua_spec.rb +171 -0
  68. data/spec/shared/attribute_map.rb +173 -0
  69. data/spec/shared/class_to_api_delegation.rb +50 -0
  70. data/spec/spec_helper.rb +48 -0
  71. data/spec/support/helper.rb +73 -0
  72. metadata +366 -0
@@ -0,0 +1,742 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples_for 'remote operation that converts attribute values' do |operation|
4
+
5
+ let(:method) { "#{operation}_object".to_sym }
6
+
7
+ let(:klass) do
8
+ Class.new(subject) do
9
+ map :C_California1 => :california
10
+ attr_checkbox(:california)
11
+ end
12
+ end
13
+
14
+ context "when #{operation.to_s.pluralize} object" do
15
+ it 'should convert value before saving' do
16
+ if(operation == :update)
17
+ object = klass.new(:id => 1)
18
+ flexmock(object.class).should_receive(method).\
19
+ with(1, {'C_California1' => 'Yes'}).once
20
+ else
21
+ object = klass.new
22
+ flexmock(object.class).should_receive(method).\
23
+ with({'C_California1' => 'Yes'}).once
24
+ end
25
+
26
+
27
+ object.california = true
28
+ object.save
29
+ end
30
+
31
+ end
32
+ end
33
+
34
+ shared_examples_for "class method delegates to set_callback" do |method, callback, state|
35
+
36
+ context "#self.#{method}" do
37
+
38
+ it "should delegate to set_callback #{callback}, #{state}, &block" do
39
+ block = Proc.new {}
40
+ klass = flexmock(subject)
41
+ klass.should_receive(:set_callback).with(callback, state, block).once
42
+ klass.send(method, &block)
43
+ end
44
+
45
+
46
+ it "should be able to set a symbol as the final argument for a method" do
47
+ callback_method = :object_id
48
+
49
+ klass = flexmock(subject)
50
+ klass.should_receive(:set_callback).with(callback, state, callback_method).once
51
+ klass.send(method, callback_method)
52
+ end
53
+
54
+ end
55
+
56
+ end
57
+
58
+ describe Eloqua::RemoteObject do
59
+
60
+ subject do
61
+ Class.new(Eloqua::RemoteObject) do
62
+ self.remote_type = Eloqua::Api.remote_type('Contact')
63
+ self.remote_group = :entity
64
+
65
+ attr_accessor :callbacks_called
66
+ attr_accessor :test_callbacks
67
+
68
+ def test_callback(type, state, &block)
69
+ class_eval do
70
+ set_callback(type, state, &block)
71
+ end
72
+ end
73
+
74
+ [:save, :update, :create].each do |callback_type|
75
+ [:before, :after].each do |callback_state|
76
+ set_callback(callback_type, callback_state) do
77
+ self.callbacks_called ||= {}
78
+ self.callbacks_called[callback_type] ||= []
79
+ self.callbacks_called[callback_type] << callback_state
80
+ end
81
+ end
82
+ end
83
+
84
+ def self.name
85
+ 'ContactEntity'
86
+ end
87
+
88
+ end
89
+ end
90
+
91
+ let(:remote_type) do
92
+ subject.api.remote_type('Contact')
93
+ end
94
+
95
+ it_behaves_like 'uses attribute map'
96
+ it_behaves_like 'class level delegation of remote operations for', :entity
97
+
98
+ [:save, :update, :create].each do |callback_type|
99
+ [:before, :after].each do |callback_state|
100
+ it_behaves_like "class method delegates to set_callback",
101
+ "#{callback_state}_#{callback_type}".to_sym, callback_type, callback_state
102
+ end
103
+ end
104
+
105
+ context "#self.remote_group" do
106
+ specify { subject.remote_group.should == :entity }
107
+ end
108
+
109
+
110
+ context "#initialize" do
111
+
112
+ context "when :remote" do
113
+ before do
114
+ @class = Class.new(subject) do
115
+ map :ContactID => :id
116
+ map :C_EmailAddress => :email
117
+ attr_checkbox :california, :arizona
118
+ end
119
+ end
120
+
121
+ let(:input) do
122
+ {
123
+ :C_EmailAddress => 'email@address.com',
124
+ :ContactID => '1',
125
+ :normal_id => 'wow',
126
+ :C_California => 'Yes',
127
+ :C_Arizona => 'No'
128
+ }
129
+ end
130
+
131
+ let(:expected) do
132
+ {
133
+ :email => 'email@address.com',
134
+ :id => '1',
135
+ :normal_id => 'wow',
136
+ :california => true,
137
+ :arizona => false
138
+ }.with_indifferent_access
139
+ end
140
+
141
+ it 'should map objects for adding them to #attributes' do
142
+ object = @class.new(input, :remote) # true is remote == true
143
+ object.attributes.should == expected
144
+ end
145
+
146
+
147
+
148
+ end
149
+
150
+
151
+ end
152
+
153
+ context "#reload" do
154
+
155
+ let(:new_attr) { {:C_EmailAddress => 'new'} }
156
+
157
+ before do
158
+ flexmock(subject).should_receive(:find_object, 1).\
159
+ and_return(new_attr).\
160
+ once
161
+
162
+ @object = subject.new({:id => 1, :C_EmailAddress => 'old'}, :remote)
163
+ @object.reload
164
+ end
165
+
166
+ it 'should have updated email to new' do
167
+ @object.email_address.should == 'new'
168
+ end
169
+
170
+ it 'should not be dirty' do
171
+ @object.attribute_changed?(:email_address).should be_false
172
+ end
173
+
174
+ end
175
+
176
+ context '#persisted?' do
177
+
178
+ it 'should be false when created with new' do
179
+ subject.new.should_not be_persisted
180
+ end
181
+
182
+ it 'should be true when initializing with id' do
183
+ subject.new(:id => '1').should be_persisted
184
+ end
185
+
186
+ context 'when initialized with :remote' do
187
+ it 'should be considered persisted' do
188
+ subject.new({:C_EmailAddress => 'email'}, :remote).should be_persisted
189
+ end
190
+ end
191
+ end
192
+
193
+ context "#valid?" do
194
+ let(:klass) do
195
+ Class.new(subject) do
196
+ map :C_EmailAddress => :email
197
+ validates_presence_of :email
198
+
199
+ def self.name
200
+ 'Contact'
201
+ end
202
+
203
+ end
204
+ end
205
+
206
+ context 'when valid' do
207
+
208
+ before do
209
+ @object = klass.new(:email => 'wow')
210
+ end
211
+
212
+ it 'should be valid?' do
213
+ @object.should be_valid
214
+ end
215
+
216
+ it 'should not have any errors' do
217
+ @object.valid?
218
+ @object.errors[:email].should be_empty
219
+ end
220
+
221
+ end
222
+
223
+ context 'when invalid' do
224
+
225
+ before do
226
+ @object = klass.new()
227
+ @results = @object.valid?
228
+ end
229
+
230
+ it 'should be invalid?' do
231
+ @object.should be_invalid
232
+ end
233
+
234
+ it 'should have errors on :email' do
235
+ @object.errors[:email].should_not be_empty
236
+ end
237
+
238
+ end
239
+
240
+ end
241
+
242
+ context "#read_attribute" do
243
+ let(:object) { subject.new(:email => 'address') }
244
+ specify { object.read_attribute(:email).should == 'address' }
245
+ end
246
+
247
+ context '#write_attribute' do
248
+ let(:object) { subject.new(:email => 'address') }
249
+
250
+ it 'should set attribute' do
251
+ object.write_attribute(:email, 'test')
252
+ object.attributes[:email].should == 'test'
253
+ end
254
+ end
255
+
256
+ context "#is_attribute_method?" do
257
+
258
+ let(:object) { subject.new(:email => 'address') }
259
+
260
+ it 'should return true for writers' do
261
+ object.is_attribute_method?(:email=).should == :write
262
+ end
263
+
264
+ it 'should return true for readers' do
265
+ object.is_attribute_method?(:email).should == :read
266
+ end
267
+
268
+ it 'should not return true for missing attrs' do
269
+ object.attributes.delete(:email)
270
+ object.is_attribute_method?(:email).should be_false
271
+ end
272
+
273
+ end
274
+
275
+ context "when calling attribute method without concrete definition" do
276
+
277
+ let(:klass) do
278
+ Class.new(subject) do
279
+ map :C_EmailAddress => 'email'
280
+ end
281
+ end
282
+
283
+
284
+ let(:object) do
285
+ klass.new({:C_EmailAddress => 'james@lightsofapollo.com'}, :remote)
286
+ end
287
+
288
+ specify { object.respond_to?(:email) }
289
+ specify { object.respond_to?(:email=) }
290
+
291
+ it 'should allow us to access attributes via accessors (email)' do
292
+ object.email.should == 'james@lightsofapollo.com'
293
+ end
294
+
295
+ it 'should allow us to alter email via email=' do
296
+ object.email = 'newemail'
297
+ object.email.should == 'newemail'
298
+ object.attributes[:email].should == 'newemail'
299
+ end
300
+
301
+ context 'when initalizing empty object' do
302
+ let(:object) { klass.new }
303
+
304
+ it 'should respond to mapped attribute email' do
305
+ object.respond_to?(:email).should be_true
306
+ end
307
+
308
+ it 'should allow us to set and read attribute' do
309
+ object.email = 'email'
310
+ object.email.should == 'email'
311
+ end
312
+
313
+ end
314
+
315
+ end
316
+
317
+ context 'dirty attributes' do
318
+
319
+ let(:klass) do
320
+ Class.new(subject) do
321
+ map :C_EmailAddress => :email
322
+ end
323
+ end
324
+
325
+ let(:object) do
326
+ klass.new
327
+ end
328
+
329
+ it 'should call attribute_will_change! when using attribute_write' do
330
+ flexmock(object).should_receive(:attribute_will_change!).with("email").once
331
+ object.email = 'email'
332
+ end
333
+
334
+ context 'when email has changed' do
335
+ before do
336
+ object.email = 'old'
337
+ object.email = 'new'
338
+ end
339
+
340
+ it 'should have old value available via attribute_was' do
341
+ object.attribute_was(:email).should == 'old'
342
+ end
343
+
344
+ it 'should have old and new value available via attribue_change' do
345
+ object.attribute_change(:email).should == ['old', 'new']
346
+ end
347
+
348
+ it 'should provide a list of all changed attributes via changed' do
349
+ object.changed.should == ['email']
350
+ end
351
+ end
352
+ end
353
+
354
+ context "when persisting object" do
355
+ let(:input) do
356
+ {:email => 'email', :name => 'first'}
357
+ end
358
+
359
+ let(:klass) do
360
+ Class.new(subject) do
361
+ map :C_EmailAddress => :email
362
+ map :C_FirstName => :name
363
+ map :ContactID => :id
364
+
365
+ validates_presence_of :email
366
+ end
367
+ end
368
+
369
+ let(:object) { klass.new(:id => 1) }
370
+
371
+ let(:expected) do
372
+ {
373
+ :C_EmailAddress => 'email',
374
+ :C_FirstName => 'first'
375
+ }.with_indifferent_access
376
+ end
377
+
378
+
379
+ it_behaves_like 'remote operation that converts attribute values', :update
380
+
381
+
382
+ context "#update" do
383
+
384
+ before do
385
+ flexmock(klass).should_receive(:update_object).\
386
+ with(1, expected).and_return(true)
387
+
388
+ object.email = 'email'
389
+ object.name = 'first'
390
+
391
+ @result = object.update
392
+ end
393
+
394
+ it "should have called before and after callbacks for update" do
395
+ object.callbacks_called[:update].should == [:before, :after]
396
+ end
397
+
398
+ it 'should call update entity to make the api call' do
399
+ @result.should be_true
400
+ end
401
+
402
+ specify { object.email.should == 'email' }
403
+ specify { object.name.should == 'first' }
404
+ end
405
+
406
+
407
+ it_behaves_like 'remote operation that converts attribute values', :create
408
+
409
+ context "#create" do
410
+ context "when successfully creating record" do
411
+ let(:object) { klass.new }
412
+
413
+ before do
414
+ flexmock(klass).should_receive(:create_object).\
415
+ with(expected).and_return({:id => 1})
416
+
417
+ object.email = 'email'
418
+ object.name = 'first'
419
+ @result = object.create
420
+ end
421
+
422
+ it "should call before and after callbacks" do
423
+ object.callbacks_called[:create].should == [:before, :after]
424
+ end
425
+
426
+ it 'should call update entity to make the api call' do
427
+ @result.should be_true
428
+ end
429
+
430
+ specify { object.id.should == 1 }
431
+ specify { object.email.should == 'email' }
432
+ specify { object.name.should == 'first' }
433
+ end
434
+ end
435
+
436
+ context "#save" do
437
+
438
+ context 'when save will create' do
439
+ let(:object) do
440
+ klass.new(:email => 'james@lightsofapollo.com')
441
+ end
442
+
443
+ before do
444
+ flexmock(klass).should_receive(:create_object).\
445
+ with({'C_EmailAddress' => 'james@lightsofapollo.com'}).\
446
+ and_return({:id => 1}).once
447
+ object.save
448
+ end
449
+
450
+ it 'should now be persisted?' do
451
+ object.should be_persisted
452
+ end
453
+
454
+ it 'should now have an id' do
455
+ object.id.should == 1
456
+ end
457
+
458
+ it "should call before and after callbacks" do
459
+ object.callbacks_called[:save].should == [:before, :after]
460
+ end
461
+
462
+ end
463
+
464
+ context 'when save will update' do
465
+
466
+ let(:object) do
467
+ klass.new(:id => 1, :email => 'james@lightsofapollo.com')
468
+ end
469
+
470
+ before do
471
+ flexmock(klass).should_receive(:update_object).\
472
+ with(1, {'C_EmailAddress' => 'new'}).\
473
+ and_return(true).once
474
+
475
+ object.email = 'new'
476
+ object.save
477
+ end
478
+
479
+ it 'should now be persisted?' do
480
+ object.should be_persisted
481
+ end
482
+
483
+ it 'should have updated email address to "new"' do
484
+ object.email.should == 'new'
485
+ end
486
+
487
+ end
488
+
489
+ context "when record is invalid" do
490
+
491
+ let(:object) do
492
+ klass.new(:id => 1)
493
+ end
494
+
495
+ it "should not have called any callbacks" do
496
+ object.callbacks_called.should be_nil
497
+ end
498
+
499
+ it 'should not be valid' do
500
+ object.should_not be_valid
501
+ end
502
+
503
+ it 'should return false when saving' do
504
+ object.save.should be_false
505
+ end
506
+
507
+ end
508
+
509
+ end
510
+
511
+ context "#update_attributes" do
512
+
513
+ context "when successfuly updating the record and ignoring sanitization" do
514
+ let(:klass) do
515
+ Class.new(subject) do
516
+ map :C_EmailAddress => :email
517
+ map :C_FirstName => :name
518
+ map :ContactID => :id
519
+
520
+ attr_accessible :email
521
+ end
522
+ end
523
+
524
+ let(:object) { klass.new(:id => 1, :name => 'james') }
525
+
526
+ before do
527
+ flexmock(klass).should_receive(:update_object).\
528
+ with(1, {'C_EmailAddress' => 'new', 'C_FirstName' => 'gomez'}).\
529
+ and_return(true)
530
+
531
+ @result = object.update_attributes({
532
+ :email => 'new',
533
+ :name => 'gomez'
534
+ }, true)
535
+ end
536
+
537
+ it 'should call update entity to make the api call' do
538
+ @result.should be_true
539
+ end
540
+
541
+ specify { object.email.should == 'new' }
542
+ specify { object.name.should == 'gomez' }
543
+
544
+ end
545
+
546
+ context "when successfuly updating record" do
547
+ let(:klass) do
548
+ Class.new(subject) do
549
+ map :C_EmailAddress => :email
550
+ map :C_FirstName => :name
551
+ map :ContactID => :id
552
+
553
+ attr_accessible :email
554
+ end
555
+ end
556
+
557
+ let(:object) { klass.new(:id => 1, :name => 'james') }
558
+
559
+ let(:expected) do
560
+ {
561
+ :email => 'email',
562
+ }.with_indifferent_access
563
+ end
564
+
565
+ before do
566
+ flexmock(klass).should_receive(:update_object).\
567
+ with(1, {'C_EmailAddress' => 'email'}).and_return(true)
568
+
569
+ @result = object.update_attributes(input)
570
+ end
571
+
572
+ it 'should call update entity to make the api call' do
573
+ @result.should be_true
574
+ end
575
+
576
+ specify { object.email.should == 'email' }
577
+ specify { object.name.should == 'james' }
578
+
579
+ end
580
+
581
+
582
+ context 'when updating attributes of invalid object' do
583
+
584
+ let(:input) do
585
+ {}
586
+ end
587
+
588
+ let(:object) { klass.new }
589
+
590
+ before do
591
+ flexmock(object).should_receive(:create).never
592
+ flexmock(object).should_receive(:update).never
593
+ end
594
+
595
+ it 'should be invalid' do
596
+ object.should_not be_valid
597
+ end
598
+
599
+ it 'should return false' do
600
+ object = klass.new
601
+ object.update_attributes(input).should be_false
602
+ end
603
+
604
+ end
605
+
606
+ end
607
+
608
+
609
+ end
610
+
611
+
612
+ context "#self.attr_type_hash" do
613
+
614
+ let(:expected) do
615
+ {
616
+ :type => :my_name,
617
+ :import => :import_my_name,
618
+ :export => :export_my_name
619
+ }
620
+ end
621
+
622
+ it 'should return a hash with the expected output' do
623
+ subject.attr_type_hash(:my_name).should == expected
624
+ end
625
+
626
+ end
627
+
628
+ context '#convert_attribute_values' do
629
+ let(:klass) do
630
+ Class.new(subject) do
631
+ map :C_California1 => :california
632
+ attr_checkbox(:california)
633
+ end
634
+ end
635
+
636
+ context 'when :import' do
637
+ it 'should call import_boolean_checkbox' do
638
+ object = klass.new(:california => 'Yes')
639
+ flexmock(object.class).should_receive(:import_boolean_checkbox).with(:california, 'Yes').and_return(true)
640
+ attrs = object.convert_attribute_values(object.attributes)
641
+ attrs[:california].should === true
642
+ end
643
+ end
644
+
645
+ context 'when :export' do
646
+
647
+ it 'should call export_boolean_checkbox' do
648
+ object = klass.new(:california => 'Yes')
649
+ flexmock(object.class).should_receive(:export_boolean_checkbox).with(:california, true).and_return('Yes')
650
+ attrs = object.convert_attribute_values(object.attributes, :export)
651
+ attrs[:california].should === 'Yes'
652
+ end
653
+
654
+ end
655
+
656
+ end
657
+
658
+ context '#export_boolean_checkbox' do
659
+ let(:object) { subject.new }
660
+
661
+ it 'should return Yes when given true' do
662
+ object.send(:export_boolean_checkbox, :mock, true).should == 'Yes'
663
+ end
664
+
665
+ it 'should return No when given false' do
666
+ object.send(:export_boolean_checkbox, :mock, false).should == 'No'
667
+ end
668
+
669
+ end
670
+
671
+ context "#self.attr_checkbox" do
672
+
673
+ let(:klass) do
674
+ Class.new(subject) do
675
+ map :C_California1 => :california
676
+ attr_checkbox :california
677
+ end
678
+ end
679
+
680
+ it 'should have registered "california" as :checkbox in attribute_types' do
681
+ klass.attribute_types[:california].should == {
682
+ :type => :boolean_checkbox,
683
+ :import => :import_boolean_checkbox,
684
+ :export => :export_boolean_checkbox
685
+ }.with_indifferent_access
686
+ end
687
+
688
+ context "when creating object with checkbox as Yes" do
689
+ let(:object) { klass.new(:california => 'Yes') }
690
+ specify { object.attributes[:california].should == true }
691
+ end
692
+
693
+ context 'when creating object with checkbox as No' do
694
+ let(:object) { klass.new(:california => 'No') }
695
+ specify { object.attributes[:california].should == false }
696
+ end
697
+
698
+ context 'when creating object with checkbox as true' do
699
+ let(:object) { klass.new(:california => true) }
700
+ specify { object.attributes[:california].should == true }
701
+ end
702
+
703
+ context 'when creating object with checkbox as false' do
704
+ let(:object) { klass.new(:california => false) }
705
+ specify { object.attributes[:california].should == false }
706
+ end
707
+
708
+ end
709
+
710
+ context '#self.primary_key' do
711
+ it 'is "id" by default' do
712
+ subject.primary_key.should == 'id'
713
+ end
714
+ end
715
+
716
+ context '#self.eloqua_attribute' do
717
+
718
+ before do
719
+ @class = Class.new(subject) do
720
+ map :C_EmailAddress => :email
721
+ end
722
+ end
723
+
724
+ it 'should return eloqua name "C_EmailAddress"' do
725
+ @class.eloqua_attribute(:email).should == 'C_EmailAddress'
726
+ end
727
+
728
+ end
729
+
730
+ context "#self.api" do
731
+ it 'should have api on the class level' do
732
+ subject.api.should == Eloqua::Api::Service
733
+ end
734
+ end
735
+
736
+ context "#api" do
737
+ it "should have api on the instance level" do
738
+ subject.new.api.should == Eloqua::Api::Service
739
+ end
740
+ end
741
+
742
+ end