odata4 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,3 @@
1
1
  module OData4
2
- VERSION = '0.7.0'
2
+ VERSION = '0.8.0'
3
3
  end
@@ -19,16 +19,16 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = %w{lib}
20
20
 
21
21
  spec.add_development_dependency 'bundler', '~> 1.6'
22
- spec.add_development_dependency 'rake'
23
- spec.add_development_dependency 'simplecov', '~> 0.15.1'
24
- spec.add_development_dependency 'rspec', '~> 3.7.0'
25
- spec.add_development_dependency 'rspec-autotest', '~> 1.0.0'
26
- spec.add_development_dependency 'autotest', '~> 4.4.6'
27
- spec.add_development_dependency 'vcr', '~> 4.0.0'
28
- spec.add_development_dependency 'timecop', '~> 0.9.1'
29
- spec.add_development_dependency 'equivalent-xml', '~> 0.6.0'
22
+ spec.add_development_dependency 'rake', '~> 0'
23
+ spec.add_development_dependency 'simplecov', '~> 0.15'
24
+ spec.add_development_dependency 'rspec', '~> 3.7'
25
+ spec.add_development_dependency 'rspec-autotest', '~> 1.0'
26
+ spec.add_development_dependency 'autotest', '~> 4.4'
27
+ spec.add_development_dependency 'vcr', '~> 4.0'
28
+ spec.add_development_dependency 'timecop', '~> 0.9'
29
+ spec.add_development_dependency 'equivalent-xml', '~> 0.6'
30
30
 
31
- spec.add_dependency 'nokogiri', '~> 1.8.1'
32
- spec.add_dependency 'typhoeus', '~> 1.3.0'
33
- spec.add_dependency 'andand', '~> 1.3.3'
31
+ spec.add_dependency 'nokogiri', '~> 1.8'
32
+ spec.add_dependency 'typhoeus', '~> 1.3'
33
+ spec.add_dependency 'andand', '~> 1.3'
34
34
  end
@@ -7,26 +7,6 @@ describe OData4::ComplexType, vcr: {cassette_name: 'complex_type_specs'} do
7
7
 
8
8
  let(:service) { OData4::ServiceRegistry['ODataDemo'] }
9
9
 
10
- describe '.new' do
11
- it 'requires type name' do
12
- expect {
13
- OData4::ComplexType.new(service: service)
14
- }.to raise_error(ArgumentError)
15
- end
16
-
17
- it 'requires service instance' do
18
- expect {
19
- OData4::ComplexType.new(name: 'Address')
20
- }.to raise_error(ArgumentError)
21
- end
22
-
23
- it 'requires name to refer to a valid complex type' do
24
- expect {
25
- OData4::ComplexType.new(name: 'NotAType', service: service)
26
- }.to raise_error(ArgumentError)
27
- end
28
- end
29
-
30
10
  let(:address) { {
31
11
  'Street' => '123 Main St',
32
12
  'City' => 'Huntington Beach',
@@ -35,7 +15,7 @@ describe OData4::ComplexType, vcr: {cassette_name: 'complex_type_specs'} do
35
15
  'Country' => 'USA'
36
16
  } }
37
17
 
38
- let(:complex_type) { service.complex_types['Address'] }
18
+ let(:complex_type) { service.complex_types['ODataDemo.Address'] }
39
19
  let(:subject) { complex_type.property_class.new('Address', nil) }
40
20
 
