ruby_odata 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. data/.gitignore +3 -2
  2. data/.travis.yml +2 -1
  3. data/.yardopts +6 -0
  4. data/CHANGELOG.md +102 -0
  5. data/Guardfile +14 -0
  6. data/README.md +285 -0
  7. data/Rakefile +0 -7
  8. data/features/basic_auth.feature +3 -2
  9. data/features/batch_request.feature +7 -6
  10. data/features/cassettes/basic_auth_protected_resource.yml +57 -0
  11. data/features/cassettes/batch_request_additions.yml +69 -0
  12. data/features/cassettes/batch_request_deletes.yml +69 -0
  13. data/features/cassettes/batch_request_updates.yml +69 -0
  14. data/features/cassettes/clean_database_for_testing.yml +46 -0
  15. data/features/cassettes/cucumber_tags/basic_auth.yml +297 -0
  16. data/features/cassettes/cucumber_tags/batch_request.yml +1459 -0
  17. data/features/cassettes/cucumber_tags/complex_types.yml +326 -0
  18. data/features/cassettes/cucumber_tags/error_handling.yml +64 -0
  19. data/features/cassettes/cucumber_tags/query_builder.yml +2025 -0
  20. data/features/cassettes/cucumber_tags/service.yml +234 -0
  21. data/features/cassettes/cucumber_tags/service_manage.yml +937 -0
  22. data/features/cassettes/cucumber_tags/service_methods.yml +647 -0
  23. data/features/cassettes/cucumber_tags/ssl.yml +203 -0
  24. data/features/cassettes/cucumber_tags/type_conversion.yml +337 -0
  25. data/features/cassettes/service_manage_additions.yml +65 -0
  26. data/features/cassettes/service_manage_deletions.yml +58 -0
  27. data/features/cassettes/service_manage_deletions_2.yml +58 -0
  28. data/features/cassettes/unsecured_metadata.yml +89 -0
  29. data/features/complex_types.feature +4 -3
  30. data/features/error_handling.feature +14 -0
  31. data/features/query_builder.feature +30 -9
  32. data/features/service.feature +4 -3
  33. data/features/service_manage.feature +6 -5
  34. data/features/service_methods.feature +3 -2
  35. data/features/ssl.feature +8 -8
  36. data/features/step_definitions/service_steps.rb +38 -24
  37. data/features/support/env.rb +1 -3
  38. data/features/support/hooks.rb +3 -2
  39. data/features/support/pickle.rb +29 -18
  40. data/features/support/vcr.rb +24 -0
  41. data/features/type_conversion.feature +16 -17
  42. data/lib/ruby_odata/association.rb +7 -6
  43. data/lib/ruby_odata/class_builder.rb +6 -7
  44. data/lib/ruby_odata/exceptions.rb +4 -0
  45. data/lib/ruby_odata/helpers.rb +11 -0
  46. data/lib/ruby_odata/operation.rb +5 -6
  47. data/lib/ruby_odata/property_metadata.rb +4 -5
  48. data/lib/ruby_odata/query_builder.rb +98 -63
  49. data/lib/ruby_odata/service.rb +118 -103
  50. data/lib/ruby_odata/version.rb +3 -1
  51. data/lib/ruby_odata.rb +20 -18
  52. data/ruby_odata.gemspec +16 -12
  53. data/spec/query_builder_spec.rb +78 -14
  54. data/spec/service_spec.rb +83 -83
  55. data/spec/support/sample_service_matcher.rb +15 -0
  56. data/test/RubyODataService/RubyODataService/App_Data/.gitkeep +0 -0
  57. data/test/blueprints.rb +15 -9
  58. data/test/usage_samples/querying.rb +5 -1
  59. data/test/usage_samples/sample_data.rb +1 -3
  60. metadata +213 -39
  61. data/CHANGELOG.rdoc +0 -88
  62. data/README.rdoc +0 -259
@@ -1,34 +1,98 @@
1
- require 'spec_helper'
1
+ require "spec_helper"
2
2
 
3
3
  module OData
4
4
  describe QueryBuilder do
5
5
  describe "#initialize" do
6
- it "handles additional parameters" do
7
- builder = QueryBuilder.new 'Products', { :x=>1, :y=>2 }
6
+ it "handles additional parameters" do
7
+ builder = QueryBuilder.new "Products", { :x=>1, :y=>2 }
8
8
  builder.query.should eq "Products?x=1&y=2"
