hoodoo 2.5.1 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/lib/hoodoo/active/active_record/manually_dated.rb +2 -1
- data/lib/hoodoo/active/active_record/secure.rb +121 -10
- data/lib/hoodoo/active/active_record/security_helper.rb +143 -0
- data/lib/hoodoo/active/active_record/writer.rb +150 -120
- data/lib/hoodoo/client/client.rb +6 -0
- data/lib/hoodoo/communicators/pool.rb +1 -1
- data/lib/hoodoo/services/services/context.rb +6 -0
- data/lib/hoodoo/services/services/request.rb +6 -6
- data/lib/hoodoo/version.rb +2 -2
- data/spec/active/active_record/secure_spec.rb +213 -0
- data/spec/active/active_record/security_helper_spec.rb +201 -0
- data/spec/active/active_record/writer_spec.rb +14 -0
- data/spec/client/client_spec.rb +11 -2
- data/spec/services/services/context_spec.rb +27 -13
- metadata +6 -3
data/lib/hoodoo/client/client.rb
CHANGED
@@ -355,5 +355,11 @@ module Hoodoo
|
|
355
355
|
return endpoint
|
356
356
|
end
|
357
357
|
|
358
|
+
# Alias of #resource, as syntax sugar for those who prefer to think of
|
359
|
+
# the return value as an endpoint that is used to contact a resource,
|
360
|
+
# rather than a remote abstraction of the resource as an entity.
|
361
|
+
#
|
362
|
+
alias_method :endpoint, :resource
|
363
|
+
|
358
364
|
end
|
359
365
|
end
|
@@ -456,7 +456,7 @@ module Hoodoo
|
|
456
456
|
#
|
457
457
|
def handle_exception( exception, communicator )
|
458
458
|
begin
|
459
|
-
report = "
|
459
|
+
report = "Communicator class #{ communicator.class.name } raised exception '#{ exception }': #{ exception.backtrace }"
|
460
460
|
$stderr.puts( report )
|
461
461
|
|
462
462
|
rescue
|
@@ -149,5 +149,11 @@ module Hoodoo; module Services
|
|
149
149
|
return endpoint
|
150
150
|
end
|
151
151
|
|
152
|
+
# Alias of #resource, as syntax sugar for those who prefer to think of
|
153
|
+
# the return value as an endpoint that is used to contact a resource,
|
154
|
+
# rather than a remote abstraction of the resource as an entity.
|
155
|
+
#
|
156
|
+
alias_method :endpoint, :resource
|
157
|
+
|
152
158
|
end
|
153
159
|
end; end
|
@@ -74,12 +74,12 @@ module Hoodoo; module Services
|
|
74
74
|
# intentionally compatible so that pass-through / proxy scenarios from
|
75
75
|
# resource implementation to another resource are assisted:
|
76
76
|
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
#
|
77
|
+
# * +offset+
|
78
|
+
# * +limit+
|
79
|
+
# * +sort+ (keys from the Hash under attribute #sort_data)
|
80
|
+
# * +direction+ (values from the Hash under #sort_data)
|
81
|
+
# * +search+ (deep-duplicated value of attribute #search_data)
|
82
|
+
# * +filter+ (deep-duplicated value of attribute #filter_data)
|
83
83
|
#
|
84
84
|
# Sort, direction, search and filter data, if not empty, also have
|
85
85
|
# String keys / values. A single sort-direction key-value pair will be
|
data/lib/hoodoo/version.rb
CHANGED
@@ -12,11 +12,11 @@ module Hoodoo
|
|
12
12
|
# The Hoodoo gem version. If this changes, be sure to re-run
|
13
13
|
# <tt>bundle install</tt> or <tt>bundle update</tt>.
|
14
14
|
#
|
15
|
-
VERSION = '2.
|
15
|
+
VERSION = '2.6.0'
|
16
16
|
|
17
17
|
# The Hoodoo gem date. If this changes, be sure to re-run
|
18
18
|
# <tt>bundle install</tt> or <tt>bundle update</tt>.
|
19
19
|
#
|
20
|
-
DATE = '2018-05-
|
20
|
+
DATE = '2018-05-23'
|
21
21
|
|
22
22
|
end
|
@@ -17,6 +17,11 @@ describe Hoodoo::ActiveRecord::Secure do
|
|
17
17
|
ActiveRecord::Migration.create_table( :r_spec_model_secure_test_as, &migration )
|
18
18
|
ActiveRecord::Migration.create_table( :r_spec_model_secure_test_bs, &migration )
|
19
19
|
ActiveRecord::Migration.create_table( :r_spec_model_secure_test_cs, &migration )
|
20
|
+
ActiveRecord::Migration.create_table( :r_spec_model_secure_test_ds, &migration )
|
21
|
+
ActiveRecord::Migration.create_table( :r_spec_model_secure_test_es, &migration )
|
22
|
+
ActiveRecord::Migration.create_table( :r_spec_model_secure_test_fs, &migration )
|
23
|
+
|
24
|
+
# ======================================================================
|
20
25
|
|
21
26
|
class RSpecModelSecureTestA < ActiveRecord::Base
|
22
27
|
include Hoodoo::ActiveRecord::Secure
|
@@ -27,6 +32,8 @@ describe Hoodoo::ActiveRecord::Secure do
|
|
27
32
|
)
|
28
33
|
end
|
29
34
|
|
35
|
+
# ======================================================================
|
36
|
+
|
30
37
|
class RSpecModelSecureTestB < ActiveRecord::Base
|
31
38
|
include Hoodoo::ActiveRecord::Secure
|
32
39
|
|
@@ -36,6 +43,8 @@ describe Hoodoo::ActiveRecord::Secure do
|
|
36
43
|
)
|
37
44
|
end
|
38
45
|
|
46
|
+
# ======================================================================
|
47
|
+
|
39
48
|
class RSpecModelSecureTestC < ActiveRecord::Base
|
40
49
|
include Hoodoo::ActiveRecord::Secure
|
41
50
|
|
@@ -62,9 +71,49 @@ describe Hoodoo::ActiveRecord::Secure do
|
|
62
71
|
}
|
63
72
|
)
|
64
73
|
end
|
74
|
+
|
75
|
+
# ======================================================================
|
76
|
+
|
77
|
+
class RSpecModelSecureTestD < ActiveRecord::Base
|
78
|
+
include Hoodoo::ActiveRecord::Secure
|
79
|
+
|
80
|
+
secure_with(
|
81
|
+
:creator => {
|
82
|
+
:session_field_name => 'authorised_creators',
|
83
|
+
:exemptions => Hoodoo::ActiveRecord::Secure::ENUMERABLE_INCLUDES_STAR
|
84
|
+
}
|
85
|
+
)
|
86
|
+
end
|
87
|
+
|
88
|
+
class RSpecModelSecureTestE < ActiveRecord::Base
|
89
|
+
include Hoodoo::ActiveRecord::Secure
|
90
|
+
|
91
|
+
secure_with(
|
92
|
+
'distributor' => {
|
93
|
+
:session_field_name => :authorised_distributor,
|
94
|
+
:exemptions => Hoodoo::ActiveRecord::Secure::OBJECT_EQLS_STAR
|
95
|
+
}
|
96
|
+
)
|
97
|
+
end
|
98
|
+
|
99
|
+
class RSpecModelSecureTestF < ActiveRecord::Base
|
100
|
+
include Hoodoo::ActiveRecord::Secure
|
101
|
+
|
102
|
+
secure_with(
|
103
|
+
:field => {
|
104
|
+
:session_field_name => :authorised_suppliers,
|
105
|
+
:exemptions => Proc.new { | security_values |
|
106
|
+
security_values.is_a?( Enumerable ) &&
|
107
|
+
security_values.include?( 'Dolphin' ) rescue false
|
108
|
+
}
|
109
|
+
}
|
110
|
+
)
|
111
|
+
end
|
65
112
|
end
|
66
113
|
end
|
67
114
|
|
115
|
+
# ==========================================================================
|
116
|
+
|
68
117
|
before :each do
|
69
118
|
# Get a good-enough-for-test interaction which has a context
|
70
119
|
# that contains a Session we can modify.
|
@@ -202,6 +251,8 @@ describe Hoodoo::ActiveRecord::Secure do
|
|
202
251
|
it_behaves_like 'a secure model'
|
203
252
|
end
|
204
253
|
|
254
|
+
# ==========================================================================
|
255
|
+
|
205
256
|
context 'works with custom Procs' do
|
206
257
|
before :each do
|
207
258
|
@scoped_4 = RSpecModelSecureTestC.new
|
@@ -265,6 +316,168 @@ describe Hoodoo::ActiveRecord::Secure do
|
|
265
316
|
end
|
266
317
|
end
|
267
318
|
|
319
|
+
# ==========================================================================
|
320
|
+
|
321
|
+
# We assume that security_helper_spec.rb takes care of all of the security
|
322
|
+
# helper Proc generators, so all that's left to test is the out-of-box Procs
|
323
|
+
# defined in constants within 'secure.rb' and make sure a custom Proc works
|
324
|
+
# as expected.
|
325
|
+
#
|
326
|
+
context 'with security exemptions' do
|
327
|
+
|
328
|
+
# Call the shared examples with the Hash to set in the @session scoping
|
329
|
+
# value, then true/false values for whether a scoped find-by-ID query
|
330
|
+
# should find the three records created below (true => should find it).
|
331
|
+
#
|
332
|
+
shared_examples 'a secure model' do | session_scoping, s4_bool, s5_bool, s6_bool |
|
333
|
+
before :each do
|
334
|
+
@scoped_4 = @class_to_test.new
|
335
|
+
@scoped_4.creator = 'C1'
|
336
|
+
@scoped_4.distributor = 'D1'
|
337
|
+
@scoped_4.field = 'S1'
|
338
|
+
@scoped_4.save!
|
339
|
+
|
340
|
+
@scoped_5 = @class_to_test.new
|
341
|
+
@scoped_5.creator = 'C2'
|
342
|
+
@scoped_5.distributor = 'D2'
|
343
|
+
@scoped_5.field = 'S2'
|
344
|
+
@scoped_5.save!
|
345
|
+
|
346
|
+
@scoped_6 = @class_to_test.new
|
347
|
+
@scoped_6.creator = 'C3'
|
348
|
+
@scoped_6.distributor = 'D3'
|
349
|
+
@scoped_6.field = 'S3'
|
350
|
+
@scoped_6.save!
|
351
|
+
|
352
|
+
@results = [ @scoped4, @scoped5, @scoped6 ]
|
353
|
+
end
|
354
|
+
|
355
|
+
# Convenience method to DRY up a few tests later.
|
356
|
+
#
|
357
|
+
def expect_none
|
358
|
+
found = @class_to_test.secure( @context ).find_by_id( @scoped_4.id )
|
359
|
+
expect( found ).to be_nil
|
360
|
+
|
361
|
+
found = @class_to_test.secure( @context ).find_by_id( @scoped_5.id )
|
362
|
+
expect( found ).to be_nil
|
363
|
+
|
364
|
+
found = @class_to_test.secure( @context ).find_by_id( @scoped_6.id )
|
365
|
+
expect( found ).to be_nil
|
366
|
+
end
|
367
|
+
|
368
|
+
it 'finds with exemptions from the class' do
|
369
|
+
@session.scoping = session_scoping
|
370
|
+
|
371
|
+
found = @class_to_test.secure( @context ).find_by_id( @scoped_4.id )
|
372
|
+
expect( found ).to eq( s4_bool ? @scoped_4 : nil )
|
373
|
+
|
374
|
+
found = @class_to_test.secure( @context ).find_by_id( @scoped_5.id )
|
375
|
+
expect( found ).to eq( s5_bool ? @scoped_5 : nil )
|
376
|
+
|
377
|
+
found = @class_to_test.secure( @context ).find_by_id( @scoped_6.id )
|
378
|
+
expect( found ).to eq( s6_bool ? @scoped_6 : nil )
|
379
|
+
end
|
380
|
+
|
381
|
+
# Only fully effective if at some point there is a "true, true, true"
|
382
|
+
# case which expects to match all. Otherwise, some of the expectations
|
383
|
+
# aren't useful (the "expects daft lookup to be nil" cases would be
|
384
|
+
# nil anyway, if 'false' indicates no-find-result-expected).
|
385
|
+
#
|
386
|
+
it 'finds with exemptions with a chain' do
|
387
|
+
@session.scoping = session_scoping
|
388
|
+
|
389
|
+
found = @class_to_test.where( :field => @scoped_4.field ).secure( @context ).find_by_id( @scoped_4.id )
|
390
|
+
expect( found ).to eq( s4_bool ? @scoped_4 : nil )
|
391
|
+
|
392
|
+
found = @class_to_test.where( :field => @scoped_4.field + '!' ).secure( @context ).find_by_id( @scoped_4.id )
|
393
|
+
expect( found ).to be_nil
|
394
|
+
|
395
|
+
found = @class_to_test.where( :field => @scoped_5.field ).secure( @context ).find_by_id( @scoped_5.id )
|
396
|
+
expect( found ).to eq( s5_bool ? @scoped_5 : nil )
|
397
|
+
|
398
|
+
found = @class_to_test.where( :field => @scoped_5.field + '!' ).secure( @context ).find_by_id( @scoped_5.id )
|
399
|
+
expect( found ).to be_nil
|
400
|
+
|
401
|
+
found = @class_to_test.where( :field => @scoped_6.field ).secure( @context ).find_by_id( @scoped_6.id )
|
402
|
+
expect( found ).to eq( s6_bool ? @scoped_6 : nil )
|
403
|
+
|
404
|
+
found = @class_to_test.where( :field => @scoped_6.field + '!' ).secure( @context ).find_by_id( @scoped_6.id )
|
405
|
+
expect( found ).to be_nil
|
406
|
+
end
|
407
|
+
|
408
|
+
it 'finds nothing if scope lacks required values' do
|
409
|
+
new_session_scoping = {}
|
410
|
+
|
411
|
+
session_scoping.each do | key, value |
|
412
|
+
new_session_scoping[ key ] = if value.is_a?( Array )
|
413
|
+
[ 'will not match any records' ]
|
414
|
+
else
|
415
|
+
'will not match any records'
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
@session.scoping = new_session_scoping
|
420
|
+
expect_none()
|
421
|
+
end
|
422
|
+
|
423
|
+
it 'finds nothing if scope lacks required keys' do
|
424
|
+
@session.scoping = { :some_authorised_thing => '*' }
|
425
|
+
expect_none()
|
426
|
+
end
|
427
|
+
|
428
|
+
it 'finds nothing if scope is missing' do
|
429
|
+
expect_none()
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
# A reminder of RSpecModelSecureTestD rules:
|
434
|
+
#
|
435
|
+
# :creator => {
|
436
|
+
# :session_field_name => 'authorised_creators',
|
437
|
+
# :exemptions => Hoodoo::ActiveRecord::Secure::ENUMERABLE_INCLUDES_STAR
|
438
|
+
# }
|
439
|
+
#
|
440
|
+
context 'works with ENUMERABLE_INCLUDES_STAR' do
|
441
|
+
before( :all ) { @class_to_test = RSpecModelSecureTestD }
|
442
|
+
|
443
|
+
it_behaves_like 'a secure model', { :authorised_creators => [ 'C1', '*' ] }, true, true, true
|
444
|
+
it_behaves_like 'a secure model', { 'authorised_creators' => [ 'C2' ] }, false, true, false
|
445
|
+
end
|
446
|
+
|
447
|
+
# A reminder of RSpecModelSecureTestE rules:
|
448
|
+
#
|
449
|
+
# 'distributor' => {
|
450
|
+
# :session_field_name => :authorised_distributor,
|
451
|
+
# :exemptions => Hoodoo::ActiveRecord::Secure::OBJECT_EQLS_STAR
|
452
|
+
# }
|
453
|
+
#
|
454
|
+
context 'works with OBJECT_EQLS_STAR' do
|
455
|
+
before( :all ) { @class_to_test = RSpecModelSecureTestE }
|
456
|
+
|
457
|
+
it_behaves_like 'a secure model', { :authorised_distributor => '*' }, true, true, true
|
458
|
+
it_behaves_like 'a secure model', { 'authorised_distributor' => 'D3' }, false, false, true
|
459
|
+
end
|
460
|
+
|
461
|
+
# A reminder of RSpecModelSecureTestF rules:
|
462
|
+
#
|
463
|
+
# :field => {
|
464
|
+
# :session_field_name => :authorised_suppliers,
|
465
|
+
# :exemptions => Proc.new { | security_values |
|
466
|
+
# security_values.is_a?( Enumerable ) &&
|
467
|
+
# security_values.include?( 'Dolphin' ) rescue false
|
468
|
+
# }
|
469
|
+
# }
|
470
|
+
#
|
471
|
+
context 'works with a custom Proc' do
|
472
|
+
before( :all ) { @class_to_test = RSpecModelSecureTestF }
|
473
|
+
|
474
|
+
it_behaves_like 'a secure model', { :authorised_suppliers => [ 'Dolphin' ] }, true, true, true
|
475
|
+
it_behaves_like 'a secure model', { 'authorised_suppliers' => [ 'S1', 'S3' ] }, true, false, true
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
# ==========================================================================
|
480
|
+
|
268
481
|
# See also presenters/base_spec.rb
|
269
482
|
#
|
270
483
|
context 'rendering' do
|
@@ -0,0 +1,201 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Hoodoo::ActiveRecord::Secure::SecurityHelper do
|
4
|
+
|
5
|
+
class TestAllMatchersObject
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
def eql?( thing ); true; end
|
9
|
+
def include?( thing ); true; end
|
10
|
+
def match?( thing ); true; end
|
11
|
+
end
|
12
|
+
|
13
|
+
class TestRescueAllMatchersObject
|
14
|
+
include Enumerable
|
15
|
+
|
16
|
+
def eql?( thing ); raise "boo!"; end
|
17
|
+
def include?( thing ); raise "boo!"; end
|
18
|
+
def match?( thing ); raise "boo!"; end
|
19
|
+
end
|
20
|
+
|
21
|
+
context '::eqls_wildcard' do
|
22
|
+
before :each do
|
23
|
+
@proc = Hoodoo::ActiveRecord::Secure::SecurityHelper.eqls_wildcard( '!' )
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'matches when it should' do
|
27
|
+
expect( @proc.call( '!' ) ).to eql( true )
|
28
|
+
expect( @proc.call( TestAllMatchersObject.new ) ).to eql( true )
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'misses when it should' do
|
32
|
+
expect( @proc.call( '*' ) ).to eql( false )
|
33
|
+
expect( @proc.call( ' !' ) ).to eql( false )
|
34
|
+
expect( @proc.call( '! ' ) ).to eql( false )
|
35
|
+
expect( @proc.call( "!\n" ) ).to eql( false )
|
36
|
+
expect( @proc.call( 42 ) ).to eql( false )
|
37
|
+
expect( @proc.call( { :hello => :world } ) ).to eql( false )
|
38
|
+
expect( @proc.call( [ 1, 2, 3, 4 ] ) ).to eql( false )
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'rescues' do
|
42
|
+
expect( @proc.call( TestRescueAllMatchersObject.new ) ).to eql( false )
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context '::includes_wildcard' do
|
47
|
+
before :each do
|
48
|
+
@proc = Hoodoo::ActiveRecord::Secure::SecurityHelper.includes_wildcard( '!' )
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'matches when it should' do
|
52
|
+
expect( @proc.call( [ '!' ] ) ).to eql( true )
|
53
|
+
expect( @proc.call( [ '!', 1, 2, 3, 4 ] ) ).to eql( true )
|
54
|
+
expect( @proc.call( [ 1, 2, '!', 3, 4 ] ) ).to eql( true )
|
55
|
+
expect( @proc.call( [ 1, 2, 3, 4, '!' ] ) ).to eql( true )
|
56
|
+
expect( @proc.call( TestAllMatchersObject.new ) ).to eql( true )
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'misses when it should' do
|
60
|
+
expect( @proc.call( '!' ) ).to eql( false )
|
61
|
+
expect( @proc.call( [ '*' ] ) ).to eql( false )
|
62
|
+
expect( @proc.call( [ ' !' ] ) ).to eql( false )
|
63
|
+
expect( @proc.call( [ '! ' ] ) ).to eql( false )
|
64
|
+
expect( @proc.call( [ "!\n" ] ) ).to eql( false )
|
65
|
+
expect( @proc.call( 42 ) ).to eql( false )
|
66
|
+
expect( @proc.call( { :hello => :world } ) ).to eql( false )
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'rescues' do
|
70
|
+
expect( @proc.call( TestRescueAllMatchersObject.new ) ).to eql( false )
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context '::matches_wildcard' do
|
75
|
+
let( :param ) { '^..!.*' }
|
76
|
+
let( :proc ) { Hoodoo::ActiveRecord::Secure::SecurityHelper.matches_wildcard( param ) }
|
77
|
+
|
78
|
+
shared_examples 'a ::matches_wildcard Proc' do
|
79
|
+
it 'and matches when it should' do
|
80
|
+
expect( proc().call( '12!' ) ).to eql( true )
|
81
|
+
expect( proc().call( '12!3' ) ).to eql( true )
|
82
|
+
|
83
|
+
if ''.respond_to?( :match? )
|
84
|
+
expect( proc().call( TestAllMatchersObject.new ) ).to eql( true )
|
85
|
+
else
|
86
|
+
expect_any_instance_of( Regexp ).to receive( :match ).and_return( true )
|
87
|
+
proc().call( TestAllMatchersObject.new )
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'and misses when it should' do
|
92
|
+
expect( proc().call( '123!4' ) ).to eql( false )
|
93
|
+
expect( proc().call( '1!4' ) ).to eql( false )
|
94
|
+
expect( proc().call( 42 ) ).to eql( false )
|
95
|
+
expect( proc().call( { :hello => :world } ) ).to eql( false )
|
96
|
+
expect( proc().call( [ 1, 2, 3, 4 ] ) ).to eql( false )
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'and rescues' do
|
100
|
+
if ''.respond_to?( :match? )
|
101
|
+
expect( proc().call( TestRescueAllMatchersObject.new ) ).to eql( false )
|
102
|
+
else
|
103
|
+
expect_any_instance_of( Regexp ).to receive( :match ).and_raise( RuntimeError )
|
104
|
+
proc().call( TestRescueAllMatchersObject.new )
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Tests running on Ruby >= 2.4 need String#match? knocking out for a
|
110
|
+
# while, for code coverage.
|
111
|
+
#
|
112
|
+
context 'with slow matcher' do
|
113
|
+
before :each do
|
114
|
+
@unbound_method = nil
|
115
|
+
|
116
|
+
if ''.respond_to?( :match? )
|
117
|
+
@unbound_method = String.instance_method( :match? )
|
118
|
+
String.send( :remove_method, :match? )
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
after :each do
|
123
|
+
unless @unbound_method.nil?
|
124
|
+
String.send( :define_method, :match?, @unbound_method )
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context 'constructed with a String' do
|
129
|
+
it_behaves_like 'a ::matches_wildcard Proc'
|
130
|
+
end
|
131
|
+
|
132
|
+
context 'constructed with a Regexp' do
|
133
|
+
let( :param ) { /^..!.*/ }
|
134
|
+
it_behaves_like 'a ::matches_wildcard Proc'
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# Tests running on Ruby < 2.4 can't do the fast match tests.
|
139
|
+
#
|
140
|
+
if ''.respond_to?( :match? )
|
141
|
+
context 'with fast matcher' do
|
142
|
+
context 'constructed with a String' do
|
143
|
+
it_behaves_like 'a ::matches_wildcard Proc'
|
144
|
+
end
|
145
|
+
|
146
|
+
context 'constructed with a Regexp' do
|
147
|
+
let( :param ) { /^..!.*/ }
|
148
|
+
it_behaves_like 'a ::matches_wildcard Proc'
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context '::matches_wildcard_enumerable' do
|
155
|
+
let( :proc ) { Hoodoo::ActiveRecord::Secure::SecurityHelper.matches_wildcard_enumerable( param ) }
|
156
|
+
let( :param ) { '^..!.*' }
|
157
|
+
|
158
|
+
shared_examples 'a ::matches_wildcard Proc' do
|
159
|
+
it 'and matches when it should' do
|
160
|
+
expect( proc().call( [ '12!34', '1', 2, :three, 4 ] ) ).to eql( true )
|
161
|
+
expect( proc().call( [ '1', 2, :three, '12!34', 4 ] ) ).to eql( true )
|
162
|
+
expect( proc().call( [ '1', 2, :three, 4, '12!34' ] ) ).to eql( true )
|
163
|
+
expect( proc().call( [ '12!' ] ) ).to eql( true )
|
164
|
+
|
165
|
+
if ''.respond_to?( :match? )
|
166
|
+
expect( proc().call( [ TestAllMatchersObject.new ] ) ).to eql( true )
|
167
|
+
else
|
168
|
+
expect_any_instance_of( Regexp ).to receive( :match ).and_return( true )
|
169
|
+
proc().call( [ TestAllMatchersObject.new ] )
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'and misses when it should' do
|
174
|
+
expect( proc().call( [ '123!34' ] ) ).to eql( false )
|
175
|
+
expect( proc().call( [ '1!4' ] ) ).to eql( false )
|
176
|
+
expect( proc().call( { :hello => :world } ) ).to eql( false )
|
177
|
+
expect( proc().call( [ 1, 2, 3, 4 ] ) ).to eql( false )
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'and rescues' do
|
181
|
+
expect( proc().call( 42 ) ).to eql( false )
|
182
|
+
|
183
|
+
if ''.respond_to?( :match? )
|
184
|
+
expect( proc().call( [ TestRescueAllMatchersObject.new ] ) ).to eql( false )
|
185
|
+
else
|
186
|
+
expect_any_instance_of( Regexp ).to receive( :match ).and_raise( RuntimeError )
|
187
|
+
proc().call( [ TestRescueAllMatchersObject.new ] )
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
context 'constructed with a String' do
|
193
|
+
it_behaves_like 'a ::matches_wildcard Proc'
|
194
|
+
end
|
195
|
+
|
196
|
+
context 'constructed with a Regexp' do
|
197
|
+
let( :param ) { /^..!.*/ }
|
198
|
+
it_behaves_like 'a ::matches_wildcard Proc'
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|