ruby_odata 0.0.10 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (173) hide show
  1. data/.gitignore +9 -3
  2. data/.travis.yml +4 -0
  3. data/CHANGELOG.rdoc +18 -1
  4. data/README.rdoc +77 -19
  5. data/config/cucumber.yml +4 -3
  6. data/features/basic_auth.feature +5 -7
  7. data/features/batch_request.feature +11 -11
  8. data/features/complex_types.feature +11 -11
  9. data/features/query_builder.feature +27 -18
  10. data/features/service.feature +8 -8
  11. data/features/service_manage.feature +27 -12
  12. data/features/service_methods.feature +37 -0
  13. data/features/ssl.feature +4 -4
  14. data/features/step_definitions/pickle_steps.rb +100 -0
  15. data/features/step_definitions/service_steps.rb +99 -65
  16. data/features/support/constants.rb +3 -0
  17. data/features/support/custom_helpers.rb +54 -0
  18. data/features/support/env.rb +0 -10
  19. data/features/support/hooks.rb +1 -1
  20. data/features/support/pickle.rb +82 -0
  21. data/features/type_conversion.feature +10 -10
  22. data/lib/ruby_odata.rb +4 -1
  23. data/lib/ruby_odata/association.rb +36 -0
  24. data/lib/ruby_odata/class_builder.rb +96 -16
  25. data/lib/ruby_odata/helpers.rb +10 -0
  26. data/lib/ruby_odata/operation.rb +7 -5
  27. data/lib/ruby_odata/property_metadata.rb +11 -6
  28. data/lib/ruby_odata/query_builder.rb +20 -1
  29. data/lib/ruby_odata/service.rb +407 -94
  30. data/lib/ruby_odata/version.rb +1 -1
  31. data/ruby_odata.gemspec +2 -0
  32. data/spec/association_spec.rb +48 -0
  33. data/spec/class_builder_spec.rb +11 -2
  34. data/spec/fixtures/inheritance/edmx_pluralsight.xml +111 -0
  35. data/spec/fixtures/inheritance/result_pluralsight_courses.xml +229 -0
  36. data/spec/fixtures/links/result_links_query.xml +6 -0
  37. data/spec/fixtures/partial/partial_feed_metadata.xml +25 -0
  38. data/spec/fixtures/partial/partial_feed_part_1.xml +42 -0
  39. data/spec/fixtures/partial/partial_feed_part_2.xml +42 -0
  40. data/spec/fixtures/partial/partial_feed_part_3.xml +40 -0
  41. data/spec/fixtures/sample_service/edmx_categories_products.xml +1 -0
  42. data/spec/fixtures/sample_service/result_category_names.xml +5 -0
  43. data/spec/fixtures/sample_service/result_entity_category_web_get.xml +29 -0
  44. data/spec/fixtures/sample_service/result_entity_single_category_web_get.xml +23 -0
  45. data/spec/fixtures/sample_service/result_first_category_id.xml +2 -0
  46. data/spec/fixtures/sample_service/result_multiple_category_products.xml +57 -0
  47. data/spec/fixtures/sample_service/result_single_category.xml +18 -0
  48. data/spec/fixtures/sample_service/result_single_product.xml +26 -0
  49. data/spec/fixtures/sample_service/result_single_product_not_found.xml +4 -0
  50. data/spec/fixtures/sap/edmx_sap_demo_flight.xml +62 -58
  51. data/spec/property_metadata_spec.rb +9 -2
  52. data/spec/query_builder_spec.rb +11 -0
  53. data/spec/revised_service_spec.rb +197 -0
  54. data/spec/service_spec.rb +463 -4
  55. data/test/RubyODataService/RubyODataService.sln +20 -0
  56. data/test/RubyODataService/RubyODataService/App_Start/EntityFramework.SqlServerCompact.cs +12 -0
  57. data/test/RubyODataService/RubyODataService/BasicAuth/RubyOData.svc +3 -0
  58. data/test/RubyODataService/RubyODataService/BasicAuth/RubyOData.svc.cs +107 -0
  59. data/test/RubyODataService/RubyODataService/Global.asax +1 -0
  60. data/test/RubyODataService/RubyODataService/Global.asax.cs +49 -0
  61. data/test/RubyODataService/RubyODataService/Models/AuditFields.cs +16 -0
  62. data/test/RubyODataService/RubyODataService/Models/Category.cs +16 -0
  63. data/test/RubyODataService/RubyODataService/Models/Product.cs +20 -0
  64. data/test/RubyODataService/RubyODataService/Properties/AssemblyInfo.cs +35 -0
  65. data/test/RubyODataService/RubyODataService/RubyOData.svc +3 -0
  66. data/test/RubyODataService/RubyODataService/RubyOData.svc.cs +57 -0
  67. data/test/RubyODataService/RubyODataService/RubyODataContext.cs +16 -0
  68. data/test/RubyODataService/RubyODataService/RubyODataService.csproj +159 -0
  69. data/test/RubyODataService/RubyODataService/RubyODataService.csproj.user +31 -0
  70. data/test/RubyODataService/RubyODataService/Web.Debug.config +30 -0
  71. data/test/RubyODataService/RubyODataService/Web.Release.config +31 -0
  72. data/test/RubyODataService/RubyODataService/Web.config +27 -0
  73. data/test/RubyODataService/RubyODataService/bin/EntityFramework.dll +0 -0
  74. data/test/RubyODataService/RubyODataService/bin/Microsoft.Data.Edm.dll +0 -0
  75. data/test/RubyODataService/RubyODataService/bin/Microsoft.Data.OData.dll +0 -0
  76. data/test/RubyODataService/RubyODataService/bin/Microsoft.Data.Services.Client.dll +0 -0
  77. data/test/RubyODataService/RubyODataService/bin/Microsoft.Data.Services.dll +0 -0
  78. data/test/RubyODataService/RubyODataService/bin/Microsoft.Data.Spatial.dll +0 -0
  79. data/test/RubyODataService/RubyODataService/bin/RubyODataService.dll +0 -0
  80. data/test/RubyODataService/RubyODataService/bin/System.Data.SqlServerCe.Entity.dll +0 -0
  81. data/test/RubyODataService/RubyODataService/bin/System.Data.SqlServerCe.dll +0 -0
  82. data/test/RubyODataService/RubyODataService/bin/System.Spatial.dll +0 -0
  83. data/test/RubyODataService/RubyODataService/bin/WebActivator.dll +0 -0
  84. data/test/RubyODataService/RubyODataService/bin/amd64/Microsoft.VC90.CRT/Microsoft.VC90.CRT.manifest +6 -0
  85. data/test/RubyODataService/RubyODataService/bin/amd64/Microsoft.VC90.CRT/README_ENU.txt +0 -0
  86. data/test/RubyODataService/RubyODataService/bin/amd64/Microsoft.VC90.CRT/msvcr90.dll +0 -0
  87. data/test/RubyODataService/RubyODataService/bin/amd64/sqlcecompact40.dll +0 -0
  88. data/test/RubyODataService/RubyODataService/bin/amd64/sqlceer40EN.dll +0 -0
  89. data/test/RubyODataService/RubyODataService/bin/amd64/sqlceme40.dll +0 -0
  90. data/test/RubyODataService/RubyODataService/bin/amd64/sqlceqp40.dll +0 -0
  91. data/test/RubyODataService/RubyODataService/bin/amd64/sqlcese40.dll +0 -0
  92. data/test/RubyODataService/RubyODataService/bin/x86/Microsoft.VC90.CRT/Microsoft.VC90.CRT.manifest +6 -0
  93. data/test/RubyODataService/RubyODataService/bin/x86/Microsoft.VC90.CRT/README_ENU.txt +0 -0
  94. data/test/RubyODataService/RubyODataService/bin/x86/Microsoft.VC90.CRT/msvcr90.dll +0 -0
  95. data/test/RubyODataService/RubyODataService/bin/x86/sqlcecompact40.dll +0 -0
  96. data/test/RubyODataService/RubyODataService/bin/x86/sqlceer40EN.dll +0 -0
  97. data/test/RubyODataService/RubyODataService/bin/x86/sqlceme40.dll +0 -0
  98. data/test/RubyODataService/RubyODataService/bin/x86/sqlceqp40.dll +0 -0
  99. data/test/RubyODataService/RubyODataService/bin/x86/sqlcese40.dll +0 -0
  100. data/test/RubyODataService/RubyODataService/packages.config +7 -0
  101. data/test/RubyODataService/packages/EntityFramework.4.2.0.0/EntityFramework.4.2.0.0.nupkg +0 -0
  102. data/test/RubyODataService/packages/EntityFramework.4.2.0.0/lib/net40/EntityFramework.dll +0 -0
  103. data/test/RubyODataService/packages/EntityFramework.4.2.0.0/lib/net40/EntityFramework.xml +13488 -0
  104. data/test/RubyODataService/packages/EntityFramework.SqlServerCompact.4.1.8482.2/Content/App_Start/EntityFramework.SqlServerCompact.cs.pp +12 -0
  105. data/test/RubyODataService/packages/EntityFramework.SqlServerCompact.4.1.8482.2/EULA_ENU.rtf +969 -0
  106. data/test/RubyODataService/packages/EntityFramework.SqlServerCompact.4.1.8482.2/EntityFramework.SqlServerCompact.4.1.8482.2.nupkg +0 -0
  107. data/test/RubyODataService/packages/EntityFramework.SqlServerCompact.4.1.8482.2/lib/System.Data.SqlServerCe.Entity.dll +0 -0
  108. data/test/RubyODataService/packages/EntityFramework.SqlServerCompact.4.1.8482.2/tools/install.ps1 +3 -0
  109. data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/Content/web.config.transform +8 -0
  110. data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/amd64/Microsoft.VC90.CRT/Microsoft.VC90.CRT.manifest +6 -0
  111. data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/amd64/Microsoft.VC90.CRT/README_ENU.txt +0 -0
  112. data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/amd64/Microsoft.VC90.CRT/msvcr90.dll +0 -0
  113. data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/amd64/sqlcecompact40.dll +0 -0
  114. data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/amd64/sqlceer40EN.dll +0 -0
  115. data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/amd64/sqlceme40.dll +0 -0
  116. data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/amd64/sqlceqp40.dll +0 -0
  117. data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/amd64/sqlcese40.dll +0 -0
  118. data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/x86/Microsoft.VC90.CRT/Microsoft.VC90.CRT.manifest +6 -0
  119. data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/x86/Microsoft.VC90.CRT/README_ENU.txt +0 -0
  120. data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/x86/Microsoft.VC90.CRT/msvcr90.dll +0 -0
  121. data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/x86/sqlcecompact40.dll +0 -0
  122. data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/x86/sqlceer40EN.dll +0 -0
  123. data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/x86/sqlceme40.dll +0 -0
  124. data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/x86/sqlceqp40.dll +0 -0
  125. data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/x86/sqlcese40.dll +0 -0
  126. data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/SQLCE_EULA_ENU.rtf +778 -0
  127. data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/SqlServerCompact.4.0.8482.1.nupkg +0 -0
  128. data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/Tools/GetSqlCEPostBuildCmd.ps1 +12 -0
  129. data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/Tools/install.ps1 +11 -0
  130. data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/Tools/uninstall.ps1 +9 -0
  131. data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/lib/System.Data.SqlServerCe.dll +0 -0
  132. data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/DataSvcUtil.exe +0 -0
  133. data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/License.rtf +708 -0
  134. data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/Microsoft.Data.Edm.dll +0 -0
  135. data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/Microsoft.Data.Edm.xml +4150 -0
  136. data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/Microsoft.Data.OData.dll +0 -0
  137. data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/Microsoft.Data.OData.xml +1969 -0
  138. data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/Microsoft.Data.Services.Client.dll +0 -0
  139. data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/Microsoft.Data.Services.Client.xml +1442 -0
  140. data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/Microsoft.Data.Services.Design.dll +0 -0
  141. data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/Microsoft.Data.Services.Design.xml +191 -0
  142. data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/Microsoft.Data.Services.dll +0 -0
  143. data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/Microsoft.Data.Services.xml +2559 -0
  144. data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/Microsoft.Data.Spatial.dll +0 -0
  145. data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/Microsoft.Data.Spatial.xml +15 -0
  146. data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/Microsoft.VsDesigner.DataServices.Adapter.dll +0 -0
  147. data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/README.txt +6 -0
  148. data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/System.Spatial.dll +0 -0
  149. data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/System.Spatial.xml +2276 -0
  150. data/test/RubyODataService/packages/WebActivator.1.0.0.0/WebActivator.1.0.0.0.nupkg +0 -0
  151. data/test/RubyODataService/packages/WebActivator.1.0.0.0/lib/WebActivator.dll +0 -0
  152. data/test/RubyODataService/packages/repositories.config +4 -0
  153. data/test/applicationhost.config.template +2 -2
  154. data/test/blueprints.rb +5 -4
  155. data/test/iisExpress x64.bat b/data/test/iisExpress → x64.bat +0 -0
  156. data/test/iisExpress x86.bat b/data/test/iisExpress → x86.bat +0 -0
  157. data/test/setpath.rb +13 -3
  158. data/test/usage_samples/querying.rb +45 -0
  159. data/test/usage_samples/reflection.rb +16 -0
  160. data/test/usage_samples/sample_data.rb +30 -0
  161. metadata +327 -36
  162. data/test/Cassini x64.bat +0 -1
  163. data/test/Cassini x86.bat +0 -1
  164. data/test/SampleService/App_Code/AuditFields.cs +0 -13
  165. data/test/SampleService/App_Code/Entities.cs +0 -145
  166. data/test/SampleService/App_Code/Model.Designer.cs +0 -578
  167. data/test/SampleService/App_Code/Model.edmx +0 -157
  168. data/test/SampleService/App_Code/ModelContainerExtended.cs +0 -32
  169. data/test/SampleService/App_Data/_TestDB.mdf +0 -0
  170. data/test/SampleService/App_Data/_TestDB_Log.ldf +0 -0
  171. data/test/SampleService/BasicAuth/Entities.svc +0 -1
  172. data/test/SampleService/Entities.svc +0 -1
  173. data/test/SampleService/web.config +0 -37