9
9
  end
10
- it "handles empty additional parameters" do
11
- builder = QueryBuilder.new 'Products'
10
+ it "handles empty additional parameters" do
11
+ builder = QueryBuilder.new "Products"
12
12
  builder.query.should eq "Products"
13
- end
14
- end
15
- describe "#query" do
16
- it "should append additional parameters to the end" do
17
- builder = QueryBuilder.new 'Products', { :x=>1, :y=>2 }
13
+ end
14
+ it "should append additional parameters to the end of the query" do
15
+ builder = QueryBuilder.new "Products", { :x=>1, :y=>2 }
18
16
  builder.top(10)
19
17
  builder.query.should eq "Products?$top=10&x=1&y=2"
20
18
  end
19
+ end
20
+
21
+ describe "#links" do
21
22
  it "should properly handle queries for links" do
22
- builder = QueryBuilder.new 'Categories(1)'
23
- builder.links('Products')
23
+ builder = QueryBuilder.new "Categories(1)"
24
+ builder.links("Products")
24
25
  builder.query.should eq "Categories(1)/$links/Products"
25
26
  end
26
27
  it "should properly handle queries for links with additional operations" do
27
- builder = QueryBuilder.new 'Categories(1)'
28
- builder.links('Products')
28
+ builder = QueryBuilder.new "Categories(1)"
29
+ builder.links("Products")
29
30
  builder.top(5)
30
31
  builder.query.should eq "Categories(1)/$links/Products?$top=5"
31
32
  end
33
+ it "should throw an execption if count was already called on the builder" do
34
+ builder = QueryBuilder.new "Categories(1)"
35
+ builder.count
36
+ lambda { builder.links("Products") }.should raise_error(OData::NotSupportedError, "You cannot call both the `links` method and the `count` method in the same query.")
37
+ end
38
+ end
39
+
40
+ describe "#count" do
41
+ it "should accept the count method" do
42
+ builder = QueryBuilder.new "Products"
43
+ lambda { builder.count }.should_not raise_error
44
+ end
45
+ it "should properly handle the count method" do
46
+ builder = QueryBuilder.new "Products"
47
+ builder.count
48
+ builder.query.should eq "Products/$count"
49
+ end
50
+ it "should properly handle the count method with additional operators" do
51
+ builder = QueryBuilder.new "Products"
52
+ builder.filter("Name eq 'Widget 1'")
53
+ builder.count
54
+ builder.query.should eq "Products/$count?$filter=Name+eq+%27Widget+1%27"
55
+ end
56
+ it "should throw an execption if links was already called on the builder" do
57
+ builder = QueryBuilder.new "Categories(1)"
58
+ builder.links("Products")
59
+ lambda { builder.count }.should raise_error(OData::NotSupportedError, "You cannot call both the `links` method and the `count` method in the same query.")
60
+ end
61
+ end
62
+
63
+ describe "#navigate" do
64
+ it "should allow a user to drill down into a navigaion property on an initial query" do
65
+ builder = QueryBuilder.new "Genres('Horror Movies')"
66
+ builder.navigate("Titles")
67
+ builder.filter("Name eq 'Halloween'")
68
+ builder.query.should eq "Genres('Horror%20Movies')/Titles?$filter=Name+eq+%27Halloween%27"
69
+ end
70
+ it "should allow for multiple levels of drill down" do
71
+ builder = QueryBuilder.new "Genres('Horror Movies')"
72
+ builder.navigate("Titles('6aBu')")
73
+ builder.navigate("Awards")
74
+ builder.filter("Type eq 'Afi'")
75
+ builder.query.should eq "Genres('Horror%20Movies')/Titles('6aBu')/Awards?$filter=Type+eq+%27Afi%27"
76
+ end
77
+ it "should allow for a drill down plus links" do
78
+ builder = QueryBuilder.new "Genres('Horror Movies')"
79
+ builder.navigate("Titles('6aBu')")
80
+ builder.links("Awards")
81
+ builder.query.should eq "Genres('Horror%20Movies')/Titles('6aBu')/$links/Awards"
82
+ end
83
+ it "should allow for a drill down plus count" do
84
+ builder = QueryBuilder.new "Genres('Horror Movies')"
85
+ builder.navigate("Titles")
86
+ builder.count
87
+ builder.query.should eq "Genres('Horror%20Movies')/Titles/$count"
88
+ end
89
+ end
90
+
91
+ describe "#query" do
92
+ it "should encode spaces in IDs" do
93
+ builder = QueryBuilder.new "Categories('Cool Stuff')"
94
+ builder.query.should eq "Categories('Cool%20Stuff')"
95
+ end
32
96
  end
