hoodoo 1.0.2

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 (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