@@ -18,6 +18,17 @@ module OData
18
18
  builder.top(10)
19
19
  builder.query.should eq "Products?$top=10&x=1&y=2"
20
20
  end
21
+ it "should properly handle queries for links" do
22
+ builder = QueryBuilder.new 'Categories(1)'
23
+ builder.links('Products')
24
+ builder.query.should eq "Categories(1)/$links/Products"
25
+ end
26
+ it "should properly handle queries for links with additional operations" do
27
+ builder = QueryBuilder.new 'Categories(1)'
28
+ builder.links('Products')
29
+ builder.top(5)
30
+ builder.query.should eq "Categories(1)/$links/Products?$top=5"
31
+ end
21
32
  end
22
33
  end
23
34
  end
@@ -0,0 +1,197 @@
1
+ require 'spec_helper'
2
+
3
+ module OData
4
+ describe Service do
5
+ before(:all) do
6
+ stub_request(:get, /http:\/\/test\.com\/test\.svc\/\$metadata(?:\?.+)?/).
7
+ with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
8
+ to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/sample_service/edmx_categories_products.xml", __FILE__)), :headers => {})
9
+
10
+ @cat_prod_service = OData::Service.new "http://test.com/test.svc"
11
+ end
12
+ subject { @cat_prod_service }
13
+
14
+ context "methods" do
15
+ it { should respond_to :update_object }
16
+ it { should respond_to :delete_object }
17
+ it { should respond_to :save_changes }
18
+ it { should respond_to :load_property }
19
+ it { should respond_to :add_link }
20
+ it { should respond_to :execute }
21
+ it { should respond_to :partial? }
22
+ it { should respond_to :next }
23
+ it { should respond_to :classes }
24
+ it { should respond_to :class_metadata }
25
+ it { should respond_to :collections }
26
+ it { should respond_to :options }
27
+ it { should respond_to :function_imports }
28
+
29
+ context "after parsing metadata" do
30
+ it { should respond_to :Products }
31
+ it { should respond_to :Categories }
32
+ it { should respond_to :AddToProducts }
33
+ it { should respond_to :AddToCategories }
34
+ end
35
+ end
36
+ context "collections method" do
37
+ subject { @cat_prod_service.collections }
38
+ it { should include 'Products' }
39
+ it { should include 'Categories' }
40
+ it "should expose the edmx type of objects" do
41
+ subject['Products'][:edmx_type].should eq 'RubyODataService.Product'
42
+ subject['Categories'][:edmx_type].should eq 'RubyODataService.Category'
43
+ end
44
+ it "should expose the local model type" do
45
+ subject['Products'][:type].should eq Product
46
+ subject['Categories'][:type].should eq Category
47
+ end
48
+ end
49
+ context "class metadata" do
50
+ subject { @cat_prod_service.class_metadata }
51
+ it { should_not be_empty}
52
+ it { should have_key 'Product' }
53
+ it { should have_key 'Category' }
54
+ context "should have keys for each property" do
55
+ subject { @cat_prod_service.class_metadata['Category'] }
56
+ it { should have_key 'Id' }
57
+ it { should have_key 'Name' }
58
+ it { should have_key 'Products' }
59
+ it "should return a PropertyMetadata object for each property" do
60
+ subject['Id'].should be_a PropertyMetadata
61
+ subject['Name'].should be_a PropertyMetadata
62
+ subject['Products'].should be_a PropertyMetadata
63
+ end
64
+ it "should have correct PropertyMetadata for Category.Id" do
65
+ meta = subject['Id']
66
+ meta.name.should eq 'Id'
67
+ meta.type.should eq 'Edm.Int32'
68
+ meta.nullable.should eq false
69
+ meta.fc_target_path.should be_nil
70
+ meta.fc_keep_in_content.should be_nil
71
+ meta.nav_prop.should eq false
72
+ end
73
+ it "should have correct PropertyMetadata for Category.Name" do
74
+ meta = subject['Name']
75
+ meta.name.should eq 'Name'
76
+ meta.type.should eq 'Edm.String'
77
+ meta.nullable.should eq false
78
+ meta.fc_target_path.should be_nil
79
+ meta.fc_keep_in_content.should be_nil
80
+ meta.nav_prop.should eq false
81
+ end
82
+ it "should have correct PropertyMetadata for Category.Products" do
83
+ meta = subject['Products']
84
+ meta.name.should eq 'Products'
85
+ meta.type.should be_nil
86
+ meta.nullable.should eq true
87
+ meta.fc_target_path.should be_nil
88
+ meta.fc_keep_in_content.should be_nil
89
+ meta.nav_prop.should eq true
90
+ meta.association.should_not be_nil
91
+ end
92
+ end
93
+ end
94
+ context "function_imports method" do
95
+ subject { @cat_prod_service.function_imports }
96
+ it { should_not be_empty}
97
+ it { should have_key 'CleanDatabaseForTesting' }
98
+ it { should have_key 'EntityCategoryWebGet' }
99
+ it { should have_key 'EntitySingleCategoryWebGet' }
100
+ it "should expose the http method" do
101
+ subject['CleanDatabaseForTesting'][:http_method].should eq 'POST'
102
+ subject['EntityCategoryWebGet'][:http_method].should eq 'GET'
103
+ subject['EntitySingleCategoryWebGet'][:http_method].should eq 'GET'
104
+ end
105
+ it "should expose the return type" do
106
+ subject['CleanDatabaseForTesting'][:return_typo].should be_nil
107
+ subject['EntityCategoryWebGet'][:return_type].should eq Array
108
+ subject['EntityCategoryWebGet'][:inner_return_type].should eq Category
109
+ subject['EntitySingleCategoryWebGet'][:return_type].should eq Category
110
+ subject['EntitySingleCategoryWebGet'][:inner_return_type].should be_nil
111
+ subject['CategoryNames'][:return_type].should eq Array
112
+ subject['CategoryNames'][:inner_return_type].should eq String
113
+ end
114
+ it "should provide a hash of parameters" do
115
+ subject['EntityCategoryWebGet'][:parameters].should be_nil
116
+ subject['EntitySingleCategoryWebGet'][:parameters].should be_a Hash
117
+ subject['EntitySingleCategoryWebGet'][:parameters]['id'].should eq 'Edm.Int32'
118
+ end
119
+ context "after parsing function imports" do
120
+ subject { @cat_prod_service }
121
+ it { should respond_to :CleanDatabaseForTesting }
122
+ it { should respond_to :EntityCategoryWebGet }
123
+ it { should respond_to :EntitySingleCategoryWebGet }
124
+ it { should respond_to :CategoryNames }
125
+ end
126
+ context "error checking" do
127
+ subject { @cat_prod_service }
128
+ it "should throw an exception if a parameter is passed in to a method that doesn't require one" do
129
+ lambda { subject.EntityCategoryWebGet(1) }.should raise_error(ArgumentError, "wrong number of arguments (1 for 0)")
130
+ end
131
+ it "should throw and exception if more parameters are passed in than required by the function" do
132
+ lambda { subject.EntitySingleCategoryWebGet(1,2) }.should raise_error(ArgumentError, "wrong number of arguments (2 for 1)")
133
+ end
134
+ end
135
+ context "url and http method checks" do
136
+ subject { @cat_prod_service }
137
+ before { stub_request(:any, /http:\/\/test\.com\/test\.svc\/(.*)/) }
138
+ it "should call the correct url with the correct http method for a post with no parameters" do
139
+ subject.CleanDatabaseForTesting
140
+ a_request(:post, "http://test.com/test.svc/CleanDatabaseForTesting").should have_been_made
141
+ end
142
+ it "should call the correct url with the correct http method for a get with no parameters" do
143
+ subject.EntityCategoryWebGet
144
+ a_request(:get, "http://test.com/test.svc/EntityCategoryWebGet").should have_been_made
145
+ end
146
+ it "should call the correct url with the correct http method for a get with parameters" do
147
+ subject.EntitySingleCategoryWebGet(1)
148
+ a_request(:get, "http://test.com/test.svc/EntitySingleCategoryWebGet?id=1").should have_been_made
149
+ end
150
+ end
151
+ context "function import result parsing" do
152
+ subject { @cat_prod_service }
153
+ before(:each) do
154
+ stub_request(:post, "http://test.com/test.svc/CleanDatabaseForTesting").to_return(:status => 204)
155
+
156
+ stub_request(:get, "http://test.com/test.svc/EntityCategoryWebGet").
157
+ to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/sample_service/result_entity_category_web_get.xml", __FILE__)), :headers => {})
158
+
159
+ stub_request(:get, "http://test.com/test.svc/EntitySingleCategoryWebGet?id=1").
160
+ to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/sample_service/result_entity_single_category_web_get.xml", __FILE__)), :headers => {})
161
+
162
+ stub_request(:get, "http://test.com/test.svc/CategoryNames").
163
+ to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/sample_service/result_category_names.xml", __FILE__)), :headers => {})
164
+
165
+ stub_request(:get, "http://test.com/test.svc/FirstCategoryId").
166
+ to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/sample_service/result_first_category_id.xml", __FILE__)), :headers => {})
167
+ end
168
+ it "should return true if a function import post that returns successfully and doesn't have a return value (HTTP 204)" do
169
+ result = subject.CleanDatabaseForTesting
170
+ result.should be_true
171
+ end
172
+ it "should return a collection of entities for a collection" do
173
+ result = subject.EntityCategoryWebGet
174
+ result.should be_an Enumerable
175
+ result.first.should be_a Category
176
+ result.first.Name.should eq "Test Category"
177
+ end
178
+ it "should return a single entity if it isn't a collection" do
179
+ result = subject.EntitySingleCategoryWebGet(1)
180
+ result.should be_a Category
181
+ result.Name.should eq "Test Category"
182
+ end
183
+ it "should return a collection of primitive types" do
184
+ result = subject.CategoryNames
185
+ result.should be_an Enumerable
186
+ result.first.should be_a String
187
+ result.first.should eq "Test Category 1"
188
+ end
189
+ it "should return a single primitive type" do
190
+ result = subject.FirstCategoryId
191
+ result.should be_a Fixnum
192
+ result.should eq 1
193
+ end
194
+ end
195
+ end
196
+ end
197
+ end
@@ -37,7 +37,6 @@ module OData
37
37
  end