33
97
  end
34
98
  end
data/spec/service_spec.rb CHANGED
@@ -3,12 +3,12 @@ require 'spec_helper'
3
3
  module OData
4
4
  describe Service do
5
5
  describe "#initialize" do
6
- it "truncates passed in end slash from uri when making the request" do
6
+ it "truncates passed in end slash from uri when making the request" do
7
7
  # Required for the build_classes method
8
8
  stub_request(:get, "http://test.com/test.svc/$metadata").
9
9
  with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
10
10
  to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/edmx_empty.xml", __FILE__)), :headers => {})
11
-
11
+
12
12
  svc = OData::Service.new "http://test.com/test.svc/"
13
13
  end
14
14
  it "doesn't error with lowercase entities" do
@@ -16,10 +16,10 @@ module OData
16
16
  stub_request(:get, "http://test.com/test.svc/$metadata").
17
17
  with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
18
18
  to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/edmx_lowercase.xml", __FILE__)), :headers => {})
19
-
19
+
20
20
  lambda { OData::Service.new "http://test.com/test.svc" }.should_not raise_error
21
21
  end
22
-
22
+
23
23
  describe "additional query string parameters" do
24
24
  before(:each) do
25
25
  # Required for the build_classes method
@@ -52,7 +52,7 @@ module OData
52
52
  end
53
53
  it "should pass the parameters as part of a save" do
54
54
  svc = OData::Service.new "http://test.com/test.svc/", { :additional_params => { :x=>1, :y=>2 } }
55
- new_flight = ZDemoFlight.new
55
+ new_flight = ZDemoFlight.new
56
56
  svc.AddToflight_dataCollection(new_flight)
57
57
  svc.save_changes
58
58
  a_request(:post, "http://test.com/test.svc/flight_dataCollection?x=1&y=2").should have_been_made
@@ -75,9 +75,9 @@ module OData
75
75
  end
76
76
  it "should pass the parameters as part of a batch save" do
77
77
  svc = OData::Service.new "http://test.com/test.svc/", { :additional_params => { :x=>1, :y=>2 } }
78
- new_flight = ZDemoFlight.new
78
+ new_flight = ZDemoFlight.new
79
79
  svc.AddToflight_dataCollection(new_flight)
80
- new_flight2 = ZDemoFlight.new
80
+ new_flight2 = ZDemoFlight.new
81
81
  svc.AddToflight_dataCollection(new_flight2)
82
82
  svc.save_changes
83
83
  a_request(:post, "http://test.com/test.svc/$batch?x=1&y=2").should have_been_made
@@ -103,7 +103,7 @@ module OData
103
103
  a_request(:get, "http://test.com/test.svc/get_top_flight?x=1&y=2").should have_been_made
104
104
  end
105
105
  end
106
-
106
+
107
107
  describe "lowercase collections" do
108
108
  before(:each) do
109
109
  # Required for the build_classes method
@@ -111,12 +111,12 @@ module OData
111
111
  with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
112
112
  to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/edmx_lowercase.xml", __FILE__)), :headers => {})
113
113
  end
114
-
114
+
115
115
  it "should respond_to a lowercase collection" do
116
116
  svc = OData::Service.new "http://test.com/test.svc"
117
117
  svc.respond_to?('acronyms').should be_true
118
118
  end
119
-
119
+
120
120
  it "should allow a lowercase collections to be queried" do
121
121
  svc = OData::Service.new "http://test.com/test.svc"
122
122
  lambda { svc.send('acronyms') }.should_not raise_error
@@ -142,19 +142,19 @@ module OData
142
142
  results.first.should be_a_kind_of(ZDemoFlight)
143
143
  end
144
144
  end
145
-
145
+
146
146
  describe "collections, objects, metadata etc" do
147
147
  before(:each) do
148
148
  # Metadata
