Skip to content

Commit

Permalink
Merge pull request #64 from k2nr/bquorning/improve-ulid-validator
Browse files Browse the repository at this point in the history
Test and improve #valid_ulid? method
  • Loading branch information
bquorning authored Dec 12, 2023
2 parents 26bce04 + 10a99ad commit 303080e
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 1 deletion.
8 changes: 7 additions & 1 deletion lib/ulid/rails/type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,21 @@ def cast_string_to_ulid(value, data_class: Data)
end

class Data < ActiveModel::Type::Binary::Data
INVALID_CHARACTERS_REGEX = /[ilou]/i.freeze
VALID_INITIAL_CHARACTER_REGEX = /^[0-7]/i.freeze

def self.from_serialized(data)
deserialized = Base32::Crockford.encode(data.hex).rjust(26, "0")
new(deserialized)
end

def self.valid_ulid?(str)
return true if str.nil?
return false unless str.length == 26
return false if INVALID_CHARACTERS_REGEX.match?(str)
return false unless VALID_INITIAL_CHARACTER_REGEX.match?(str)

str.length == 26 && Base32::Crockford.valid?(str)
Base32::Crockford.valid?(str)
end

def initialize(value)
Expand Down
54 changes: 54 additions & 0 deletions test/ulid/rails/type_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
require "test_helper"

class ULID::Rails::Type::DataTest < Minitest::Test
def test_has_26_valid_characters
id = "01BX5ZZKBKACTAV9WEVGEMMVRZ"

assert ULID::Rails::Type::Data.valid_ulid?(id)
end

def test_length_less_than_26
id = "A" * 25

refute ULID::Rails::Type::Data.valid_ulid?(id)
end

def test_length_greater_than_26
id = "A" * 27

refute ULID::Rails::Type::Data.valid_ulid?(id)
end

# Crockford's Base32 is used as shown. This alphabet excludes
# the letters I, L, O, and U to avoid confusion and abuse.
# https://github.com/ulid/spec#encoding
def test_has_invalid_characters
invalid_characters = %w[I L O U]

invalid_characters.each do |char|
id = char * 26

refute ULID::Rails::Type::Data.valid_ulid?(id)
end
end

# The first character in a ULID must be 0, 7, or in between.
# Anything larger than 7, and the id would not fit into 16 bytes.
def test_does_not_exceed_16_bytes
valid_first_characters = ("0".."7").to_a

valid_first_characters.each do |char|
id = "#{char}#{"A" * 25}"

assert ULID::Rails::Type::Data.valid_ulid?(id)
end

invalid_first_characters = ("8".."9").to_a + ("A".."Z").to_a

invalid_first_characters.each do |char|
id = "#{char}#{"A" * 25}"

refute ULID::Rails::Type::Data.valid_ulid?(id)
end
end
end

0 comments on commit 303080e

Please sign in to comment.