ruby_odata 0.1.0 → 0.1.1

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