149
149
  stub_request(:get, "http://test.com/test.svc/$metadata").
150
150
  with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
151
151
  to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/feed_customization/edmx_feed_customization.xml", __FILE__)), :headers => {})
152
-
152
+
153
153
  # Content - Products
154
154
  stub_request(:get, /http:\/\/test\.com\/test\.svc\/Products(?:.*)/).
155
155
  with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
156
156
  to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/feed_customization/result_feed_customization_products_expand.xml", __FILE__)), :headers => {})
157
-
157
+
158
158
  # Content - Categories expanded Products
159
159
  stub_request(:get, /http:\/\/test\.com\/test\.svc\/Categories(?:.*)/).
160
160
  with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
@@ -208,9 +208,9 @@ module OData
208
208
  meta.nullable.should eq true
209
209
  meta.fc_target_path.should eq "SyndicationSummary"
210
210
  meta.fc_keep_in_content.should eq false
211
- end
212
- end
213
-
211
+ end
212
+ end
213
+
214
214
  describe "single class" do
215
215
  it "should handle properties where a property is represented in the syndication title instead of the properties collection" do
216
216
  svc = OData::Service.new "http://test.com/test.svc/"
@@ -224,46 +224,46 @@ module OData
224
224
  results = svc.execute
225
225
  results.first.Description.should eq "Whole grain bread"
226
226
  end
227
- end
228
-
227
+ end
228
+
229
229
  describe "expanded inline class" do
230
230
  it "should handle properties where a property is represented in the syndication title instead of the properties collection" do
231
231
  svc = OData::Service.new "http://test.com/test.svc/"
232
232
  svc.Categories
233
233
  results = svc.execute
234
-
234
+
235
235
  beverages = results[1]
236
-
236
+
237
237
  milk = beverages.Products.first
238
238
  milk.Name.should eq "Milk"
239
239
  milk.Description.should eq "Low fat milk"
240
-
240
+
241
241
  lemonade = beverages.Products.last
242
242
  lemonade.Name.should eq "Pink Lemonade"
243
243
  lemonade.Description.should eq "36 Ounce Cans (Pack of 3)"
244
244
  end
245
245
  end
246
246
  end
247
-
247
+
248
248
  describe "handling inline collections/properties" do
249
249
  it "should make plural named properties arrays and not a single class" do
250
250
  svc = OData::Service.new "http://test.com/test.svc/"
251
251
  svc.Categories
252
252
  results = svc.execute
253
253
  food = results[0]
254
-
254
+
255
255
  food.Products.should be_an Array
256
256
  end
257
-
257
+
258
258
  it "should not make an array if the navigation property name is singular" do
259
259
  svc = OData::Service.new "http://test.com/test.svc/"
260
260
  svc.Products
261
261
  results = svc.execute
262
262
  product = results.first
263
263
  product.Category.should_not be_an Array
264
- end
264
+ end
265
265
  end
266
-
266
+
267
267
  describe "navigation properties" do
268
268
  it "should fill in PropertyMetadata for navigation properties" do
269
269
  svc = OData::Service.new "http://test.com/test.svc/"
@@ -271,27 +271,27 @@ module OData
271
271
  end
272
272
  end
273
273
  end
274
-
274
+
275
275
  describe "single layer inheritance" do
276
276
  before(:each) do
277
277
  # Metadata
278
278
  stub_request(:get, "http://test.com/test.svc/$metadata").
279
279
  with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
280
280
  to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/inheritance/edmx_pluralsight.xml", __FILE__)), :headers => {})
281
-
281
+
282
282
  # Content - Courses
283
283
  stub_request(:get, /http:\/\/test\.com\/test\.svc\/Courses(?:.*)/).
284
284
  with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
285
285
  to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/inheritance/result_pluralsight_courses.xml", __FILE__)), :headers => {})
286
286
  end
287
-
287
+
288
288
  it "should build all inherited attributes" do
289
289
  OData::Service.new "http://test.com/test.svc/"
290
290
  methods = Course.instance_methods.reject {|m| Object.methods.index(m)}
291
-
291
+
292
292
  # Ruby 1.9 uses symbols, and 1.8 uses strings, so this normalizes the data
293
293
  methods.map! {|m| m.to_sym}
294
-
294
+
295
295
  methods.should include(:Title)
296
296
  methods.should include(:Description)
