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,384 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hoodoo::ActiveRecord::Finder::SearchHelper do
4
+
5
+ # Note all tests check that when no input parameter is given, the
6
+ # returned Proc obeys the first passed argument, using it in the query.
7
+ # This is in case callers decide to re-use a Proc for other searches; it
8
+ # might happen, and they'd break unless the inbound field attribute was
9
+ # being honoured.
10
+ #
11
+ # Obviously, when passed a parameter, the model attribute name is being
12
+ # explicitly specified so this cannot be used for something else and the
13
+ # Proc's first argument is intentionally ignored.
14
+ #
15
+ # All tests also check that 'nil' values are matched in the manner
16
+ # documented by the SearchHelper RDoc information.
17
+
18
+ before :all do
19
+ spec_helper_silence_stdout() do
20
+ ActiveRecord::Migration.create_table( :r_spec_model_search_helper_tests ) do | t |
21
+ t.text :field
22
+ t.timestamps
23
+ end
24
+ end
25
+
26
+ class RSpecModelSearchHelperTest < ActiveRecord::Base
27
+ end
28
+ end
29
+
30
+ before :each do
31
+ @f1 = RSpecModelSearchHelperTest.create
32
+ @f2 = RSpecModelSearchHelperTest.create( :field => 'hello' )
33
+ @f3 = RSpecModelSearchHelperTest.create( :field => 'hello' )
34
+ @f4 = RSpecModelSearchHelperTest.create( :field => 'HELLO' )
35
+ @f5 = RSpecModelSearchHelperTest.create
36
+ @f6 = RSpecModelSearchHelperTest.create( :field => 'world' )
37
+ @f7 = RSpecModelSearchHelperTest.create( :field => 'world' )
38
+ @f8 = RSpecModelSearchHelperTest.create( :field => 'WORLD' )
39
+ end
40
+
41
+ def find( clause )
42
+ RSpecModelSearchHelperTest.where( *clause ).all
43
+ end
44
+
45
+ def find_not( clause )
46
+ RSpecModelSearchHelperTest.where.not( *clause ).all
47
+ end
48
+
49
+ #############################################################################
50
+
51
+ context '#cs_match' do
52
+ it 'generates expected no-input-parameter output' do
53
+ result = described_class.cs_match
54
+ expect( result.call( 'a', 'b' ) ).to eq( [ 'a = ? AND a IS NOT NULL', 'b' ] )
55
+ end
56
+
57
+ it 'generates expected one-input-parameter output' do
58
+ result = described_class.cs_match( :bar )
59
+ expect( result.call( 'a', 'b' ) ).to eq( [ 'bar = ? AND bar IS NOT NULL', 'b' ] )
60
+ end
61
+
62
+ it 'finds expected things' do
63
+ result = find( described_class.cs_match.call( 'field', 'hello' ) )
64
+ expect( result ).to match_array( [ @f2, @f3 ] )
65
+
66
+ result = find( described_class.cs_match.call( 'field', 'HELLO' ) )
67
+ expect( result ).to match_array( [ @f4 ] )
68
+
69
+ result = find( described_class.cs_match.call( 'field', 'hell' ) )
70
+ expect( result ).to match_array( [] )
71
+
72
+ result = find( described_class.cs_match.call( 'field', 'llo' ) )
73
+ expect( result ).to match_array( [] )
74
+
75
+ result = find( described_class.cs_match.call( 'field', 'heLLo' ) )
76
+ expect( result ).to match_array( [] )
77
+ end
78
+
79
+ it 'finds expected things negated' do
80
+ result = find_not( described_class.cs_match.call( 'field', 'hello' ) )
81
+ expect( result ).to match_array( [ @f1, @f4, @f5, @f6, @f7, @f8 ] )
82
+
83
+ result = find_not( described_class.cs_match.call( 'field', 'HELLO' ) )
84
+ expect( result ).to match_array( [ @f1, @f2, @f3, @f5, @f6, @f7, @f8 ] )
85
+
86
+ result = find_not( described_class.cs_match.call( 'field', 'hell' ) )
87
+ expect( result ).to match_array( [ @f1, @f2, @f3, @f4, @f5, @f6, @f7, @f8 ] )
88
+
89
+ result = find_not( described_class.cs_match.call( 'field', 'llo' ) )
90
+ expect( result ).to match_array( [ @f1, @f2, @f3, @f4, @f5, @f6, @f7, @f8 ] )
91
+
92
+ result = find_not( described_class.cs_match.call( 'field', 'heLLo' ) )
93
+ expect( result ).to match_array( [ @f1, @f2, @f3, @f4, @f5, @f6, @f7, @f8 ] )
94
+ end
95
+ end
96
+
97
+ #############################################################################
98
+
99
+ context '#cs_match_csv' do
100
+ it 'generates expected no-input-parameter output' do
101
+ result = described_class.cs_match_csv()
102
+ expect( result.call( 'a', 'b,c,d' ) ).to eq( [ 'a IN (?) AND a IS NOT NULL', [ 'b', 'c', 'd' ] ] )
103
+ end
104
+
105
+ it 'generates expected one-input-parameter output' do
106
+ result = described_class.cs_match_csv( :bar )
107
+ expect( result.call( 'a', 'b,c,d' ) ).to eq( [ 'bar IN (?) AND bar IS NOT NULL', [ 'b', 'c', 'd' ] ] )
108
+ end
109
+
110
+ it 'finds expected things' do
111
+ result = find( described_class.cs_match_csv.call( 'field', 'hello,world' ) )
112
+ expect( result ).to match_array( [ @f2, @f3, @f6, @f7 ] )
113
+
114
+ result = find( described_class.cs_match_csv.call( 'field', 'HELLO,WORLD' ) )
115
+ expect( result ).to match_array( [ @f4, @f8 ] )
116
+
117
+ result = find( described_class.cs_match_csv.call( 'field', 'hell,worl' ) )
118
+ expect( result ).to match_array( [] )
119
+
120
+ result = find( described_class.cs_match_csv.call( 'field', 'llo,ld' ) )
121
+ expect( result ).to match_array( [] )
122
+
123
+ result = find( described_class.cs_match_csv.call( 'field', 'heLLo,WORld' ) )
124
+ expect( result ).to match_array( [] )
125
+ end
126
+
127
+ it 'finds expected things negated' do
128
+ result = find_not( described_class.cs_match_csv.call( 'field', 'hello,world' ) )
129
+ expect( result ).to match_array( [ @f1, @f4, @f5, @f8 ] )
130
+
131
+ result = find_not( described_class.cs_match_csv.call( 'field', 'HELLO,WORLD' ) )
132
+ expect( result ).to match_array( [ @f1, @f2, @f3, @f5, @f6, @f7 ] )
133
+
134
+ result = find_not( described_class.cs_match_csv.call( 'field', 'hell,worl' ) )
135
+ expect( result ).to match_array( [ @f1, @f2, @f3, @f4, @f5, @f6, @f7, @f8 ] )
136
+
137
+ result = find_not( described_class.cs_match_csv.call( 'field', 'llo,ld' ) )
138
+ expect( result ).to match_array( [ @f1, @f2, @f3, @f4, @f5, @f6, @f7, @f8 ] )
139
+
140
+ result = find_not( described_class.cs_match_csv.call( 'field', 'heLLo,WORld' ) )
141
+ expect( result ).to match_array( [ @f1, @f2, @f3, @f4, @f5, @f6, @f7, @f8 ] )
142
+ end
143
+ end
144
+
145
+ #############################################################################
146
+
147
+ context '#cs_match_array' do
148
+ it 'generates expected no-input-parameter output' do
149
+ result = described_class.cs_match_array()
150
+ expect( result.call( 'a', [ 'b', 'c', 'd' ] ) ).to eq( [ 'a IN (?) AND a IS NOT NULL', [ 'b', 'c', 'd' ] ] )
151
+ end
152
+
153
+ it 'generates expected one-input-parameter output' do
154
+ result = described_class.cs_match_array( :bar )
155
+ expect( result.call( 'a', [ 'b', 'c', 'd' ] ) ).to eq( [ 'bar IN (?) AND bar IS NOT NULL', [ 'b', 'c', 'd' ] ] )
156
+ end
157
+
158
+ it 'finds expected things' do
159
+ result = find( described_class.cs_match_array.call( 'field', [ 'hello', 'world' ] ) )
160
+ expect( result ).to match_array( [ @f2, @f3, @f6, @f7 ] )
161
+
162
+ result = find( described_class.cs_match_array.call( 'field', [ 'HELLO', 'WORLD' ] ) )
163
+ expect( result ).to match_array( [ @f4, @f8 ] )
164
+
165
+ result = find( described_class.cs_match_array.call( 'field', [ 'hell', 'worl' ] ) )
166
+ expect( result ).to match_array( [] )
167
+
168
+ result = find( described_class.cs_match_array.call( 'field', [ 'llo', 'ld' ] ) )
169
+ expect( result ).to match_array( [] )
170
+
171
+ result = find( described_class.cs_match_array.call( 'field', [ 'heLLo', 'WORld' ] ) )
172
+ expect( result ).to match_array( [] )
173
+ end
174
+
175
+ it 'finds expected things negated' do
176
+ result = find_not( described_class.cs_match_array.call( 'field', [ 'hello', 'world' ] ) )
177
+ expect( result ).to match_array( [ @f1, @f4, @f5, @f8 ] )
178
+
179
+ result = find_not( described_class.cs_match_array.call( 'field', [ 'HELLO', 'WORLD' ] ) )
180
+ expect( result ).to match_array( [ @f1, @f2, @f3, @f5, @f6, @f7 ] )
181
+
182
+ result = find_not( described_class.cs_match_array.call( 'field', [ 'hell', 'worl' ] ) )
183
+ expect( result ).to match_array( [ @f1, @f2, @f3, @f4, @f5, @f6, @f7, @f8 ] )
184
+
185
+ result = find_not( described_class.cs_match_array.call( 'field', [ 'llo', 'ld' ] ) )
186
+ expect( result ).to match_array( [ @f1, @f2, @f3, @f4, @f5, @f6, @f7, @f8 ] )
187
+
188
+ result = find_not( described_class.cs_match_array.call( 'field', [ 'heLLo', 'WORld' ] ) )
189
+ expect( result ).to match_array( [ @f1, @f2, @f3, @f4, @f5, @f6, @f7, @f8 ] )
190
+ end
191
+ end
192
+
193
+ #############################################################################
194
+
195
+ context '#ci_match_generic' do
196
+ it 'generates expected no-input-parameter output' do
197
+ result = described_class.ci_match_generic()
198
+ expect( result.call( 'a', 'B' ) ).to eq( [ 'lower(a) = ? AND a IS NOT NULL', 'b' ] )
199
+ end
200
+
201
+ it 'generates expected one-input-parameter output' do
202
+ result = described_class.ci_match_generic( :bar )
203
+ expect( result.call( 'a', 'B' ) ).to eq( [ 'lower(bar) = ? AND bar IS NOT NULL', 'b' ] )
204
+ end
205
+
206
+ it 'finds expected things' do
207
+ result = find( described_class.ci_match_generic.call( 'field', 'hello' ) )
208
+ expect( result ).to match_array( [ @f2, @f3, @f4 ] )
209
+
210
+ result = find( described_class.ci_match_generic.call( 'field', 'HELLO' ) )
211
+ expect( result ).to match_array( [ @f2, @f3, @f4 ] )
212
+
213
+ result = find( described_class.ci_match_generic.call( 'field', 'hell' ) )
214
+ expect( result ).to match_array( [] )
215
+
216
+ result = find( described_class.ci_match_generic.call( 'field', 'llo' ) )
217
+ expect( result ).to match_array( [] )
218
+
219
+ result = find( described_class.ci_match_generic.call( 'field', 'heLLo' ) )
220
+ expect( result ).to match_array( [ @f2, @f3, @f4 ] )
221
+ end
222
+
223
+ it 'finds expected things negated' do
224
+ result = find_not( described_class.ci_match_generic.call( 'field', 'hello' ) )
225
+ expect( result ).to match_array( [ @f1, @f5, @f6, @f7, @f8 ] )
226
+
227
+ result = find_not( described_class.ci_match_generic.call( 'field', 'HELLO' ) )
228
+ expect( result ).to match_array( [ @f1, @f5, @f6, @f7, @f8 ] )
229
+
230
+ result = find_not( described_class.ci_match_generic.call( 'field', 'hell' ) )
231
+ expect( result ).to match_array( [ @f1, @f2, @f3, @f4, @f5, @f6, @f7, @f8 ] )
232
+
233
+ result = find_not( described_class.ci_match_generic.call( 'field', 'llo' ) )
234
+ expect( result ).to match_array( [ @f1, @f2, @f3, @f4, @f5, @f6, @f7, @f8 ] )
235
+
236
+ result = find_not( described_class.ci_match_generic.call( 'field', 'heLLo' ) )
237
+ expect( result ).to match_array( [ @f1, @f5, @f6, @f7, @f8 ] )
238
+ end
239
+ end
240
+
241
+ #############################################################################
242
+
243
+ context '#ciaw_match_generic' do
244
+ it 'generates expected no-input-parameter output' do
245
+ result = described_class.ciaw_match_generic()
246
+ expect( result.call( 'a', 'B' ) ).to eq( [ 'lower(a) LIKE ? AND a IS NOT NULL', '%b%' ] )
247
+ end
248
+
249
+ it 'generates expected one-input-parameter output' do
250
+ result = described_class.ciaw_match_generic( :bar )
251
+ expect( result.call( 'a', 'B' ) ).to eq( [ 'lower(bar) LIKE ? AND bar IS NOT NULL', '%b%' ] )
252
+ end
253
+
254
+ it 'finds expected things' do
255
+ result = find( described_class.ciaw_match_generic.call( 'field', 'hello' ) )
256
+ expect( result ).to match_array( [ @f2, @f3, @f4 ] )
257
+
258
+ result = find( described_class.ciaw_match_generic.call( 'field', 'HELLO' ) )
259
+ expect( result ).to match_array( [ @f2, @f3, @f4 ] )
260
+
261
+ result = find( described_class.ciaw_match_generic.call( 'field', 'hell' ) )
262
+ expect( result ).to match_array( [ @f2, @f3, @f4 ] )
263
+
264
+ result = find( described_class.ciaw_match_generic.call( 'field', 'llo' ) )
265
+ expect( result ).to match_array( [ @f2, @f3, @f4 ] )
266
+
267
+ result = find( described_class.ciaw_match_generic.call( 'field', 'heLLo' ) )
268
+ expect( result ).to match_array( [ @f2, @f3, @f4 ] )
269
+ end
270
+
271
+ it 'finds expected things negated' do
272
+ result = find_not( described_class.ciaw_match_generic.call( 'field', 'hello' ) )
273
+ expect( result ).to match_array( [ @f1, @f5, @f6, @f7, @f8 ] )
274
+
275
+ result = find_not( described_class.ciaw_match_generic.call( 'field', 'HELLO' ) )
276
+ expect( result ).to match_array( [ @f1, @f5, @f6, @f7, @f8 ] )
277
+
278
+ result = find_not( described_class.ciaw_match_generic.call( 'field', 'hell' ) )
279
+ expect( result ).to match_array( [ @f1, @f5, @f6, @f7, @f8 ] )
280
+
281
+ result = find_not( described_class.ciaw_match_generic.call( 'field', 'llo' ) )
282
+ expect( result ).to match_array( [ @f1, @f5, @f6, @f7, @f8 ] )
283
+
284
+ result = find_not( described_class.ciaw_match_generic.call( 'field', 'heLLo' ) )
285
+ expect( result ).to match_array( [ @f1, @f5, @f6, @f7, @f8 ] )
286
+ end
287
+ end
288
+
289
+ #############################################################################
290
+
291
+ context '#ci_match_postgres' do
292
+ it 'generates expected no-input-parameter output' do
293
+ result = described_class.ci_match_postgres()
294
+ expect( result.call( 'a', 'B' ) ).to eq( [ 'a ILIKE ? AND a IS NOT NULL', 'B' ] )
295
+ end
296
+
297
+ it 'generates expected one-input-parameter output' do
298
+ result = described_class.ci_match_postgres( :bar )
299
+ expect( result.call( 'a', 'B' ) ).to eq( [ 'bar ILIKE ? AND bar IS NOT NULL', 'B' ] )
300
+ end
301
+
302
+ it 'finds expected things' do
303
+ result = find( described_class.ci_match_postgres.call( 'field', 'hello' ) )
304
+ expect( result ).to match_array( [ @f2, @f3, @f4 ] )
305
+
306
+ result = find( described_class.ci_match_postgres.call( 'field', 'HELLO' ) )
307
+ expect( result ).to match_array( [ @f2, @f3, @f4 ] )
308
+
309
+ result = find( described_class.ci_match_postgres.call( 'field', 'hell' ) )
310
+ expect( result ).to match_array( [] )
311
+
312
+ result = find( described_class.ci_match_postgres.call( 'field', 'llo' ) )
313
+ expect( result ).to match_array( [] )
314
+
315
+ result = find( described_class.ci_match_postgres.call( 'field', 'heLLo' ) )
316
+ expect( result ).to match_array( [ @f2, @f3, @f4 ] )
317
+ end
318
+
319
+ it 'finds expected things negated' do
320
+ result = find_not( described_class.ci_match_postgres.call( 'field', 'hello' ) )
321
+ expect( result ).to match_array( [ @f1, @f5, @f6, @f7, @f8 ] )
322
+
323
+ result = find_not( described_class.ci_match_postgres.call( 'field', 'HELLO' ) )
324
+ expect( result ).to match_array( [ @f1, @f5, @f6, @f7, @f8 ] )
325
+
326
+ result = find_not( described_class.ci_match_postgres.call( 'field', 'hell' ) )
327
+ expect( result ).to match_array( [ @f1, @f2, @f3, @f4, @f5, @f6, @f7, @f8 ] )
328
+
329
+ result = find_not( described_class.ci_match_postgres.call( 'field', 'llo' ) )
330
+ expect( result ).to match_array( [ @f1, @f2, @f3, @f4, @f5, @f6, @f7, @f8 ] )
331
+
332
+ result = find_not( described_class.ci_match_postgres.call( 'field', 'heLLo' ) )
333
+ expect( result ).to match_array( [ @f1, @f5, @f6, @f7, @f8 ] )
334
+ end
335
+ end
336
+
337
+ #############################################################################
338
+
339
+ context '#ciaw_match_postgres' do
340
+ it 'generates expected no-input-parameter output' do
341
+ result = described_class.ciaw_match_postgres()
342
+ expect( result.call( 'a', 'B' ) ).to eq( [ 'a ILIKE ? AND a IS NOT NULL', '%B%' ] )
343
+ end
344
+
345
+ it 'generates expected one-input-parameter output' do
346
+ result = described_class.ciaw_match_postgres( :bar )
347
+ expect( result.call( 'a', 'B' ) ).to eq( [ 'bar ILIKE ? AND bar IS NOT NULL', '%B%' ] )
348
+ end
349
+
350
+ it 'finds expected things' do
351
+ result = find( described_class.ciaw_match_postgres.call( 'field', 'hello' ) )
352
+ expect( result ).to match_array( [ @f2, @f3, @f4 ] )
353
+
354
+ result = find( described_class.ciaw_match_postgres.call( 'field', 'HELLO' ) )
355
+ expect( result ).to match_array( [ @f2, @f3, @f4 ] )
356
+
357
+ result = find( described_class.ciaw_match_postgres.call( 'field', 'hell' ) )
358
+ expect( result ).to match_array( [ @f2, @f3, @f4 ] )
359
+
360
+ result = find( described_class.ciaw_match_postgres.call( 'field', 'llo' ) )
361
+ expect( result ).to match_array( [ @f2, @f3, @f4 ] )
362
+
363
+ result = find( described_class.ciaw_match_postgres.call( 'field', 'heLLo' ) )
364
+ expect( result ).to match_array( [ @f2, @f3, @f4 ] )
365
+ end
366
+
367
+ it 'finds expected things negated' do
368
+ result = find_not( described_class.ciaw_match_postgres.call( 'field', 'hello' ) )
369
+ expect( result ).to match_array( [ @f1, @f5, @f6, @f7, @f8 ] )
370
+
371
+ result = find_not( described_class.ciaw_match_postgres.call( 'field', 'HELLO' ) )
372
+ expect( result ).to match_array( [ @f1, @f5, @f6, @f7, @f8 ] )
373
+
374
+ result = find_not( described_class.ciaw_match_postgres.call( 'field', 'hell' ) )
375
+ expect( result ).to match_array( [ @f1, @f5, @f6, @f7, @f8 ] )
376
+
377
+ result = find_not( described_class.ciaw_match_postgres.call( 'field', 'llo' ) )
378
+ expect( result ).to match_array( [ @f1, @f5, @f6, @f7, @f8 ] )
379
+
380
+ result = find_not( described_class.ciaw_match_postgres.call( 'field', 'heLLo' ) )
381
+ expect( result ).to match_array( [ @f1, @f5, @f6, @f7, @f8 ] )
382
+ end
383
+ end
384
+ end
@@ -0,0 +1,435 @@
1
+ require 'spec_helper'
2
+ require 'active_record'
3
+
4
+ describe Hoodoo::ActiveRecord::Secure do
5
+ before :all do
6
+
7
+ spec_helper_silence_stdout() do
8
+
9
+ migration = Proc.new do | t |
10
+ t.text :creator
11
+ t.text :distributor
12
+ t.text :field
13
+
14
+ t.timestamps
15
+ end
16
+
17
+ ActiveRecord::Migration.create_table( :r_spec_model_secure_test_as, &migration )
18
+ ActiveRecord::Migration.create_table( :r_spec_model_secure_test_bs, &migration )
19
+ ActiveRecord::Migration.create_table( :r_spec_model_secure_test_cs, &migration )
20
+
21
+ class RSpecModelSecureTestA < ActiveRecord::Base
22
+ include Hoodoo::ActiveRecord::Secure
23
+
24
+ secure_with(
25
+ :creator => 'authorised_creators', # Array
26
+ 'distributor' => :authorised_distributor # Single item
27
+ )
28
+ end
29
+
30
+ class RSpecModelSecureTestB < ActiveRecord::Base
31
+ include Hoodoo::ActiveRecord::Secure
32
+
33
+ secure_with(
34
+ :creator => { :session_field_name => 'authorised_creators' },
35
+ 'distributor' => { :session_field_name => :authorised_distributor } # Single item
36
+ )
37
+ end
38
+
39
+ class RSpecModelSecureTestC < ActiveRecord::Base
40
+ include Hoodoo::ActiveRecord::Secure
41
+
42
+ # Custom Proc matching "or", straight out of the #secure RDoc
43
+ # but with our required column name of "distributor" inserted.
44
+ #
45
+ or_matcher = Proc.new do | model_class, database_column_name, session_field_value |
46
+
47
+ # This example works for non-array and array field values.
48
+ #
49
+ session_field_value = [ session_field_value ].flatten
50
+
51
+ [
52
+ "\"#{ database_column_name }\" IN (?) OR \"distributor\" IN (?)",
53
+ session_field_value,
54
+ session_field_value
55
+ ]
56
+ end
57
+
58
+ secure_with(
59
+ :creator => {
60
+ :session_field_name => 'authorised_creators',
61
+ :using => or_matcher
62
+ }
63
+ )
64
+ end
65
+ end
66
+ end
67
+
68
+ before :each do
69
+ # Get a good-enough-for-test interaction which has a context
70
+ # that contains a Session we can modify.
71
+
72
+ @interaction = Hoodoo::Services::Middleware::Interaction.new( {}, nil )
73
+ @interaction.context = Hoodoo::Services::Context.new(
74
+ Hoodoo::Services::Session.new,
75
+ @interaction.context.request,
76
+ @interaction.context.response,
77
+ @interaction
78
+ )
79
+
80
+ @context = @interaction.context
81
+ @session = @interaction.context.session
82
+ end
83
+
84
+ shared_examples 'a secure model' do
85
+ before :each do
86
+ @scoped_1 = @class_to_test.new
87
+ @scoped_1.creator = 'creator 1'
88
+ @scoped_1.distributor = 'distributor 1'
89
+ @scoped_1.field = 'scoped 1'
90
+ @scoped_1.save!
91
+
92
+ @scoped_2 = @class_to_test.new
93
+ @scoped_2.creator = 'creator 1'
94
+ @scoped_2.distributor = 'distributor 2'
95
+ @scoped_2.field = 'scoped 2'
96
+ @scoped_2.save!
97
+
98
+ @scoped_3 = @class_to_test.new
99
+ @scoped_3.creator = 'creator 2'
100
+ @scoped_3.distributor = 'distributor 2'
101
+ @scoped_3.field = 'scoped 3'
102
+ @scoped_3.save!
103
+ end
104
+
105
+ it 'finds with secure scopes from the class' do
106
+ @session.scoping = { :authorised_creators => [ 'creator 1' ], :authorised_distributor => 'distributor 1' }
107
+
108
+ found = @class_to_test.secure( @context ).find_by_id( @scoped_1.id )
109
+ expect( found ).to eq( @scoped_1 )
110
+
111
+ found = @class_to_test.secure( @context ).find_by_id( @scoped_2.id )
112
+ expect( found ).to be_nil
113
+
114
+ found = @class_to_test.secure( @context ).find_by_id( @scoped_3.id )
115
+ expect( found ).to be_nil
116
+
117
+ @session.scoping.authorised_distributor = 'distributor 2'
118
+
119
+ found = @class_to_test.secure( @context ).find_by_id( @scoped_1.id )
120
+ expect( found ).to be_nil
121
+
122
+ found = @class_to_test.secure( @context ).find_by_id( @scoped_2.id )
123
+ expect( found ).to eq( @scoped_2 )
124
+
125
+ found = @class_to_test.secure( @context ).find_by_id( @scoped_3.id )
126
+ expect( found ).to be_nil
127
+
128
+ @session.scoping.authorised_creators = [ 'creator 2' ]
129
+
130
+ found = @class_to_test.secure( @context ).find_by_id( @scoped_1.id )
131
+ expect( found ).to be_nil
132
+
133
+ found = @class_to_test.secure( @context ).find_by_id( @scoped_2.id )
134
+ expect( found ).to be_nil
135
+
136
+ found = @class_to_test.secure( @context ).find_by_id( @scoped_3.id )
137
+ expect( found ).to eq( @scoped_3 )
138
+
139
+ @session.scoping.authorised_creators = [ 'creator 1', 'creator 2' ]
140
+
141
+ found = @class_to_test.secure( @context ).find_by_id( @scoped_1.id )
142
+ expect( found ).to be_nil
143
+
144
+ found = @class_to_test.secure( @context ).find_by_id( @scoped_2.id )
145
+ expect( found ).to eq( @scoped_2 )
146
+
147
+ found = @class_to_test.secure( @context ).find_by_id( @scoped_3.id )
148
+ expect( found ).to eq( @scoped_3 )
149
+ end
150
+
151
+ it 'finds with secure scopes with a chain' do
152
+ @session.scoping = { :authorised_creators => [ 'creator 1' ], :authorised_distributor => 'distributor 1' }
153
+
154
+ found = @class_to_test.where( :field => @scoped_1.field ).secure( @context ).find_by_id( @scoped_1.id )
155
+ expect( found ).to eq( @scoped_1 )
156
+
157
+ found = @class_to_test.where( :field => @scoped_1.field + '!' ).secure( @context ).find_by_id( @scoped_1.id )
158
+ expect( found ).to be_nil
159
+
160
+ found = @class_to_test.where( :field => @scoped_2.field ).secure( @context ).find_by_id( @scoped_2.id )
161
+ expect( found ).to be_nil
162
+
163
+ found = @class_to_test.where( :field => @scoped_3.field ).secure( @context ).find_by_id( @scoped_3.id )
164
+ expect( found ).to be_nil
165
+
166
+ @session.scoping.authorised_creators = [ 'creator 1', 'creator 2' ]
167
+ @session.scoping.authorised_distributor = 'distributor 2'
168
+
169
+ found = @class_to_test.where( :field => @scoped_1.field ).secure( @context ).find_by_id( @scoped_1.id )
170
+ expect( found ).to be_nil
171
+
172
+ found = @class_to_test.where( :field => @scoped_2.field ).secure( @context ).find_by_id( @scoped_2.id )
173
+ expect( found ).to eq( @scoped_2 )
174
+
175
+ found = @class_to_test.where( :field => @scoped_3.field ).secure( @context ).find_by_id( @scoped_3.id )
176
+ expect( found ).to eq( @scoped_3 )
177
+
178
+ found = @class_to_test.where( :field => @scoped_3.field + '!' ).secure( @context ).find_by_id( @scoped_3.id )
179
+ expect( found ).to be_nil
180
+ end
181
+
182
+ it 'finds nothing if scope lacks required keys' do
183
+ @session.scoping = { :authorised_distributor => 'distributor 1' }
184
+
185
+ found = @class_to_test.secure( @context ).find_by_id( @scoped_1.id )
186
+ expect( found ).to be_nil
187
+ end
188
+
189
+ it 'finds nothing if scope is missing' do
190
+ found = @class_to_test.secure( @context ).find_by_id( @scoped_1.id )
191
+ expect( found ).to be_nil
192
+ end
193
+ end
194
+
195
+ context 'works with a Symbol' do
196
+ before( :all ) { @class_to_test = RSpecModelSecureTestA }
197
+ it_behaves_like 'a secure model'
198
+ end
199
+
200
+ context 'works with a Hash' do
201
+ before( :all ) { @class_to_test = RSpecModelSecureTestB }
202
+ it_behaves_like 'a secure model'
203
+ end
204
+
205
+ context 'works with custom Procs' do
206
+ before :each do
207
+ @scoped_4 = RSpecModelSecureTestC.new
208
+ @scoped_4.creator = 'creator 3'
209
+ @scoped_4.distributor = 'nothing'
210
+ @scoped_4.field = 'scoped 3'
211
+ @scoped_4.save!
212
+
213
+ @scoped_5 = RSpecModelSecureTestC.new
214
+ @scoped_5.creator = 'nothing'
215
+ @scoped_5.distributor = 'creator 3'
216
+ @scoped_5.field = 'scoped 3'
217
+ @scoped_5.save!
218
+
219
+ @scoped_6 = RSpecModelSecureTestC.new
220
+ @scoped_6.creator = 'nothing'
221
+ @scoped_6.distributor = 'nothing'
222
+ @scoped_6.field = 'scoped 3'
223
+ @scoped_6.save!
224
+ end
225
+
226
+ it 'finds with secure scopes from the class' do
227
+ @session.scoping = { :authorised_creators => [ 'creator 3' ] }
228
+
229
+ found = RSpecModelSecureTestC.secure( @context ).find_by_id( @scoped_4.id )
230
+ expect( found ).to eq( @scoped_4 )
231
+
232
+ found = RSpecModelSecureTestC.secure( @context ).find_by_id( @scoped_5.id )
233
+ expect( found ).to eq( @scoped_5 )
234
+
235
+ found = RSpecModelSecureTestC.secure( @context ).find_by_id( @scoped_6.id )
236
+ expect( found ).to be_nil
237
+ end
238
+
239
+ it 'finds with secure scopes with a chain' do
240
+ @session.scoping = { :authorised_creators => [ 'creator 3' ] }
241
+
242
+ found = RSpecModelSecureTestC.where( :field => @scoped_4.field ).secure( @context ).find_by_id( @scoped_4.id )
243
+ expect( found ).to eq( @scoped_4 )
244
+
245
+ found = RSpecModelSecureTestC.where( :field => @scoped_4.field + '!' ).secure( @context ).find_by_id( @scoped_4.id )
246
+ expect( found ).to be_nil
247
+
248
+ found = RSpecModelSecureTestC.where( :field => @scoped_5.field ).secure( @context ).find_by_id( @scoped_5.id )
249
+ expect( found ).to eq( @scoped_5 )
250
+
251
+ found = RSpecModelSecureTestC.where( :field => @scoped_5.field + '!' ).secure( @context ).find_by_id( @scoped_5.id )
252
+ expect( found ).to be_nil
253
+ end
254
+
255
+ it 'finds nothing if scope lacks required keys' do
256
+ @session.scoping = { :authorised_creators => [ 'missing' ] }
257
+
258
+ found = RSpecModelSecureTestC.secure( @context ).find_by_id( @scoped_4.id )
259
+ expect( found ).to be_nil
260
+ end
261
+
262
+ it 'finds nothing if scope is missing' do
263
+ found = RSpecModelSecureTestC.secure( @context ).find_by_id( @scoped_4.id )
264
+ expect( found ).to be_nil
265
+ end
266
+ end
267
+
268
+ # See also presenters/base_spec.rb
269
+ #
270
+ context 'rendering' do
271
+ class RSpecModelSecureRenderA < ActiveRecord::Base
272
+ include Hoodoo::ActiveRecord::Secure
273
+
274
+ secure_with( {
275
+ :creating_caller_uuid => :authorised_caller_uuids,
276
+ :programme_code => :authorised_programme_codes
277
+ } )
278
+ end
279
+
280
+ class RSpecModelSecureRenderB < ActiveRecord::Base
281
+ include Hoodoo::ActiveRecord::Secure
282
+
283
+ secure_with( {
284
+ :creating_caller_uuid => {
285
+ :session_field_name => :authorised_caller_uuids,
286
+ :resource_field_name => :caller_id # Note renaming of field
287
+ },
288
+
289
+ :programme_code => {
290
+ :session_field_name => :authorised_programme_codes,
291
+ :hide_from_resource => true
292
+ }
293
+ } )
294
+ end
295
+
296
+ # Same as RSpecModelSecureRenderB, but includes a ":using" key. We
297
+ # really don't expect this to change anything, but test coverage is
298
+ # included just in case. By coping 'B', we can just duplicate the
299
+ # tests of 'B' and expect identical results for 'C'.
300
+
301
+ class RSpecModelSecureRenderC < ActiveRecord::Base
302
+ include Hoodoo::ActiveRecord::Secure
303
+
304
+ # Matches Secure's DEFAULT_SECURE_PROC at the time of writing, but
305
+ # I don't want to reference that internal constant here in case (say)
306
+ # its name changes in future.
307
+ #
308
+ simple_matcher = Proc.new { | model_class, database_column_name, session_field_value |
309
+ [ { database_column_name => session_field_value } ]
310
+ }
311
+
312
+ secure_with( {
313
+ :creating_caller_uuid => {
314
+ :session_field_name => :authorised_caller_uuids,
315
+ :resource_field_name => :caller_id, # Note renaming of field
316
+ :using => simple_matcher
317
+ },
318
+
319
+ :programme_code => {
320
+ :session_field_name => :authorised_programme_codes,
321
+ :hide_from_resource => true
322
+ }
323
+ } )
324
+ end
325
+
326
+ before :all do
327
+ spec_helper_silence_stdout() do
328
+
329
+ # This is set up to match examples in the RDoc data for #secure(_with)
330
+ # at the time of writing.
331
+
332
+ migration = Proc.new do | t |
333
+ t.text :creating_caller_uuid
334
+ t.text :programme_code
335
+ t.timestamps
336
+ end
337
+
338
+ ActiveRecord::Migration.create_table( :r_spec_model_secure_render_as, &migration )
339
+ ActiveRecord::Migration.create_table( :r_spec_model_secure_render_bs, &migration )
340
+ ActiveRecord::Migration.create_table( :r_spec_model_secure_render_cs, &migration )
341
+ end
342
+ end
343
+
344
+ before :each do
345
+ @authorised_caller_uuids = [
346
+ Hoodoo::UUID.generate,
347
+ Hoodoo::UUID.generate,
348
+ Hoodoo::UUID.generate
349
+ ]
350
+
351
+ @authorised_programme_codes = [
352
+ 'AA',
353
+ 'BB'
354
+ ]
355
+
356
+ @session.scoping = { 'authorised_caller_uuids' => @authorised_caller_uuids,
357
+ 'authorised_programme_codes' => @authorised_programme_codes }
358
+
359
+ [ RSpecModelSecureRenderA, RSpecModelSecureRenderB, RSpecModelSecureRenderC ].each do | klass |
360
+ item = klass.new
361
+ item.programme_code = @authorised_programme_codes.last
362
+ item.creating_caller_uuid = @authorised_caller_uuids.last
363
+ item.save!
364
+ end
365
+ end
366
+
367
+ class TestPresenterSecure < Hoodoo::Presenters::Base
368
+ schema do
369
+ string :three, :length => 15, :required => false, :default => 'default_three'
370
+ internationalised
371
+ end
372
+ end
373
+
374
+ it 'renders with default security' do
375
+ found = RSpecModelSecureRenderA.secure( @context ).first
376
+ expect( found ).to_not be_nil
377
+
378
+ data = {}
379
+ t = Time.now.utc
380
+ u = Hoodoo::UUID.generate
381
+ options = { :uuid => u, :created_at => t, :secured_with => found }
382
+ expect(TestPresenterSecure.render_in(@context, data, options)).to eq({
383
+ 'id' => u,
384
+ 'kind' => 'TestPresenterSecure',
385
+ 'created_at' => t.iso8601,
386
+ 'language' => 'en-nz',
387
+ 'three' => 'default_three',
388
+ 'secured_with' => {
389
+ 'creating_caller_uuid' => found.creating_caller_uuid,
390
+ 'programme_code' => found.programme_code
391
+ }
392
+ })
393
+ end
394
+
395
+ it 'renders with custom security' do
396
+ found = RSpecModelSecureRenderB.secure( @context ).first
397
+ expect( found ).to_not be_nil
398
+
399
+ data = {}
400
+ t = Time.now.utc
401
+ u = Hoodoo::UUID.generate
402
+ options = { :uuid => u, :created_at => t, :secured_with => found }
403
+ expect(TestPresenterSecure.render_in(@context, data, options)).to eq({
404
+ 'id' => u,
405
+ 'kind' => 'TestPresenterSecure',
406
+ 'created_at' => t.iso8601,
407
+ 'language' => 'en-nz',
408
+ 'three' => 'default_three',
409
+ 'secured_with' => {
410
+ 'caller_id' => found.creating_caller_uuid
411
+ }
412
+ })
413
+ end
414
+
415
+ it 'renders with custom security and custom matcher' do
416
+ found = RSpecModelSecureRenderC.secure( @context ).first
417
+ expect( found ).to_not be_nil
418
+
419
+ data = {}
420
+ t = Time.now.utc
421
+ u = Hoodoo::UUID.generate
422
+ options = { :uuid => u, :created_at => t, :secured_with => found }
423
+ expect(TestPresenterSecure.render_in(@context, data, options)).to eq({
424
+ 'id' => u,
425
+ 'kind' => 'TestPresenterSecure',
426
+ 'created_at' => t.iso8601,
427
+ 'language' => 'en-nz',
428
+ 'three' => 'default_three',
429
+ 'secured_with' => {
430
+ 'caller_id' => found.creating_caller_uuid
431
+ }
432
+ })
433
+ end
434
+ end
435
+ end