From 26f5ca59f228ef1462e93cb3c88982eda90b0743 Mon Sep 17 00:00:00 2001 From: Rubens Stulzer Date: Wed, 27 Mar 2024 11:05:27 +0100 Subject: [PATCH] Random letter prefix to CUID2 This commit introduces a random letter prefix to the CUID2 generation process. This change is intended to reduce the likelihood of CUID2 collisions. The random letter is generated from the range 'a' to 'z'. The tests have been updated to reflect this change. A new test has been added to ensure that CUID2s do not have the same first character. The collision test run and CUID2s per run values have been reduced for testing purposes. The version of the library has been bumped to 1.0.1. --- lib/cuid2.rb | 5 +---- lib/cuid2/version.rb | 2 +- spec/cuid2_spec.rb | 27 +++++++++++++++++++++++++-- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/lib/cuid2.rb b/lib/cuid2.rb index aaa2c5f..613345c 100644 --- a/lib/cuid2.rb +++ b/lib/cuid2.rb @@ -42,6 +42,7 @@ def self.create(input, length = BIG_LENGTH) class << self def call(length = DEFAULT_LENGTH) + random_letter = ('a'..'z').to_a[(rand * 26).floor] hash_input = (time + Entropy.create(length) + count + fingerprint).to_s "#{random_letter}#{Cuid2::Hash.create(hash_input, length)[2..length]}" @@ -67,10 +68,6 @@ def counter (rand + 1) * 2057 end - def random_letter - ('a'..'z').to_a[(random * 26).floor] - end - def fingerprint Cuid2::Hash.create("#{((random + 1) * 2063).floor} #{Object.constants.map(&:to_s)}") end diff --git a/lib/cuid2/version.rb b/lib/cuid2/version.rb index 4a8998a..13ead70 100644 --- a/lib/cuid2/version.rb +++ b/lib/cuid2/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Cuid2 - VERSION = '1.0.0' + VERSION = '1.0.1' end diff --git a/spec/cuid2_spec.rb b/spec/cuid2_spec.rb index f902c91..67cd74e 100644 --- a/spec/cuid2_spec.rb +++ b/spec/cuid2_spec.rb @@ -2,8 +2,8 @@ require 'cuid2' -COLISION_TEST_RUN = ENV.fetch('COLISION_TEST_RUN', 10).to_i -CUIDS_PER_RUN = ENV.fetch('CUIDS_PER_RUN', 100).to_i +COLISION_TEST_RUN = ENV.fetch('COLISION_TEST_RUN', 1).to_i +CUIDS_PER_RUN = ENV.fetch('CUIDS_PER_RUN', 10).to_i RSpec.describe Cuid2 do it 'has a version number' do @@ -25,4 +25,27 @@ expect(cuids.uniq.sort).to eq(cuids.sort) expect(cuids.sample).to match(/[a-z0-9]{24}/) end + + it 'should not collide with prefix' do + cuids = [] + COLISION_TEST_RUN.times do + CUIDS_PER_RUN.times do + cuids << Cuid2.call(prefix: 'test') + end + end + expect(cuids.uniq.size).to eq(cuids.size) + expect(cuids.size).to eq(COLISION_TEST_RUN * CUIDS_PER_RUN) + expect(cuids.uniq.size).to eq(COLISION_TEST_RUN * CUIDS_PER_RUN) + expect(cuids.uniq.sort).to eq(cuids.sort) + expect(cuids.sample).to match(/test[a-z0-9]{24}/) + end + + it 'should not have the same first character' do + cuids = [] + 5000.times do + cuids << Cuid2.call[0] + end + + expect(cuids.uniq.size).to be > 1 + end end