lazy-uuid 0.5.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.
@@ -0,0 +1,3 @@
1
+ module LazyUuid
2
+ VERSION = '0.5.0'
3
+ end
@@ -0,0 +1,43 @@
1
+ require 'securerandom'
2
+ require 'lazy-uuid/uuid'
3
+
4
+ FactoryGirl.define do
5
+ factory :uuid_str, class: String do
6
+ trait :no_dashes do
7
+ after(:build) do |uuid_str|
8
+ uuid_str.delete!('-')
9
+ end
10
+ end
11
+
12
+ initialize_with { SecureRandom.uuid }
13
+ end
14
+
15
+ factory :uuid_value, class: String do
16
+ transient do
17
+ association :source, :factory => :uuid_str, :strategy => :build
18
+ end
19
+
20
+ initialize_with { source.delete('-').scan(/../).map(&:hex).pack('C*') }
21
+ end
22
+
23
+ factory :uuid, class: Uuid do
24
+ transient do
25
+ source nil
26
+ end
27
+
28
+ initialize_with do
29
+ case source
30
+ when nil
31
+ Uuid.generate
32
+ when Uuid
33
+ Uuid.new(source.value)
34
+ else
35
+ if source.length == 16
36
+ Uuid.new(source)
37
+ else
38
+ Uuid.new(build(:uuid_value, :source => source))
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,85 @@
1
+ if RUBY_PLATFORM != 'java'
2
+ # Code Climate test coverage.
3
+ begin
4
+ require 'codeclimate-test-reporter'
5
+ CodeClimate::TestReporter.start
6
+ rescue
7
+ # Continue without Code Climate test coverage.
8
+ end
9
+ end
10
+
11
+ require 'rspec'
12
+ require 'factory_girl'
13
+
14
+ RSpec.configure do |config|
15
+ # rspec-expectations config goes here. You can use an alternate
16
+ # assertion/expectation library such as wrong or the stdlib/minitest
17
+ # assertions if you prefer.
18
+ config.expect_with :rspec do |expectations|
19
+ # This option will default to `true` in RSpec 4. It makes the `description`
20
+ # and `failure_message` of custom matchers include text for helper methods
21
+ # defined using `chain`, e.g.:
22
+ # be_bigger_than(2).and_smaller_than(4).description
23
+ # # => "be bigger than 2 and smaller than 4"
24
+ # ...rather than:
25
+ # # => "be bigger than 2"
26
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
27
+ end
28
+
29
+ # rspec-mocks config goes here. You can use an alternate test double
30
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
31
+ config.mock_with :rspec do |mocks|
32
+ # Prevents you from mocking or stubbing a method that does not exist on
33
+ # a real object. This is generally recommended, and will default to
34
+ # `true` in RSpec 4.
35
+ mocks.verify_partial_doubles = true
36
+ end
37
+
38
+ # Allows RSpec to persist some state between runs in order to support
39
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
40
+ # you configure your source control system to ignore this file.
41
+ config.example_status_persistence_file_path = 'spec/examples.txt'
42
+
43
+ # Limits the available syntax to the non-monkey patched syntax that is
44
+ # recommended. For more details, see:
45
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
46
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
47
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
48
+ config.disable_monkey_patching!
49
+
50
+ # This setting enables warnings. It's recommended, but in some cases may
51
+ # be too noisy due to issues in dependencies.
52
+ config.warnings = true
53
+
54
+ # Many RSpec users commonly either run the entire suite or an individual
55
+ # file, and it's useful to allow more verbose output when running an
56
+ # individual spec file.
57
+ if config.files_to_run.one?
58
+ # Use the documentation formatter for detailed output,
59
+ # unless a formatter has already been configured
60
+ # (e.g. via a command-line flag).
61
+ config.default_formatter = 'doc'
62
+ end
63
+
64
+ # Run specs in random order to surface order dependencies. If you find an
65
+ # order dependency and want to debug it, you can fix the order by providing
66
+ # the seed, which is printed after each run.
67
+ # --seed 1234
68
+ config.order = :random
69
+
70
+ # Seed global randomization in this process using the `--seed` CLI option.
71
+ # Setting this allows you to use `--seed` to deterministically reproduce
72
+ # test failures related to randomization by passing the same `--seed` value
73
+ # as the one that triggered the failure.
74
+ Kernel.srand config.seed
75
+
76
+ # Include FactoryGirl for building test objects.
77
+ config.include FactoryGirl::Syntax::Methods
78
+ end
79
+
80
+ # Include the library.
81
+ require_relative '../lib/lazy-uuid'
82
+
83
+ # Include factories.
84
+ FactoryGirl.definition_file_paths << File.join(File.dirname(__FILE__), 'factories')
85
+ FactoryGirl.find_definitions
@@ -0,0 +1,457 @@
1
+ require_relative 'spec_helper'
2
+
3
+ RSpec::Matchers.define :be_a_valid_uuid_string do
4
+ match do |actual|
5
+ !!/^\A[0-9a-f]{8}(-?)[0-9a-f]{4}\1[1-5][0-9a-f]{3}\1[89ab][0-9a-f]{3}\1[0-9a-f]{12}\z$/i.match(actual)
6
+ end
7
+
8
+ description do
9
+ 'be a valid UUID string'
10
+ end
11
+
12
+ failure_message do |actual|
13
+ "expected that #{actual} would be a valid UUID string"
14
+ end
15
+
16
+ failure_message_when_negated do |actual|
17
+ "expected that #{actual} would not be a valid UUID string"
18
+ end
19
+ end
20
+
21
+ RSpec.describe Uuid do
22
+
23
+ describe '::DEFAULT' do
24
+ subject { Uuid::DEFAULT }
25
+
26
+ it 'is all zeroes' do
27
+ is_expected.to eq("\x0" * 16)
28
+ end
29
+
30
+ it 'is frozen' do
31
+ is_expected.to be_frozen
32
+ end
33
+ end
34
+
35
+ describe '#initialize' do
36
+ context 'with a valid value' do
37
+ let(:uuid_value) { build(:uuid_value) }
38
+ subject(:uuid) { described_class.new(uuid_value) }
39
+
40
+ describe 'the value' do
41
+ subject { uuid.value }
42
+
43
+ it 'is stored' do
44
+ is_expected.to eq uuid_value
45
+ end
46
+ end
47
+ end
48
+
49
+ context 'with an invalid value' do
50
+ let(:uuid_value) { 'foobar' }
51
+
52
+ it 'throws an ArgumentError' do
53
+ expect { subject }.to raise_error(ArgumentError)
54
+ end
55
+ end
56
+ end
57
+
58
+ describe '.generate' do
59
+ subject(:uuid) { described_class.generate }
60
+
61
+ describe 'the value' do
62
+ subject { uuid.value }
63
+
64
+ # The UUID standards don't allow generated UUID to be all zeroes.
65
+ it 'is not DEFAULT' do
66
+ is_expected.to_not eq("\x0" * 16)
67
+ end
68
+
69
+ # The chances of two randomly generated UUIDs being identical is virtually impossible.
70
+ it 'is random' do
71
+ other = build(:uuid)
72
+ is_expected.to_not eq other
73
+ end
74
+ end
75
+
76
+ describe 'the string' do
77
+ subject { uuid.to_s }
78
+
79
+ it 'is valid' do
80
+ is_expected.to be_a_valid_uuid_string
81
+ end
82
+ end
83
+ end
84
+
85
+ describe '.parse' do
86
+ subject { described_class.parse(uuid_str) }
87
+
88
+ context 'with a valid argument' do
89
+ context 'with dashes' do
90
+ let(:uuid_str) { build(:uuid_str) }
91
+
92
+ it 'parses correctly' do
93
+ is_expected.to eq uuid_str
94
+ end
95
+ end
96
+
97
+ context 'without dashes' do
98
+ let(:uuid_str) { build(:uuid_str, :no_dashes) }
99
+
100
+ it 'parses correctly' do
101
+ is_expected.to eq uuid_str
102
+ end
103
+ end
104
+ end
105
+
106
+ context 'with a malformed string' do
107
+ let(:uuid_str) { 'foobar' }
108
+
109
+ it 'returns nil' do
110
+ is_expected.to be_nil
111
+ end
112
+ end
113
+
114
+ context 'with an invalid argument' do
115
+ let(:uuid_str) { 5 }
116
+
117
+ it 'raises an ArgumentError' do
118
+ expect { subject }.to raise_error(ArgumentError)
119
+ end
120
+ end
121
+
122
+ context 'with newlines' do
123
+ let(:uuid_str) { "\n" + build(:uuid_str) + "\n" }
124
+
125
+ it 'returns nil' do
126
+ is_expected.to be_nil
127
+ end
128
+ end
129
+ end
130
+
131
+ describe '#value' do
132
+ let(:uuid) { build(:uuid) }
133
+ subject(:value) { uuid.value }
134
+
135
+ it 'is a string' do
136
+ is_expected.to be_a String
137
+ end
138
+
139
+ it 'is frozen' do
140
+ is_expected.to be_frozen
141
+ end
142
+
143
+ it 'is 16 bytes' do
144
+ expect(value.length).to be 16
145
+ end
146
+ end
147
+
148
+ describe '#eql?' do
149
+ let(:uuid) { build(:uuid) }
150
+ subject { uuid.eql?(other) }
151
+
152
+ context 'with two identical UUIDs' do
153
+ let(:other) { build(:uuid, :source => uuid) }
154
+
155
+ it 'returns true' do
156
+ is_expected.to eq true
157
+ end
158
+ end
159
+
160
+ context 'with two different UUIDs' do
161
+ let(:other) { build(:uuid) }
162
+
163
+ it 'returns false' do
164
+ is_expected.to eq false
165
+ end
166
+ end
167
+
168
+ context 'without a UUID' do
169
+ let(:other) { 'foobar' }
170
+
171
+ it 'returns false' do
172
+ is_expected.to eq false
173
+ end
174
+ end
175
+ end
176
+
177
+ describe '#==' do
178
+ let(:uuid) { build(:uuid) }
179
+ subject { uuid == other }
180
+
181
+ context 'with equal UUIDs' do
182
+ let(:other) { build(:uuid, :source => uuid) }
183
+
184
+ it 'is true' do
185
+ is_expected.to be true
186
+ end
187
+ end
188
+
189
+ context 'with the same instance' do
190
+ let(:other) { uuid }
191
+
192
+ it 'is true' do
193
+ is_expected.to be true
194
+ end
195
+ end
196
+
197
+ context 'with unequal UUIDs' do
198
+ let(:other) { build(:uuid) }
199
+
200
+ it 'is false' do
201
+ is_expected.to be false
202
+ end
203
+ end
204
+
205
+ context 'with nil' do
206
+ let(:other) { nil }
207
+
208
+ it 'is false' do
209
+ is_expected.to be false
210
+ end
211
+ end
212
+
213
+ context 'with a malformed string' do
214
+ let(:other) { 'foobar' }
215
+
216
+ it 'is false' do
217
+ is_expected.to be false
218
+ end
219
+ end
220
+
221
+ context 'with a non-string' do
222
+ let(:other) { 5 }
223
+
224
+ it 'is false' do
225
+ is_expected.to be false
226
+ end
227
+ end
228
+
229
+ context 'with identical value' do
230
+ let(:other) { uuid.value }
231
+
232
+ it 'is true' do
233
+ is_expected.to be true
234
+ end
235
+ end
236
+
237
+ context 'with identical string' do
238
+ let(:other) { uuid.to_s }
239
+
240
+ it 'is true' do
241
+ is_expected.to be true
242
+ end
243
+ end
244
+ end
245
+
246
+ describe '#<=>' do
247
+ let(:lesser) { 'de305d54-75b4-431b-adb2-eb6b9e546014' }
248
+ let(:greater) { 'de305d54-75b4-431b-adb2-eb6b9e546020' }
249
+ subject { first <=> second }
250
+
251
+ context 'with an equal UUID' do
252
+ let(:first) { build(:uuid) }
253
+ let(:second) { build(:uuid, :source => first) }
254
+
255
+ it 'is 0' do
256
+ is_expected.to eq 0
257
+ end
258
+ end
259
+
260
+ context 'with the same instance' do
261
+ let(:first) { build(:uuid) }
262
+ let(:second) { first }
263
+
264
+ it 'is 0' do
265
+ is_expected.to eq 0
266
+ end
267
+ end
268
+
269
+ context 'with a lesser UUID' do
270
+ let(:first) { build(:uuid, :source => greater) }
271
+ let(:second) { build(:uuid, :source => lesser) }
272
+
273
+ it 'is 1' do
274
+ is_expected.to eq 1
275
+ end
276
+ end
277
+
278
+ context 'with a greater UUID' do
279
+ let(:first) { build(:uuid, :source => lesser) }
280
+ let(:second) { build(:uuid, :source => greater) }
281
+
282
+ it 'is -1' do
283
+ is_expected.to eq(-1)
284
+ end
285
+ end
286
+
287
+ context 'with nil' do
288
+ let(:first) { build(:uuid) }
289
+ let(:second) { nil }
290
+
291
+ it 'is nil' do
292
+ is_expected.to be_nil
293
+ end
294
+ end
295
+
296
+ context 'with a number' do
297
+ let(:first) { build(:uuid) }
298
+ let(:second) { 500 }
299
+
300
+ it 'is nil' do
301
+ is_expected.to be_nil
302
+ end
303
+ end
304
+
305
+ context 'with an identical value' do
306
+ let(:first) { build(:uuid) }
307
+ let(:second) { first.value }
308
+
309
+ it 'is 0' do
310
+ is_expected.to eq 0
311
+ end
312
+ end
313
+
314
+ context 'with a lesser value' do
315
+ let(:first) { build(:uuid, :source => greater) }
316
+ let(:second) { build(:uuid_value, :source => lesser) }
317
+
318
+ it 'is 1' do
319
+ is_expected.to eq 1
320
+ end
321
+ end
322
+
323
+ context 'with a greater value' do
324
+ let(:first) { build(:uuid, :source => lesser) }
325
+ let(:second) { build(:uuid_value, :source => greater) }
326
+
327
+ it 'is -1' do
328
+ is_expected.to eq(-1)
329
+ end
330
+ end
331
+
332
+ context 'with an equal string' do
333
+ let(:first) { build(:uuid) }
334
+ let(:second) { first.to_s }
335
+
336
+ it 'is 0' do
337
+ is_expected.to eq 0
338
+ end
339
+ end
340
+
341
+ context 'with a lesser string' do
342
+ let(:first) { build(:uuid, :source => greater) }
343
+ let(:second) { lesser }
344
+
345
+ it 'is 1' do
346
+ is_expected.to eq 1
347
+ end
348
+ end
349
+
350
+ context 'with a greater string' do
351
+ let(:first) { build(:uuid, :source => lesser) }
352
+ let(:second) { greater }
353
+
354
+ it 'is -1' do
355
+ is_expected.to eq(-1)
356
+ end
357
+ end
358
+
359
+ context 'with an invalid string' do
360
+ let(:first) { build(:uuid) }
361
+ let(:second) { 'foobar' }
362
+
363
+ it 'is nil' do
364
+ is_expected.to be_nil
365
+ end
366
+ end
367
+ end
368
+
369
+ describe '#hash' do
370
+ let(:uuid) { build(:uuid) }
371
+ subject { uuid.hash }
372
+
373
+ it 'is a Fixnum' do
374
+ is_expected.to be_a Fixnum
375
+ end
376
+
377
+ context 'with identical UUIDs' do
378
+ let(:first) { build(:uuid) }
379
+ let(:second) { build(:uuid, :source => first) }
380
+
381
+ it 'returns identical values' do
382
+ expect(first.hash).to eq(second.hash)
383
+ end
384
+ end
385
+
386
+ context 'with different UUIDs' do
387
+ let(:first) { build(:uuid) }
388
+ let(:second) { build(:uuid) }
389
+
390
+ it 'returns different values' do
391
+ expect(first.hash).to_not eq(second.hash)
392
+ end
393
+ end
394
+ end
395
+
396
+ describe '#to_s' do
397
+ let(:uuid_str) { build(:uuid_str) }
398
+ let(:uuid) { build(:uuid, :source => uuid_str) }
399
+ subject { uuid.to_s }
400
+
401
+ it 'is a String' do
402
+ is_expected.to be_a String
403
+ end
404
+
405
+ it 'is a valid UUID string' do
406
+ is_expected.to be_a_valid_uuid_string
407
+ end
408
+
409
+ it 'equals the initial value' do
410
+ is_expected.to eq uuid_str
411
+ end
412
+
413
+ it 'contains dashes' do
414
+ is_expected.to include '-'
415
+ end
416
+
417
+ context 'with bytes less than 16' do
418
+ let(:uuid_str) { '05305d54-7502-431b-adb2-eb6b9e546000' }
419
+ let(:uuid) { build(:uuid, :source => uuid_str) }
420
+
421
+ it 'pads with zeroes' do
422
+ is_expected.to eq uuid_str
423
+ end
424
+ end
425
+
426
+ context 'with dashes set to false' do
427
+ let(:uuid_str) { build(:uuid_str, :no_dashes) }
428
+ subject { uuid.to_s(false) }
429
+
430
+ it 'is a String' do
431
+ is_expected.to be_a String
432
+ end
433
+
434
+ it 'is a valid UUID string' do
435
+ is_expected.to be_a_valid_uuid_string
436
+ end
437
+
438
+ it 'equals the initial value' do
439
+ is_expected.to eq uuid_str
440
+ end
441
+
442
+ it 'does not contain dashes' do
443
+ is_expected.not_to include '-'
444
+ end
445
+
446
+ context 'with bytes less than 16' do
447
+ let(:uuid_str) { '05305d547502431badb2eb6b9e546000' }
448
+ let(:uuid) { build(:uuid, :source => uuid_str) }
449
+
450
+ it 'pads with zeroes' do
451
+ is_expected.to eq uuid_str
452
+ end
453
+ end
454
+ end
455
+ end
456
+
457
+ end