38
38
  end
39
39
  end
40
-
41
40
  describe "additional query string parameters" do
42
41
  before(:each) do
43
42
  # Required for the build_classes method
@@ -83,7 +82,27 @@ module OData
83
82
  svc.save_changes
84
83
  a_request(:post, "http://test.com/test.svc/$batch?x=1&y=2").should have_been_made
85
84
  end
86
- end
85
+ it "should pass the parameters as part of an add link" do
86
+ svc = OData::Service.new "http://test.com/test.svc/", { :additional_params => { :x=>1, :y=>2 } }
87
+ existing_flight1 = ZDemoFlight.new
88
+ existing_flight1.__metadata = { :uri => "http://test.com/test.svc/flight_dataCollection/1" }
89
+ existing_flight2 = ZDemoFlight.new
90
+ existing_flight2.__metadata = { :uri => "http://test.com/test.svc/flight_dataCollection/2" }
91
+ svc.add_link(existing_flight1, "flight_data_r", existing_flight2)
92
+ svc.save_changes
93
+ a_request(:post, "http://test.com/test.svc/flight_dataCollection/1/$links/flight_data_r?x=1&y=2").should have_been_made
94
+ end
95
+ it "should pass the parameters as part of a function import with a parameter" do
96
+ svc = OData::Service.new "http://test.com/test.svc/", { :additional_params => { :x=>1, :y=>2 } }
97
+ svc.get_flight(1)
98
+ a_request(:get, "http://test.com/test.svc/get_flight?id=1&x=1&y=2").should have_been_made
99
+ end
100
+ it "should pass the parameters as part of a function import without parameters" do
101
+ svc = OData::Service.new "http://test.com/test.svc/", { :additional_params => { :x=>1, :y=>2 } }
102
+ svc.get_top_flight
103
+ a_request(:get, "http://test.com/test.svc/get_top_flight?x=1&y=2").should have_been_made
104
+ end
105
+ end
87
106
 