41
21
  describe 'is properly parsed from service metadata' do
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe OData4::EntityContainer do
4
+ let(:subject) { OData4::EntityContainer.new(service) }
5
+ let(:service) do
6
+ OData4::Service.open('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(OData4::EntitySet)) }
36
+ it { expect {subject['Nonexistant']}.to raise_error(ArgumentError) }
37
+ end
38
+ end
@@ -8,7 +8,7 @@ describe OData4::EntitySet, vcr: {cassette_name: 'entity_set_specs'} do
8
8
  let(:subject) { OData4::EntitySet.new(options) }
9
9
  let(:options) { {
10
10
  container: 'DemoService', namespace: 'ODataDemo', name: 'Products',
11
- type: 'Product', service_name: 'ODataDemo'
11
+ type: 'ODataDemo.Product', service_name: 'ODataDemo'
12
12
  } }
13
13
 
14
14
  it { expect(subject).to respond_to(:name) }
@@ -24,7 +24,7 @@ describe OData4::EntitySet, vcr: {cassette_name: 'entity_set_specs'} do
24
24
  it { expect(subject.container).to eq('DemoService') }
25
25
  it { expect(subject.namespace).to eq('ODataDemo') }
26
26
  it { expect(subject.service_name).to eq('ODataDemo') }
27
- it { expect(subject.type).to eq('Product') }
27
+ it { expect(subject.type).to eq('ODataDemo.Product') }
28
28
 
29
29
  describe '#each' do
30
30
  it { expect(subject).to respond_to(:each) }
@@ -8,27 +8,7 @@ describe OData4::EnumType, vcr: {cassette_name: 'enum_type_specs'} do
8
8
  let(:metadata_file) { 'spec/fixtures/files/metadata.xml' }
9
9
  let(:service) { OData4::ServiceRegistry['ODataDemo'] }
10
10
 
11
- describe '.new' do
12
- it 'requires type name' do
13
- expect {
14
- OData4::EnumType.new(service: service)
15
- }.to raise_error(ArgumentError)
16
- end
17
-
18
- it 'requires service instance' do
19
- expect {
20
- OData4::EnumType.new(name: 'Address')
21
- }.to raise_error(ArgumentError)
22
- end
23
-
24
- it 'requires name to refer to a valid enum type' do
25
- expect {
26
- OData4::EnumType.new(name: 'NotAType', service: service)
27
- }.to raise_error(ArgumentError)
28
- end
29
- end
30
-
31
- let(:enum_type) { service.enum_types['ProductStatus'] }
11
+ let(:enum_type) { service.enum_types['ODataDemo.ProductStatus'] }
32
12
  let(:subject) { enum_type.property_class.new('ProductStatus', nil) }
33
13
 
34
14
  describe 'is properly parsed from service metadata' do
@@ -54,12 +34,10 @@ describe OData4::EnumType, vcr: {cassette_name: 'enum_type_specs'} do
54
34
  expect(subject.value).to eq('Available')
55
35
  end
56
36
 
57
- it 'ignores invalid values' do
37
+ it 'does not allow setting an invalid value' do
58
38
  expect {
59
39
  subject.value = 'Invalid'
60
- }.not_to raise_error
61
-
62
- expect(subject.value).to be_nil
40
+ }.to raise_error(ArgumentError)
63
41
  end
64
42
 
65
43
  it 'allows setting by numeric value' do
@@ -87,12 +65,10 @@ describe OData4::EnumType, vcr: {cassette_name: 'enum_type_specs'} do
87
65
  expect(subject.value).to eq(%w[Available Backordered])
88
66
  end
89
67
 
90
- it 'allows setting an invalid value' do
68
+ it 'does not allow setting invalid values' do
91
69
  expect {
92
70
  subject.value = 'Available, Invalid'
93
- }.not_to raise_error
94
-
95
- expect(subject.value).to eq(['Available'])
71
+ }.to raise_error(ArgumentError)
96
72
  end
97
73
 
98
74
  it 'allows setting by numeric value' do
@@ -104,29 +80,31 @@ describe OData4::EnumType, vcr: {cassette_name: 'enum_type_specs'} do
104
80
  end
105
81
  end
106
82
 
107
- describe 'strict mode' do
108
- let(:subject) { enum_type.property_class.new('ProductStatus', nil, strict: true) }
109
-
110
- describe '#strict?' do
111
- it { expect(subject).to be_strict }
83
+ describe 'lenient validation' do
84
+ let(:subject) do
85
+ enum_type.property_class.new('ProductStatus', nil, strict: false)
112
86
  end
113
87
 
114
88
  describe '#value=' do
115
- it 'does not allow setting an invalid value' do
89
+ it 'ignores invalid values' do
116
90
  expect {
117
91
  subject.value = 'Invalid'
118
- }.to raise_error(ArgumentError)
92
+ }.not_to raise_error
93
+
94
+ expect(subject.value).to be_nil
119
95
  end
120
96
 
121
- context 'when is_flags=true' do
97
+ context 'when `IsFlags` is true' do
122
98
  before do
123
99
  subject.define_singleton_method(:is_flags?) { true }
124
100
  end
125
101
 
