frodo 0.10.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.
Files changed (153) hide show
  1. checksums.yaml +7 -0
  2. data/.autotest +2 -0
  3. data/.circleci/config.yml +54 -0
  4. data/.gitignore +24 -0
  5. data/.gitlab-ci.yml +9 -0
  6. data/.rspec +2 -0
  7. data/.ruby-gemset +1 -0
  8. data/.ruby-version +1 -0
  9. data/.travis.yml +75 -0
  10. data/CHANGELOG.md +163 -0
  11. data/Gemfile +4 -0
  12. data/LICENSE.txt +23 -0
  13. data/README.md +479 -0
  14. data/Rakefile +7 -0
  15. data/TODO.md +55 -0
  16. data/frodo.gemspec +39 -0
  17. data/images/frodo.jpg +0 -0
  18. data/lib/frodo/abstract_client.rb +11 -0
  19. data/lib/frodo/client.rb +6 -0
  20. data/lib/frodo/concerns/api.rb +292 -0
  21. data/lib/frodo/concerns/authentication.rb +32 -0
  22. data/lib/frodo/concerns/base.rb +84 -0
  23. data/lib/frodo/concerns/caching.rb +26 -0
  24. data/lib/frodo/concerns/connection.rb +79 -0
  25. data/lib/frodo/concerns/verbs.rb +68 -0
  26. data/lib/frodo/config.rb +143 -0
  27. data/lib/frodo/entity.rb +335 -0
  28. data/lib/frodo/entity_container.rb +75 -0
  29. data/lib/frodo/entity_set.rb +131 -0
  30. data/lib/frodo/errors.rb +70 -0
  31. data/lib/frodo/middleware/authentication/token.rb +13 -0
  32. data/lib/frodo/middleware/authentication.rb +87 -0
  33. data/lib/frodo/middleware/authorization.rb +18 -0
  34. data/lib/frodo/middleware/caching.rb +30 -0
  35. data/lib/frodo/middleware/custom_headers.rb +14 -0
  36. data/lib/frodo/middleware/gzip.rb +33 -0
  37. data/lib/frodo/middleware/instance_url.rb +20 -0
  38. data/lib/frodo/middleware/logger.rb +42 -0
  39. data/lib/frodo/middleware/multipart.rb +64 -0
  40. data/lib/frodo/middleware/odata_headers.rb +13 -0
  41. data/lib/frodo/middleware/raise_error.rb +47 -0
  42. data/lib/frodo/middleware.rb +33 -0
  43. data/lib/frodo/navigation_property/proxy.rb +80 -0
  44. data/lib/frodo/navigation_property.rb +29 -0
  45. data/lib/frodo/properties/binary.rb +50 -0
  46. data/lib/frodo/properties/boolean.rb +37 -0
  47. data/lib/frodo/properties/collection.rb +50 -0
  48. data/lib/frodo/properties/complex.rb +114 -0
  49. data/lib/frodo/properties/date.rb +27 -0
  50. data/lib/frodo/properties/date_time.rb +83 -0
  51. data/lib/frodo/properties/date_time_offset.rb +17 -0
  52. data/lib/frodo/properties/decimal.rb +54 -0
  53. data/lib/frodo/properties/enum.rb +62 -0
  54. data/lib/frodo/properties/float.rb +67 -0
  55. data/lib/frodo/properties/geography/base.rb +162 -0
  56. data/lib/frodo/properties/geography/line_string.rb +33 -0
  57. data/lib/frodo/properties/geography/point.rb +31 -0
  58. data/lib/frodo/properties/geography/polygon.rb +38 -0
  59. data/lib/frodo/properties/geography.rb +13 -0
  60. data/lib/frodo/properties/guid.rb +17 -0
  61. data/lib/frodo/properties/integer.rb +107 -0
  62. data/lib/frodo/properties/number.rb +14 -0
  63. data/lib/frodo/properties/string.rb +72 -0
  64. data/lib/frodo/properties/time.rb +40 -0
  65. data/lib/frodo/properties/time_of_day.rb +27 -0
  66. data/lib/frodo/properties.rb +32 -0
  67. data/lib/frodo/property.rb +139 -0
  68. data/lib/frodo/property_registry.rb +41 -0
  69. data/lib/frodo/query/criteria/comparison_operators.rb +49 -0
  70. data/lib/frodo/query/criteria/date_functions.rb +61 -0
  71. data/lib/frodo/query/criteria/geography_functions.rb +21 -0
  72. data/lib/frodo/query/criteria/lambda_operators.rb +27 -0
  73. data/lib/frodo/query/criteria/string_functions.rb +40 -0
  74. data/lib/frodo/query/criteria.rb +92 -0
  75. data/lib/frodo/query/in_batches.rb +58 -0
  76. data/lib/frodo/query.rb +221 -0
  77. data/lib/frodo/railtie.rb +19 -0
  78. data/lib/frodo/schema/complex_type.rb +79 -0
  79. data/lib/frodo/schema/enum_type.rb +95 -0
  80. data/lib/frodo/schema.rb +164 -0
  81. data/lib/frodo/service.rb +199 -0
  82. data/lib/frodo/service_registry.rb +52 -0
  83. data/lib/frodo/version.rb +3 -0
  84. data/lib/frodo.rb +67 -0
  85. data/spec/fixtures/auth_success_response.json +11 -0
  86. data/spec/fixtures/error.json +11 -0
  87. data/spec/fixtures/files/entity_to_xml.xml +18 -0
  88. data/spec/fixtures/files/error.xml +5 -0
  89. data/spec/fixtures/files/metadata.xml +150 -0
  90. data/spec/fixtures/files/metadata_with_error.xml +157 -0
  91. data/spec/fixtures/files/product_0.json +10 -0
  92. data/spec/fixtures/files/product_0.xml +28 -0
  93. data/spec/fixtures/files/products.json +106 -0
  94. data/spec/fixtures/files/products.xml +308 -0
  95. data/spec/fixtures/files/supplier_0.json +26 -0
  96. data/spec/fixtures/files/supplier_0.xml +32 -0
  97. data/spec/fixtures/leads.json +923 -0
  98. data/spec/fixtures/refresh_error_response.json +8 -0
  99. data/spec/frodo/abstract_client_spec.rb +13 -0
  100. data/spec/frodo/client_spec.rb +57 -0
  101. data/spec/frodo/concerns/authentication_spec.rb +79 -0
  102. data/spec/frodo/concerns/base_spec.rb +68 -0
  103. data/spec/frodo/concerns/caching_spec.rb +40 -0
  104. data/spec/frodo/concerns/connection_spec.rb +65 -0
  105. data/spec/frodo/config_spec.rb +127 -0
  106. data/spec/frodo/entity/shared_examples.rb +83 -0
  107. data/spec/frodo/entity_container_spec.rb +38 -0
  108. data/spec/frodo/entity_set_spec.rb +169 -0
  109. data/spec/frodo/entity_spec.rb +153 -0
  110. data/spec/frodo/errors_spec.rb +48 -0
  111. data/spec/frodo/middleware/authentication/token_spec.rb +87 -0
  112. data/spec/frodo/middleware/authentication_spec.rb +83 -0
  113. data/spec/frodo/middleware/authorization_spec.rb +17 -0
  114. data/spec/frodo/middleware/custom_headers_spec.rb +21 -0
  115. data/spec/frodo/middleware/gzip_spec.rb +68 -0
  116. data/spec/frodo/middleware/instance_url_spec.rb +27 -0
  117. data/spec/frodo/middleware/logger_spec.rb +21 -0
  118. data/spec/frodo/middleware/odata_headers_spec.rb +15 -0
  119. data/spec/frodo/middleware/raise_error_spec.rb +66 -0
  120. data/spec/frodo/navigation_property/proxy_spec.rb +46 -0
  121. data/spec/frodo/navigation_property_spec.rb +55 -0
  122. data/spec/frodo/properties/binary_spec.rb +50 -0
  123. data/spec/frodo/properties/boolean_spec.rb +72 -0
  124. data/spec/frodo/properties/collection_spec.rb +44 -0
  125. data/spec/frodo/properties/date_spec.rb +23 -0
  126. data/spec/frodo/properties/date_time_offset_spec.rb +30 -0
  127. data/spec/frodo/properties/date_time_spec.rb +23 -0
  128. data/spec/frodo/properties/decimal_spec.rb +50 -0
  129. data/spec/frodo/properties/float_spec.rb +45 -0
  130. data/spec/frodo/properties/geography/line_string_spec.rb +33 -0
  131. data/spec/frodo/properties/geography/point_spec.rb +29 -0
  132. data/spec/frodo/properties/geography/polygon_spec.rb +55 -0
  133. data/spec/frodo/properties/geography/shared_examples.rb +72 -0
  134. data/spec/frodo/properties/guid_spec.rb +17 -0
  135. data/spec/frodo/properties/integer_spec.rb +58 -0
  136. data/spec/frodo/properties/string_spec.rb +46 -0
  137. data/spec/frodo/properties/time_of_day_spec.rb +23 -0
  138. data/spec/frodo/properties/time_spec.rb +15 -0
  139. data/spec/frodo/property_registry_spec.rb +16 -0
  140. data/spec/frodo/property_spec.rb +71 -0
  141. data/spec/frodo/query/criteria_spec.rb +229 -0
  142. data/spec/frodo/query_spec.rb +156 -0
  143. data/spec/frodo/schema/complex_type_spec.rb +97 -0
  144. data/spec/frodo/schema/enum_type_spec.rb +112 -0
  145. data/spec/frodo/schema_spec.rb +113 -0
  146. data/spec/frodo/service_registry_spec.rb +19 -0
  147. data/spec/frodo/service_spec.rb +153 -0
  148. data/spec/frodo/usage_example_spec.rb +161 -0
  149. data/spec/spec_helper.rb +35 -0
  150. data/spec/support/coverage.rb +2 -0
  151. data/spec/support/fixture_helpers.rb +14 -0
  152. data/spec/support/middleware.rb +19 -0
  153. metadata +479 -0
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Frodo::Middleware::Logger do
6
+ let(:logger) { double('logger') }
7
+ let(:middleware) { described_class.new app, logger, options }
8
+
9
+ describe '.call' do
10
+ subject { lambda { middleware.call(env) } }
11
+
12
+ before do
13
+ expect(app).to receive(:call).once.and_return(app)
14
+ expect(app).to receive(:on_complete).once { middleware.on_complete(env) }
15
+ expect(logger).to receive(:debug).with('request')
16
+ expect(logger).to receive(:debug).with('response')
17
+ end
18
+
19
+ it { should_not raise_error }
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Frodo::Middleware::OdataHeaders do
6
+ describe '.call' do
7
+
8
+ before do
9
+ subject.call(env)
10
+ end
11
+
12
+ it { expect(env[:request_headers]['OData-Version']).to eq '4.0' }
13
+ it { expect(env[:request_headers]['Content-type']).to eq 'application/json' }
14
+ end
15
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Frodo::Middleware::RaiseError do
6
+ let(:body) { JSON.parse(fixture('error')) }
7
+ let(:env) { { status: status, body: body } }
8
+ let(:middleware) { described_class.new app }
9
+
10
+ describe '.on_complete' do
11
+ subject(:on_complete) { middleware.on_complete(env) }
12
+
13
+ context 'when the status code is 404' do
14
+ let(:status) { 404 }
15
+
16
+ it "raises an error" do
17
+ expect { on_complete }.to raise_error Faraday::Error::ResourceNotFound
18
+ end
19
+ end
20
+
21
+ context 'when the status code is 300' do
22
+ let(:status) { 300 }
23
+
24
+ it "raises an error" do
25
+ expect { on_complete }.to raise_error Faraday::Error::ClientError,
26
+ /300: The external ID provided/
27
+ end
28
+ end
29
+
30
+ context 'when the status code is 400' do
31
+ let(:status) { 400 }
32
+
33
+ it "raises an error" do
34
+ expect { on_complete }.to raise_error Faraday::Error::ClientError,
35
+ /Resource not found for the segment/
36
+ end
37
+ end
38
+
39
+ context 'when the status code is 401' do
40
+ let(:status) { 401 }
41
+
42
+ it "raises an error" do
43
+ expect { on_complete }.to raise_error Frodo::UnauthorizedError,
44
+ /Resource not found for the segment/
45
+ end
46
+ end
47
+
48
+ context 'when the status code is 413' do
49
+ let(:status) { 413 }
50
+
51
+ it "raises an error" do
52
+ expect { on_complete }.to raise_error Faraday::Error::ClientError,
53
+ '413: Request Entity Too Large'
54
+ end
55
+ end
56
+
57
+ context 'when status is 400+ and body is a string' do
58
+ let(:body) { 'An error occured' }
59
+ let(:status) { 406 }
60
+
61
+ it 'raises an error with a non-existing error code' do
62
+ expect { on_complete }.to raise_error Faraday::Error::ClientError, /An error occured/
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ describe Frodo::NavigationProperty::Proxy, vcr: {cassette_name: 'navigation_property_proxy_specs'} do
4
+ before :each do
5
+ Frodo::Service.new('http://services.odata.org/V4/OData/OData.svc', name: 'ODataDemo', metadata_file: metadata_file)
6
+ end
7
+
8
+ let(:metadata_file) { 'spec/fixtures/files/metadata.xml' }
9
+ let(:entity) { Frodo::ServiceRegistry['ODataDemo']['Products'][1] }
10
+
11
+ let(:categories_proxy) { Frodo::NavigationProperty::Proxy.new(entity, 'Categories') }
12
+ let(:detail_proxy) { Frodo::NavigationProperty::Proxy.new(entity, 'ProductDetail') }
13
+ let(:supplier_proxy) { Frodo::NavigationProperty::Proxy.new(entity, 'Supplier') }
14
+
15
+ describe 'value' do
16
+ # FIXME Commenting until we figure out wether we need this or not
17
+ # it { expect(categories_proxy.value).to be_a(Enumerable) }
18
+ # it { expect(supplier_proxy.value).to be_a(Frodo::Entity) }
19
+ # it { expect(detail_proxy.value).to be_a(Frodo::Entity) }
20
+
21
+ # context 'when value was explicitly set' do
22
+ # let(:supplier) { double('supplier') }
23
+
24
+ # it 'returns the set value' do
25
+ # supplier_proxy.value = supplier
26
+ # expect(supplier_proxy.value).to eq(supplier)
27
+ # end
28
+ # end
29
+
30
+ # context 'when no links exist for an entity' do
31
+ # before(:each) do
32
+ # expect(entity).to receive(:links) do
33
+ # { 'Categories' => nil, 'Supplier' => nil }
34
+ # end
35
+ # end
36
+
37
+ # context 'for a many NavigationProperty' do
38
+ # it { expect(categories_proxy.value).to eq([]) }
39
+ # end
40
+
41
+ # context 'for a singular NavigationProperty' do
42
+ # it { expect(supplier_proxy.value).to eq(nil) }
43
+ # end
44
+ # end
45
+ end
46
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe Frodo::NavigationProperty do
4
+ let(:options) { {
5
+ name: 'Categories',
6
+ type: 'Collection(ODataDemo.Category)',
7
+ partner: 'Products',
8
+ } }
9
+ let(:subject) do
10
+ Frodo::NavigationProperty.new(options)
11
+ end
12
+
13
+ it { expect(subject).to respond_to(:name) }
14
+ it { expect(subject.name).to eq('Categories') }
15
+
16
+ it { expect(subject).to respond_to(:type) }
17
+ it { expect(subject.type).to eq('Collection(ODataDemo.Category)') }
18
+
19
+ it { expect(subject).to respond_to(:nav_type) }
20
+ it { expect(subject.nav_type).to eq(:collection) }
21
+
22
+ it { expect(subject).to respond_to(:nullable) }
23
+
24
+ it { expect(subject).to respond_to(:partner) }
25
+ it { expect(subject.partner).to eq('Products') }
26
+
27
+ describe '.new' do
28
+ it 'requires name' do
29
+ expect {
30
+ Frodo::NavigationProperty.new(type: 'Collection(ODataDemo.Category)')
31
+ }.to raise_error(ArgumentError)
32
+ end
33
+
34
+ it 'requires type' do
35
+ expect {
36
+ Frodo::NavigationProperty.new(name: 'Categories')
37
+ }.to raise_error(ArgumentError)
38
+ end
39
+ end
40
+
41
+ describe '#build' do
42
+ let(:metadata_file) { File.read 'spec/fixtures/files/metadata.xml' }
43
+ let(:metadata_xml) { Nokogiri::XML(metadata_file).remove_namespaces! }
44
+ let(:navigation_properties) { metadata_xml.xpath('//NavigationProperty') }
45
+ let(:subject) {
46
+ Frodo::NavigationProperty.build(navigation_properties.first)
47
+ }
48
+
49
+ it { expect(subject.name).to eq('Categories') }
50
+ it { expect(subject.type).to eq('Collection(ODataDemo.Category)') }
51
+ it { expect(subject.partner).to eq('Products') }
52
+ it { expect(subject.nullable).to eq(true) }
53
+ it { expect(subject.nav_type).to eq(:collection) }
54
+ end
55
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe Frodo::Properties::Binary do
4
+ let(:subject) { Frodo::Properties::Binary.new('On', '1') }
5
+
6
+ it { expect(subject.type).to eq('Edm.Binary') }
7
+ it { expect(subject.value).to eq(1) }
8
+
9
+ it { expect {subject.value = 'bad'}.to raise_error(ArgumentError) }
10
+
11
+ it { expect(subject.url_value).to eq("binary'1'") }
12
+
13
+ describe 'setting to 0' do
14
+ it { expect(lambda {
15
+ subject.value = 0
16
+ subject.value
17
+ }.call).to eq(0) }
18
+
19
+ it { expect(lambda {
20
+ subject.value = false
21
+ subject.value
22
+ }.call).to eq(0) }
23
+
24
+ it { expect(lambda {
25
+ subject.value = '0'
26
+ subject.value
27
+ }.call).to eq(0) }
28
+ end
29
+
30
+ describe 'setting to 1' do
31
+ let(:subject) { Frodo::Properties::Binary.new('On', '0') }
32
+
33
+ it { expect(subject.value).to eq(0) }
34
+
35
+ it { expect(lambda {
36
+ subject.value = 1
37
+ subject.value
38
+ }.call).to eq(1) }
39
+
40
+ it { expect(lambda {
41
+ subject.value = true
42
+ subject.value
43
+ }.call).to eq(1) }
44
+
45
+ it { expect(lambda {
46
+ subject.value = '1'
47
+ subject.value
48
+ }.call).to eq(1) }
49
+ end
50
+ end
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+
3
+ describe Frodo::Properties::Boolean do
4
+ let(:truthy1) { Frodo::Properties::Boolean.new('Truthy', 'true') }
5
+ let(:truthy2) { Frodo::Properties::Boolean.new('Truthy', '1') }
6
+ let(:falsey1) { Frodo::Properties::Boolean.new('Falsey', 'false') }
7
+ let(:falsey2) { Frodo::Properties::Boolean.new('Falsey', '0') }
8
+ let(:nily) { Frodo::Properties::Boolean.new('Nily', nil) }
9
+
10
+ it { expect(truthy1.type).to eq('Edm.Boolean') }
11
+ it { expect(truthy1.value).to eq(true) }
12
+ it { expect(truthy2.value).to eq(true) }
13
+
14
+ it { expect(falsey1.value).to eq(false) }
15
+ it { expect(falsey2.value).to eq(false) }
16
+
17
+ it { expect(nily.value).to eq(nil) }
18
+
19
+ it { expect {truthy1.value = 'bad'}.to raise_error(ArgumentError) }
20
+
21
+ describe 'setting to false' do
22
+ let(:subject) { Frodo::Properties::Boolean.new('Truthy', 'true') }
23
+
24
+ it { expect(subject.value).to eq(true) }
25
+
26
+ it { expect(lambda {
27
+ subject.value = false
28
+ subject.value
29
+ }.call).to eq(false) }
30
+
31
+ it { expect(lambda {
32
+ subject.value = 'false'
33
+ subject.value
34
+ }.call).to eq(false) }
35
+
36
+ it { expect(lambda {
37
+ subject.value = '0'
38
+ subject.value
39
+ }.call).to eq(false) }
40
+ end
41
+
42
+ describe 'setting to true' do
43
+ let(:subject) { Frodo::Properties::Boolean.new('Falsey', 'false') }
44
+
45
+ it { expect(subject.value).to eq(false) }
46
+
47
+ it { expect(lambda {
48
+ subject.value = true
49
+ subject.value
50
+ }.call).to eq(true) }
51
+
52
+ it { expect(lambda {
53
+ subject.value = 'true'
54
+ subject.value
55
+ }.call).to eq(true) }
56
+
57
+ it { expect(lambda {
58
+ subject.value = '1'
59
+ subject.value
60
+ }.call).to eq(true) }
61
+ end
62
+
63
+ describe 'setting to null' do
64
+ let(:subject) { Frodo::Properties::Boolean.new('Truthy', 'true') }
65
+
66
+ it { expect(subject.allows_nil?).to eq(true) }
67
+ it { expect(lambda {
68
+ subject.value = nil
69
+ subject.value
70
+ }.call).to eq(nil) }
71
+ end
72
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ describe Frodo::Properties::Collection do
4
+ let(:subject) { Frodo::Properties::Collection.new('Names', names) }
5
+ let(:names) { %w[Dan Greg Jon] }
6
+ let(:new_names) { %w[Andrew Doug Paul] }
7
+
8
+ it { expect(subject.type).to eq('Collection(Edm.String)') }
9
+ it { expect(subject.value).to eq(['Dan', 'Greg', 'Jon']) }
10
+ it { expect(subject.url_value).to eq("['Dan','Greg','Jon']") }
11
+
12
+ describe '#value=' do
13
+ it 'allows an array of string values to be set' do
14
+ subject.value = new_names
15
+ expect(subject.value).to eq(new_names)
16
+ end
17
+ end
18
+
19
+ # TODO: Make collection type work properly with data types other than string
20
+ xcontext 'with value type other than Edm.String' do
21
+ let(:subject) { Frodo::Properties::Collection.new('Bits', [1, 0, 1], value_type: 'Edm.Binary') }
22
+
23
+ it { expect(subject.type).to eq('Collection(Edm.Int32)') }
24
+ it { expect(subject.value).to eq([1, 0, 1]) }
25
+ it { expect(subject.url_value).to eq('[1,0,1]') }
26
+
27
+ it 'does not allow other property types to be set' do
28
+ expect {
29
+ subject.value = names
30
+ }.to raise_error(ArgumentError)
31
+ end
32
+
33
+ xdescribe 'lenient validation' do
34
+ let(:subject) do
35
+ Frodo::Properties::Collection.new('Names', names, value_type: 'Edm.String', strict: false)
36
+ end
37
+
38
+ it 'ignores invalid values' do
39
+ subject.value = [1, 2, 3]
40
+ expect(subject.value).to eq([])
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Frodo::Properties::Date do
4
+ let(:subject) { Frodo::Properties::Date.new('Date', '2000-01-01') }
5
+ let(:new_date) { Date.strptime('2004-05-01', '%Y-%m-%d') }
6
+
7
+ it { expect(subject.type).to eq('Edm.Date') }
8
+ it { expect(subject.value).to eq(Date.parse('2000-01-01')) }
9
+
10
+ it { expect(subject.url_value).to eq("2000-01-01")}
11
+
12
+ it { expect {subject.value = 'bad'}.to raise_error(ArgumentError) }
13
+
14
+ it { expect(lambda {
15
+ subject.value = '2004-05-01'
16
+ subject.value
17
+ }.call).to eq(new_date) }
18
+
19
+ it { expect(lambda {
20
+ subject.value = new_date
21
+ subject.value
22
+ }.call).to eq(new_date) }
23
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe Frodo::Properties::DateTimeOffset do
4
+ let(:subject) { Frodo::Properties::DateTimeOffset.new('DateTime', '2000-01-01T16:00:00-09:00') }
5
+ let(:new_datetime) { DateTime.strptime('2004-05-01T14:32:00+02:00', '%Y-%m-%dT%H:%M:%S%:z') }
6
+
7
+ it { expect(subject.type).to eq('Edm.DateTimeOffset') }
8
+ it { expect(subject.value).to eq(DateTime.strptime('2000-01-01T16:00:00-09:00', '%Y-%m-%dT%H:%M:%S%:z')) }
9
+
10
+ it { expect(subject.url_value).to eq("2000-01-01T16:00:00-09:00")}
11
+
12
+ it { expect {subject.value = 'bad'}.to raise_error(ArgumentError) }
13
+
14
+ it { expect(lambda {
15
+ subject.value = new_datetime
16
+ subject.value
17
+ }.call).to eq(new_datetime) }
18
+
19
+ it { expect(lambda {
20
+ subject.value = nil
21
+ }).not_to raise_error }
22
+
23
+ context 'with allows_nil option set to false' do
24
+ let(:subject) { Frodo::Properties::DateTimeOffset.new('DateTime', '2000-01-01T16:00:00Z-09:00', allows_nil: false) }
25
+
26
+ it { expect(lambda {
27
+ subject.value = nil
28
+ }).to raise_error(ArgumentError) }
29
+ end
30
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Frodo::Properties::DateTime do
4
+ let(:subject) { Frodo::Properties::DateTime.new('DateTime', '2000-01-01T16:00:00.000') }
5
+ let(:new_datetime) { DateTime.strptime('2004-05-01T14:32:00.000', '%Y-%m-%dT%H:%M:%S.%L') }
6
+
7
+ it { expect(subject.type).to eq('Edm.DateTime') }
8
+ it { expect(subject.value).to eq(DateTime.parse('2000-01-01T16:00:00.000')) }
9
+
10
+ it { expect(subject.url_value).to eq("2000-01-01T16:00:00.000")}
11
+
12
+ it { expect {subject.value = 'bad'}.to raise_error(ArgumentError) }
13
+
14
+ it { expect(lambda {
15
+ subject.value = '2004-05-01T14:32:00.000'
16
+ subject.value
17
+ }.call).to eq(new_datetime) }
18
+
19
+ it { expect(lambda {
20
+ subject.value = new_datetime
21
+ subject.value
22
+ }.call).to eq(new_datetime) }
23
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe Frodo::Properties::Decimal do
4
+ let(:subject) { Frodo::Properties::Decimal.new('Decimal', '678.90325') }
5
+
6
+ it { expect(subject.type).to eq('Edm.Decimal') }
7
+ it { expect(subject.value).to eq(BigDecimal('678.90325')) }
8
+
9
+ it { expect(subject.url_value).to eq('678.90325') }
10
+
11
+ it { expect { subject.value = BigDecimal((7.9 * (10**28)), 2) + 1 }.to raise_error(ArgumentError) }
12
+ it { expect { subject.value = BigDecimal((-7.9 * (10**28)), 2) - 1 }.to raise_error(ArgumentError) }
13
+ it { expect { subject.value = BigDecimal((3.4 * (10**-28)), 2) * 3.14151 + 5 }.to raise_error(ArgumentError) }
14
+
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
20
+
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
+ expect{ subject.value = 'foobar' }. to raise_error ArgumentError
33
+ end
34
+
35
+ it 'does not allow values outside a certain range' do
36
+ expect { subject.value = 'Infinity' }.to raise_error(ArgumentError)
37
+ end
38
+
39
+ describe 'lenient validation' do
40
+ let(:subject) do
41
+ Frodo::Properties::Decimal.new('Decimal', '678.90325', strict: false)
42
+ end
43
+
44
+ it 'ignores invalid values' do
45
+ subject.value = 'Infinity'
46
+ expect(subject.value).to eq(BigDecimal('Infinity'))
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ describe Frodo::Properties::Float do
4
+ describe 'double precision' do
5
+ let(:subject) { Frodo::Properties::Double.new('Float', '678.90325') }
6
+
7
+ it { expect(subject.type).to eq('Edm.Double') }
8
+ it { expect(subject.value).to eq(678.90325) }
9
+
10
+ it { expect { subject.value = (1.7 * (10**308) * 2) }.to raise_error(ArgumentError) }
11
+ it { expect { subject.value = (-1.7 * (10**308) * 2) }.to raise_error(ArgumentError) }
12
+
13
+ it { expect(lambda {
14
+ subject.value = '19.89043256'
15
+ subject.value
16
+ }.call).to eq(19.89043256) }
17
+
18
+ it { expect(lambda {
19
+ subject.value = 19.89043256
20
+ subject.value
21
+ }.call).to eq(19.89043256) }
22
+ end
23
+
24
+ describe 'single precision' do
25
+ let(:subject) { Frodo::Properties::Single.new('Float', '678.90325') }
26
+
27
+ it { expect(subject.type).to eq('Edm.Single') }
28
+ it { expect(subject.value).to eq(678.90325) }
29
+
30
+ it { expect(subject.url_value).to eq('678.90325F') }
31
+
32
+ it { expect { subject.value = (3.4 * (10**38) * 2) }.to raise_error(ArgumentError) }
33
+ it { expect { subject.value = (-3.4 * (10**38) * 2) }.to raise_error(ArgumentError) }
34
+
35
+ it { expect(lambda {
36
+ subject.value = '19.89043256'
37
+ subject.value
38
+ }.call).to eq(19.89043256) }
39
+
40
+ it { expect(lambda {
41
+ subject.value = 19.89043256
42
+ subject.value
43
+ }.call).to eq(19.89043256) }
44
+ end
45
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+ require_relative 'shared_examples'
3
+
4
+ describe Frodo::Properties::Geography::LineString do
5
+ let(:klass) { Frodo::Properties::Geography::LineString }
6
+ let(:property_name) { 'Boundary' }
7
+ let(:srid) { 4326 }
8
+ let(:coordinates) { [[100.0, 0.0], [101.0, 1.0]] }
9
+ let(:property_as_text) { "geography'SRID=4326;LineString(100.0 0.0,101.0 1.0)'" }
10
+ let(:property_as_json) { {
11
+ type: 'LineString',
12
+ coordinates: [
13
+ [100.0, 0.0],
14
+ [101.0, 1.0]
15
+ ],
16
+ crs: {
17
+ type: 'name',
18
+ properties: { name: 'EPSG:4326' }
19
+ }
20
+ } }
21
+ let(:property_as_xml) { <<-END }
22
+ <data:Boundary metadata:type="Edm.GeographyLineString">
23
+ <gml:LineString gml:srsName="http://www.opengis.net/def/crs/EPSG/0/4326">
24
+ <gml:pos>100.0 0.0</gml:pos>
25
+ <gml:pos>101.0 1.0</gml:pos>
26
+ </gml:LineString>
27
+ </data:Boundary>
28
+ END
29
+ let(:new_value) { [[0.0, 100.0], [1.0, 101.0]] }
30
+ let(:new_value_as_text) { "geography'SRID=0;LineString(0.0 100.0,1.0 101.0)'" }
31
+
32
+ it_behaves_like 'a geographic property', 'Edm.GeographyLineString'
33
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+ require_relative 'shared_examples'
3
+
4
+ describe Frodo::Properties::Geography::Point do
5
+ let(:klass) { Frodo::Properties::Geography::Point }
6
+ let(:property_name) { 'Location' }
7
+ let(:srid) { 4326 }
8
+ let(:coordinates) { [ 142.1, 64.1 ]}
9
+ let(:property_as_text) { "geography'SRID=4326;Point(142.1 64.1)'" }
10
+ let(:property_as_json) { {
11
+ type: 'Point',
12
+ coordinates: [142.1, 64.1],
13
+ crs: {
14
+ type: 'name',
15
+ properties: { name: 'EPSG:4326' }
16
+ }
17
+ } }
18
+ let(:property_as_xml) { <<-END }
19
+ <data:Location metadata:type="Edm.GeographyPoint">
20
+ <gml:Point gml:srsName="http://www.opengis.net/def/crs/EPSG/0/4326">
21
+ <gml:pos>142.1 64.1</gml:pos>
22
+ </gml:Point>
23
+ </data:Location>
24
+ END
25
+ let(:new_value) { [ 100.0, 0.0 ] }
26
+ let(:new_value_as_text) { "geography'SRID=0;Point(100.0 0.0)'" }
27
+
28
+ it_behaves_like 'a geographic property', 'Edm.GeographyPoint'
29
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+ require_relative 'shared_examples'
3
+
4
+ describe Frodo::Properties::Geography::Polygon do
5
+ let(:klass) { Frodo::Properties::Geography::Polygon }
6
+ let(:property_name) { 'Area' }
7
+ let(:srid) { 4326 }
8
+ let(:coordinates) { [
9
+ [100.0, 0.0],
10
+ [101.0, 0.0],
11
+ [101.0, 1.0],
12
+ [100.0, 1.0],
13
+ [100.0, 0.0]
14
+ ] }
15
+ let(:property_as_text) { "geography'SRID=4326;Polygon((100.0 0.0,101.0 0.0,101.0 1.0,100.0 1.0,100.0 0.0))'" }
16
+ let(:property_as_json) { {
17
+ type: 'Polygon',
18
+ coordinates: [
19
+ [100.0, 0.0],
20
+ [101.0, 0.0],
21
+ [101.0, 1.0],
22
+ [100.0, 1.0],
23
+ [100.0, 0.0]
24
+ ],
25
+ crs: {
26
+ type: 'name',
27
+ properties: { name: 'EPSG:4326' }
28
+ }
29
+ } }
30
+ let(:property_as_xml) { <<-END }
31
+ <data:Area metadata:type="Edm.GeographyPolygon">
32
+ <gml:Polygon gml:srsName="http://www.opengis.net/def/crs/EPSG/0/4326">
33
+ <gml:exterior>
34
+ <gml:LinearRing>
35
+ <gml:pos>100.0 0.0</gml:pos>
36
+ <gml:pos>101.0 0.0</gml:pos>
37
+ <gml:pos>101.0 1.0</gml:pos>
38
+ <gml:pos>100.0 1.0</gml:pos>
39
+ <gml:pos>100.0 0.0</gml:pos>
40
+ </gml:LinearRing>
41
+ </gml:exterior>
42
+ </gml:Polygon>
43
+ </data:Area>
44
+ END
45
+ let(:new_value) { [
46
+ [200.0, 10.0],
47
+ [201.0, 10.0],
48
+ [201.0, 11.0],
49
+ [200.0, 11.0],
50
+ [200.0, 10.0]
51
+ ] }
52
+ let(:new_value_as_text) { "geography'SRID=0;Polygon((200.0 10.0,201.0 10.0,201.0 11.0,200.0 11.0,200.0 10.0))'" }
53
+
54
+ it_behaves_like 'a geographic property', 'Edm.GeographyPolygon'
55
+ end