297
297
  methods.should include(:VideoLength)
@@ -319,7 +319,7 @@ module OData
319
319
  course.Category.should_not be_nil
320
320
  end
321
321
  end
322
-
322
+
323
323
  describe "handling partial collections" do
324
324
  before(:each) do
325
325
  # Metadata
@@ -361,14 +361,14 @@ module OData
361
361
  results.count.should eq 3
362
362
  end
363
363
  end
364
-
364
+
365
365
  describe "link queries" do
366
366
  before(:each) do
367
367
  # Required for the build_classes method
368
368
  stub_request(:get, /http:\/\/test\.com\/test\.svc\/\$metadata(?:\?.+)?/).
369
369
  with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
370
370
  to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/sample_service/edmx_categories_products.xml", __FILE__)), :headers => {})
371
-
371
+
372
372
  stub_request(:get, "http://test.com/test.svc/Categories(1)/$links/Products").
373
373
  with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
374
374
  to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/links/result_links_query.xml", __FILE__)), :headers => {})
@@ -381,72 +381,72 @@ module OData
381
381
  results.first.should be_a_kind_of(URI)
382
382
  results[0].path.should eq "/SampleService/RubyOData.svc/Products(1)"
383
383
  results[1].path.should eq "/SampleService/RubyOData.svc/Products(2)"
384
- results[2].path.should eq "/SampleService/RubyOData.svc/Products(3)"
384
+ results[2].path.should eq "/SampleService/RubyOData.svc/Products(3)"
385
385
  end
386
386
  end
387
-
387
+
388
388
  describe "sample service" do
389
389
  before(:each) do
390
390
  # Required for the build_classes method
391
391
  stub_request(:get, /http:\/\/test\.com\/test\.svc\/\$metadata(?:\?.+)?/).
392
392
  with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
393
393
  to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/sample_service/edmx_categories_products.xml", __FILE__)), :headers => {})
394
-
394
+
395
395
  stub_request(:get, /http:\/\/test\.com\/test\.svc\/Products\(\d\)/).
396
396
  with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
397
397
  to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/sample_service/result_single_product.xml", __FILE__)), :headers => {})
398
-
398
+
399
399
  stub_request(:get, /http:\/\/test\.com\/test\.svc\/Products\(\d{2,}\)/).
400
400
  with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
401
401
  to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/sample_service/result_single_product_not_found.xml", __FILE__)), :headers => {})
402
-
402
+
403
403
  stub_request(:get, "http://test.com/test.svc/Products(1)/Category").
404
404
  with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
405
405
  to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/sample_service/result_single_category.xml", __FILE__)), :headers => {})
406
-
406
+
407
407
  stub_request(:get, "http://test.com/test.svc/Categories(1)").
408
408
  with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
409
409
  to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/sample_service/result_single_category.xml", __FILE__)), :headers => {})
410
-
410
+
411
411
  stub_request(:get, "http://test.com/test.svc/Categories(1)/Products").
412
412
  with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
413
413
  to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/sample_service/result_multiple_category_products.xml", __FILE__)), :headers => {})
414
-
414
+
415
415
  stub_request(:post, "http://test.com/test.svc/Categories(1)/$links/Products").to_return(:status => 204)
416
416
  stub_request(:post, "http://test.com/test.svc/$batch").to_return(:status => 202)
417
417
  end
418
-
418
+
419
419
  describe "lazy loading" do
420
420
  after(:each) do
421
421
  Object.send(:remove_const, 'Product') if Object.const_defined? 'Product'
422
422
  Object.send(:remove_const, 'Category') if Object.const_defined? 'Category'
423
423
  end
424
-
424
+
425
425
  it "should have a load property method" do
426
426
  svc = OData::Service.new "http://test.com/test.svc/"
427
427
  svc.should respond_to(:load_property)
428
428
  end
429
-
429
+
430
430
  it "should throw an exception if the object isn't tracked" do
431
431
  svc = OData::Service.new "http://test.com/test.svc/"
432
432
  new_object = Product.new
433
- lambda { svc.load_property(new_object, "Category") }.should raise_error(ArgumentError, "You cannot load a property on an entity that isn't tracked")
433
+ lambda { svc.load_property(new_object, "Category") }.should raise_error(NotSupportedError, "You cannot load a property on an entity that isn't tracked")
434
434
  end