88
107
  describe "lowercase collections" do
89
108
  before(:each) do
@@ -124,7 +143,7 @@ module OData
124
143
  end
125
144
  end
126
145
 
127
- describe "collections, objects, etc" do
146
+ describe "collections, objects, metadata etc" do
128
147
  before(:each) do
129
148
  # Metadata
130
149
  stub_request(:get, "http://test.com/test.svc/$metadata").
@@ -244,9 +263,449 @@ module OData
244
263
  product.Category.should_not be_an Array
245
264
  end
246
265
  end
266
+
267
+ describe "navigation properties" do
268
+ it "should fill in PropertyMetadata for navigation properties" do
269
+ svc = OData::Service.new "http://test.com/test.svc/"
270
+ svc.class_metadata['Product'].should have_key 'Category'
271
+ end
272
+ end
247
273
  end
248
- end
249
274
 
275
+ describe "single layer inheritance" do
276
+ before(:each) do
277
+ # Metadata
278
+ stub_request(:get, "http://test.com/test.svc/$metadata").
279
+ with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
280
+ to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/inheritance/edmx_pluralsight.xml", __FILE__)), :headers => {})
281
+
282
+ # Content - Courses
283
+ stub_request(:get, /http:\/\/test\.com\/test\.svc\/Courses(?:.*)/).
284
+ with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
285
+ to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/inheritance/result_pluralsight_courses.xml", __FILE__)), :headers => {})
286
+ end
287
+
288
+ it "should build all inherited attributes" do
289
+ OData::Service.new "http://test.com/test.svc/"
290
+ methods = Course.instance_methods.reject {|m| Object.methods.index(m)}
291
+
292
+ # Ruby 1.9 uses symbols, and 1.8 uses strings, so this normalizes the data
293
+ methods.map! {|m| m.to_sym}
294
+
295
+ methods.should include(:Title)
296
+ methods.should include(:Description)
297
+ methods.should include(:VideoLength)
298
+ methods.should include(:Category)
299
+
300
+ methods.should include(:Title=)
301
+ methods.should include(:Description=)
302
+ methods.should include(:VideoLength=)
303
+ methods.should include(:Category=)
304
+ end
305
+
306
+ it "should not build abstract classes" do
307
+ OData::Service.new "http://test.com/test.svc/"
308
+ defined?(ModelItemBase).should eq nil
309
+ end
310
+
311
+ it "should fill inherited properties" do
312
+ svc = OData::Service.new "http://test.com/test.svc/"
313
+ svc.Courses
314
+ courses = svc.execute
315
+ course = courses.first
316
+ course.Title.should_not be_nil
317
+ course.Description.should_not be_nil
318
+ course.VideoLength.should_not be_nil
319
+ course.Category.should_not be_nil
320
+ end
321
+ end
322
+
323
+ describe "handling partial collections" do
324
+ before(:each) do
325
+ # Metadata
326
+ stub_request(:get, "http://test.com/test.svc/$metadata").
327
+ with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
328
+ to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/partial/partial_feed_metadata.xml", __FILE__)), :headers => {})
329
+
330
+ # Content - Partial
331
+ stub_request(:get, "http://test.com/test.svc/Partials").
332
+ with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
333
+ to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/partial/partial_feed_part_1.xml", __FILE__)), :headers => {})
334
+
335
+ stub_request(:get, "http://test.com/test.svc/Partials?$skiptoken='ERNSH'").
336
+ with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
337
+ to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/partial/partial_feed_part_2.xml", __FILE__)), :headers => {})
338
+
339
+ stub_request(:get, "http://test.com/test.svc/Partials?$skiptoken='ERNSH2'").
340
+ with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
341
+ to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/partial/partial_feed_part_3.xml", __FILE__)), :headers => {})
342
+
343
+ end
344
+
345
+ it "should return the whole collection by default" do
346
+ svc = OData::Service.new "http://test.com/test.svc/"
347
+ svc.Partials
348
+ results = svc.execute
349
+ results.count.should eq 3
350
+ end
351
+
352
+ it "should return only the partial when specified by options" do
353
+ svc = OData::Service.new("http://test.com/test.svc/", :eager_partial => false)
354
+ svc.Partials
355
+ results = svc.execute
356
+ results.count.should eq 1
357
+ svc.should be_partial
358
+ while svc.partial?
359
+ results.concat svc.next
360
+ end
361
+ results.count.should eq 3
362
+ end
363
+ end
364
+
365
+ describe "link queries" do
366
+ before(:each) do
367
+ # Required for the build_classes method
368
+ stub_request(:get, /http:\/\/test\.com\/test\.svc\/\$metadata(?:\?.+)?/).
369
+ with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
370
+ to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/sample_service/edmx_categories_products.xml", __FILE__)), :headers => {})
371
+
372
+ stub_request(:get, "http://test.com/test.svc/Categories(1)/$links/Products").
373
+ with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
374
+ to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/links/result_links_query.xml", __FILE__)), :headers => {})
375
+ end
376
+ it "should be able to parse the results of a links query" do
377
+ svc = OData::Service.new "http://test.com/test.svc/"
378
+ svc.Categories(1).links('Products')
379
+ results = svc.execute
380
+ results.count.should eq 3
381
+ results.first.should be_a_kind_of(URI)
382
+ results[0].path.should eq "/SampleService/RubyOData.svc/Products(1)"
383
+ results[1].path.should eq "/SampleService/RubyOData.svc/Products(2)"
384
+ results[2].path.should eq "/SampleService/RubyOData.svc/Products(3)"
385
+ end
386
+ end
387
+
388
+ describe "sample service" do
389
+ before(:each) do
390
+ # Required for the build_classes method
391
+ stub_request(:get, /http:\/\/test\.com\/test\.svc\/\$metadata(?:\?.+)?/).
392
+ with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
393
+ to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/sample_service/edmx_categories_products.xml", __FILE__)), :headers => {})
394
+
395
+ stub_request(:get, /http:\/\/test\.com\/test\.svc\/Products\(\d\)/).
396
+ with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
397
+ to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/sample_service/result_single_product.xml", __FILE__)), :headers => {})
398
+
399
+ stub_request(:get, /http:\/\/test\.com\/test\.svc\/Products\(\d{2,}\)/).
400
+ with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
401
+ to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/sample_service/result_single_product_not_found.xml", __FILE__)), :headers => {})
402
+
403
+ stub_request(:get, "http://test.com/test.svc/Products(1)/Category").
404
+ with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
405
+ to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/sample_service/result_single_category.xml", __FILE__)), :headers => {})
406
+
407
+ stub_request(:get, "http://test.com/test.svc/Categories(1)").
408
+ with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
409
+ to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/sample_service/result_single_category.xml", __FILE__)), :headers => {})
410
+
411
+ stub_request(:get, "http://test.com/test.svc/Categories(1)/Products").
412
+ with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
413
+ to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/sample_service/result_multiple_category_products.xml", __FILE__)), :headers => {})
414
+
415
+ stub_request(:post, "http://test.com/test.svc/Categories(1)/$links/Products").to_return(:status => 204)
416
+ stub_request(:post, "http://test.com/test.svc/$batch").to_return(:status => 202)
417
+ end
418
+
419
+ describe "lazy loading" do
420
+ after(:each) do
421
+ Object.send(:remove_const, 'Product') if Object.const_defined? 'Product'
422
+ Object.send(:remove_const, 'Category') if Object.const_defined? 'Category'
423
+ end
424
+
425
+ it "should have a load property method" do
426
+ svc = OData::Service.new "http://test.com/test.svc/"
427
+ svc.should respond_to(:load_property)
428
+ end
429
+
430
+ it "should throw an exception if the object isn't tracked" do
431
+ svc = OData::Service.new "http://test.com/test.svc/"
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")
434
+ end
435
+
436
+ it "should throw an exception if there isn't a method matching the navigation property passed in" do
437
+ svc = OData::Service.new "http://test.com/test.svc/"
438
+ svc.Products(1)
439
+ product = svc.execute.first
440
+ lambda { svc.load_property(product, "NoMatchingMethod") }.should raise_error(ArgumentError, "'NoMatchingMethod' is not a valid navigation property")
441
+ end
442
+
443
+ it "should throw an exception if the method passed in is a standard property (non-navigation)" do
444
+ svc = OData::Service.new "http://test.com/test.svc/"
445
+ svc.Products(1)
446
+ product = svc.execute.first
447
+ lambda { svc.load_property(product, "Name") }.should raise_error(ArgumentError, "'Name' is not a valid navigation property")
448
+ end
449
+
450
+ it "should fill a single navigation property" do
451
+ svc = OData::Service.new "http://test.com/test.svc/"
452
+ svc.Products(1)
453
+ product = svc.execute.first
454
+ svc.load_property(product, "Category")
455
+ product.Category.should_not be_nil
456
+ product.Category.Id.should eq 1
457
+ product.Category.Name.should eq 'Category 1'
458
+ end
459
+
460
+ it "should fill a collection navigation property" do
461
+ svc = OData::Service.new "http://test.com/test.svc/"
462
+ svc.Categories(1)
463
+ category = svc.execute.first
464
+ svc.load_property(category, "Products")
465
+ category.Products.first.should be_a Product
466
+ category.Products[0].Id.should eq 1
467
+ category.Products[1].Id.should eq 2
468
+ end
469
+ end
470
+
471
+ describe "find, create, add, update, and delete" do
472
+ after(:each) do
473
+ Object.send(:remove_const, 'Product') if Object.const_defined? 'Product'
474
+ Object.send(:remove_const, 'Category') if Object.const_defined? 'Category'
475
+ end
476
+
477
+ it "should implement an AddTo method for collection" do
478
+ svc = OData::Service.new "http://test.com/test.svc/"
479
+ svc.should respond_to :AddToCategories
480
+ svc.should respond_to :AddToProducts
481
+ end
482
+
483
+ it "should create objects with an initialize method that can build the object from a hash" do
484
+ svc = OData::Service.new "http://test.com/test.svc/"
485
+ product = Product.new 'Id' => 1000, 'Name' => 'New Product'
486
+ product.Id.should eq 1000
487
+ product.Name.should eq 'New Product'
488
+ end
489
+
490
+ it "should create objects that rejects keys that don't have corresponding methods" do
491
+ svc = OData::Service.new "http://test.com/test.svc/"
492
+ lambda { Product.new 'NotAProperty' => true }.should raise_error NoMethodError
493
+ end
494
+
495
+ it "should create objects that expose a properties class method that lists the properties for the object" do
496
+ svc = OData::Service.new "http://test.com/test.svc/"
497
+ Product.properties.should include 'Id'
498
+ Product.properties.should include 'Name'
499
+ Product.properties.should include 'Category'
500
+ end
501
+
502
+ it "should have full metadata for a property returned from the properties method" do
503
+ svc = OData::Service.new "http://test.com/test.svc/"
504
+ Product.properties['Category'].should be_a PropertyMetadata
505
+ Product.properties['Category'].nav_prop.should be_true
506
+ end
507
+
508
+ it "should create objects that expose an id property" do
509
+ svc = OData::Service.new "http://test.com/test.svc/"
510
+ svc.Products(1)
511
+ product = svc.execute.first
512
+ product.should respond_to :id
513
+ end
514
+
515
+ it "should extract the id from the metadata" do
516
+ svc = OData::Service.new "http://test.com/test.svc/"
517
+ svc.Products(1)
518
+ product = svc.execute.first
519
+ product.id.should eq 1
520
+ end
521
+
522
+ describe "Class.first method" do
523
+ it "should exist on the create server objects" do
524
+ svc = OData::Service.new "http://test.com/test.svc/"
525
+ Product.should respond_to :first
526
+ end
527
+ it "should return nil if an id isn't passed in" do
528
+ svc = OData::Service.new "http://test.com/test.svc/"
529
+ product = Product.first(nil)
530
+ product.should be_nil
531
+ end
532
+ it "should return nil if an id isn't found" do
533
+ svc = OData::Service.new "http://test.com/test.svc/"
534
+ product = Product.first(1234567890)
535
+ product.should be_nil
536
+ end
537
+ it "should return a product if an id is found" do
538
+ svc = OData::Service.new "http://test.com/test.svc/"
539
+ product = Product.first(1)
540
+ product.should_not be_nil
541
+ end
542
+ end
543
+ end
544
+
545
+ describe "namespaces" do
546
+ after(:each) do
547
+ VisoftInc::Sample::Models.send(:remove_const, 'Product') if VisoftInc::Sample::Models.const_defined? 'Product'
548
+ VisoftInc::Sample::Models.send(:remove_const, 'Category') if VisoftInc::Sample::Models.const_defined? 'Category'
549
+
550
+ VisoftInc::Sample.send(:remove_const, 'Models') if VisoftInc::Sample.const_defined? 'Models'
551
+ VisoftInc.send(:remove_const, 'Sample') if VisoftInc.const_defined? 'Sample'
552
+ Object.send(:remove_const, 'VisoftInc') if Object.const_defined? 'VisoftInc'
553
+ end
554
+
555
+ it "should create models in the specified namespace if the option is set (using a .NET style namespace with dots)" do
556
+ svc = OData::Service.new "http://test.com/test.svc/", { :namespace => 'VisoftInc.Sample.Models' }
557
+ defined?(VisoftInc::Sample::Models::Product).nil?.should be_false, 'VisoftInc::Sample::Models::Product was expected to be defined, but was not'
558
+ defined?(VisoftInc::Sample::Models::Category).nil?.should be_false, 'VisoftInc::Sample::Models::Category was expected to be defined, but was not'
559
+ end
560
+
561
+ it "should create models in the specified namespace if the option is set (using Ruby style namespaces with double colons)" do
562
+ svc = OData::Service.new "http://test.com/test.svc/", { :namespace => 'VisoftInc::Sample::Models' }
563
+ defined?(VisoftInc::Sample::Models::Product).nil?.should be_false, 'VisoftInc::Sample::Models::Product was expected to be defined, but was not'
564
+ defined?(VisoftInc::Sample::Models::Category).nil?.should be_false, 'VisoftInc::Sample::Models::Category was expected to be defined, but was not'
565
+ end
566
+
567
+ it "should fill object defined in a namespace" do
568
+ svc = OData::Service.new "http://test.com/test.svc/", { :namespace => 'VisoftInc::Sample::Models' }
569
+ svc.Categories(1)
570
+ categories = svc.execute
571
+ categories.should_not be_nil
572
+ category = categories.first
573
+ category.Id.should eq 1
574
+ category.Name.should eq 'Category 1'
575
+ end
576
+
577
+ it "should fill the class_metadata hash" do
578
+ svc = OData::Service.new "http://test.com/test.svc/", { :namespace => 'VisoftInc::Sample::Models' }
579
+ svc.class_metadata.should_not be_empty
580
+ end
581
+
582
+ it "should add a key (based on the name) for each property class_metadata hash" do
583
+ svc = OData::Service.new "http://test.com/test.svc/", { :namespace => 'VisoftInc::Sample::Models' }
584
+ svc.class_metadata['VisoftInc::Sample::Models::Product'].should have_key 'Id'
585
+ svc.class_metadata['VisoftInc::Sample::Models::Product'].should have_key 'Name'
586
+ svc.class_metadata['VisoftInc::Sample::Models::Product'].should have_key 'Description'
587
+ end
588
+
589
+ it "should lazy load objects defined in a namespace" do
590
+ svc = OData::Service.new "http://test.com/test.svc/", { :namespace => 'VisoftInc::Sample::Models' }
591
+ svc.Categories(1)
592
+ category = svc.execute.first
593
+ svc.load_property category, 'Products'
594
+ category.Products.should_not be_nil
595
+ category.Products.first.Id.should eq 1
596
+ category.Products.first.Name.should eq 'Widget 1'
597
+ end
598
+ end
599
+
600
+ describe "add_link method" do
601
+ it "should exist as a method on the service" do
602
+ svc = OData::Service.new "http://test.com/test.svc/"
603
+ svc.should respond_to(:add_link)
604
+ end
605
+
606
+ it "shouldn't be allowed if a parent isn't tracked" do
607
+ svc = OData::Service.new "http://test.com/test.svc/"
608
+ category = Category.new :Name => 'New Category'
609
+ property = nil # Not needed for this test
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)")
612
+ end
613
+
614
+ it "shouldn't be allowed if a property isn't found on the parent" do
615
+ svc = OData::Service.new "http://test.com/test.svc/"
616
+ svc.Categories(1)
617
+ category = svc.execute.first
618
+ property = 'NotAProperty'
619
+ product = nil # Not needed for this test
620
+ lambda { svc.add_link(category, property, product) }.should raise_error(ArgumentError, "'NotAProperty' is not a valid navigation property for Category")
621
+ end
622
+
623
+ it "shouldn't be allowed if a property isn't a navigation property on the parent" do
624
+ svc = OData::Service.new "http://test.com/test.svc/"
625
+ svc.Categories(1)
626
+ category = svc.execute.first
627
+ property = 'Name'
628
+ product = nil # Not needed for this test
629
+ lambda { svc.add_link(category, property, product) }.should raise_error(ArgumentError, "'Name' is not a valid navigation property for Category")
630
+ end
631
+
632
+ it "shouldn't be allowed if a child isn't tracked" do
633
+ svc = OData::Service.new "http://test.com/test.svc/"
634
+ svc.Categories(1)
635
+ category = svc.execute.first
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)")
639
+ end
640
+
641
+ it "should perform a post against the correct URL with the correct body on a single_save" do
642
+ svc = OData::Service.new "http://test.com/test.svc/"
643
+ svc.Categories(1)
644
+ category = svc.execute.first
645
+ svc.Products(1)
646
+ product = svc.execute.first
647
+ property = 'Products'
648
+ svc.add_link(category, property, product)
649
+ svc.save_changes
650
+ a_request(:post, "http://test.com/test.svc/Categories(1)/$links/Products").
651
+ with(:body => { "uri" => "http://test.com/test.svc/Products(1)" },
652
+ :headers => {'Content-Type' => 'application/json'}).should have_been_made
653
+ end
654
+
655
+ it "should add the child to the parent's navigation property on a single_save" do
656
+ svc = OData::Service.new "http://test.com/test.svc/"
657
+ svc.Categories(1)
658
+ category = svc.execute.first
659
+ svc.Products(1)
660
+ product = svc.execute.first
661
+ property = 'Products'
662
+ svc.add_link(category, property, product)
663
+ svc.save_changes
664
+ category.Products.should include product
665
+ end
666
+
667
+ it "should add the parent to the child's navigation property on a single_save" do
668
+ svc = OData::Service.new "http://test.com/test.svc/"
669
+ svc.Categories(1)
670
+ category = svc.execute.first
671
+ svc.Products(1)
672
+ product = svc.execute.first
673
+ property = 'Products'
674
+ svc.add_link(category, property, product)
675
+ svc.save_changes
676
+ product.Category.should eq category
677
+ end
678
+
679
+ describe "batch_save" do
680
+ before(:each) do
681
+ @svc = OData::Service.new "http://test.com/test.svc/"
682
+ @category = Category.first(1)
683
+ @product = Product.first(1)
684
+ new_category = Category.new
685
+ @svc.AddToCategories(new_category)
686
+ @svc.add_link(@category, 'Products', @product)
687
+ @svc.save_changes
688
+ end
689
+
690
+ it "should perform a post with the correct URL and body on a batch_save" do
691
+ WebMock.should have_requested(:post, "http://test.com/test.svc/$batch").with { |request|
692
+ request.body.include? "POST http://test.com/test.svc/Categories(1)/$links/Products HTTP/1.1"
693
+ request.body.include? '{"uri":"http://test.com/test.svc/Products(1)"}'
694
+ }
695
+ end
696
+ context "child is a part of the parent's collection" do
697
+ subject { @category.Products }
698
+ it { should include @product }
699
+ end
700
+ context "parent object should be filled in on the child" do
701
+ subject { @product.Category }
702
+ it { should eq @category }
703
+ end
704
+ end
705
+ end
706
+ end
707
+ end
708
+
250
709
  describe_private OData::Service do
251
710
  describe "parse value" do
252
711
  before(:each) do