scimitar 1.0.3 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -15,6 +15,19 @@ RSpec.describe Scimitar::Resources::User do
15
15
  expect(user.as_json['name']['errors']).to be_nil
16
16
  end
17
17
 
18
+ it 'treats attributes as case-insensitive' do
19
+ user = described_class.new(name: Scimitar::ComplexTypes::Name.new(
20
+ FAMILYNAME: 'Smith',
21
+ GIVENNAME: 'John',
22
+ FORMATTED: 'John Smith'
23
+ ))
24
+
25
+ expect(user.name.familyName).to eql('Smith')
26
+ expect(user.name.givenName).to eql('John')
27
+ expect(user.name.formatted).to eql('John Smith')
28
+ expect(user.as_json['name']['errors']).to be_nil
29
+ end
30
+
18
31
  it 'validates that the provided name matches the name schema' do
19
32
  user = described_class.new(name: Scimitar::ComplexTypes::Email.new(
20
33
  value: 'john@smoth.com',
@@ -29,25 +42,25 @@ RSpec.describe Scimitar::Resources::User do
29
42
  let(:user) { described_class.new }
30
43
 
31
44
  it 'adds the error when the value is a string' do
32
- user.add_errors_from_hash(key: 'some error')
45
+ user.add_errors_from_hash(errors_hash: {key: 'some error'})
33
46
  expect(user.errors.messages.to_h).to eql({key: ['some error']})
34
47
  expect(user.errors.full_messages).to eql(['Key some error'])
35
48
  end
36
49
 
37
50
  it 'adds the error when the value is an array' do
38
- user.add_errors_from_hash(key: ['error1', 'error2'])
51
+ user.add_errors_from_hash(errors_hash: {key: ['error1', 'error2']})
39
52
  expect(user.errors.messages.to_h).to eql({key: ['error1', 'error2']})
40
53
  expect(user.errors.full_messages).to eql(['Key error1', 'Key error2'])
41
54
  end
42
55
 
43
56
  it 'adds the error with prefix when the value is a string' do
44
- user.add_errors_from_hash({key: 'some error'}, prefix: :pre)
57
+ user.add_errors_from_hash(errors_hash: {key: 'some error'}, prefix: :pre)
45
58
  expect(user.errors.messages.to_h).to eql({:'pre.key' => ['some error']})
46
59
  expect(user.errors.full_messages).to eql(['Pre key some error'])
47
60
  end
48
61
 
49
62
  it 'adds the error wity prefix when the value is an array' do
50
- user.add_errors_from_hash({key: ['error1', 'error2']}, prefix: :pre)
63
+ user.add_errors_from_hash(errors_hash: {key: ['error1', 'error2']}, prefix: :pre)
51
64
  expect(user.errors.messages.to_h).to eql({:'pre.key' => ['error1', 'error2']})
52
65
  expect(user.errors.full_messages).to eql(['Pre key error1', 'Pre key error2'])
53
66
  end
@@ -146,36 +146,35 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
146
146
 
147
147
  context '#create' do
148
148
  context 'creates an item' do
149
- it 'with minimal parameters' do
150
- mock_before = MockUser.all.to_a
149
+ shared_examples 'a creator' do | force_upper_case: |
150
+ it 'with minimal parameters' do
151
+ mock_before = MockUser.all.to_a
151
152
 
152
- expect_any_instance_of(MockUsersController).to receive(:create).once.and_call_original
153
- expect {
154
- post "/Users", params: {
155
- format: :scim,
156
- userName: '4' # Minimum required by schema
157
- }
158
- }.to change { MockUser.count }.by(1)
153
+ attributes = { userName: '4' } # Minimum required by schema
154
+ attributes = spec_helper_hupcase(attributes) if force_upper_case
159
155
 
160
- mock_after = MockUser.all.to_a
161
- new_mock = (mock_after - mock_before).first
156
+ expect_any_instance_of(MockUsersController).to receive(:create).once.and_call_original
157
+ expect {
158
+ post "/Users", params: attributes.merge(format: :scim)
159
+ }.to change { MockUser.count }.by(1)
162
160
 
163
- expect(response.status).to eql(201)
164
- result = JSON.parse(response.body)
161
+ mock_after = MockUser.all.to_a
162
+ new_mock = (mock_after - mock_before).first
165
163
 
166
- expect(result['id']).to eql(new_mock.id.to_s)
167
- expect(result['meta']['resourceType']).to eql('User')
168
- expect(new_mock.username).to eql('4')
169
- end
164
+ expect(response.status).to eql(201)
165
+ result = JSON.parse(response.body)
170
166
 
171
- # A bit of extra coverage just for general confidence.
172
- #
173
- it 'with more comprehensive parameters' do
174
- mock_before = MockUser.all.to_a
167
+ expect(result['id']).to eql(new_mock.id.to_s)
168
+ expect(result['meta']['resourceType']).to eql('User')
169
+ expect(new_mock.username).to eql('4')
170
+ end
175
171
 
176
- expect {
177
- post "/Users", params: {
178
- format: :scim,
172
+ # A bit of extra coverage just for general confidence.
173
+ #
174
+ it 'with more comprehensive parameters' do
175
+ mock_before = MockUser.all.to_a
176
+
177
+ attributes = {
179
178
  userName: '4',
180
179
  name: {
181
180
  givenName: 'Given',
@@ -192,22 +191,36 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
192
191
  }
193
192
  ]
194
193
  }
195
- }.to change { MockUser.count }.by(1)
196
194
 
197
- mock_after = MockUser.all.to_a
198
- new_mock = (mock_after - mock_before).first
195
+ attributes = spec_helper_hupcase(attributes) if force_upper_case
199
196
 
200
- expect(response.status).to eql(201)
201
- result = JSON.parse(response.body)
197
+ expect {
198
+ post "/Users", params: attributes.merge(format: :scim)
199
+ }.to change { MockUser.count }.by(1)
202
200
 
203
- expect(result['id']).to eql(new_mock.id.to_s)
204
- expect(result['meta']['resourceType']).to eql('User')
205
- expect(new_mock.username).to eql('4')
206
- expect(new_mock.first_name).to eql('Given')
207
- expect(new_mock.last_name).to eql('Family')
208
- expect(new_mock.home_email_address).to eql('home_4@test.com')
209
- expect(new_mock.work_email_address).to eql('work_4@test.com')
210
- end
201
+ mock_after = MockUser.all.to_a
202
+ new_mock = (mock_after - mock_before).first
203
+
204
+ expect(response.status).to eql(201)
205
+ result = JSON.parse(response.body)
206
+
207
+ expect(result['id']).to eql(new_mock.id.to_s)
208
+ expect(result['meta']['resourceType']).to eql('User')
209
+ expect(new_mock.username).to eql('4')
210
+ expect(new_mock.first_name).to eql('Given')
211
+ expect(new_mock.last_name).to eql('Family')
212
+ expect(new_mock.home_email_address).to eql('home_4@test.com')
213
+ expect(new_mock.work_email_address).to eql('work_4@test.com')
214
+ end
215
+ end # "shared_examples 'a creator' do | force_upper_case: |"
216
+
217
+ context 'using schema-matched case' do
218
+ it_behaves_like 'a creator', force_upper_case: false
219
+ end # "context 'using schema-matched case' do"
220
+
221
+ context 'using upper case' do
222
+ it_behaves_like 'a creator', force_upper_case: true
223
+ end # "context 'using upper case' do"
211
224
  end
212
225
 
213
226
  it 'returns 409 for duplicates (by Rails validation)' do
@@ -258,28 +271,38 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
258
271
  # ===========================================================================
259
272
 
260
273
  context '#replace' do
261
- it 'replaces all attributes in an instance' do
262
- expect_any_instance_of(MockUsersController).to receive(:replace).once.and_call_original
263
- expect {
264
- put "/Users/#{@u2.id}", params: {
265
- format: :scim,
266
- userName: '4' # Minimum required by schema
267
- }
268
- }.to_not change { MockUser.count }
274
+ shared_examples 'a replacer' do | force_upper_case: |
275
+ it 'which replaces all attributes in an instance' do
276
+ attributes = { userName: '4' } # Minimum required by schema
277
+ attributes = spec_helper_hupcase(attributes) if force_upper_case
269
278
 
270
- expect(response.status).to eql(200)
271
- result = JSON.parse(response.body)
279
+ expect_any_instance_of(MockUsersController).to receive(:replace).once.and_call_original
280
+ expect {
281
+ put "/Users/#{@u2.id}", params: attributes.merge(format: :scim)
282
+ }.to_not change { MockUser.count }
272
283
 
273
- expect(result['id']).to eql(@u2.id.to_s)
274
- expect(result['meta']['resourceType']).to eql('User')
284
+ expect(response.status).to eql(200)
285
+ result = JSON.parse(response.body)
275
286
 
276
- @u2.reload
287
+ expect(result['id']).to eql(@u2.id.to_s)
288
+ expect(result['meta']['resourceType']).to eql('User')
277
289
 
278
- expect(@u2.username).to eql('4')
279
- expect(@u2.first_name).to be_nil
280
- expect(@u2.last_name).to be_nil
281
- expect(@u2.home_email_address).to be_nil
282
- end
290
+ @u2.reload
291
+
292
+ expect(@u2.username).to eql('4')
293
+ expect(@u2.first_name).to be_nil
294
+ expect(@u2.last_name).to be_nil
295
+ expect(@u2.home_email_address).to be_nil
296
+ end
297
+ end # "shared_examples 'a replacer' do | force_upper_case: |"
298
+
299
+ context 'using schema-matched case' do
300
+ it_behaves_like 'a replacer', force_upper_case: false
301
+ end # "context 'using schema-matched case' do"
302
+
303
+ context 'using upper case' do
304
+ it_behaves_like 'a replacer', force_upper_case: true
305
+ end # "context 'using upper case' do"
283
306
 
284
307
  it 'notes schema validation failures' do
285
308
  expect {
@@ -341,11 +364,9 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
341
364
  # ===========================================================================
342
365
 
343
366
  context '#update' do
344
- it 'patches specific attributes' do
345
- expect_any_instance_of(MockUsersController).to receive(:update).once.and_call_original
346
- expect {
347
- patch "/Users/#{@u2.id}", params: {
348
- format: :scim,
367
+ shared_examples 'an updater' do | force_upper_case: |
368
+ it 'which patches specific attributes' do
369
+ payload = {
349
370
  Operations: [
350
371
  {
351
372
  op: 'add',
@@ -359,33 +380,36 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
359
380
  }
360
381
  ]
361
382
  }
362
- }.to_not change { MockUser.count }
363
383
 
364
- expect(response.status).to eql(200)
365
- result = JSON.parse(response.body)
384
+ payload = spec_helper_hupcase(payload) if force_upper_case
366
385
 
367
- expect(result['id']).to eql(@u2.id.to_s)
368
- expect(result['meta']['resourceType']).to eql('User')
386
+ expect_any_instance_of(MockUsersController).to receive(:update).once.and_call_original
387
+ expect {
388
+ patch "/Users/#{@u2.id}", params: payload.merge(format: :scim)
389
+ }.to_not change { MockUser.count }
369
390
 
370
- @u2.reload
391
+ expect(response.status).to eql(200)
392
+ result = JSON.parse(response.body)
371
393
 
372
- expect(@u2.username).to eql('4')
373
- expect(@u2.first_name).to eql('Foo')
374
- expect(@u2.last_name).to eql('Bar')
375
- expect(@u2.home_email_address).to eql('home_2@test.com')
376
- expect(@u2.work_email_address).to eql('work_4@test.com')
377
- end
394
+ expect(result['id']).to eql(@u2.id.to_s)
395
+ expect(result['meta']['resourceType']).to eql('User')
378
396
 
379
- context 'clears attributes' do
380
- before :each do
381
- @u2.update!(work_email_address: 'work_2@test.com')
397
+ @u2.reload
398
+
399
+ expect(@u2.username).to eql('4')
400
+ expect(@u2.first_name).to eql('Foo')
401
+ expect(@u2.last_name).to eql('Bar')
402
+ expect(@u2.home_email_address).to eql('home_2@test.com')
403
+ expect(@u2.work_email_address).to eql('work_4@test.com')
382
404
  end
383
405
 
384
- it 'with simple paths' do
385
- expect_any_instance_of(MockUsersController).to receive(:update).once.and_call_original
386
- expect {
387
- patch "/Users/#{@u2.id}", params: {
388
- format: :scim,
406
+ context 'which clears attributes' do
407
+ before :each do
408
+ @u2.update!(work_email_address: 'work_2@test.com')
409
+ end
410
+
411
+ it 'with simple paths' do
412
+ payload = {
389
413
  Operations: [
390
414
  {
391
415
  op: 'remove',
@@ -393,28 +417,31 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
393
417
  }
394
418
  ]
395
419
  }
396
- }.to_not change { MockUser.count }
397
420
 
398
- expect(response.status).to eql(200)
399
- result = JSON.parse(response.body)
421
+ payload = spec_helper_hupcase(payload) if force_upper_case
400
422
 
401
- expect(result['id']).to eql(@u2.id.to_s)
402
- expect(result['meta']['resourceType']).to eql('User')
423
+ expect_any_instance_of(MockUsersController).to receive(:update).once.and_call_original
424
+ expect {
425
+ patch "/Users/#{@u2.id}", params: payload.merge(format: :scim)
426
+ }.to_not change { MockUser.count }
403
427
 
404
- @u2.reload
428
+ expect(response.status).to eql(200)
429
+ result = JSON.parse(response.body)
405
430
 
406
- expect(@u2.username).to eql('2')
407
- expect(@u2.first_name).to be_nil
408
- expect(@u2.last_name).to eql('Bar')
409
- expect(@u2.home_email_address).to eql('home_2@test.com')
410
- expect(@u2.work_email_address).to eql('work_2@test.com')
411
- end
431
+ expect(result['id']).to eql(@u2.id.to_s)
432
+ expect(result['meta']['resourceType']).to eql('User')
412
433
 
413
- it 'by array entry filter match' do
414
- expect_any_instance_of(MockUsersController).to receive(:update).once.and_call_original
415
- expect {
416
- patch "/Users/#{@u2.id}", params: {
417
- format: :scim,
434
+ @u2.reload
435
+
436
+ expect(@u2.username).to eql('2')
437
+ expect(@u2.first_name).to be_nil
438
+ expect(@u2.last_name).to eql('Bar')
439
+ expect(@u2.home_email_address).to eql('home_2@test.com')
440
+ expect(@u2.work_email_address).to eql('work_2@test.com')
441
+ end
442
+
443
+ it 'by array entry filter match' do
444
+ payload = {
418
445
  Operations: [
419
446
  {
420
447
  op: 'remove',
@@ -422,28 +449,31 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
422
449
  }
423
450
  ]
424
451
  }
425
- }.to_not change { MockUser.count }
426
452
 
427
- expect(response.status).to eql(200)
428
- result = JSON.parse(response.body)
453
+ payload = spec_helper_hupcase(payload) if force_upper_case
429
454
 
430
- expect(result['id']).to eql(@u2.id.to_s)
431
- expect(result['meta']['resourceType']).to eql('User')
455
+ expect_any_instance_of(MockUsersController).to receive(:update).once.and_call_original
456
+ expect {
457
+ patch "/Users/#{@u2.id}", params: payload.merge(format: :scim)
458
+ }.to_not change { MockUser.count }
432
459
 
433
- @u2.reload
460
+ expect(response.status).to eql(200)
461
+ result = JSON.parse(response.body)
434
462
 
435
- expect(@u2.username).to eql('2')
436
- expect(@u2.first_name).to eql('Foo')
437
- expect(@u2.last_name).to eql('Bar')
438
- expect(@u2.home_email_address).to eql('home_2@test.com')
439
- expect(@u2.work_email_address).to be_nil
440
- end
463
+ expect(result['id']).to eql(@u2.id.to_s)
464
+ expect(result['meta']['resourceType']).to eql('User')
441
465
 
442
- it 'by whole collection' do
443
- expect_any_instance_of(MockUsersController).to receive(:update).once.and_call_original
444
- expect {
445
- patch "/Users/#{@u2.id}", params: {
446
- format: :scim,
466
+ @u2.reload
467
+
468
+ expect(@u2.username).to eql('2')
469
+ expect(@u2.first_name).to eql('Foo')
470
+ expect(@u2.last_name).to eql('Bar')
471
+ expect(@u2.home_email_address).to eql('home_2@test.com')
472
+ expect(@u2.work_email_address).to be_nil
473
+ end
474
+
475
+ it 'by whole collection' do
476
+ payload = {
447
477
  Operations: [
448
478
  {
449
479
  op: 'remove',
@@ -451,23 +481,38 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
451
481
  }
452
482
  ]
453
483
  }
454
- }.to_not change { MockUser.count }
455
484
 
456
- expect(response.status).to eql(200)
457
- result = JSON.parse(response.body)
485
+ payload = spec_helper_hupcase(payload) if force_upper_case
458
486
 
459
- expect(result['id']).to eql(@u2.id.to_s)
460
- expect(result['meta']['resourceType']).to eql('User')
487
+ expect_any_instance_of(MockUsersController).to receive(:update).once.and_call_original
488
+ expect {
489
+ patch "/Users/#{@u2.id}", params: payload.merge(format: :scim)
490
+ }.to_not change { MockUser.count }
461
491
 
462
- @u2.reload
492
+ expect(response.status).to eql(200)
493
+ result = JSON.parse(response.body)
463
494
 
464
- expect(@u2.username).to eql('2')
465
- expect(@u2.first_name).to eql('Foo')
466
- expect(@u2.last_name).to eql('Bar')
467
- expect(@u2.home_email_address).to be_nil
468
- expect(@u2.work_email_address).to be_nil
469
- end
470
- end # "context 'clears attributes' do"
495
+ expect(result['id']).to eql(@u2.id.to_s)
496
+ expect(result['meta']['resourceType']).to eql('User')
497
+
498
+ @u2.reload
499
+
500
+ expect(@u2.username).to eql('2')
501
+ expect(@u2.first_name).to eql('Foo')
502
+ expect(@u2.last_name).to eql('Bar')
503
+ expect(@u2.home_email_address).to be_nil
504
+ expect(@u2.work_email_address).to be_nil
505
+ end
506
+ end # "context 'which clears attributes' do"
507
+ end # "shared_examples 'an updater' do | force_upper_case: |"
508
+
509
+ context 'using schema-matched case' do
510
+ it_behaves_like 'an updater', force_upper_case: false
511
+ end # "context 'using schema-matched case' do"
512
+
513
+ context 'using upper case' do
514
+ it_behaves_like 'an updater', force_upper_case: true
515
+ end # "context 'using upper case' do"
471
516
 
472
517
  it 'notes Rails validation failures' do
473
518
  expect {
@@ -23,7 +23,6 @@ RSpec.describe Scimitar::ApplicationController do
23
23
 
24
24
  expect(response).to have_http_status(:bad_request)
25
25
  expect(JSON.parse(response.body)['detail']).to start_with('Invalid JSON - ')
26
- expect(JSON.parse(response.body)['detail']).to include("'not-json-12345'")
27
26
  end
28
27
 
29
28
  it 'translates Content-Type to Rails request format' do
@@ -10,11 +10,36 @@ RSpec.describe Scimitar::Engine do
10
10
  # "params" given here as a String, expecting the engine's custom parser to
11
11
  # decode it for us.
12
12
  #
13
- it 'decodes JSON', type: :model do
13
+ it 'decodes simple JSON', type: :model do
14
14
  post '/Users.scim', params: '{"userName": "foo"}', headers: { 'CONTENT_TYPE' => 'application/scim+json' }
15
15
 
16
16
  expect(response.status).to eql(201)
17
17
  expect(JSON.parse(response.body)['userName']).to eql('foo')
18
18
  end
19
+
20
+ it 'decodes nested JSON', type: :model do
21
+ post '/Users.scim', params: '{"userName": "foo", "name": {"givenName": "bar", "familyName": "baz"}}', headers: { 'CONTENT_TYPE' => 'application/scim+json' }
22
+
23
+ expect(response.status).to eql(201)
24
+ expect(JSON.parse(response.body)['userName']).to eql('foo')
25
+ expect(JSON.parse(response.body)['name']['givenName']).to eql('bar')
26
+ expect(JSON.parse(response.body)['name']['familyName']).to eql('baz')
27
+ end
28
+
29
+ it 'is case insensitive at the top level', type: :model do
30
+ post '/Users.scim', params: '{"USERNAME": "foo"}', headers: { 'CONTENT_TYPE' => 'application/scim+json' }
31
+
32
+ expect(response.status).to eql(201)
33
+ expect(JSON.parse(response.body)['userName']).to eql('foo')
34
+ end
35
+
36
+ it 'is case insensitive in nested levels', type: :model do
37
+ post '/Users.scim', params: '{"USERNAME": "foo", "NAME": {"GIVENNAME": "bar", "FAMILYNAME": "baz"}}', headers: { 'CONTENT_TYPE' => 'application/scim+json' }
38
+
39
+ expect(response.status).to eql(201)
40
+ expect(JSON.parse(response.body)['userName']).to eql('foo')
41
+ expect(JSON.parse(response.body)['name']['givenName']).to eql('bar')
42
+ expect(JSON.parse(response.body)['name']['familyName']).to eql('baz')
43
+ end
19
44
  end # "context 'parameter parser' do"
20
45
  end
data/spec/spec_helper.rb CHANGED
@@ -64,3 +64,30 @@ def spec_helper_capture_stdout( &block )
64
64
 
65
65
  return result
66
66
  end
67
+
68
+ # Recursively transform the keys of any given Hash or any Hashes in a given
69
+ # Array into uppercase form, retaining Symbol or String keys. Returns the
70
+ # transformed duplicate structure.
71
+ #
72
+ # Only Hashes or Hash entries within an Array are converted. Other data is left
73
+ # alone. The original input item is not modified.
74
+ #
75
+ # IMPORTANT: HashWithIndifferentAccess or similar subclasses are not supported.
76
+ #
77
+ # +item+:: Hash or Array that might contain some Hashes.
78
+ #
79
+ def spec_helper_hupcase(item)
80
+ if item.is_a?(Hash)
81
+ rehash = item.transform_keys(&:upcase)
82
+ rehash.each do | key, value |
83
+ rehash[key] = spec_helper_hupcase(value)
84
+ end
85
+ rehash
86
+ elsif item.is_a?(Array)
87
+ item.map do | array_entry |
88
+ spec_helper_hupcase(array_entry)
89
+ end
90
+ else
91
+ item
92
+ end
93
+ end
@@ -0,0 +1,30 @@
1
+ # Self-test. Sometimes tests call into utility methods in spec_helper.rb;
2
+ # if those aren't doing what they should, then the tests might give false
3
+ # positive passes.
4
+ #
5
+ require 'spec_helper'
6
+
7
+ RSpec.describe 'spec_helper.rb self-test' do
8
+ context '#spec_helper_hupcase' do
9
+ it 'converts a flat Hash, preserving data type of keys' do
10
+ input = {:one => 1, 'two' => 2}
11
+ output = spec_helper_hupcase(input)
12
+
13
+ expect(output).to eql({:ONE => 1, 'TWO' => 2})
14
+ end
15
+
16
+ it 'converts a nested Hash' do
17
+ input = {:one => 1, 'two' => {:tHrEe => {'fOuR' => 4}}}
18
+ output = spec_helper_hupcase(input)
19
+
20
+ expect(output).to eql({:ONE => 1, 'TWO' => {:THREE => {'FOUR' => 4}}})
21
+ end
22
+
23
+ it 'converts an Array with Hashes' do
24
+ input = {:one => 1, 'two' => [true, 42, {:tHrEe => {'fOuR' => 4}}]}
25
+ output = spec_helper_hupcase(input)
26
+
27
+ expect(output).to eql({:ONE => 1, 'TWO' => [true, 42, {:THREE => {'FOUR' => 4}}]})
28
+ end
29
+ end # "context '#spec_helper_hupcase' do"
30
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Scimitar::Support::HashWithIndifferentCaseInsensitiveAccess do
4
+ shared_examples 'an indifferent access, case insensitive Hash' do
5
+ context 'where keys set as strings' do
6
+ it 'can be retrieved via any case' do
7
+ subject()['foo'] = 1
8
+
9
+ expect(subject()['FOO']).to eql(1)
10
+ expect(subject()[:FoO ]).to eql(1)
11
+ expect(subject()['bar']).to be_nil
12
+ end
13
+
14
+ it 'can be checked for via any case' do
15
+ subject()['foo'] = 1
16
+
17
+ expect(subject()).to have_key('FOO')
18
+ expect(subject()).to have_key(:FoO )
19
+ expect(subject()).to_not have_key('bar')
20
+ end
21
+ end # "context 'where keys set as strings' do"
22
+
23
+ context 'where keys set as symbols' do
24
+ it 'retrieves via any case' do
25
+ subject()[:foo] = 1
26
+
27
+ expect(subject()['FOO']).to eql(1)
28
+ expect(subject()[:FoO ]).to eql(1)
29
+ expect(subject()['bar']).to be_nil
30
+ end
31
+
32
+ it 'enquires via any case' do
33
+ subject()[:foo] = 1
34
+
35
+ expect(subject()).to have_key('FOO')
36
+ expect(subject()).to have_key(:FoO )
37
+ expect(subject()).to_not have_key('bar')
38
+ end
39
+ end # "context 'where keys set as symbols' do"
40
+ end # "shared_examples 'an indifferent access, case insensitive Hash' do"
41
+
42
+ context 'when created directly' do
43
+ subject do
44
+ described_class.new()
45
+ end
46
+
47
+ it_behaves_like 'an indifferent access, case insensitive Hash'
48
+ end # "context 'when created directly' do"
49
+
50
+ context 'when created through conversion' do
51
+ subject do
52
+ { 'test' => 2 }.with_indifferent_access.with_indifferent_case_insensitive_access()
53
+ end
54
+
55
+ it 'includes the original data' do
56
+ expect(subject()[:TEST]).to eql(2)
57
+ end
58
+
59
+ it_behaves_like 'an indifferent access, case insensitive Hash'
60
+ end # "context 'converting hashes' do"
61
+ end