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,537 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hoodoo::Utilities do
4
+
5
+ describe '#symbolize' do
6
+ it 'should symbolize keys on a nested hash' do
7
+ data = {
8
+ 'one' => 1,
9
+ 'two' => {
10
+ 'three' => :three,
11
+ 'four' => {
12
+ :five => 'five',
13
+ 'six' => '6'
14
+ }
15
+ }
16
+ }
17
+
18
+ data[0] = 'zero'
19
+
20
+ expect(Hoodoo::Utilities.symbolize(data)).to eq({
21
+ :'0' => 'zero',
22
+ :one => 1,
23
+ :two => {
24
+ :three => :three,
25
+ :four => {
26
+ :five => 'five',
27
+ :six => '6'
28
+ }
29
+ }
30
+ })
31
+ end
32
+
33
+ it 'should handle outer arrays' do
34
+ data = [
35
+ {
36
+ 'one' => 1,
37
+ 'two' => {
38
+ 'three' => :three,
39
+ 'four' => {
40
+ :five => 'five',
41
+ 'six' => '6'
42
+ }
43
+ }
44
+ },
45
+ {
46
+ 'one' => 5,
47
+ 'two' => {
48
+ 'three' => :three,
49
+ 'four' => {
50
+ :five => 'five',
51
+ 'six' => '6'
52
+ }
53
+ }
54
+ }
55
+ ]
56
+
57
+ expect(Hoodoo::Utilities.symbolize(data)).to eq([
58
+ {
59
+ :one => 1,
60
+ :two => {
61
+ :three => :three,
62
+ :four => {
63
+ :five => 'five',
64
+ :six => '6'
65
+ }
66
+ }
67
+ },
68
+ {
69
+ :one => 5,
70
+ :two => {
71
+ :three => :three,
72
+ :four => {
73
+ :five => 'five',
74
+ :six => '6'
75
+ }
76
+ }
77
+ }
78
+ ])
79
+ end
80
+
81
+ it 'should handle inner arrays' do
82
+
83
+ data = {
84
+ 'one' => 1,
85
+ 'two' => [
86
+ {
87
+ 'three' => :three,
88
+ 'four' => {
89
+ :five => 'five',
90
+ 'six' => '6'
91
+ }
92
+ },
93
+ {
94
+ 'three' => :nine,
95
+ 'four' => {
96
+ :five => 'five',
97
+ 'six' => '6'
98
+ }
99
+ },
100
+ ]
101
+ }
102
+
103
+ expect(Hoodoo::Utilities.symbolize(data)).to eq({
104
+ :one => 1,
105
+ :two => [
106
+ {
107
+ :three => :three,
108
+ :four => {
109
+ :five => 'five',
110
+ :six => '6'
111
+ }
112
+ },
113
+ {
114
+ :three => :nine,
115
+ :four => {
116
+ :five => 'five',
117
+ :six => '6'
118
+ }
119
+ }
120
+ ]
121
+ })
122
+ end
123
+ end
124
+
125
+ describe '#stringify' do
126
+ it 'should stringify keys on a nested hash' do
127
+ data = {
128
+ :one => 1,
129
+ :two => {
130
+ :three => :three,
131
+ :four => {
132
+ 'five' => 'five',
133
+ :six => '6'
134
+ }
135
+ }
136
+ }
137
+
138
+ data[0] = 'zero'
139
+
140
+ expect(Hoodoo::Utilities.stringify(data)).to eq({
141
+ '0' => 'zero',
142
+ 'one' => 1,
143
+ 'two' => {
144
+ 'three' => :three,
145
+ 'four' => {
146
+ 'five' => 'five',
147
+ 'six' => '6'
148
+ }
149
+ }
150
+ })
151
+ end
152
+
153
+ it 'should handle outer arrays' do
154
+ data = [
155
+ {
156
+ :one => 1,
157
+ :two => {
158
+ :three => :three,
159
+ :four => {
160
+ 'five' => 'five',
161
+ :six => '6'
162
+ }
163
+ }
164
+ },
165
+ {
166
+ :one => 5,
167
+ :two => {
168
+ :three => :three,
169
+ :four => {
170
+ 'five' => 'five',
171
+ :six => '6'
172
+ }
173
+ }
174
+ }
175
+ ]
176
+
177
+ expect(Hoodoo::Utilities.stringify(data)).to eq([
178
+ {
179
+ 'one' => 1,
180
+ 'two' => {
181
+ 'three' => :three,
182
+ 'four' => {
183
+ 'five' => 'five',
184
+ 'six' => '6'
185
+ }
186
+ }
187
+ },
188
+ {
189
+ 'one' => 5,
190
+ 'two' => {
191
+ 'three' => :three,
192
+ 'four' => {
193
+ 'five' => 'five',
194
+ 'six' => '6'
195
+ }
196
+ }
197
+ }
198
+ ])
199
+ end
200
+
201
+ it 'should handle inner arrays' do
202
+
203
+ data = {
204
+ 'one' => 1,
205
+ 'two' => [
206
+ {
207
+ :three => :three,
208
+ :four => {
209
+ :five => 'five',
210
+ 'six' => '6'
211
+ }
212
+ },
213
+ {
214
+ :three => :nine,
215
+ :four => {
216
+ :five => 'five',
217
+ 'six' => '6'
218
+ }
219
+ },
220
+ ]
221
+ }
222
+
223
+ expect(Hoodoo::Utilities.stringify(data)).to eq({
224
+ 'one' => 1,
225
+ 'two' => [
226
+ {
227
+ 'three' => :three,
228
+ 'four' => {
229
+ 'five' => 'five',
230
+ 'six' => '6'
231
+ }
232
+ },
233
+ {
234
+ 'three' => :nine,
235
+ 'four' => {
236
+ 'five' => 'five',
237
+ 'six' => '6'
238
+ }
239
+ }
240
+ ]
241
+ })
242
+ end
243
+ end
244
+
245
+ describe '#deep_dup' do
246
+ it 'survives non-duplicable duplication attempts' do
247
+ fixnum = 2
248
+ expect( Hoodoo::Utilities.deep_dup( fixnum ).object_id ).to eq( fixnum.object_id )
249
+ end
250
+
251
+ it 'duplicates simple things' do
252
+ str = 'hello world'
253
+ expect( Hoodoo::Utilities.deep_dup( str ) ).to eq( str )
254
+ expect( Hoodoo::Utilities.deep_dup( str ).object_id ).to_not eq( str.object_id )
255
+ end
256
+
257
+ it 'duplicates arrays' do
258
+ h = { :foo => :bar }
259
+ a = [ 1, 2, h ]
260
+
261
+ # Make sure Ruby works :-P - changing 'h' should change the array's
262
+ # apparent contents, since the array entry is by-reference to 'h'.
263
+
264
+ expect( a ).to eq( [ 1, 2, { :foo => :bar } ] )
265
+ h[ :foo ] = :baz
266
+ expect( a ).to eq( [ 1, 2, { :foo => :baz } ] )
267
+
268
+ expect( Hoodoo::Utilities.deep_dup( a ) ).to eq( a )
269
+ expect( Hoodoo::Utilities.deep_dup( a ).object_id ).to_not eq( a.object_id )
270
+ expect( Hoodoo::Utilities.deep_dup( a )[ 2 ].object_id ).to_not eq( h.object_id )
271
+
272
+ # Changing 'h' should not change the duplicated array's apparent
273
+ # contents, because the array values were duplicated if #deep_dup is
274
+ # working.
275
+
276
+ dup = Hoodoo::Utilities.deep_dup( a )
277
+ expect( dup ).to eq( [ 1, 2, { :foo => :baz } ] )
278
+ h[ :foo ] = :boo
279
+ expect( dup ).to eq( [ 1, 2, { :foo => :baz } ] ) # I.e. unchanged
280
+ end
281
+
282
+ it 'duplicates hashes' do
283
+ h1 = { :foo => 1 }
284
+ h2 = { :bar => { :baz => h1 } }
285
+
286
+ # As with arrays, make sure Ruby works as expected
287
+
288
+ expect( h2 ).to eq( { :bar => { :baz => { :foo => 1 } } } )
289
+ h1[ :foo ] = 2
290
+ expect( h2 ).to eq( { :bar => { :baz => { :foo => 2 } } } )
291
+
292
+ expect( Hoodoo::Utilities.deep_dup( h2 ) ).to eq( h2 )
293
+ expect( Hoodoo::Utilities.deep_dup( h2 ).object_id ).to_not eq( h2.object_id )
294
+ expect( Hoodoo::Utilities.deep_dup( h2 )[ :bar ][ :baz ].object_id ).to_not eq( h1.object_id )
295
+
296
+ dup = Hoodoo::Utilities.deep_dup( h2 )
297
+ expect( dup ).to eq( { :bar => { :baz => { :foo => 2 } } } )
298
+ h1[ :foo ] = 3
299
+ expect( dup ).to eq( { :bar => { :baz => { :foo => 2 } } } ) # I.e. unchanged
300
+ end
301
+ end
302
+
303
+ describe '#deep_merge_into' do
304
+ it 'merges hashes' do
305
+ target_hash = { :one => { :two => { :three => 3 } } }
306
+ inbound_hash = { :one => { :two => { :and_four => 4 } } }
307
+ result_hash = Hoodoo::Utilities.deep_merge_into( target_hash, inbound_hash )
308
+
309
+ expect( result_hash ).to eq( {
310
+ :one => { :two => { :three => 3, :and_four => 4 } }
311
+ } )
312
+ end
313
+
314
+ it 'overwrites non-Hash values at any level' do
315
+ target_hash = { :foo => :bar, :one => { :two => { :three => 3, :five => 5 } } }
316
+ inbound_hash = { :foo => 'baz', :one => { :two => { :and_four => 4, :five => 'five' } } }
317
+ result_hash = Hoodoo::Utilities.deep_merge_into( target_hash, inbound_hash )
318
+
319
+ expect( result_hash ).to eq( {
320
+ :foo => 'baz', :one => { :two => { :three => 3, :and_four => 4, :five => 'five' } }
321
+ } )
322
+ end
323
+ end
324
+
325
+ describe '#hash_diff' do
326
+ it 'works with the RDoc example code in both directions' do
327
+ hash1 = { :foo => { :bar => 2 }, :baz => true, :boo => false }
328
+ hash2 = { :foo => { :bar => 3 }, :boo => false }
329
+
330
+ diff = Hoodoo::Utilities.hash_diff( hash1, hash2 )
331
+ expect( diff ).to eq( { :foo => { :bar => [ 2, 3 ] }, :baz => [ true, nil ] } )
332
+
333
+ diff = Hoodoo::Utilities.hash_diff( hash2, hash1 )
334
+ expect( diff ).to eq( { :foo => { :bar => [ 3, 2 ] }, :baz => [ nil, true ] } )
335
+ end
336
+
337
+ it 'works when both hashes are totally mismatched' do
338
+ hash1 = { :foo => 1 }
339
+ hash2 = { :bar => 2 }
340
+
341
+ diff = Hoodoo::Utilities.hash_diff( hash1, hash2 )
342
+ expect( diff ).to eq( { :foo => [ 1, nil ], :bar => [ nil, 2 ] } )
343
+ end
344
+
345
+ it 'works for deep paths' do
346
+ hash1 = { :foo => { :bar => { :baz => [ 1, 2, 3 ] } } }
347
+ hash2 = {}
348
+
349
+ diff = Hoodoo::Utilities.hash_diff( hash1, hash2 )
350
+ expect( diff ).to eq( { :foo => [ { :bar => { :baz => [ 1, 2, 3 ] } }, nil ] } )
351
+ end
352
+
353
+ it 'works for identical hashes' do
354
+ hash1 = { :foo => { :bar => 2 }, :baz => true, :boo => false }
355
+
356
+ diff = Hoodoo::Utilities.hash_diff( hash1, hash1 )
357
+ expect( diff ).to eq( {} )
358
+ end
359
+ end
360
+
361
+ describe '#hash_key_paths' do
362
+ it 'works for empty hashes' do
363
+ hash = {}
364
+ expect( Hoodoo::Utilities.hash_key_paths( hash ) ).to eq( [] )
365
+ end
366
+
367
+ it 'works for flat hashes' do
368
+ hash = { :one => 1, :two => 2, :three => 3 }
369
+ expect( Hoodoo::Utilities.hash_key_paths( hash ) ).to eq( [ 'one', 'two', 'three' ] )
370
+ end
371
+
372
+ it 'works with the RDoc example code' do
373
+ hash = { :foo => 1, :bar => { :baz => 2, :boo => { :hello => :world } } }
374
+ expect( Hoodoo::Utilities.hash_key_paths( hash ) ).to eq( [ 'foo', 'bar.baz', 'bar.boo.hello' ] )
375
+ end
376
+ end
377
+
378
+ describe '#collated_hash_from' do
379
+ it 'works for empty Arrays' do
380
+ array = []
381
+ expect( Hoodoo::Utilities.collated_hash_from( array ) ).to eq( {} )
382
+ end
383
+
384
+ it 'works for simple Arrays' do
385
+ array = [ [ 'search', 'foo=bar' ], [ 'search', 'bar=baz' ] ]
386
+ expect( Hoodoo::Utilities.collated_hash_from( array ) ).to eq( { 'search' => [ 'foo=bar', 'bar=baz' ] } )
387
+ end
388
+
389
+ it 'works for more complex Arrays' do
390
+ array = [ [ :one, 1 ], [ :two, 2 ], [ :one, 42 ], [ :two , 2 ] ]
391
+ expect( Hoodoo::Utilities.collated_hash_from( array ) ).to eq( { :one => [ 1, 42 ], :two => [ 2 ] } )
392
+ end
393
+
394
+ it 'allows duplicates if so asked' do
395
+ array = [ [ :one, 1 ], [ :two, 2 ], [ :one, 42 ], [ :two , 2 ] ]
396
+ expect( Hoodoo::Utilities.collated_hash_from( array, true ) ).to eq( { :one => [ 1, 42 ], :two => [ 2, 2 ] } )
397
+ end
398
+ end
399
+
400
+ describe '#spare_port' do
401
+ it 'should return a port number' do
402
+
403
+ # Deeper tests happen implicitly when this call is used
404
+ # to find real spare ports for running web server instances.
405
+ # If it didn't work, those tests would fail (intermittently
406
+ # or always).
407
+ #
408
+ expect( Hoodoo::Utilities.spare_port ).to be_a( Integer )
409
+ end
410
+ end
411
+
412
+ describe '#to_integer?' do
413
+ it 'should return integer equivalents for valid values' do
414
+ expect( Hoodoo::Utilities.to_integer?( 21 ) ).to eq( 21 )
415
+ expect( Hoodoo::Utilities.to_integer?( '21' ) ).to eq( 21 )
416
+ expect( Hoodoo::Utilities.to_integer?( :'21' ) ).to eq( 21 )
417
+ end
418
+
419
+ it 'should return nil for invalid values' do
420
+ expect( Hoodoo::Utilities.to_integer?( 2.1 ) ).to eq( nil )
421
+ expect( Hoodoo::Utilities.to_integer?( 'hello' ) ).to eq( nil )
422
+ expect( Hoodoo::Utilities.to_integer?( Time.now ) ).to eq( nil )
423
+ end
424
+ end
425
+
426
+ # Much of this is similar at the time of writing to the code in
427
+ # types/date_time_spec.rb, but kept here as independent tests in
428
+ # case the DateTime type code stops calling the Utility validation
429
+ # code in future for any reason.
430
+ #
431
+ describe '#valid_iso8601_subset_datetime?' do
432
+ it 'accepts valid' do
433
+ expect( Hoodoo::Utilities.valid_iso8601_subset_datetime?( '2014-12-11T00:00:00Z' ) ).to be_a( DateTime )
434
+ expect( Hoodoo::Utilities.valid_iso8601_subset_datetime?( '2012-02-29T00:00:00Z' ) ).to be_a( DateTime )
435
+ expect( Hoodoo::Utilities.valid_iso8601_subset_datetime?( '2012-02-29T00:00:00.0Z' ) ).to be_a( DateTime )
436
+ expect( Hoodoo::Utilities.valid_iso8601_subset_datetime?( '2012-02-29T00:00:00.0000Z' ) ).to be_a( DateTime )
437
+ expect( Hoodoo::Utilities.valid_iso8601_subset_datetime?( '2012-02-29T00:00:00.000000000Z' ) ).to be_a( DateTime )
438
+ expect( Hoodoo::Utilities.valid_iso8601_subset_datetime?( '2012-02-29T00:00:00+12:30' ) ).to be_a( DateTime )
439
+ expect( Hoodoo::Utilities.valid_iso8601_subset_datetime?( '2012-02-29T00:00:00-12:30' ) ).to be_a( DateTime )
440
+ expect( Hoodoo::Utilities.valid_iso8601_subset_datetime?( '2012-02-29T00:00:00.0+12:30' ) ).to be_a( DateTime )
441
+ expect( Hoodoo::Utilities.valid_iso8601_subset_datetime?( '2012-02-29T00:00:00.0-12:30' ) ).to be_a( DateTime )
442
+ end
443
+
444
+ it 'rejects invalid' do
445
+ expect( Hoodoo::Utilities.valid_iso8601_subset_datetime?( '2014-12-11T12:12:61Z' ) ).to eq( false )
446
+ expect( Hoodoo::Utilities.valid_iso8601_subset_datetime?( '2014-12-11T12:60:00Z' ) ).to eq( false )
447
+ expect( Hoodoo::Utilities.valid_iso8601_subset_datetime?( '2014-12-11T25:00:00Z' ) ).to eq( false )
448
+ expect( Hoodoo::Utilities.valid_iso8601_subset_datetime?( '2014-02-29T00:00:00Z' ) ).to eq( false )
449
+ expect( Hoodoo::Utilities.valid_iso8601_subset_datetime?( '2014-13-01T00:00:00Z' ) ).to eq( false )
450
+ expect( Hoodoo::Utilities.valid_iso8601_subset_datetime?( '2014-99-99T00:00:00Z' ) ).to eq( false )
451
+ expect( Hoodoo::Utilities.valid_iso8601_subset_datetime?( 'asckn' ) ).to eq( false )
452
+ expect( Hoodoo::Utilities.valid_iso8601_subset_datetime?( '2014-12-11' ) ).to eq( false )
453
+ expect( Hoodoo::Utilities.valid_iso8601_subset_datetime?( 34534.234 ) ).to eq( false )
454
+ expect( Hoodoo::Utilities.valid_iso8601_subset_datetime?( 38247 ) ).to eq( false )
455
+ expect( Hoodoo::Utilities.valid_iso8601_subset_datetime?( true ) ).to eq( false )
456
+ expect( Hoodoo::Utilities.valid_iso8601_subset_datetime?( {} ) ).to eq( false )
457
+ expect( Hoodoo::Utilities.valid_iso8601_subset_datetime?( [] ) ).to eq( false )
458
+ end
459
+ end
460
+
461
+ # Much of this is similar at the time of writing to the code in
462
+ # types/date_spec.rb, but kept here as independent tests in case
463
+ # the Date type code stops calling the Utility validation code
464
+ # in future for any reason.
465
+ #
466
+ describe '#valid_iso8601_subset_date?' do
467
+ it 'accepts valid' do
468
+ expect( Hoodoo::Utilities.valid_iso8601_subset_date?( '2014-12-11' ) ).to be_a( Date )
469
+ expect( Hoodoo::Utilities.valid_iso8601_subset_date?( '2012-02-29' ) ).to be_a( Date )
470
+ end
471
+
472
+ it 'rejects invalid' do
473
+ expect( Hoodoo::Utilities.valid_iso8601_subset_date?( '2014-02-29' ) ).to eq( false )
474
+ expect( Hoodoo::Utilities.valid_iso8601_subset_date?( '2014-13-01' ) ).to eq( false )
475
+ expect( Hoodoo::Utilities.valid_iso8601_subset_date?( '2014-99-99' ) ).to eq( false )
476
+ expect( Hoodoo::Utilities.valid_iso8601_subset_date?( 'asckn' ) ).to eq( false )
477
+ expect( Hoodoo::Utilities.valid_iso8601_subset_date?( '2014-12-11T00:00:00Z' ) ).to eq( false )
478
+ expect( Hoodoo::Utilities.valid_iso8601_subset_date?( 34534.234 ) ).to eq( false )
479
+ expect( Hoodoo::Utilities.valid_iso8601_subset_date?( 38247 ) ).to eq( false )
480
+ expect( Hoodoo::Utilities.valid_iso8601_subset_date?( true ) ).to eq( false )
481
+ expect( Hoodoo::Utilities.valid_iso8601_subset_date?( {} ) ).to eq( false )
482
+ expect( Hoodoo::Utilities.valid_iso8601_subset_date?( [] ) ).to eq( false )
483
+ end
484
+ end
485
+
486
+ describe '#nanosecond_iso8601' do
487
+ it 'should convert DateTime to a nanosecond precision String' do
488
+ now = DateTime.now()
489
+ iso = now.iso8601( 9 )
490
+
491
+ expect( Hoodoo::Utilities.nanosecond_iso8601( now ) ).to eq( iso )
492
+ end
493
+
494
+ it 'should convert Time to a nanosecond precision String' do
495
+ now = Time.now()
496
+ iso = now.iso8601( 9 )
497
+
498
+ expect( Hoodoo::Utilities.nanosecond_iso8601( now ) ).to eq( iso )
499
+ end
500
+ end
501
+
502
+ describe '#rationalise_datetime' do
503
+ it 'accepts and returns nil' do
504
+ expect( Hoodoo::Utilities.rationalise_datetime( nil ) ).to eq( nil )
505
+ end
506
+
507
+ it 'accepts and returns a DateTime' do
508
+ now = DateTime.now
509
+ expect( Hoodoo::Utilities.rationalise_datetime( now ) ).to eq( now )
510
+ end
511
+
512
+ it 'accepts a Time and returns a DateTime' do
513
+ now = Time.now
514
+ expect( Hoodoo::Utilities.rationalise_datetime( now ) ).to eq( now.to_datetime )
515
+ end
516
+
517
+ # If this fails your system might report time to beyond-nanosecond
518
+ # precision, so the str-to-DateTime result mismatches the original
519
+ # DateTime in the fractional seconds.
520
+ #
521
+ it 'accepts a parseable String and returns a DateTime' do
522
+ now = DateTime.now
523
+ str = Hoodoo::Utilities.nanosecond_iso8601( now )
524
+ expect( Hoodoo::Utilities.rationalise_datetime( str ) ).to eq( now )
525
+ end
526
+
527
+ it 'rejects invalid input with an exception' do
528
+ expect {
529
+ Hoodoo::Utilities.rationalise_datetime( "hello" )
530
+ }.to raise_exception
531
+
532
+ expect {
533
+ Hoodoo::Utilities.rationalise_datetime( Array.new )
534
+ }.to raise_exception
535
+ end
536
+ end
537
+ end