435
-
435
+
436
436
  it "should throw an exception if there isn't a method matching the navigation property passed in" do
437
437
  svc = OData::Service.new "http://test.com/test.svc/"
438
438
  svc.Products(1)
439
439
  product = svc.execute.first
440
- lambda { svc.load_property(product, "NoMatchingMethod") }.should raise_error(ArgumentError, "'NoMatchingMethod' is not a valid navigation property")
440
+ lambda { svc.load_property(product, "NoMatchingMethod") }.should raise_error(ArgumentError, "'NoMatchingMethod' is not a valid navigation property")
441
441
  end
442
-
442
+
443
443
  it "should throw an exception if the method passed in is a standard property (non-navigation)" do
444
444
  svc = OData::Service.new "http://test.com/test.svc/"
445
445
  svc.Products(1)
446
446
  product = svc.execute.first
447
- lambda { svc.load_property(product, "Name") }.should raise_error(ArgumentError, "'Name' is not a valid navigation property")
447
+ lambda { svc.load_property(product, "Name") }.should raise_error(ArgumentError, "'Name' is not a valid navigation property")
448
448
  end
449
-
449
+
450
450
  it "should fill a single navigation property" do
451
451
  svc = OData::Service.new "http://test.com/test.svc/"
452
452
  svc.Products(1)
@@ -456,7 +456,7 @@ module OData
456
456
  product.Category.Id.should eq 1
457
457
  product.Category.Name.should eq 'Category 1'
458
458
  end
459
-
459
+
460
460
  it "should fill a collection navigation property" do
461
461
  svc = OData::Service.new "http://test.com/test.svc/"
462
462
  svc.Categories(1)
@@ -467,58 +467,58 @@ module OData
467
467
  category.Products[1].Id.should eq 2
468
468
  end
469
469
  end
470
-
470
+
471
471
  describe "find, create, add, update, and delete" do
472
472
  after(:each) do
473
473
  Object.send(:remove_const, 'Product') if Object.const_defined? 'Product'
474
474
  Object.send(:remove_const, 'Category') if Object.const_defined? 'Category'
475
475
  end
476
-
476
+
477
477
  it "should implement an AddTo method for collection" do
478
478
  svc = OData::Service.new "http://test.com/test.svc/"
479
479
  svc.should respond_to :AddToCategories
480
480
  svc.should respond_to :AddToProducts
481
481
  end
482
-
482
+
483
483
  it "should create objects with an initialize method that can build the object from a hash" do
484
484
  svc = OData::Service.new "http://test.com/test.svc/"
485
485
  product = Product.new 'Id' => 1000, 'Name' => 'New Product'
486
486
  product.Id.should eq 1000
487
487
  product.Name.should eq 'New Product'
488
488
  end
489
-
489
+
490
490
  it "should create objects that rejects keys that don't have corresponding methods" do
491
491
  svc = OData::Service.new "http://test.com/test.svc/"
492
492
  lambda { Product.new 'NotAProperty' => true }.should raise_error NoMethodError
493
493
  end
494
-
494
+
495
495
  it "should create objects that expose a properties class method that lists the properties for the object" do
496
496
  svc = OData::Service.new "http://test.com/test.svc/"
497
497
  Product.properties.should include 'Id'
498
498
  Product.properties.should include 'Name'
499
- Product.properties.should include 'Category'
499
+ Product.properties.should include 'Category'
500
500
  end
501
-
501
+
502
502
  it "should have full metadata for a property returned from the properties method" do
503
503
  svc = OData::Service.new "http://test.com/test.svc/"
504
504
  Product.properties['Category'].should be_a PropertyMetadata
505
505
  Product.properties['Category'].nav_prop.should be_true
506
506
  end
507
-
507
+
508
508
  it "should create objects that expose an id property" do
509
509
  svc = OData::Service.new "http://test.com/test.svc/"
510
510
  svc.Products(1)
511
511
  product = svc.execute.first
512
512
  product.should respond_to :id
513
513
  end
514
-
514
+
515
515
  it "should extract the id from the metadata" do
516
516
  svc = OData::Service.new "http://test.com/test.svc/"
517
517
  svc.Products(1)
518
518
  product = svc.execute.first
519
519
  product.id.should eq 1
520
520
  end
