hoodoo 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (216) hide show
  1. checksums.yaml +7 -0
  2. data/bin/hoodoo +5 -0
  3. data/lib/hoodoo.rb +27 -0
  4. data/lib/hoodoo/active.rb +32 -0
  5. data/lib/hoodoo/active/active_model/uuid_validator.rb +45 -0
  6. data/lib/hoodoo/active/active_record/base.rb +81 -0
  7. data/lib/hoodoo/active/active_record/creator.rb +134 -0
  8. data/lib/hoodoo/active/active_record/dated.rb +343 -0
  9. data/lib/hoodoo/active/active_record/error_mapping.rb +351 -0
  10. data/lib/hoodoo/active/active_record/finder.rb +606 -0
  11. data/lib/hoodoo/active/active_record/search_helper.rb +189 -0
  12. data/lib/hoodoo/active/active_record/secure.rb +431 -0
  13. data/lib/hoodoo/active/active_record/support.rb +106 -0
  14. data/lib/hoodoo/active/active_record/translated.rb +87 -0
  15. data/lib/hoodoo/active/active_record/uuid.rb +80 -0
  16. data/lib/hoodoo/active/active_record/writer.rb +321 -0
  17. data/lib/hoodoo/client.rb +23 -0
  18. data/lib/hoodoo/client/augmented_array.rb +29 -0
  19. data/lib/hoodoo/client/augmented_base.rb +168 -0
  20. data/lib/hoodoo/client/augmented_hash.rb +23 -0
  21. data/lib/hoodoo/client/client.rb +354 -0
  22. data/lib/hoodoo/client/endpoint/endpoint.rb +427 -0
  23. data/lib/hoodoo/client/endpoint/endpoints/amqp.rb +180 -0
  24. data/lib/hoodoo/client/endpoint/endpoints/auto_session.rb +194 -0
  25. data/lib/hoodoo/client/endpoint/endpoints/http.rb +203 -0
  26. data/lib/hoodoo/client/endpoint/endpoints/http_based.rb +367 -0
  27. data/lib/hoodoo/client/endpoint/endpoints/not_found.rb +59 -0
  28. data/lib/hoodoo/client/headers.rb +269 -0
  29. data/lib/hoodoo/communicators.rb +23 -0
  30. data/lib/hoodoo/communicators/fast.rb +44 -0
  31. data/lib/hoodoo/communicators/pool.rb +601 -0
  32. data/lib/hoodoo/communicators/slow.rb +84 -0
  33. data/lib/hoodoo/data.rb +51 -0
  34. data/lib/hoodoo/data/resources/caller.rb +39 -0
  35. data/lib/hoodoo/data/resources/errors.rb +28 -0
  36. data/lib/hoodoo/data/resources/log.rb +31 -0
  37. data/lib/hoodoo/data/resources/session.rb +26 -0
  38. data/lib/hoodoo/data/types/error_primitive.rb +27 -0
  39. data/lib/hoodoo/data/types/permissions.rb +40 -0
  40. data/lib/hoodoo/data/types/permissions_defaults.rb +32 -0
  41. data/lib/hoodoo/data/types/permissions_full.rb +28 -0
  42. data/lib/hoodoo/data/types/permissions_resources.rb +31 -0
  43. data/lib/hoodoo/discovery.rb +20 -0
  44. data/lib/hoodoo/errors.rb +19 -0
  45. data/lib/hoodoo/errors/error_descriptions.rb +229 -0
  46. data/lib/hoodoo/errors/errors.rb +322 -0
  47. data/lib/hoodoo/generator.rb +139 -0
  48. data/lib/hoodoo/logger.rb +23 -0
  49. data/lib/hoodoo/logger/fast_writer.rb +27 -0
  50. data/lib/hoodoo/logger/flattener_mixin.rb +36 -0
  51. data/lib/hoodoo/logger/logger.rb +387 -0
  52. data/lib/hoodoo/logger/slow_writer.rb +49 -0
  53. data/lib/hoodoo/logger/writer_mixin.rb +52 -0
  54. data/lib/hoodoo/logger/writers/file_writer.rb +45 -0
  55. data/lib/hoodoo/logger/writers/log_entries_dot_com_writer.rb +64 -0
  56. data/lib/hoodoo/logger/writers/stream_writer.rb +43 -0
  57. data/lib/hoodoo/middleware.rb +33 -0
  58. data/lib/hoodoo/presenters.rb +45 -0
  59. data/lib/hoodoo/presenters/base.rb +281 -0
  60. data/lib/hoodoo/presenters/base_dsl.rb +519 -0
  61. data/lib/hoodoo/presenters/common_resource_fields.rb +31 -0
  62. data/lib/hoodoo/presenters/embedding.rb +232 -0
  63. data/lib/hoodoo/presenters/types/array.rb +118 -0
  64. data/lib/hoodoo/presenters/types/boolean.rb +26 -0
  65. data/lib/hoodoo/presenters/types/date.rb +26 -0
  66. data/lib/hoodoo/presenters/types/date_time.rb +26 -0
  67. data/lib/hoodoo/presenters/types/decimal.rb +47 -0
  68. data/lib/hoodoo/presenters/types/enum.rb +55 -0
  69. data/lib/hoodoo/presenters/types/field.rb +158 -0
  70. data/lib/hoodoo/presenters/types/float.rb +26 -0
  71. data/lib/hoodoo/presenters/types/hash.rb +361 -0
  72. data/lib/hoodoo/presenters/types/integer.rb +26 -0
  73. data/lib/hoodoo/presenters/types/object.rb +117 -0
  74. data/lib/hoodoo/presenters/types/string.rb +53 -0
  75. data/lib/hoodoo/presenters/types/tags.rb +24 -0
  76. data/lib/hoodoo/presenters/types/text.rb +26 -0
  77. data/lib/hoodoo/presenters/types/uuid.rb +54 -0
  78. data/lib/hoodoo/services.rb +34 -0
  79. data/lib/hoodoo/services/discovery/discoverers/by_consul.rb +66 -0
  80. data/lib/hoodoo/services/discovery/discoverers/by_convention.rb +173 -0
  81. data/lib/hoodoo/services/discovery/discoverers/by_drb/by_drb.rb +195 -0
  82. data/lib/hoodoo/services/discovery/discoverers/by_drb/drb_server.rb +166 -0
  83. data/lib/hoodoo/services/discovery/discoverers/by_drb/drb_server_start.rb +37 -0
  84. data/lib/hoodoo/services/discovery/discovery.rb +186 -0
  85. data/lib/hoodoo/services/discovery/results/for_amqp.rb +58 -0
  86. data/lib/hoodoo/services/discovery/results/for_http.rb +85 -0
  87. data/lib/hoodoo/services/discovery/results/for_local.rb +85 -0
  88. data/lib/hoodoo/services/discovery/results/for_remote.rb +57 -0
  89. data/lib/hoodoo/services/middleware/amqp_log_message.rb +186 -0
  90. data/lib/hoodoo/services/middleware/amqp_log_writer.rb +119 -0
  91. data/lib/hoodoo/services/middleware/endpoints/inter_resource_local.rb +130 -0
  92. data/lib/hoodoo/services/middleware/endpoints/inter_resource_remote.rb +202 -0
  93. data/lib/hoodoo/services/middleware/exception_reporting/base_reporter.rb +105 -0
  94. data/lib/hoodoo/services/middleware/exception_reporting/exception_reporting.rb +115 -0
  95. data/lib/hoodoo/services/middleware/exception_reporting/reporters/airbrake_reporter.rb +64 -0
  96. data/lib/hoodoo/services/middleware/exception_reporting/reporters/raygun_reporter.rb +63 -0
  97. data/lib/hoodoo/services/middleware/interaction.rb +127 -0
  98. data/lib/hoodoo/services/middleware/middleware.rb +2705 -0
  99. data/lib/hoodoo/services/middleware/rack_monkey_patch.rb +73 -0
  100. data/lib/hoodoo/services/services/context.rb +153 -0
  101. data/lib/hoodoo/services/services/implementation.rb +132 -0
  102. data/lib/hoodoo/services/services/interface.rb +934 -0
  103. data/lib/hoodoo/services/services/permissions.rb +250 -0
  104. data/lib/hoodoo/services/services/request.rb +189 -0
  105. data/lib/hoodoo/services/services/response.rb +316 -0
  106. data/lib/hoodoo/services/services/service.rb +141 -0
  107. data/lib/hoodoo/services/services/session.rb +729 -0
  108. data/lib/hoodoo/utilities.rb +12 -0
  109. data/lib/hoodoo/utilities/string_inquirer.rb +54 -0
  110. data/lib/hoodoo/utilities/utilities.rb +380 -0
  111. data/lib/hoodoo/utilities/uuid.rb +44 -0
  112. data/lib/hoodoo/version.rb +17 -0
  113. data/spec/active/active_record/base_spec.rb +57 -0
  114. data/spec/active/active_record/creator_spec.rb +88 -0
  115. data/spec/active/active_record/dated_spec.rb +248 -0
  116. data/spec/active/active_record/error_mapping_spec.rb +360 -0
  117. data/spec/active/active_record/finder_spec.rb +744 -0
  118. data/spec/active/active_record/search_helper_spec.rb +384 -0
  119. data/spec/active/active_record/secure_spec.rb +435 -0
  120. data/spec/active/active_record/support_spec.rb +225 -0
  121. data/spec/active/active_record/translated_spec.rb +19 -0
  122. data/spec/active/active_record/uuid_spec.rb +72 -0
  123. data/spec/active/active_record/writer_spec.rb +272 -0
  124. data/spec/alchemy/alchemy-amq.rb +33 -0
  125. data/spec/client/augmented_array_spec.rb +15 -0
  126. data/spec/client/augmented_base_spec.rb +50 -0
  127. data/spec/client/augmented_hash_spec.rb +15 -0
  128. data/spec/client/client_spec.rb +955 -0
  129. data/spec/client/endpoint/endpoint_spec.rb +70 -0
  130. data/spec/client/endpoint/endpoints/amqp_spec.rb +16 -0
  131. data/spec/client/endpoint/endpoints/auto_session_spec.rb +9 -0
  132. data/spec/client/endpoint/endpoints/http_based_spec.rb +9 -0
  133. data/spec/client/endpoint/endpoints/http_spec.rb +103 -0
  134. data/spec/client/endpoint/endpoints/not_found_spec.rb +35 -0
  135. data/spec/client/headers_spec.rb +172 -0
  136. data/spec/communicators/fast_spec.rb +9 -0
  137. data/spec/communicators/pool_spec.rb +339 -0
  138. data/spec/communicators/slow_spec.rb +15 -0
  139. data/spec/data/resources/caller_spec.rb +156 -0
  140. data/spec/data/resources/errors_spec.rb +22 -0
  141. data/spec/data/resources/log_spec.rb +20 -0
  142. data/spec/data/resources/session_spec.rb +15 -0
  143. data/spec/data/types/error_primitive_spec.rb +15 -0
  144. data/spec/data/types/permissions_defaults_spec.rb +25 -0
  145. data/spec/data/types/permissions_full_spec.rb +44 -0
  146. data/spec/data/types/permissions_resources_spec.rb +34 -0
  147. data/spec/data/types/permissions_spec.rb +37 -0
  148. data/spec/errors/error_descriptions_spec.rb +98 -0
  149. data/spec/errors/errors_spec.rb +346 -0
  150. data/spec/integration/service_actions_spec.rb +112 -0
  151. data/spec/logger/fast_writer_spec.rb +18 -0
  152. data/spec/logger/logger_spec.rb +259 -0
  153. data/spec/logger/slow_writer_spec.rb +144 -0
  154. data/spec/logger/writers/file_writer_spec.rb +37 -0
  155. data/spec/logger/writers/log_entries_dot_com_writer_spec.rb +29 -0
  156. data/spec/logger/writers/stream_writer_spec.rb +38 -0
  157. data/spec/presenters/base_dsl_spec.rb +111 -0
  158. data/spec/presenters/base_spec.rb +871 -0
  159. data/spec/presenters/common_resource_fields_spec.rb +30 -0
  160. data/spec/presenters/embedding_spec.rb +87 -0
  161. data/spec/presenters/types/array_spec.rb +249 -0
  162. data/spec/presenters/types/boolean_spec.rb +51 -0
  163. data/spec/presenters/types/date_spec.rb +57 -0
  164. data/spec/presenters/types/date_time_spec.rb +59 -0
  165. data/spec/presenters/types/decimal_spec.rb +58 -0
  166. data/spec/presenters/types/enum_spec.rb +71 -0
  167. data/spec/presenters/types/field_spec.rb +77 -0
  168. data/spec/presenters/types/float_spec.rb +50 -0
  169. data/spec/presenters/types/hash_spec.rb +1069 -0
  170. data/spec/presenters/types/integer_spec.rb +50 -0
  171. data/spec/presenters/types/object_spec.rb +177 -0
  172. data/spec/presenters/types/string_spec.rb +65 -0
  173. data/spec/presenters/types/tags_spec.rb +56 -0
  174. data/spec/presenters/types/text_spec.rb +50 -0
  175. data/spec/presenters/types/uuid_spec.rb +46 -0
  176. data/spec/presenters/walk_spec.rb +198 -0
  177. data/spec/services/discovery/discoverers/by_consul_spec.rb +29 -0
  178. data/spec/services/discovery/discoverers/by_convention_spec.rb +67 -0
  179. data/spec/services/discovery/discoverers/by_drb/by_drb_spec.rb +80 -0
  180. data/spec/services/discovery/discoverers/by_drb/drb_server_spec.rb +205 -0
  181. data/spec/services/discovery/discovery_spec.rb +73 -0
  182. data/spec/services/discovery/results/for_amqp_spec.rb +17 -0
  183. data/spec/services/discovery/results/for_http_spec.rb +37 -0
  184. data/spec/services/discovery/results/for_local_spec.rb +21 -0
  185. data/spec/services/discovery/results/for_remote_spec.rb +15 -0
  186. data/spec/services/middleware/amqp_log_message_spec.rb +60 -0
  187. data/spec/services/middleware/amqp_log_writer_spec.rb +95 -0
  188. data/spec/services/middleware/endpoints/inter_resource_local_spec.rb +9 -0
  189. data/spec/services/middleware/endpoints/inter_resource_remote_spec.rb +9 -0
  190. data/spec/services/middleware/exception_reporting/base_reporter_spec.rb +16 -0
  191. data/spec/services/middleware/exception_reporting/exception_reporting_spec.rb +92 -0
  192. data/spec/services/middleware/exception_reporting/reporters/airbrake_reporter_spec.rb +24 -0
  193. data/spec/services/middleware/exception_reporting/reporters/raygun_reporter_spec.rb +23 -0
  194. data/spec/services/middleware/middleware_cors_spec.rb +93 -0
  195. data/spec/services/middleware/middleware_create_update_spec.rb +489 -0
  196. data/spec/services/middleware/middleware_dated_at_spec.rb +186 -0
  197. data/spec/services/middleware/middleware_exotic_communication_spec.rb +560 -0
  198. data/spec/services/middleware/middleware_logging_spec.rb +356 -0
  199. data/spec/services/middleware/middleware_multi_local_spec.rb +1094 -0
  200. data/spec/services/middleware/middleware_multi_remote_spec.rb +1440 -0
  201. data/spec/services/middleware/middleware_permissions_spec.rb +1014 -0
  202. data/spec/services/middleware/middleware_public_spec.rb +238 -0
  203. data/spec/services/middleware/middleware_spec.rb +1569 -0
  204. data/spec/services/middleware/string_inquirer_spec.rb +30 -0
  205. data/spec/services/services/application_spec.rb +74 -0
  206. data/spec/services/services/context_spec.rb +48 -0
  207. data/spec/services/services/implementation_spec.rb +45 -0
  208. data/spec/services/services/interface_spec.rb +262 -0
  209. data/spec/services/services/permissions_spec.rb +249 -0
  210. data/spec/services/services/request_spec.rb +95 -0
  211. data/spec/services/services/response_spec.rb +250 -0
  212. data/spec/services/services/session_spec.rb +432 -0
  213. data/spec/spec_helper.rb +298 -0
  214. data/spec/utilities/utilities_spec.rb +537 -0
  215. data/spec/utilities/uuid_spec.rb +20 -0
  216. metadata +615 -0
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hoodoo::Logger::LogEntriesDotComWriter do
4
+
5
+ let( :example_token ) do
6
+ # https://logentries.com/doc/input-token/
7
+ '2bfbea1e-10c3-4419-bdad-7e6435882e1f'
8
+ end
9
+
10
+ before( :each ) do
11
+ @instance = described_class.new( example_token() )
12
+ @logger = @instance.class.class_variable_get( '@@logger' )
13
+ end
14
+
15
+ it 'creates an appropriate logger instance' do
16
+ example = Le.new( example_token(), :ssl => true )
17
+ expect( @logger.class ).to eq( example.class )
18
+ end
19
+
20
+ it 'calls the logger instance by log level method' do
21
+ expect( @logger ).to receive( :info ).once
22
+ @instance.report( :info, :b, :c, :d )
23
+ end
24
+
25
+ it 'converts unrecognised debug levels to "unknown"' do
26
+ expect( @logger ).to receive( :unknown ).once
27
+ @instance.report( :a, :b, :c, :d )
28
+ end
29
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+ require 'time'
3
+
4
+ describe Hoodoo::Logger::StreamWriter do
5
+ before :all do
6
+ temp_name = Dir::Tmpname.make_tmpname( 'hoodoo_rspec_', nil )
7
+ @temp_path = File.join( Dir::Tmpname.tmpdir, temp_name )
8
+ @stream = File.open( @temp_path, 'ab' )
9
+ end
10
+
11
+ after :all do
12
+ begin
13
+ @stream.close
14
+ rescue
15
+ end
16
+
17
+ begin
18
+ File.unlink( @temp_path )
19
+ rescue
20
+ end
21
+ end
22
+
23
+ it 'writes to streams' do
24
+
25
+ instance = described_class.new( @stream )
26
+
27
+ time = Time.parse("2014-01-01 00:00:00 UTC")
28
+ expect( Time ).to receive( :now ).at_least( 1 ).times.and_return( time )
29
+
30
+ instance.report( :a, :b, :c, :d )
31
+ expect( File.exist?( @temp_path ) ).to be( true )
32
+ @stream.close
33
+
34
+ logged = File.read( @temp_path )
35
+ expect( logged ).to eq( "A [2014-01-01T00:00:00.000000Z] b - c: :d\n")
36
+
37
+ end
38
+ end
@@ -0,0 +1,111 @@
1
+ require "spec_helper"
2
+
3
+ describe Hoodoo::Presenters::BaseDSL do
4
+
5
+ # There are few tests needed beyond the base presenter tests at
6
+ # present.
7
+
8
+ describe '#type' do
9
+ class Hoodoo::Data::Types::TestType < Hoodoo::Presenters::Base
10
+ schema do
11
+ text :name
12
+ end
13
+ end
14
+
15
+ class ArbitraryTestType < Hoodoo::Presenters::Base
16
+ schema do
17
+ float :floaty
18
+ end
19
+ end
20
+
21
+ it 'should raise an error for unrecognised types' do
22
+ expect {
23
+ class BaseDSLTest < Hoodoo::Presenters::Base
24
+ schema do
25
+ object :obj do
26
+ type :DoesNotExist
27
+ end
28
+ end
29
+ end
30
+ }.to raise_error(RuntimeError, "Hoodoo::Presenters::Base#type: Unrecognised type name 'DoesNotExist'")
31
+ end
32
+
33
+ it 'should not raise an error for existing types' do
34
+ expect {
35
+ class BaseDSLTest < Hoodoo::Presenters::Base
36
+ schema do
37
+ type :TestType
38
+ end
39
+ end
40
+ }.not_to raise_error
41
+
42
+ expect {
43
+ class BaseDSLTest < Hoodoo::Presenters::Base
44
+ schema do
45
+ type Hoodoo::Data::Types::TestType
46
+ end
47
+ end
48
+ }.not_to raise_error
49
+
50
+ expect {
51
+ class BaseDSLTest < Hoodoo::Presenters::Base
52
+ schema do
53
+ type ArbitraryTestType
54
+ end
55
+ end
56
+ }.not_to raise_error
57
+ end
58
+ end
59
+
60
+ describe '#resource' do
61
+ class Hoodoo::Data::Resources::TestResource < Hoodoo::Presenters::Base
62
+ schema do
63
+ internationalised
64
+
65
+ text :name
66
+ end
67
+ end
68
+
69
+ class ArbitraryTestResource < Hoodoo::Presenters::Base
70
+ schema do
71
+ float :floaty
72
+ end
73
+ end
74
+
75
+ it 'should raise an error for unrecognised resources' do
76
+ expect {
77
+ class BaseDSLTest < Hoodoo::Presenters::Base
78
+ schema do
79
+ resource :DoesNotExist
80
+ end
81
+ end
82
+ }.to raise_error(RuntimeError, "Hoodoo::Presenters::Base#resource: Unrecognised resource name 'DoesNotExist'")
83
+ end
84
+
85
+ it 'should not raise an error for existing resources' do
86
+ expect {
87
+ class BaseDSLTest < Hoodoo::Presenters::Base
88
+ schema do
89
+ resource :TestResource
90
+ end
91
+ end
92
+ }.not_to raise_error
93
+
94
+ expect {
95
+ class BaseDSLTest < Hoodoo::Presenters::Base
96
+ schema do
97
+ resource Hoodoo::Data::Resources::TestResource
98
+ end
99
+ end
100
+ }.not_to raise_error
101
+
102
+ expect {
103
+ class BaseDSLTest < Hoodoo::Presenters::Base
104
+ schema do
105
+ resource ArbitraryTestResource
106
+ end
107
+ end
108
+ }.not_to raise_error
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,871 @@
1
+ require "spec_helper"
2
+
3
+ describe '#schema' do
4
+
5
+ before do
6
+
7
+ class TestPresenter < Hoodoo::Presenters::Base
8
+
9
+ schema do
10
+ integer :one, :required => true
11
+ boolean :two, :required => true
12
+ string :three, :length => 15, :required => false, :default => 'default_three'
13
+ datetime :four
14
+ end
15
+
16
+ end
17
+
18
+ class TestPresenter2 < Hoodoo::Presenters::Base
19
+
20
+ schema do
21
+ object :four, :required => true do
22
+ decimal :five, :precision => 20
23
+ float :six
24
+ date :seven, :required => true
25
+ array :eight
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ class TestPresenter3 < Hoodoo::Presenters::Base
32
+
33
+ schema do
34
+ integer :one, :required => true
35
+ object :four, :required => true do
36
+ decimal :five, :precision => 20
37
+ float :six
38
+ date :seven, :required => true
39
+ array :eight
40
+ end
41
+ end
42
+
43
+ end
44
+
45
+ class TestPresenter4 < Hoodoo::Presenters::Base
46
+
47
+ schema do
48
+ array :an_array, :required => true do
49
+ integer :an_integer
50
+ datetime :a_datetime
51
+ end
52
+ enum :an_enum, :from => [ :one, 'two', 3 ]
53
+ text :some_text
54
+ end
55
+
56
+ end
57
+
58
+
59
+ # Just in case someone's deliberately excluding other source files to
60
+ # check on code coverage...
61
+ #
62
+ module Hoodoo
63
+ module Data
64
+ module Types
65
+ end
66
+ module Resources
67
+ end
68
+ end
69
+ end
70
+
71
+ # This exercises basic type definition using the Presenters DSL's #text
72
+ # and #internationalised methods.
73
+ #
74
+ class Hoodoo::Data::Types::Hello < Hoodoo::Presenters::Base
75
+ schema do
76
+ internationalised
77
+ text :name, :required => true
78
+ end
79
+ end
80
+
81
+ # This exercises basic resource definition with extended DSL methods #tags,
82
+ # #uuid and #type, with the #object and #array parts checking methods from
83
+ # both the extended and Presenters base DSL. The type reference is deeply
84
+ # nested to make sure that internationalisation in the Hello type "taints"
85
+ # the referencing type all the way up to the top level schema.
86
+
87
+ class Hoodoo::Data::Resources::World < Hoodoo::Presenters::Base
88
+ schema do
89
+ uuid :errors_id, :resource => :Errors
90
+ tags :test_tags
91
+
92
+ object :test_object, :required => true do
93
+ object :nested_object do
94
+ type :Hello
95
+ string :obj_suffix, :length => 1
96
+ end
97
+
98
+ array :test_array do
99
+ type :Hello
100
+ string :ary_suffix, :length => 2
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ # Check the 'resource' reference part of the DSL works too
107
+
108
+ class Hoodoo::Data::Resources::HelloWorld < Hoodoo::Presenters::Base
109
+ schema do
110
+ type :Hello
111
+ resource :World
112
+ end
113
+ end
114
+
115
+ class NastyNesting < Hoodoo::Presenters::Base
116
+ schema do
117
+ array :outer_array, :required => true do
118
+ text :one, :required => true
119
+ text :two, :required => true
120
+ array :middle_array, :required => true do
121
+ text :three, :required => true
122
+ text :four, :required => true
123
+ array :inner_array, :required => true do
124
+ text :five, :required => true
125
+ text :six, :required => true
126
+ object :inner_object, :required => true do
127
+ text :seven, :required => true
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
134
+
135
+ # For testing resource validation for internationalised (or not) resources.
136
+
137
+ class Internationalised < Hoodoo::Presenters::Base
138
+ schema do
139
+ internationalised
140
+ end
141
+ end
142
+
143
+ class NotInternationalised < Hoodoo::Presenters::Base
144
+ schema do
145
+ end
146
+ end
147
+
148
+ # For testing hashes with type references
149
+
150
+ class Internationalised2 < Hoodoo::Presenters::Base
151
+ schema do
152
+ internationalised
153
+ text :hello
154
+ end
155
+ end
156
+
157
+ class HashGainsInternationalisation < Hoodoo::Presenters::Base
158
+ schema do
159
+ hash :inter do
160
+ keys do
161
+ type :Internationalised2
162
+ end
163
+ end
164
+ end
165
+ end
166
+
167
+ class HashGainsInternationalisation2 < Hoodoo::Presenters::Base
168
+ schema do
169
+ hash :inter do
170
+ key :one do
171
+ text :foo
172
+ end
173
+ key :two do
174
+ type :Internationalised2
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end
180
+
181
+ describe '#validate' do
182
+ it 'should have a simple schema defined properly' do
183
+ schema = TestPresenter.get_schema
184
+
185
+ expect(schema.properties.count).to eq(4)
186
+ expect(schema.properties['one']).to be_a(Hoodoo::Presenters::Integer)
187
+ expect(schema.properties['one'].required).to eq(true)
188
+ expect(schema.properties['two']).to be_a(Hoodoo::Presenters::Boolean)
189
+ expect(schema.properties['two'].required).to eq(true)
190
+ expect(schema.properties['three']).to be_a(Hoodoo::Presenters::String)
191
+ expect(schema.properties['three'].required).to eq(false)
192
+ expect(schema.properties['three'].length).to eq(15)
193
+ expect(schema.properties['four']).to be_a(Hoodoo::Presenters::DateTime)
194
+ expect(schema.properties['four'].required).to eq(false)
195
+ end
196
+
197
+ it 'should have a nested schema defined properly' do
198
+ schema = TestPresenter2.get_schema
199
+
200
+ expect(schema.properties.length).to eq(1)
201
+ expect(schema.properties['four']).to be_a(Hoodoo::Presenters::Object)
202
+ expect(schema.properties['four'].properties.length).to eq(4)
203
+ expect(schema.properties['four'].properties['five']).to be_a(Hoodoo::Presenters::Decimal)
204
+ expect(schema.properties['four'].properties['five'].precision).to eq(20)
205
+ expect(schema.properties['four'].properties['six']).to be_a(Hoodoo::Presenters::Float)
206
+ expect(schema.properties['four'].properties['seven']).to be_a(Hoodoo::Presenters::Date)
207
+ expect(schema.properties['four'].properties['seven'].required).to eq(true)
208
+ expect(schema.properties['four'].properties['eight']).to be_a(Hoodoo::Presenters::Array)
209
+ end
210
+
211
+ it 'should have a nested schema for arrays' do
212
+ schema = TestPresenter4.get_schema
213
+ expect(schema.properties.length).to eq(3)
214
+ expect(schema.properties['an_array']).to be_a(Hoodoo::Presenters::Array)
215
+ expect(schema.properties['an_array'].required).to eq(true)
216
+ expect(schema.properties['an_array'].properties.length).to eq(2)
217
+ expect(schema.properties['an_array'].properties['an_integer']).to be_a(Hoodoo::Presenters::Integer)
218
+ expect(schema.properties['an_array'].properties['an_integer'].required).to eq(false)
219
+ expect(schema.properties['an_array'].properties['a_datetime']).to be_a(Hoodoo::Presenters::DateTime)
220
+ expect(schema.properties['an_array'].properties['a_datetime'].required).to eq(false)
221
+ expect(schema.properties['an_enum']).to be_a(Hoodoo::Presenters::Enum)
222
+ expect(schema.properties['an_enum'].required).to eq(false)
223
+ expect(schema.properties['an_enum'].from).to eq(['one', 'two', '3'])
224
+ expect(schema.properties['some_text']).to be_a(Hoodoo::Presenters::Text)
225
+ expect(schema.properties['some_text'].required).to eq(false)
226
+ end
227
+
228
+ it 'should return no errors with a simple schema and valid data' do
229
+ data = {
230
+ 'one' => 1,
231
+ 'two' => true,
232
+ 'three' => 'hello',
233
+ }
234
+
235
+ expect(TestPresenter.validate(data).errors).to eq([])
236
+ end
237
+
238
+ it 'should return correct errors with a simple schema and invalid data' do
239
+ data = {
240
+ 'one' => 'test',
241
+ 'three' => 9323423,
242
+ }
243
+
244
+ errors = TestPresenter.validate(data)
245
+ expect(errors.errors).to eq([
246
+ {'code'=>"generic.invalid_integer", 'message'=>"Field `one` is an invalid integer", 'reference'=>"one"},
247
+ {'code'=>"generic.required_field_missing", 'message'=>"Field `two` is required", 'reference'=>"two"},
248
+ {'code'=>"generic.invalid_string", 'message'=>"Field `three` is an invalid string", 'reference'=>"three"},
249
+ ])
250
+ end
251
+
252
+ it 'should have nested complex schema defined properly' do
253
+
254
+ schema = Hoodoo::Data::Types::Hello.get_schema
255
+
256
+ expect(Hoodoo::Data::Types::Hello.is_internationalised?()).to eq(true)
257
+ expect(schema.is_internationalised?()).to eq(true)
258
+ expect(schema.properties.count).to eq(1)
259
+ expect(schema.properties['name']).to be_a(Hoodoo::Presenters::Text)
260
+ expect(schema.properties['name'].required).to eq(true)
261
+
262
+ schema = Hoodoo::Data::Resources::World.get_schema
263
+
264
+ expect(Hoodoo::Data::Resources::World.is_internationalised?()).to eq(true)
265
+ expect(schema.is_internationalised?()).to eq(true)
266
+ expect(schema.properties.count).to eq(3)
267
+ expect(schema.properties['errors_id']).to be_a(Hoodoo::Presenters::UUID)
268
+ expect(schema.properties['errors_id'].required).to eq(false)
269
+ expect(schema.properties['errors_id'].resource).to eq(:Errors)
270
+ expect(schema.properties['test_tags']).to be_a(Hoodoo::Presenters::Tags)
271
+ expect(schema.properties['test_tags'].required).to eq(false)
272
+ expect(schema.properties['test_object']).to be_a(Hoodoo::Presenters::Object)
273
+ expect(schema.properties['test_object'].required).to eq(true)
274
+ expect(schema.properties['test_object'].properties['nested_object']).to be_a(Hoodoo::Presenters::Object)
275
+ expect(schema.properties['test_object'].properties['nested_object'].required).to eq(false)
276
+ expect(schema.properties['test_object'].properties['nested_object'].properties['name']).to be_a(Hoodoo::Presenters::Text)
277
+ expect(schema.properties['test_object'].properties['nested_object'].properties['obj_suffix']).to be_a(Hoodoo::Presenters::String)
278
+ expect(schema.properties['test_object'].properties['nested_object'].properties['obj_suffix'].length).to eq(1)
279
+ expect(schema.properties['test_object'].properties['test_array']).to be_a(Hoodoo::Presenters::Array)
280
+ expect(schema.properties['test_object'].properties['test_array'].required).to eq(false)
281
+ expect(schema.properties['test_object'].properties['test_array'].properties['name']).to be_a(Hoodoo::Presenters::Text)
282
+ expect(schema.properties['test_object'].properties['test_array'].properties['ary_suffix']).to be_a(Hoodoo::Presenters::String)
283
+ expect(schema.properties['test_object'].properties['test_array'].properties['ary_suffix'].length).to eq(2)
284
+
285
+ schema = Hoodoo::Data::Resources::HelloWorld.get_schema
286
+
287
+ expect(Hoodoo::Data::Resources::World.is_internationalised?()).to eq(true)
288
+ expect(schema.is_internationalised?()).to eq(true)
289
+ expect(schema.properties.count).to eq(4)
290
+ expect(schema.properties['name']).to be_a(Hoodoo::Presenters::Text)
291
+ expect(schema.properties['name'].required).to eq(true)
292
+ expect(schema.properties['errors_id']).to be_a(Hoodoo::Presenters::UUID)
293
+ expect(schema.properties['errors_id'].required).to eq(false)
294
+ expect(schema.properties['errors_id'].resource).to eq(:Errors)
295
+ expect(schema.properties['test_tags']).to be_a(Hoodoo::Presenters::Tags)
296
+ expect(schema.properties['test_tags'].required).to eq(false)
297
+ expect(schema.properties['test_object']).to be_a(Hoodoo::Presenters::Object)
298
+ expect(schema.properties['test_object'].required).to eq(true)
299
+ expect(schema.properties['test_object'].properties['nested_object']).to be_a(Hoodoo::Presenters::Object)
300
+ expect(schema.properties['test_object'].properties['nested_object'].required).to eq(false)
301
+ expect(schema.properties['test_object'].properties['nested_object'].properties['name']).to be_a(Hoodoo::Presenters::Text)
302
+ expect(schema.properties['test_object'].properties['nested_object'].properties['obj_suffix']).to be_a(Hoodoo::Presenters::String)
303
+ expect(schema.properties['test_object'].properties['nested_object'].properties['obj_suffix'].length).to eq(1)
304
+ expect(schema.properties['test_object'].properties['test_array']).to be_a(Hoodoo::Presenters::Array)
305
+ expect(schema.properties['test_object'].properties['test_array'].required).to eq(false)
306
+ expect(schema.properties['test_object'].properties['test_array'].properties['name']).to be_a(Hoodoo::Presenters::Text)
307
+ expect(schema.properties['test_object'].properties['test_array'].properties['ary_suffix']).to be_a(Hoodoo::Presenters::String)
308
+ expect(schema.properties['test_object'].properties['test_array'].properties['ary_suffix'].length).to eq(2)
309
+ end
310
+
311
+ it 'should return no errors with valid data for type only' do
312
+ data = {
313
+ :errors_id => Hoodoo::UUID.generate,
314
+ :test_tags => 'foo,bar,baz',
315
+ :test_object => {
316
+ :nested_object => {
317
+ :name => 'Some name',
318
+ :obj_suffix => '!'
319
+ },
320
+ :test_array => [
321
+ { :name => 'Some name 0', :ary_suffix => '00' },
322
+ { :name => 'Some name 1' }
323
+ ]
324
+ }
325
+ }
326
+
327
+ data = Hoodoo::Utilities.stringify(data)
328
+ expect(Hoodoo::Data::Resources::World.validate(data, false).errors).to eq([])
329
+ end
330
+
331
+ it 'should return no errors with valid data for resource' do
332
+ data = {
333
+ :errors_id => Hoodoo::UUID.generate,
334
+ :test_tags => 'foo,bar,baz',
335
+ :test_object => {
336
+ :nested_object => {
337
+ :name => 'Some name',
338
+ :obj_suffix => '!'
339
+ },
340
+ :test_array => [
341
+ { :name => 'Some name 0', :ary_suffix => '00' },
342
+ { :name => 'Some name 1' }
343
+ ]
344
+ }
345
+ }
346
+
347
+ data = Hoodoo::Utilities.stringify(data)
348
+ rendered = Hoodoo::Data::Resources::World.render(
349
+ data,
350
+ Hoodoo::UUID.generate,
351
+ Time.now
352
+ )
353
+
354
+ expect(Hoodoo::Data::Resources::World.validate(rendered, true).errors).to eq([])
355
+ end
356
+
357
+ it 'should return correct errors invalid data' do
358
+ data = {
359
+ :errors_id => Hoodoo::UUID.generate,
360
+ :test_tags => 'foo,bar,baz',
361
+ :test_object => {
362
+ :nested_object => {
363
+ :name => 'Some name',
364
+ :obj_suffix => '!!!'
365
+ },
366
+ :test_array => [
367
+ { :name => 'Some name 0', :ary_suffix => '00' },
368
+ { :name => 'Some name 1' },
369
+ { :ary_suffix => 22 }
370
+ ]
371
+ }
372
+ }
373
+
374
+ data = Hoodoo::Utilities.stringify(data)
375
+ expect(Hoodoo::Data::Resources::World.validate(data, false).errors).to eq([
376
+ {
377
+ 'code' => 'generic.invalid_string',
378
+ 'message' => 'Field `test_object.nested_object.obj_suffix` is longer than maximum length `1`',
379
+ 'reference' => "test_object.nested_object.obj_suffix"
380
+ },
381
+ {
382
+ 'code' => 'generic.required_field_missing',
383
+ 'message' => 'Field `test_object.test_array[2].name` is required',
384
+ 'reference' => "test_object.test_array[2].name"
385
+ },
386
+ {
387
+ 'code' => 'generic.invalid_string',
388
+ 'message' => 'Field `test_object.test_array[2].ary_suffix` is an invalid string',
389
+ 'reference' => "test_object.test_array[2].ary_suffix"
390
+ }
391
+ ])
392
+ end
393
+
394
+ it 'should return correct paths in errors for deeply nested cases' do
395
+
396
+ # The array must be present, but that doesn't tell us anything about
397
+ # the contents yet so we only have one error.
398
+
399
+ data = {}
400
+ expect(NastyNesting.validate(data, false).errors).to eq([
401
+ {
402
+ 'code' => 'generic.required_field_missing',
403
+ 'message' => 'Field `outer_array` is required',
404
+ 'reference' => "outer_array"
405
+ }
406
+ ])
407
+
408
+ # The outer array is present but empty. That's allowed. If we had
409
+ # added entries, then their requirements would apply.
410
+
411
+ data = {
412
+ :outer_array => []
413
+ }
414
+ data = Hoodoo::Utilities.stringify(data)
415
+ expect(NastyNesting.validate(data, false).errors).to eq([])
416
+
417
+ # The outer array is present and has two entries that omit required
418
+ # fields, so we expect errors for all of them.
419
+
420
+ data = {
421
+ :outer_array => [{}, {}]
422
+ }
423
+ data = Hoodoo::Utilities.stringify(data)
424
+ expect(NastyNesting.validate(data, false).errors).to eq([
425
+ {'code' => 'generic.required_field_missing', 'message' => 'Field `outer_array[0].one` is required', 'reference' => "outer_array[0].one"},
426
+ {'code' => 'generic.required_field_missing', 'message' => 'Field `outer_array[0].two` is required', 'reference' => "outer_array[0].two"},
427
+ {'code' => 'generic.required_field_missing', 'message' => 'Field `outer_array[0].middle_array` is required', 'reference' => "outer_array[0].middle_array"},
428
+ {'code' => 'generic.required_field_missing', 'message' => 'Field `outer_array[1].one` is required', 'reference' => "outer_array[1].one"},
429
+ {'code' => 'generic.required_field_missing', 'message' => 'Field `outer_array[1].two` is required', 'reference' => "outer_array[1].two"},
430
+ {'code' => 'generic.required_field_missing', 'message' => 'Field `outer_array[1].middle_array` is required', 'reference' => "outer_array[1].middle_array"}
431
+ ])
432
+
433
+ # ...and follow that pattern for nested items...
434
+
435
+ data = {
436
+ :outer_array => [
437
+ {
438
+ :one => 'here',
439
+ :two => 'here',
440
+ :middle_array => []
441
+ }
442
+ ]
443
+ }
444
+ data = Hoodoo::Utilities.stringify(data)
445
+ expect(NastyNesting.validate(data, false).errors).to eq([])
446
+
447
+ data = {
448
+ :outer_array => [
449
+ {
450
+ :one => 'here',
451
+ :two => 'here',
452
+ :middle_array => [{},{}]
453
+ }
454
+ ]
455
+ }
456
+ data = Hoodoo::Utilities.stringify(data)
457
+ expect(NastyNesting.validate(data, false).errors).to eq([
458
+ {'code' => 'generic.required_field_missing', 'message' => 'Field `outer_array[0].middle_array[0].three` is required', 'reference' => "outer_array[0].middle_array[0].three"},
459
+ {'code' => 'generic.required_field_missing', 'message' => 'Field `outer_array[0].middle_array[0].four` is required', 'reference' => "outer_array[0].middle_array[0].four"},
460
+ {'code' => 'generic.required_field_missing', 'message' => 'Field `outer_array[0].middle_array[0].inner_array` is required', 'reference' => "outer_array[0].middle_array[0].inner_array"},
461
+ {'code' => 'generic.required_field_missing', 'message' => 'Field `outer_array[0].middle_array[1].three` is required', 'reference' => "outer_array[0].middle_array[1].three"},
462
+ {'code' => 'generic.required_field_missing', 'message' => 'Field `outer_array[0].middle_array[1].four` is required', 'reference' => "outer_array[0].middle_array[1].four"},
463
+ {'code' => 'generic.required_field_missing', 'message' => 'Field `outer_array[0].middle_array[1].inner_array` is required', 'reference' => "outer_array[0].middle_array[1].inner_array"}
464
+ ])
465
+
466
+ data = {
467
+ :outer_array => [
468
+ {
469
+ :one => 'here',
470
+ :two => 'here',
471
+ :middle_array => [
472
+ {
473
+ :three => 'here',
474
+ :four => 'here',
475
+ :inner_array => []
476
+ }
477
+ ]
478
+ }
479
+ ]
480
+ }
481
+ data = Hoodoo::Utilities.stringify(data)
482
+ expect(NastyNesting.validate(data, false).errors).to eq([])
483
+
484
+ data = {
485
+ :outer_array => [
486
+ {
487
+ :one => 'here',
488
+ :two => 'here',
489
+ :middle_array => [
490
+ {
491
+ :three => 'here',
492
+ :four => 'here',
493
+ :inner_array => [{},{}]
494
+ }
495
+ ]
496
+ }
497
+ ]
498
+ }
499
+ data = Hoodoo::Utilities.stringify(data)
500
+ expect(NastyNesting.validate(data, false).errors).to eq([
501
+ {'code' => 'generic.required_field_missing', 'message' => 'Field `outer_array[0].middle_array[0].inner_array[0].five` is required', 'reference' => "outer_array[0].middle_array[0].inner_array[0].five"},
502
+ {'code' => 'generic.required_field_missing', 'message' => 'Field `outer_array[0].middle_array[0].inner_array[0].six` is required', 'reference' => "outer_array[0].middle_array[0].inner_array[0].six"},
503
+ {'code' => 'generic.required_field_missing', 'message' => 'Field `outer_array[0].middle_array[0].inner_array[0].inner_object` is required', 'reference' => "outer_array[0].middle_array[0].inner_array[0].inner_object"},
504
+ {'code' => 'generic.required_field_missing', 'message' => 'Field `outer_array[0].middle_array[0].inner_array[0].inner_object.seven` is required', 'reference' => "outer_array[0].middle_array[0].inner_array[0].inner_object.seven"},
505
+ {'code' => 'generic.required_field_missing', 'message' => 'Field `outer_array[0].middle_array[0].inner_array[1].five` is required', 'reference' => "outer_array[0].middle_array[0].inner_array[1].five"},
506
+ {'code' => 'generic.required_field_missing', 'message' => 'Field `outer_array[0].middle_array[0].inner_array[1].six` is required', 'reference' => "outer_array[0].middle_array[0].inner_array[1].six"},
507
+ {'code' => 'generic.required_field_missing', 'message' => 'Field `outer_array[0].middle_array[0].inner_array[1].inner_object` is required', 'reference' => "outer_array[0].middle_array[0].inner_array[1].inner_object"},
508
+ {'code' => 'generic.required_field_missing', 'message' => 'Field `outer_array[0].middle_array[0].inner_array[1].inner_object.seven` is required', 'reference' => "outer_array[0].middle_array[0].inner_array[1].inner_object.seven"}
509
+ ])
510
+
511
+ data = {
512
+ :outer_array => [
513
+ {
514
+ :one => 'here',
515
+ :two => 'here',
516
+ :middle_array => [
517
+ {
518
+ :three => 'here',
519
+ :four => 'here',
520
+ :inner_array => [
521
+ {
522
+ :five => 'here',
523
+ :six => 'here',
524
+ :inner_object => {
525
+ :seven => 'here'
526
+ }
527
+ }
528
+ ]
529
+ }
530
+ ]
531
+ }
532
+ ]
533
+ }
534
+ data = Hoodoo::Utilities.stringify(data)
535
+ expect(NastyNesting.validate(data, false).errors).to eq([])
536
+ end
537
+
538
+ it 'should validate resource fields for language correctly' do
539
+ expect(Internationalised.validate({}, true).errors.count).to eq(4)
540
+ expect(NotInternationalised.validate({}, true).errors.count).to eq(3)
541
+
542
+ # Check schema redefinition for the required language field is working
543
+ # OK by repeating the above two expectations.
544
+ #
545
+ expect(Internationalised.validate({}, true).errors.count).to eq(4)
546
+ expect(NotInternationalised.validate({}, true).errors.count).to eq(3)
547
+ end
548
+
549
+ it 'should validate an internationalised hash (1)' do
550
+ result = HashGainsInternationalisation.validate({}, true)
551
+ expect(result.errors.count).to eq(4) # I.e. missing ID, created_at, kind *and language*.
552
+ end
553
+
554
+ it 'should validate an internationalised hash (2)' do
555
+ result = HashGainsInternationalisation2.validate({}, true)
556
+ expect(result.errors.count).to eq(4) # I.e. missing ID, created_at, kind *and language*.
557
+ end
558
+
559
+ it 'should validate contents correctly (1)' do
560
+ data = { 'inter' => { 'a' => { 'hello' => 'hellotext' }, 'b' => { 'hello' => 'morehellotext' } } }
561
+ result = HashGainsInternationalisation.validate( data, false ) # false => Type fields only, ignore common fields
562
+ expect(result.errors.count).to eq(0)
563
+ end
564
+
565
+ it 'should validate contents correctly (2)' do
566
+ data = { 'inter' => { 'one' => { 'foo' => 'bar' }, 'two' => { 'hello' => 'twohellotext' } } }
567
+ result = HashGainsInternationalisation2.validate( data, false ) # true => Type fields only, ignore common fields
568
+ expect(result.errors.count).to eq(0)
569
+ end
570
+ end
571
+
572
+ describe '#render' do
573
+ it 'should ignore non-schema fields' do
574
+ data = {
575
+ 'one' => 1,
576
+ 'three' => 'hello',
577
+ 'ignore' => 'me'
578
+ }
579
+
580
+ expect(TestPresenter.render(data)).to eq({
581
+ 'one'=>1,
582
+ 'three'=>'hello'
583
+ })
584
+ end
585
+
586
+ it 'should omit fields when not supplied, without defaults' do
587
+ data = {
588
+ 'one' => 1,
589
+ 'three' => 'hello'
590
+ }
591
+
592
+ expect(TestPresenter.render(data)).to eq({
593
+ 'one'=>1,
594
+ 'three'=>'hello'
595
+ })
596
+ end
597
+
598
+ it 'should include default values where available for fields when not supplied' do
599
+ data = {
600
+ 'one' => 1,
601
+ 'two' => 'hello',
602
+ }
603
+
604
+ expect(TestPresenter.render(data)).to eq({
605
+ 'one'=>1,
606
+ 'two'=>'hello',
607
+ 'three'=>'default_three',
608
+ })
609
+ end
610
+
611
+ it 'should include fields with explicit nil values and not override with defaults' do
612
+ data = {
613
+ 'one' => 1,
614
+ 'two' => nil,
615
+ 'three' => nil
616
+ }
617
+
618
+ expect(TestPresenter.render(data)).to eq({
619
+ 'one'=>1,
620
+ 'two'=>nil,
621
+ 'three'=>nil
622
+ })
623
+ end
624
+
625
+ it 'should render correctly as a type without a UUID' do
626
+ data = Hoodoo::Utilities.stringify({
627
+ :errors_id => Hoodoo::UUID.generate,
628
+ :test_tags => 'foo,bar,baz',
629
+ :test_object => {
630
+ :nested_object => {
631
+ :name => 'Some name',
632
+ :obj_suffix => '!'
633
+ },
634
+ :test_array => [
635
+ { :name => 'Some name 0', :ary_suffix => '00' },
636
+ { :name => 'Some name 1' }
637
+ ]
638
+ }
639
+ })
640
+
641
+ expect(Hoodoo::Data::Resources::World.render(data)).to eq({
642
+ 'errors_id' => data['errors_id'],
643
+ 'test_tags' => 'foo,bar,baz',
644
+ 'test_object' => {
645
+ 'nested_object' => {
646
+ 'name' => 'Some name',
647
+ 'obj_suffix' => '!'
648
+ },
649
+ 'test_array' => [
650
+ { 'name' => 'Some name 0', 'ary_suffix' => '00' },
651
+ { 'name' => 'Some name 1' }
652
+ ]
653
+ }
654
+ })
655
+ end
656
+
657
+ it 'should render correctly as a resource with a UUID' do
658
+ data = Hoodoo::Utilities.stringify({
659
+ :errors_id => Hoodoo::UUID.generate,
660
+ :test_tags => 'foo,bar,baz',
661
+ :test_object => {
662
+ :nested_object => {
663
+ :name => 'Some name',
664
+ :obj_suffix => '!'
665
+ },
666
+ :test_array => [
667
+ { :name => 'Some name 0', :ary_suffix => '00' },
668
+ { :name => 'Some name 1' }
669
+ ]
670
+ }
671
+ })
672
+
673
+ uuid = Hoodoo::UUID.generate
674
+ time = Time.now
675
+
676
+ expect(Hoodoo::Data::Resources::World.render(
677
+ data,
678
+ uuid,
679
+ time,
680
+ 'en-gb'
681
+ )).to eq({
682
+ 'id' => uuid,
683
+ 'kind' => 'World',
684
+ 'created_at' => time.utc.iso8601,
685
+ 'language' => 'en-gb',
686
+ 'errors_id' => data['errors_id'],
687
+ 'test_tags' => 'foo,bar,baz',
688
+ 'test_object' => {
689
+ 'nested_object' => {
690
+ 'name' => 'Some name',
691
+ 'obj_suffix' => '!'
692
+ },
693
+ 'test_array' => [
694
+ { 'name' => 'Some name 0', 'ary_suffix' => '00' },
695
+ { 'name' => 'Some name 1' }
696
+ ]
697
+ }
698
+ })
699
+ end
700
+
701
+ it 'should complain about resources with no creation date' do
702
+ data = {
703
+ :errors_id => Hoodoo::UUID.generate,
704
+ :test_tags => 'foo,bar,baz',
705
+ :test_object => {
706
+ :nested_object => {
707
+ :name => 'Some name',
708
+ :obj_suffix => '!'
709
+ },
710
+ :test_array => [
711
+ { :name => 'Some name 0', :ary_suffix => '00' },
712
+ { :name => 'Some name 1' }
713
+ ]
714
+ }
715
+ }
716
+
717
+ data = Hoodoo::Utilities.stringify(data)
718
+ uuid = Hoodoo::UUID.generate
719
+
720
+ expect {
721
+ Hoodoo::Data::Resources::World.render(
722
+ data,
723
+ uuid,
724
+ nil,
725
+ 'en-gb'
726
+ )
727
+ }.to raise_error(RuntimeError, "Can't render a Resource with a nil 'created_at'")
728
+ end
729
+
730
+ it 'should render hash contents correctly (1)' do
731
+ data = { 'inter' => { 'a' => { 'hello' => 'hellotext' }, 'b' => { 'hello' => 'morehellotext' } } }
732
+ result = HashGainsInternationalisation.render( data )
733
+ expect(result).to eq(data)
734
+ end
735
+
736
+ it 'should render hash contents correctly (2)' do
737
+ data = { 'inter' => { 'one' => { 'foo' => 'bar' }, 'two' => { 'hello' => 'twohellotext' } } }
738
+ result = HashGainsInternationalisation2.render( data )
739
+ expect(result).to eq(data)
740
+ end
741
+
742
+ it 'should render hash contents correctly (3)' do
743
+ data = { 'inter' => { 'one' => { 'foo' => 'bar' }, 'two' => { 'hello' => 'twohellotext' } } }
744
+ result = HashGainsInternationalisation.render( data ) # Note not the '2' variant of the class
745
+ expect(result).to eq({ 'inter' => { 'one' => {}, 'two' => { 'hello' => 'twohellotext' } } })
746
+ end
747
+ end
748
+
749
+ # Note that #render_in is tested in secure_spec.rb since a lot of the
750
+ # other complex setup therein would otherwise need copying here.
751
+
752
+ describe '#render_in' do
753
+ class RSpecTestContextForRenderInBasicImplementation < Hoodoo::Services::Implementation
754
+ end
755
+
756
+ class RSpecTestContextForRenderInBasicInterface < Hoodoo::Services::Interface
757
+ interface :RSpecTestResource do
758
+ endpoint :rspec_test_service_stub, RSpecTestContextForRenderInBasicImplementation
759
+ end
760
+ end
761
+
762
+ class RSpecTestContextForRenderInBasic < Hoodoo::Services::Service
763
+ comprised_of RSpecTestContextForRenderInBasicInterface
764
+ end
765
+
766
+ class TestPresenter5 < Hoodoo::Presenters::Base
767
+ schema do
768
+ string :three, :length => 15, :required => false, :default => 'default_three'
769
+ internationalised
770
+ end
771
+ end
772
+
773
+ before :each do
774
+ ses = Hoodoo::Services::Session.new
775
+ req = Hoodoo::Services::Request.new
776
+ res = Hoodoo::Services::Response.new( Hoodoo::UUID.generate() )
777
+ mid = Hoodoo::Services::Middleware.new( RSpecTestContextForRenderInBasic.new )
778
+ int = Hoodoo::Services::Middleware::Interaction.new( {}, mid )
779
+
780
+ req.locale = 'de'
781
+
782
+ @con = Hoodoo::Services::Context.new( ses, req, res, int )
783
+ end
784
+
785
+ it 'renders without options' do
786
+ data = {}
787
+ expect(TestPresenter5.render_in(@con, data)).to eq({
788
+ 'three' => 'default_three'
789
+ })
790
+ end
791
+
792
+ it 'renders with minimal options' do
793
+ data = {}
794
+ t = Time.now.utc
795
+ u = Hoodoo::UUID.generate
796
+ options = { :uuid => u, :created_at => t }
797
+ expect(TestPresenter5.render_in(@con, data, options)).to eq({
798
+ 'id' => u,
799
+ 'kind' => 'TestPresenter5',
800
+ 'created_at' => t.iso8601,
801
+ 'language' => 'de',
802
+ 'three' => 'default_three'
803
+ })
804
+ end
805
+
806
+ it 'overrides language' do
807
+ data = {}
808
+ t = Time.now.utc
809
+ u = Hoodoo::UUID.generate
810
+ options = { :uuid => u, :created_at => t, :language => 'fr' }
811
+ expect(TestPresenter5.render_in(@con, data, options)).to eq({
812
+ 'id' => u,
813
+ 'kind' => 'TestPresenter5',
814
+ 'created_at' => t.iso8601,
815
+ 'language' => 'fr',
816
+ 'three' => 'default_three'
817
+ })
818
+ end
819
+
820
+ it 'embeds things' do
821
+ data = {}
822
+ t = Time.now.utc
823
+ u = Hoodoo::UUID.generate
824
+ e = Hoodoo::Presenters::Embedding::Embeds.new
825
+ voucher = {'description' => 'foo'}
826
+ balances = [ {'NZD' => '23', 'X-FBPTS' => '1'} ]
827
+ e.add_one( 'voucher', voucher )
828
+ e.add_many( 'balances', balances )
829
+ options = { :uuid => u, :created_at => t, :embeds => e }
830
+ expect(TestPresenter5.render_in(@con, data, options)).to eq({
831
+ 'id' => u,
832
+ 'kind' => 'TestPresenter5',
833
+ 'created_at' => t.iso8601,
834
+ 'language' => 'de',
835
+ 'three' => 'default_three',
836
+ '_embed' => {
837
+ 'voucher' => voucher,
838
+ 'balances' => balances
839
+ }
840
+ })
841
+ end
842
+
843
+ it 'references things' do
844
+ data = {}
845
+ t = Time.now.utc
846
+ u = Hoodoo::UUID.generate
847
+ r = Hoodoo::Presenters::Embedding::References.new
848
+ voucher = Hoodoo::UUID.generate
849
+ balances = [ Hoodoo::UUID.generate, Hoodoo::UUID.generate ]
850
+ r.add_one( 'voucher', voucher )
851
+ r.add_many( 'balances', balances )
852
+ options = { :uuid => u, :created_at => t, :references => r }
853
+ expect(TestPresenter5.render_in(@con, data, options)).to eq({
854
+ 'id' => u,
855
+ 'kind' => 'TestPresenter5',
856
+ 'created_at' => t.iso8601,
857
+ 'language' => 'de',
858
+ 'three' => 'default_three',
859
+ '_reference' => {
860
+ 'voucher' => voucher,
861
+ 'balances' => balances
862
+ }
863
+ })
864
+ end
865
+
866
+ # The "secured_with" option is tested in "secure_spec.rb" as lots of
867
+ # tricky related setup is done there that would only end up being
868
+ # coped in here otherwise.
869
+
870
+ end
871
+ end