126
- it 'does not allow setting invalid values' do
102
+ it 'ignores invalid values' do
127
103
  expect {
128
104
  subject.value = 'Available, Invalid'
129
- }.to raise_error(ArgumentError)
105
+ }.not_to raise_error
106
+
107
+ expect(subject.value).to eq(['Available'])
130
108
  end
131
109
  end
132
110
  end
@@ -6,19 +6,46 @@ describe OData4::Properties::Decimal do
6
6
  it { expect(subject.type).to eq('Edm.Decimal') }
7
7
  it { expect(subject.value).to eq(BigDecimal('678.90325')) }
8
8
 
9
- it { expect(subject.url_value).to eq('678.90325M') }
9
+ it { expect(subject.url_value).to eq('678.90325') }
10
10
 
11
11
  it { expect { subject.value = BigDecimal((7.9 * (10**28)), 2) + 1 }.to raise_error(ArgumentError) }
12
12
  it { expect { subject.value = BigDecimal((-7.9 * (10**28)), 2) - 1 }.to raise_error(ArgumentError) }
13
13
  it { expect { subject.value = BigDecimal((3.4 * (10**-28)), 2) * 3.14151 + 5 }.to raise_error(ArgumentError) }
14
14
 
15
- it { expect(lambda {
16
- subject.value = '19.89043256'
17
- subject.value
18
- }.call).to eq(BigDecimal('19.89043256')) }
15
+ describe '#value=' do
16
+ it 'allows BigDecimal to be set' do
17
+ subject.value = BigDecimal('19.89043256')
18
+ expect(subject.value).to eq(BigDecimal('19.89043256'))
19
+ end
19
20
 
20
- it { expect(lambda {
21
- subject.value = BigDecimal('19.89043256')
22
- subject.value
23
- }.call).to eq(BigDecimal('19.89043256')) }
24
- end
21
+ it 'allows string value to be set' do
22
+ subject.value = '19.89043256'
23
+ expect(subject.value).to eq(BigDecimal('19.89043256'))
24
+ end
25
+
26
+ it 'ignores invalid characters' do
27
+ subject.value = '123.4-foobar-5'
28
+ expect(subject.value).to eq(BigDecimal('123.4'))
29
+ end
30
+
31
+ it 'inteprets anything that is not a number as 0' do
32
+ subject.value = 'foobar'
33
+ expect(subject.value).to eq(BigDecimal(0))
34
+ end
35
+
36
+ it 'does not allow values outside a certain range' do
37
+ expect { subject.value = 'Infinity' }.to raise_error(ArgumentError)
38
+ end
39
+
40
+ describe 'lenient validation' do
41
+ let(:subject) do
42
+ OData4::Properties::Decimal.new('Decimal', '678.90325', strict: false)
43
+ end
44
+
45
+ it 'ignores invalid values' do
46
+ subject.value = 'Infinity'
47
+ expect(subject.value).to eq(BigDecimal('Infinity'))
48
+ end
49
+ end
50
+ end
51
+ end
@@ -1,32 +1,71 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe OData4::Property do
4
+ let(:service) do
5
+ OData4::Service.open('http://services.odata.org/V4/OData/OData.svc', metadata_file: metadata_file)
6
+ end
7
+ let(:metadata_file) { 'spec/fixtures/files/metadata.xml' }
4
8
  let(:subject) { OData4::Property.new('PropertyName', '1') }
5
9
  let(:good_comparison) { OData4::Property.new('GoodComparison', '1') }
6
10
  let(:bad_comparison) { OData4::Property.new('BadComparison', '2') }
7
11
 
8
- it { expect(subject).to respond_to(:name) }
9
- it { expect(subject.name).to eq('PropertyName') }
12
+ describe '#name' do
13
+ it { expect(subject).to respond_to(:name) }
14
+ it { expect(subject.name).to eq('PropertyName') }
15
+ end
10
16
 
11
- it { expect(subject).to respond_to(:value) }
12
- it { expect(subject.value).to eq('1') }
17
+ describe '#value' do
18
+ it { expect(subject).to respond_to(:value) }
19
+ it { expect(subject.value).to eq('1') }
20
+ end
13
21
 
14
- it { expect(subject).to respond_to(:xml_value) }
15
- it { expect(subject.xml_value).to eq('1') }
22
+ describe '#xml_value' do
23
+ it { expect(subject).to respond_to(:xml_value) }
24
+ it { expect(subject.xml_value).to eq('1') }
25
+ end
16
26
 
