frodata 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +7 -0
  2. data/.autotest +2 -0
  3. data/.gitignore +24 -0
  4. data/.rspec +2 -0
  5. data/.ruby-gemset +1 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +75 -0
  8. data/CHANGELOG.md +150 -0
  9. data/Gemfile +4 -0
  10. data/LICENSE.txt +23 -0
  11. data/README.md +427 -0
  12. data/Rakefile +7 -0
  13. data/TODO.md +55 -0
  14. data/frodata.gemspec +34 -0
  15. data/lib/frodata.rb +36 -0
  16. data/lib/frodata/entity.rb +332 -0
  17. data/lib/frodata/entity_container.rb +75 -0
  18. data/lib/frodata/entity_set.rb +161 -0
  19. data/lib/frodata/errors.rb +68 -0
  20. data/lib/frodata/navigation_property.rb +29 -0
  21. data/lib/frodata/navigation_property/proxy.rb +80 -0
  22. data/lib/frodata/properties.rb +32 -0
  23. data/lib/frodata/properties/binary.rb +50 -0
  24. data/lib/frodata/properties/boolean.rb +37 -0
  25. data/lib/frodata/properties/collection.rb +50 -0
  26. data/lib/frodata/properties/complex.rb +114 -0
  27. data/lib/frodata/properties/date.rb +27 -0
  28. data/lib/frodata/properties/date_time.rb +83 -0
  29. data/lib/frodata/properties/date_time_offset.rb +17 -0
  30. data/lib/frodata/properties/decimal.rb +50 -0
  31. data/lib/frodata/properties/enum.rb +62 -0
  32. data/lib/frodata/properties/float.rb +67 -0
  33. data/lib/frodata/properties/geography.rb +13 -0
  34. data/lib/frodata/properties/geography/base.rb +162 -0
  35. data/lib/frodata/properties/geography/line_string.rb +33 -0
  36. data/lib/frodata/properties/geography/point.rb +31 -0
  37. data/lib/frodata/properties/geography/polygon.rb +38 -0
  38. data/lib/frodata/properties/guid.rb +17 -0
  39. data/lib/frodata/properties/integer.rb +107 -0
  40. data/lib/frodata/properties/number.rb +14 -0
  41. data/lib/frodata/properties/string.rb +72 -0
  42. data/lib/frodata/properties/time.rb +40 -0
  43. data/lib/frodata/properties/time_of_day.rb +27 -0
  44. data/lib/frodata/property.rb +139 -0
  45. data/lib/frodata/property_registry.rb +41 -0
  46. data/lib/frodata/query.rb +233 -0
  47. data/lib/frodata/query/criteria.rb +92 -0
  48. data/lib/frodata/query/criteria/comparison_operators.rb +49 -0
  49. data/lib/frodata/query/criteria/date_functions.rb +61 -0
  50. data/lib/frodata/query/criteria/geography_functions.rb +21 -0
  51. data/lib/frodata/query/criteria/lambda_operators.rb +27 -0
  52. data/lib/frodata/query/criteria/string_functions.rb +40 -0
  53. data/lib/frodata/query/in_batches.rb +58 -0
  54. data/lib/frodata/railtie.rb +19 -0
  55. data/lib/frodata/schema.rb +155 -0
  56. data/lib/frodata/schema/complex_type.rb +79 -0
  57. data/lib/frodata/schema/enum_type.rb +95 -0
  58. data/lib/frodata/service.rb +254 -0
  59. data/lib/frodata/service/request.rb +85 -0
  60. data/lib/frodata/service/response.rb +162 -0
  61. data/lib/frodata/service/response/atom.rb +40 -0
  62. data/lib/frodata/service/response/json.rb +41 -0
  63. data/lib/frodata/service/response/plain.rb +36 -0
  64. data/lib/frodata/service/response/xml.rb +40 -0
  65. data/lib/frodata/service_registry.rb +52 -0
  66. data/lib/frodata/version.rb +3 -0
  67. data/spec/fixtures/files/entity_to_xml.xml +17 -0
  68. data/spec/fixtures/files/error.xml +5 -0
  69. data/spec/fixtures/files/metadata.xml +150 -0
  70. data/spec/fixtures/files/product_0.json +10 -0
  71. data/spec/fixtures/files/product_0.xml +28 -0
  72. data/spec/fixtures/files/products.json +106 -0
  73. data/spec/fixtures/files/products.xml +308 -0
  74. data/spec/fixtures/files/supplier_0.json +26 -0
  75. data/spec/fixtures/files/supplier_0.xml +32 -0
  76. data/spec/fixtures/vcr_cassettes/entity_set_specs.yml +1635 -0
  77. data/spec/fixtures/vcr_cassettes/entity_set_specs/bad_entry.yml +183 -0
  78. data/spec/fixtures/vcr_cassettes/entity_set_specs/existing_entry.yml +256 -0
  79. data/spec/fixtures/vcr_cassettes/entity_set_specs/new_entry.yml +185 -0
  80. data/spec/fixtures/vcr_cassettes/entity_specs.yml +285 -0
  81. data/spec/fixtures/vcr_cassettes/navigation_property_proxy_specs.yml +346 -0
  82. data/spec/fixtures/vcr_cassettes/query/result_specs.yml +189 -0
  83. data/spec/fixtures/vcr_cassettes/query_specs.yml +1060 -0
  84. data/spec/fixtures/vcr_cassettes/schema/complex_type_specs.yml +127 -0
  85. data/spec/fixtures/vcr_cassettes/service/request_specs.yml +193 -0
  86. data/spec/fixtures/vcr_cassettes/service_registry_specs.yml +129 -0
  87. data/spec/fixtures/vcr_cassettes/service_specs.yml +127 -0
  88. data/spec/fixtures/vcr_cassettes/usage_example_specs.yml +1330 -0
  89. data/spec/frodata/entity/shared_examples.rb +82 -0
  90. data/spec/frodata/entity_container_spec.rb +38 -0
  91. data/spec/frodata/entity_set_spec.rb +168 -0
  92. data/spec/frodata/entity_spec.rb +151 -0
  93. data/spec/frodata/errors_spec.rb +48 -0
  94. data/spec/frodata/navigation_property/proxy_spec.rb +44 -0
  95. data/spec/frodata/navigation_property_spec.rb +55 -0
  96. data/spec/frodata/properties/binary_spec.rb +50 -0
  97. data/spec/frodata/properties/boolean_spec.rb +72 -0
  98. data/spec/frodata/properties/collection_spec.rb +44 -0
  99. data/spec/frodata/properties/date_spec.rb +23 -0
  100. data/spec/frodata/properties/date_time_offset_spec.rb +30 -0
  101. data/spec/frodata/properties/date_time_spec.rb +23 -0
  102. data/spec/frodata/properties/decimal_spec.rb +51 -0
  103. data/spec/frodata/properties/float_spec.rb +45 -0
  104. data/spec/frodata/properties/geography/line_string_spec.rb +33 -0
  105. data/spec/frodata/properties/geography/point_spec.rb +29 -0
  106. data/spec/frodata/properties/geography/polygon_spec.rb +55 -0
  107. data/spec/frodata/properties/geography/shared_examples.rb +72 -0
  108. data/spec/frodata/properties/guid_spec.rb +17 -0
  109. data/spec/frodata/properties/integer_spec.rb +58 -0
  110. data/spec/frodata/properties/string_spec.rb +46 -0
  111. data/spec/frodata/properties/time_of_day_spec.rb +23 -0
  112. data/spec/frodata/properties/time_spec.rb +15 -0
  113. data/spec/frodata/property_registry_spec.rb +16 -0
  114. data/spec/frodata/property_spec.rb +71 -0
  115. data/spec/frodata/query/criteria_spec.rb +229 -0
  116. data/spec/frodata/query_spec.rb +199 -0
  117. data/spec/frodata/schema/complex_type_spec.rb +96 -0
  118. data/spec/frodata/schema/enum_type_spec.rb +112 -0
  119. data/spec/frodata/schema_spec.rb +97 -0
  120. data/spec/frodata/service/request_spec.rb +49 -0
  121. data/spec/frodata/service/response_spec.rb +85 -0
  122. data/spec/frodata/service_registry_spec.rb +18 -0
  123. data/spec/frodata/service_spec.rb +191 -0
  124. data/spec/frodata/usage_example_spec.rb +188 -0
  125. data/spec/spec_helper.rb +32 -0
  126. data/spec/support/coverage.rb +2 -0
  127. data/spec/support/vcr.rb +9 -0
  128. metadata +401 -0