521
-
521
+
522
522
  describe "Class.first method" do
523
523
  it "should exist on the create server objects" do
524
524
  svc = OData::Service.new "http://test.com/test.svc/"
@@ -528,7 +528,7 @@ module OData
528
528
  svc = OData::Service.new "http://test.com/test.svc/"
529
529
  product = Product.first(nil)
530
530
  product.should be_nil
531
- end
531
+ end
532
532
  it "should return nil if an id isn't found" do
533
533
  svc = OData::Service.new "http://test.com/test.svc/"
534
534
  product = Product.first(1234567890)
@@ -541,29 +541,29 @@ module OData
541
541
  end
542
542
  end
543
543
  end
544
-
544
+
545
545
  describe "namespaces" do
546
546
  after(:each) do
547
547
  VisoftInc::Sample::Models.send(:remove_const, 'Product') if VisoftInc::Sample::Models.const_defined? 'Product'
548
548
  VisoftInc::Sample::Models.send(:remove_const, 'Category') if VisoftInc::Sample::Models.const_defined? 'Category'
549
-
549
+
550
550
  VisoftInc::Sample.send(:remove_const, 'Models') if VisoftInc::Sample.const_defined? 'Models'
551
- VisoftInc.send(:remove_const, 'Sample') if VisoftInc.const_defined? 'Sample'
551
+ VisoftInc.send(:remove_const, 'Sample') if VisoftInc.const_defined? 'Sample'
552
552
  Object.send(:remove_const, 'VisoftInc') if Object.const_defined? 'VisoftInc'
553
553
  end
554
-
554
+
555
555
  it "should create models in the specified namespace if the option is set (using a .NET style namespace with dots)" do
556
556
  svc = OData::Service.new "http://test.com/test.svc/", { :namespace => 'VisoftInc.Sample.Models' }
557
557
  defined?(VisoftInc::Sample::Models::Product).nil?.should be_false, 'VisoftInc::Sample::Models::Product was expected to be defined, but was not'
558
558
  defined?(VisoftInc::Sample::Models::Category).nil?.should be_false, 'VisoftInc::Sample::Models::Category was expected to be defined, but was not'
559
559
  end
560
-
560
+
561
561
  it "should create models in the specified namespace if the option is set (using Ruby style namespaces with double colons)" do
562
562
  svc = OData::Service.new "http://test.com/test.svc/", { :namespace => 'VisoftInc::Sample::Models' }
563
563
  defined?(VisoftInc::Sample::Models::Product).nil?.should be_false, 'VisoftInc::Sample::Models::Product was expected to be defined, but was not'
564
564
  defined?(VisoftInc::Sample::Models::Category).nil?.should be_false, 'VisoftInc::Sample::Models::Category was expected to be defined, but was not'
565
565
  end
566
-
566
+
567
567
  it "should fill object defined in a namespace" do
568
568
  svc = OData::Service.new "http://test.com/test.svc/", { :namespace => 'VisoftInc::Sample::Models' }
569
569
  svc.Categories(1)
@@ -573,19 +573,19 @@ module OData
573
573
  category.Id.should eq 1
574
574
  category.Name.should eq 'Category 1'
575
575
  end
576
-
576
+
577
577
  it "should fill the class_metadata hash" do
578
578
  svc = OData::Service.new "http://test.com/test.svc/", { :namespace => 'VisoftInc::Sample::Models' }
579
579
  svc.class_metadata.should_not be_empty
580
580
  end
581
-
581
+
582
582
  it "should add a key (based on the name) for each property class_metadata hash" do
583
583
  svc = OData::Service.new "http://test.com/test.svc/", { :namespace => 'VisoftInc::Sample::Models' }
584
584
  svc.class_metadata['VisoftInc::Sample::Models::Product'].should have_key 'Id'
585
585
  svc.class_metadata['VisoftInc::Sample::Models::Product'].should have_key 'Name'
586
586
  svc.class_metadata['VisoftInc::Sample::Models::Product'].should have_key 'Description'
587
587
  end
588
-
588
+
589
589
  it "should lazy load objects defined in a namespace" do
590
590
  svc = OData::Service.new "http://test.com/test.svc/", { :namespace => 'VisoftInc::Sample::Models' }
591
591
  svc.Categories(1)
@@ -593,7 +593,7 @@ module OData
593
593
  svc.load_property category, 'Products'