17
- it { expect(subject).to respond_to(:url_value) }
18
- it { expect(subject.url_value).to eq('1') }
27
+ describe '#url_value' do
28
+ it { expect(subject).to respond_to(:url_value) }
29
+ it { expect(subject.url_value).to eq('1') }
30
+ end
19
31
 
20
- it { expect(subject).to respond_to(:type) }
21
- it { expect(lambda {subject.type}).to raise_error(NotImplementedError) }
32
+ describe '#type' do
33
+ it { expect(subject).to respond_to(:type) }
34
+ it { expect(lambda {subject.type}).to raise_error(NotImplementedError) }
35
+ end
22
36
 
23
- it { expect(subject).to respond_to(:allows_nil?) }
24
- it { expect(subject.allows_nil?).to eq(true) }
37
+ describe '#allows_nil?' do
38
+ it { expect(subject).to respond_to(:allows_nil?) }
39
+ it { expect(subject.allows_nil?).to eq(true) }
40
+ end
25
41
 
26
- it { expect(subject).to respond_to(:concurrency_mode) }
27
- it { expect(subject.concurrency_mode).to eq(:none) }
42
+ describe '#strict?' do
43
+ it { expect(subject).to respond_to(:strict?) }
28
44
 
29
- it { expect(subject).to respond_to(:==) }
30
- it { expect(subject == good_comparison).to eq(true) }
31
- it { expect(subject == bad_comparison).to eq(false) }
32
- end
45
+ it 'defaults to true' do
46
+ expect(subject.strict?).to eq(true)
47
+ end
48
+
49
+ it 'can be switched off via constructor option' do
50
+ subject = OData4::Property.new('PropertyName', '1', strict: false)
51
+ expect(subject.strict?).to eq(false)
52
+ end
53
+
54
+ it 'can be switched off via service level option' do
55
+ service.options[:strict] = false
56
+ subject = OData4::Property.new('PropertyName', '1', service: service)
57
+ expect(subject.strict?).to eq(false)
58
+ end
59
+ end
60
+
61
+ describe '#concurrency_mode' do
62
+ it { expect(subject).to respond_to(:concurrency_mode) }
63
+ it { expect(subject.concurrency_mode).to eq(:none) }
64
+ end
65
+
66
+ describe '#==' do
67
+ it { expect(subject).to respond_to(:==) }
68
+ it { expect(subject == good_comparison).to eq(true) }
69
+ it { expect(subject == bad_comparison).to eq(false) }
70
+ end
71
+ end
@@ -13,7 +13,7 @@ shared_examples 'valid result' do
13
13
  it 'returns just OData4::Entities of the right type' do
14
14
  result.each do |entity|
15
15
  expect(entity).to be_a(OData4::Entity)
16
- expect(entity.type).to eq('Product')
16
+ expect(entity.type).to eq('ODataDemo.Product')
17
17
  end
18
18
  end
19
19
  end
@@ -8,8 +8,11 @@ describe OData4::Query, vcr: {cassette_name: 'query_specs'} do
8
8
  let(:subject) { OData4::Query.new(entity_set) }
9
9
  let(:entity_set) { OData4::EntitySet.new(options) }
10
10
  let(:options) { {
11
- container: 'DemoService', namespace: 'ODataDemo', name: 'Products',
12
- service_name: 'ODataDemo', type: 'Product'
11
+ service_name: 'ODataDemo',
12
+ container: 'DemoService',
13
+ namespace: 'ODataDemo',
14
+ name: 'Products',
15
+ type: 'ODataDemo.Product'
13
16
  } }
14
17
 
15
18
  it { expect(subject).to respond_to(:to_s) }
@@ -168,7 +171,7 @@ describe OData4::Query, vcr: {cassette_name: 'query_specs'} do
168
171
 
169
172
  batch.each do |entity|
170
173
  expect(entity).to be_a(OData4::Entity)
171
- expect(entity.type).to eq('Product')
174
+ expect(entity.type).to eq('ODataDemo.Product')
172
175
  entity_count += 1
173
176
  end
174
177
 
@@ -185,7 +188,7 @@ describe OData4::Query, vcr: {cassette_name: 'query_specs'} do
185
188
 
186
189
  subject.in_batches(of: 5).each do |entity|
187
190
  expect(entity).to be_a(OData4::Entity)