@@ -0,0 +1,82 @@
1
+ shared_examples 'a valid product' do
2
+ it { expect(subject).to be_a(FrOData::Entity) }
3
+
4
+ it { expect(subject.name).to eq('Product') }
5
+ it { expect(subject.type).to eq('ODataDemo.Product') }
6
+ it { expect(subject.namespace).to eq('ODataDemo') }
7
+ it { expect(subject.service_name).to eq('ODataDemo') }
8
+ it { expect(subject.context).to eq('http://services.odata.org/V4/OData/OData.svc/$metadata#Products/$entity') }
9
+ it { expect(subject.id).to eq('Products(0)') }
10
+
11
+ # Check property types
12
+ it { expect(subject.get_property('ID')).to be_a(FrOData::Properties::Integer) }
13
+ it { expect(subject.get_property('Name')).to be_a(FrOData::Properties::String) }
14
+ it { expect(subject.get_property('Description')).to be_a(FrOData::Properties::String) }
15
+ it { expect(subject.get_property('ReleaseDate')).to be_a(FrOData::Properties::DateTimeOffset) }
16
+ it { expect(subject.get_property('DiscontinuedDate')).to be_a(FrOData::Properties::DateTimeOffset) }
17
+ it { expect(subject.get_property('Rating')).to be_a(FrOData::Properties::Integer) }
18
+ it { expect(subject.get_property('Price')).to be_a(FrOData::Properties::Double) }
19
+
20
+ # Navigation property proxies
21
+ it { expect(subject.get_property('Categories')).to be_a(FrOData::NavigationProperty::Proxy)}
22
+ it { expect(subject.get_property('ProductDetail')).to be_a(FrOData::NavigationProperty::Proxy)}
23
+ it { expect(subject.get_property('Supplier')).to be_a(FrOData::NavigationProperty::Proxy)}
24
+
25
+ # Check property values
26
+ it { expect(subject['ID']).to eq(0) }
27
+ it { expect(subject['Name']).to eq('Bread') }
28
+ it { expect(subject['Description']).to eq('Whole grain bread') }
29
+ it { expect(subject['ReleaseDate']).to eq(DateTime.new(1992,1,1,0,0,0,0)) }
30
+ it { expect(subject['DiscontinuedDate']).to be_nil }
31
+ it { expect(subject['Rating']).to eq(4) }
32
+ it { expect(subject['Price']).to eq(2.5) }
33
+
34
+ # Navigation properties
35
+ it { expect(subject['Categories']).to be_a(Enumerable) }
36
+ it { expect(subject['ProductDetail']).to be_nil }
37
+ it { expect(subject['Supplier']).to be_a(FrOData::Entity) }
38
+
39
+ it { expect {subject['NonExistant']}.to raise_error(ArgumentError) }
40
+ it { expect {subject['NonExistant'] = 5}.to raise_error(ArgumentError) }
41
+
42
+ describe '#links' do
43
+ let(:links) do
44
+ {
45
+ 'Categories' => {type: :collection, href: 'Products(0)/Categories'},
46
+ 'Supplier' => {type: :entity, href: 'Products(0)/Supplier'},
47
+ 'ProductDetail' => {type: :entity, href: 'Products(0)/ProductDetail'}
48
+ }
49
+ end
50
+
51
+ it { expect(subject).to respond_to(:links) }
52
+ it { expect(subject.links.size).to eq(3) }
53
+ it { expect(subject.links).to eq(links) }
54
+ end
55
+ end
56
+
57
+ shared_examples 'a valid supplier' do
58
+ it { expect(subject.name).to eq('Supplier') }
59
+ it { expect(subject.type).to eq('ODataDemo.Supplier') }
60
+ it { expect(subject.namespace).to eq('ODataDemo') }
61
+ it { expect(subject.service_name).to eq('ODataDemo') }
62
+ it { expect(subject.context).to eq('http://services.odata.org/V4/OData/OData.svc/$metadata#Suppliers/$entity') }
63
+ it { expect(subject.id).to eq('Suppliers(0)') }
64
+
65
+ # Check property types
66
+ it { expect(subject.get_property('ID')).to be_a(FrOData::Properties::Integer) }
67
+ it { expect(subject.get_property('Name')).to be_a(FrOData::Properties::String) }
68
+ it { expect(subject.get_property('Address')).to be_a(FrOData::Properties::Complex) }
69
+ it { expect(subject.get_property('Location')).to be_a(FrOData::Properties::Geography::Point) }
70
+ # it { expect(subject.get_property('Products')).to be_a(FrOData::NavigationProperty::Proxy)}
71
+
72
+ # Check property values
73
+ it { expect(subject['ID']).to eq(0) }
74
+ it { expect(subject['Name']).to eq('Exotic Liquids') }
75
+ it { expect(subject['Address'][ 'Street']).to eq('NE 228th') }
76
+ it { expect(subject['Address'][ 'City']).to eq('Sammamish') }
77
+ it { expect(subject['Address'][ 'State']).to eq('WA') }
78
+ it { expect(subject['Address']['ZipCode']).to eq('98074') }
79
+ it { expect(subject['Address']['Country']).to eq('USA') }
80
+ xit { expect(subject['Location']).to eq([47.6316604614258, -122.03547668457]) }
81
+ xit { expect(subject['Products']).to be_a(FrOData::Entity) }
82
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe FrOData::EntityContainer do
4
+ let(:subject) { FrOData::EntityContainer.new(service) }
5
+ let(:service) do
6
+ FrOData::Service.new('http://services.odata.org/V4/OData/OData.svc', metadata_file: metadata_file)
7
+ end
8
+ let(:metadata_file) { 'spec/fixtures/files/metadata.xml' }
9
+
10
+ describe '#entity_sets' do
11
+ it { expect(subject).to respond_to(:entity_sets) }
12
+ it { expect(subject.entity_sets.size).to eq(7) }
13
+ it { expect(subject.entity_sets.keys).to eq(%w[
14
+ Products
15
+ ProductDetails
16
+ Categories
17
+ Suppliers
18
+ Persons
19
+ PersonDetails
20
+ Advertisements
21
+ ]) }
22
+ it { expect(subject.entity_sets.values).to eq(%w[
23
+ ODataDemo.Product
24
+ ODataDemo.ProductDetail
25
+ ODataDemo.Category
26
+ ODataDemo.Supplier
27
+ ODataDemo.Person
28
+ ODataDemo.PersonDetail
29
+ ODataDemo.Advertisement
30
+ ]) }
31
+ end
32
+
33
+ describe '#[]' do
34
+ let(:entity_sets) { subject.entity_sets.keys.map { |name| subject[name] } }
35
+ it { expect(entity_sets).to all(be_a(FrOData::EntitySet)) }
36
+ it { expect {subject['Nonexistant']}.to raise_error(ArgumentError) }
37
+ end
38
+ end
@@ -0,0 +1,168 @@
1
+ require 'spec_helper'
2
+
3
+ describe FrOData::EntitySet, vcr: {cassette_name: 'entity_set_specs'} do
4
+ before(:example) do
5
+ FrOData::Service.new('http://services.odata.org/V4/OData/OData.svc', name: 'ODataDemo')
6
+ end
7
+
8
+ let(:subject) { FrOData::EntitySet.new(options) }
9
+ let(:options) { {
10
+ container: 'DemoService', namespace: 'ODataDemo', name: 'Products',
11
+ type: 'ODataDemo.Product', service_name: 'ODataDemo'
12
+ } }
13
+
14
+ it { expect(subject).to respond_to(:name) }
15
+ it { expect(subject).to respond_to(:type) }
16
+ it { expect(subject).to respond_to(:container) }
17
+ it { expect(subject).to respond_to(:namespace) }
18
+ it { expect(subject).to respond_to(:service_name) }
19
+ it { expect(subject).to respond_to(:new_entity) }
20
+ it { expect(subject).to respond_to(:[]) }
21
+ it { expect(subject).to respond_to(:<<) }
22
+
23
+ it { expect(subject.name).to eq('Products') }
24
+ it { expect(subject.container).to eq('DemoService') }
25
+ it { expect(subject.namespace).to eq('ODataDemo') }
26
+ it { expect(subject.service_name).to eq('ODataDemo') }
27
+ it { expect(subject.type).to eq('ODataDemo.Product') }
28
+
29
+ describe '#each' do
30
+ it { expect(subject).to respond_to(:each) }
31
+ it { expect(lambda {
32
+ @counter = 0
33
+ subject.each {|entity| @counter += 1}
34
+ @counter
35
+ }.call).to eq(11) }
36
+ it { expect(lambda {
37
+ @entities = []
38
+ subject.each {|entity| @entities << entity}
39
+ @entities
40
+ }.call.shuffle.first).to be_a(FrOData::Entity) }
41
+ end
42
+
43
+ describe '#first' do
44
+ it { expect(subject).to respond_to(:first) }
45
+
46
+ describe 'retrieving a single entity' do
47
+ it { expect(subject.first).to be_a(FrOData::Entity) }
48
+ it { expect(subject.first['ID']).to eq(0) }
49
+ end
50
+
51
+ describe 'retrieving multiple entities' do
52
+ it { expect(subject.first(5)).to be_a(Array) }
53
+ it { expect(subject.first(5).length).to eq(5) }
54
+ it do
55
+ subject.first(5).each do |entity|
56
+ expect(entity).to be_a(FrOData::Entity)
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ describe '#count' do
63
+ it { expect(subject).to respond_to(:count) }
64
+ it { expect(subject.count).to eq(11) }
65
+ end
66
+
67
+ describe '#query' do
68
+ it { expect(subject).to respond_to(:query) }
69
+ it { expect(subject.query).to be_a(FrOData::Query) }
70
+ end
71
+
72
+ describe '#new_entity' do
73
+ let(:new_entity) { subject.new_entity(properties) }
74
+ let(:release_date) { DateTime.new(2014,7,5) }
75
+ let(:properties) { {
76
+ Name: 'Widget',
77
+ Description: 'Just a simple widget',
78
+ ReleaseDate: release_date,
79
+ DiscontinuedDate: nil,
80
+ Rating: 4,
81
+ Price: 3.5
82
+ } }
83
+
84
+ it { expect(new_entity.entity_set).to eq(subject) }
85
+ it { expect(new_entity['ID']).to be_nil }
86
+ it { expect(new_entity['Name']).to eq('Widget') }
87
+ it { expect(new_entity['Description']).to eq('Just a simple widget') }
88
+ it { expect(new_entity['ReleaseDate']).to eq(release_date) }
89
+ it { expect(new_entity['DiscontinuedDate']).to be_nil }
90
+ it { expect(new_entity['Rating']).to eq(4) }
91
+ it { expect(new_entity['Price']).to eq(3.5) }
92
+ end
93
+
94
+ describe '#[]' do
95
+ let(:existing_entity) { subject[0] }
96
+ let(:nonexistant_entity) { subject[99] }
97
+
98
+ it 'finds an entity by its primary key' do
99
+ expect(existing_entity).to be_a(FrOData::Entity)
100
+ expect(existing_entity['ID']).to eq(0)
101
+ end
102
+
103
+ it 'raises an error when no entity was found' do
104
+ expect { nonexistant_entity }.to raise_error(FrOData::Errors::NotFound)
105
+ end
106
+
107
+ describe 'eager loading' do
108
+ it 'works with a single property' do
109
+ product_with_categories = subject[1, expand: 'Categories']
110
+
111
+ expect(product_with_categories['Categories']).to eq([
112
+ { "ID" => 0, "Name" => "Food" },
113
+ { "ID" => 1, "Name" => "Beverages" }
114
+ ])
115
+ end
116
+
117
+ it 'works with multiple properties' do
118
+ product_with_details = subject[1, expand: %w[Categories Supplier]]
119
+
120
+ expect(product_with_details['Supplier']).to include('Name' => 'Exotic Liquids')
121
+ expect(product_with_details['Categories']).to be_a(Array)
122
+ end
123
+
124
+ it 'works with special shortcut for all properties' do
125
+ product_with_all_details = subject[1, expand: :all]
126
+
127
+ expect(product_with_all_details['Supplier']).to include('Name' => 'Exotic Liquids')
128
+ expect(product_with_all_details['Categories']).to be_a(Array)
129
+ expect(product_with_all_details['ProductDetail']).to include('Details' => 'Details of product 1')
130
+ end
131
+ end
132
+ end
133
+
134
+ describe '#<<' do
135
+ let(:new_entity) { subject.new_entity(properties) }
136
+ let(:bad_entity) { subject.new_entity }
137
+ let(:existing_entity) { subject.first }
138
+ let(:properties) { {
139
+ Name: 'Widget',
140
+ Description: 'Just a simple widget',
141
+ ReleaseDate: DateTime.now.new_offset(0),
142
+ DiscontinuedDate: nil,
143
+ Rating: 4,
144
+ Price: 3.5
145
+ } }
146
+
147
+ xdescribe 'with an existing entity', vcr: {cassette_name: 'entity_set_specs/existing_entry'} do
148
+ before(:each) do
149
+ subject << existing_entity
150
+ end
151
+
152
+ it { expect(existing_entity.any_errors?).to eq(false) }
153
+ end
154
+
155
+ xdescribe 'with a new entity', vcr: {cassette_name: 'entity_set_specs/new_entry'} do
156
+ it do
157
+ expect(new_entity['ID']).to be_nil
158
+ expect {subject << new_entity}.to_not raise_error
159
+ expect(new_entity['ID']).to_not be_nil
160
+ expect(new_entity['ID']).to eq(9999)
161
+ end
162
+ end
163
+
164
+ xdescribe 'with a bad entity', vcr: {cassette_name: 'entity_set_specs/bad_entry'} do
165
+ it { expect{subject << bad_entity}.to raise_error }
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,151 @@
1
+ require 'spec_helper'
2
+ require_relative 'entity/shared_examples'
3
+
4
+ describe FrOData::Entity, vcr: {cassette_name: 'entity_specs'} do
5
+ before(:example) do
6
+ FrOData::Service.new('http://services.odata.org/V4/OData/OData.svc', name: 'ODataDemo')
7
+ end
8
+
9
+ let(:subject) { FrOData::Entity.new(options) }
10
+ let(:options) { {
11
+ type: 'ODataDemo.Product',
12
+ namespace: 'ODataDemo',
13
+ service_name: 'ODataDemo'
14
+ } }
15
+
16
+ it { expect(subject).to respond_to(:name, :type, :namespace, :service_name) }
17
+
18
+ it { expect(subject.name).to eq('Product') }
19
+ it { expect(subject.type).to eq('ODataDemo.Product') }
20
+ it { expect(subject.namespace).to eq('ODataDemo') }
21
+ it { expect(subject.service_name).to eq('ODataDemo') }
22
+
23
+ describe '.with_properties' do
24
+ let(:subject) { FrOData::Entity.with_properties(properties, options) }
25
+ let(:properties) { {
26
+ "ID" => 0,
27
+ "Name" => "Bread",
28
+ "Description" => "Whole grain bread",
29
+ "ReleaseDate" => "1992-01-01T00:00:00Z",
30
+ "DiscontinuedDate" => nil,
31
+ "Rating" => 4,
32
+ "Price" => 2.5
33
+ } }
34
+ let(:entity_set) {
35
+ FrOData::EntitySet.new(
36
+ container: 'DemoService',
37
+ namespace: 'ODataDemo',
38
+ name: 'Products',
39
+ type: 'Product',
40
+ service_name: 'ODataDemo')
41
+ }
42
+ let(:options) { {
43
+ type: 'ODataDemo.Product',
44
+ namespace: 'ODataDemo',
45
+ service_name: 'ODataDemo',
46
+ entity_set: entity_set
47
+ } }
48
+
49
+ it_behaves_like 'a valid product'
50
+ end
51
+
52
+ describe '.from_xml' do
53
+ let(:subject) { FrOData::Entity.from_xml(product_xml, options) }
54
+ let(:product_xml) {
55
+ document = ::Nokogiri::XML(File.open('spec/fixtures/files/product_0.xml'))
56
+ document.remove_namespaces!
57
+ document.xpath('//entry').first
58
+ }
59
+
60
+ it { expect(FrOData::Entity).to respond_to(:from_xml) }
61
+
62
+ it_behaves_like 'a valid product'
63
+
64
+ context 'with a complex type property' do
65
+ let(:options) { {
66
+ type: 'ODataDemo.Supplier',
67
+ namespace: 'ODataDemo',
68
+ service_name: 'ODataDemo'
69
+ } }
70
+
71
+ let(:subject) { FrOData::Entity.from_xml(supplier_xml, options) }
72
+ let(:supplier_xml) {
73
+ document = ::Nokogiri::XML(File.open('spec/fixtures/files/supplier_0.xml'))
74
+ document.remove_namespaces!
75
+ document.xpath('//entry').first
76
+ }
77
+
78
+ it_behaves_like 'a valid supplier'
79
+ end
80
+ end
81
+
82
+ describe '#to_xml' do
83
+ let(:subject) { FrOData::Entity.with_properties(properties, options) }
84
+ let(:properties) { {
85
+ "ID" => 0,
86
+ "Name" => "Bread",
87
+ "Description" => "Whole grain bread",
88
+ "ReleaseDate" => "1992-01-01T00:00:00Z",
89
+ "DiscontinuedDate" => nil,
90
+ "Rating" => 4,
91
+ "Price" => 2.5
92
+ } }
93
+ let(:options) { {
94
+ type: 'ODataDemo.Product',
95
+ namespace: 'ODataDemo',
96
+ service_name: 'ODataDemo'
97
+ } }
98
+ let(:product_xml) {
99
+ File.read('spec/fixtures/files/entity_to_xml.xml')
100
+ }
101
+
102
+ # TODO: parse the XML and veryify property values instead?
103
+ # TODO: explicitly assert namespace URIs?
104
+ it { expect(subject.to_xml).to eq(product_xml) }
105
+ end
106
+
107
+ describe '.from_json' do
108
+ let(:subject) { FrOData::Entity.from_json(product_json, options) }
109
+ let(:product_json) {
110
+ File.read('spec/fixtures/files/product_0.json')
111
+ }
112
+
113
+ it { expect(FrOData::Entity).to respond_to(:from_json) }
114
+ it_behaves_like 'a valid product'
115
+
116
+ context 'with a complex type property' do
117
+ let(:options) { {
118
+ type: 'ODataDemo.Supplier',
119
+ namespace: 'ODataDemo',
120
+ service_name: 'ODataDemo'
121
+ } }
122
+
123
+ let(:subject) { FrOData::Entity.from_json(supplier_json, options) }
124
+ let(:supplier_json) {
125
+ File.read('spec/fixtures/files/supplier_0.json')
126
+ }
127
+
128
+ it_behaves_like 'a valid supplier'
129
+ end
130
+ end
131
+
132
+ describe '#to_json' do
133
+ let(:subject) { FrOData::Entity.with_properties(properties, options) }
134
+ let(:properties) { {
135
+ "ID" => 0,
136
+ "Name" => "Bread",
137
+ "Description" => "Whole grain bread",
138
+ "ReleaseDate" => "1992-01-01T00:00:00Z",
139
+ "DiscontinuedDate" => nil,
140
+ "Rating" => 4,
141
+ "Price" => 2.5
142
+ } }
143
+ let(:options) { {
144
+ type: 'ODataDemo.Product',
145
+ namespace: 'ODataDemo',
146
+ service_name: 'ODataDemo'
147
+ } }
148
+
149
+ it { expect(subject.to_json).to eq(properties.to_json) }
150
+ end
151
+ end
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ describe FrOData::RequestError do
4
+ subject { FrOData::RequestError.new(response, 'The server made a boo-boo.') }
5
+ let(:response) { instance_double('Faraday::Response', status: 400) }
6
+
7
+ describe '#http_status' do
8
+ it 'returns the status code' do
9
+ expect(subject.http_status).to eq(response.status)
10
+ end
11
+ end
12
+
13
+ describe '#response' do
14
+ it 'returns the response' do
15
+ expect(subject.response).to eq(response)
16
+ end
17
+ end
18
+
19
+ describe '#message' do
20
+ it 'returns the error message' do
21
+ expect(subject.message).to eq('The server made a boo-boo.')
22
+ end
23
+ end
24
+ end
25
+
26
+ describe FrOData::Errors::InternalServerError do
27
+ let(:response) { instance_double('Faraday::Response', status: 500) }
28
+
29
+ context 'with custom error message' do
30
+ subject { FrOData::Errors::InternalServerError.new(response, 'The server made a boo-boo.')}
31
+
32
+ describe '#message' do
33
+ it 'combines default message with custom message' do
34
+ expect(subject.message).to eq('500 Internal Server Error: The server made a boo-boo.')
35
+ end
36
+ end
37
+ end
38
+
39
+ context 'without custom error message' do
40
+ subject { FrOData::Errors::InternalServerError.new(response) }
41
+
42
+ describe '#message' do
43
+ it 'returns the default message' do
44
+ expect(subject.message).to eq('500 Internal Server Error')
45
+ end
46
+ end
47
+ end
48
+ end