594
594
  category.Products.should_not be_nil
595
595
  category.Products.first.Id.should eq 1
596
- category.Products.first.Name.should eq 'Widget 1'
596
+ category.Products.first.Name.should eq 'Widget 1'
597
597
  end
598
598
  end
599
599
 
@@ -602,15 +602,15 @@ module OData
602
602
  svc = OData::Service.new "http://test.com/test.svc/"
603
603
  svc.should respond_to(:add_link)
604
604
  end
605
-
605
+
606
606
  it "shouldn't be allowed if a parent isn't tracked" do
607
607
  svc = OData::Service.new "http://test.com/test.svc/"
608
608
  category = Category.new :Name => 'New Category'
609
609
  property = nil # Not needed for this test
610
610
  product = nil # Not needed for this test
611
- lambda { svc.add_link(category, property, product) }.should raise_error(ArgumentError, "You cannot add a link on an entity that isn't tracked (Category)")
611
+ lambda { svc.add_link(category, property, product) }.should raise_error(NotSupportedError, "You cannot add a link on an entity that isn't tracked (Category)")
612
612
  end
613
-
613
+
614
614
  it "shouldn't be allowed if a property isn't found on the parent" do
615
615
  svc = OData::Service.new "http://test.com/test.svc/"
616
616
  svc.Categories(1)
@@ -619,7 +619,7 @@ module OData
619
619
  product = nil # Not needed for this test
620
620
  lambda { svc.add_link(category, property, product) }.should raise_error(ArgumentError, "'NotAProperty' is not a valid navigation property for Category")
621
621
  end
622
-
622
+
623
623
  it "shouldn't be allowed if a property isn't a navigation property on the parent" do
624
624
  svc = OData::Service.new "http://test.com/test.svc/"
625
625
  svc.Categories(1)
@@ -628,16 +628,16 @@ module OData
628
628
  product = nil # Not needed for this test
629
629
  lambda { svc.add_link(category, property, product) }.should raise_error(ArgumentError, "'Name' is not a valid navigation property for Category")
630
630
  end
631
-
631
+
632
632
  it "shouldn't be allowed if a child isn't tracked" do
633
633
  svc = OData::Service.new "http://test.com/test.svc/"
634
634
  svc.Categories(1)
635
635
  category = svc.execute.first
636
636
  property = 'Products'
637
- product = Product.new :Name => 'Widget 1'
638
- lambda { svc.add_link(category, property, product) }.should raise_error(ArgumentError, "You cannot add a link on a child entity that isn't tracked (Product)")
637
+ product = Product.new :Name => 'Widget 1'
638
+ lambda { svc.add_link(category, property, product) }.should raise_error(NotSupportedError, "You cannot add a link on a child entity that isn't tracked (Product)")
639
639
  end
640
-
640
+
641
641
  it "should perform a post against the correct URL with the correct body on a single_save" do
642
642
  svc = OData::Service.new "http://test.com/test.svc/"
643
643
  svc.Categories(1)
@@ -705,7 +705,7 @@ module OData
705
705
  end
706
706
  end
707
707
  end
708
-
708
+
709
709
  describe_private OData::Service do
710
710
  describe "parse value" do
711
711
  before(:each) do
@@ -714,7 +714,7 @@ module OData
714
714
  with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
715
715
  to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/edmx_empty.xml", __FILE__)), :headers => {})
716
716
  end
717
-
717
+
718
718
  it "should not error on an 'out of range' date" do
719
719
  # This date was returned in the Netflix OData service and failed with an ArgumentError: out of range using 1.8.7 (2010-12-23 patchlevel 330) [i386-mingw32]
720
720
  svc = OData::Service.new "http://test.com/test.svc/"
@@ -0,0 +1,15 @@
1
+ require 'uri'
2
+
3
+ module OData
4
+ module Support
5
+ class SampleServiceMatcher
6
+ def self.call(req1, req2)
7
+ regexp = /^(https?:\/\/(?:[^@]*@)?)[^:]*(:\d+\/.*$)/i
8
+ request1 = req1.uri.match(regexp)
9
+ request2 = req2.uri.match(regexp)
10
+
11
+ (request1[1] == request2[1]) && (request1[2] == request2[2])
12
+ end
13
+ end
14
+ end
15
+ end