188
- expect(entity.type).to eq('Product')
191
+ expect(entity.type).to eq('ODataDemo.Product')
189
192
  entity_count += 1
190
193
  end
191
194
 
@@ -0,0 +1,97 @@
1
+ require 'spec_helper'
2
+
3
+ describe OData4::Schema do
4
+ let(:subject) { OData4::Schema.new(schema_xml, service) }
5
+ let(:service) do
6
+ OData4::Service.open('http://services.odata.org/V4/OData/OData.svc', metadata_file: metadata_file)
7
+ end
8
+ let(:metadata_file) { 'spec/fixtures/files/metadata.xml' }
9
+ let(:schema_xml) { service.metadata.xpath('//Schema').first }
10
+
11
+ let(:entity_types) { %w{Product FeaturedProduct ProductDetail Category Supplier Person Customer Employee PersonDetail Advertisement} }
12
+ let(:complex_types) { %w{Address} }
13
+ let(:enum_types) { %w{ProductStatus} }
14
+
15
+ describe '#namespace' do
16
+ it { expect(subject).to respond_to(:namespace) }
17
+ it "returns the schema's namespace attribute" do
18
+ expect(subject.namespace).to eq('ODataDemo')
19
+ end
20
+ end
21
+
22
+ describe '#actions' do
23
+ # TODO add a action definition to metadata
24
+ it { expect(subject).to respond_to(:actions) }
25
+ it { expect(subject.actions.size).to eq(0) }
26
+ end
27
+
28
+ describe '#annotations' do
29
+ # TBD
30
+ end
31
+
32
+ describe '#complex_types' do
33
+ it { expect(subject).to respond_to(:complex_types) }
34
+ it { expect(subject.complex_types.size).to eq(1) }
35
+ it { expect(subject.complex_types.keys).to eq(complex_types) }
36
+ end
37
+
38
+ describe '#entity_types' do
39
+ it { expect(subject).to respond_to(:entity_types) }
40
+ it { expect(subject.entity_types.size).to eq(10) }
41
+ it { expect(subject.entity_types).to eq(entity_types) }
42
+ end
43
+
44
+ describe '#enum_types' do
45
+ it { expect(subject).to respond_to(:enum_types) }
46
+ it { expect(subject.enum_types.size).to eq(1) }
47
+ it { expect(subject.enum_types.keys).to eq(enum_types)}
48
+ end
49
+
50
+ describe '#functions' do
51
+ # TODO add a function definition to metadata
52
+ it { expect(subject).to respond_to(:functions) }
53
+ it { expect(subject.functions.size).to eq(0) }
54
+ end
55
+
56
+ describe '#terms' do
57
+ # TBD
58
+ end
59
+
60
+ describe '#type_definitions' do
61
+ # TODO add a type definition to metadata
62
+ it { expect(subject).to respond_to(:type_definitions) }
63
+ it { expect(subject.type_definitions.size).to eq(0) }
64
+ end
65
+
66
+ describe '#navigation_properties' do
67
+ it { expect(subject).to respond_to(:navigation_properties) }
68
+ it { expect(subject.navigation_properties['Product'].size).to eq(3) }
69
+ it { expect(subject.navigation_properties['Product'].values).to all(be_a(OData4::NavigationProperty)) }
70
+ end
71
+
72
+ describe '#get_property_type' do
73
+ it { expect(subject).to respond_to(:get_property_type) }
74
+ it { expect(subject.get_property_type('Product', 'ID')).to eq('Edm.Int32') }
75
+ it { expect(subject.get_property_type('Product', 'ProductStatus')).to eq('ODataDemo.ProductStatus') }
76
+ end
77
+
78
+ describe '#primary_key_for' do
79
+ it { expect(subject).to respond_to(:primary_key_for) }
80
+ it { expect(subject.primary_key_for('Product')).to eq('ID') }
81
+ end
82
+
83
+ describe '#properties_for_entity' do
84
+ it { expect(subject).to respond_to(:properties_for_entity) }
85
+ it { expect(subject.properties_for_entity('Product').keys).to eq(%w[
86
+ ID
87
+ Name
88
+ Description
89
+ ReleaseDate
90
+ DiscontinuedDate
91
+ Rating
92
+ Price
93
+ ProductStatus
94
+ ]) }
95
+ it { expect(subject.properties_for_entity('Product').values).to all(be_a(OData4::Property)) }
96
+ end
97
+ end