odata4 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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