mirror of
https://github.com/ruby/ruby.git
synced 2025-08-28 23:45:55 +02:00
178 lines
4.8 KiB
Ruby
178 lines
4.8 KiB
Ruby
require 'test/unit'
|
|
require 'random/formatter'
|
|
|
|
module Random::Formatter
|
|
module FormatterTest
|
|
def test_random_bytes
|
|
assert_equal(16, @it.random_bytes.size)
|
|
assert_equal(Encoding::ASCII_8BIT, @it.random_bytes.encoding)
|
|
65.times do |idx|
|
|
assert_equal(idx, @it.random_bytes(idx).size)
|
|
end
|
|
end
|
|
|
|
def test_hex
|
|
s = @it.hex
|
|
assert_equal(16 * 2, s.size)
|
|
assert_match(/\A\h+\z/, s)
|
|
33.times do |idx|
|
|
s = @it.hex(idx)
|
|
assert_equal(idx * 2, s.size)
|
|
assert_match(/\A\h*\z/, s)
|
|
end
|
|
end
|
|
|
|
def test_hex_encoding
|
|
assert_equal(Encoding::US_ASCII, @it.hex.encoding)
|
|
end
|
|
|
|
def test_base64
|
|
assert_equal(16, @it.base64.unpack1('m*').size)
|
|
17.times do |idx|
|
|
assert_equal(idx, @it.base64(idx).unpack1('m*').size)
|
|
end
|
|
end
|
|
|
|
def test_urlsafe_base64
|
|
safe = /[\n+\/]/
|
|
65.times do |idx|
|
|
assert_not_match(safe, @it.urlsafe_base64(idx))
|
|
end
|
|
# base64 can include unsafe byte
|
|
assert((0..10000).any? {|idx| safe =~ @it.base64(idx)}, "None of base64(0..10000) is url-safe")
|
|
end
|
|
|
|
def test_random_number_float
|
|
101.times do
|
|
v = @it.random_number
|
|
assert_in_range(0.0...1.0, v)
|
|
end
|
|
end
|
|
|
|
def test_random_number_float_by_zero
|
|
101.times do
|
|
v = @it.random_number(0)
|
|
assert_in_range(0.0...1.0, v)
|
|
end
|
|
end
|
|
|
|
def test_random_number_int
|
|
101.times do |idx|
|
|
next if idx.zero?
|
|
v = @it.random_number(idx)
|
|
assert_in_range(0...idx, v)
|
|
end
|
|
end
|
|
|
|
def test_uuid
|
|
uuid = @it.uuid
|
|
assert_equal(36, uuid.size)
|
|
|
|
# Check time_hi_and_version and clock_seq_hi_res bits (RFC 4122 4.4)
|
|
assert_equal('4', uuid[14])
|
|
assert_include(%w'8 9 a b', uuid[19])
|
|
|
|
assert_match(/\A\h{8}-\h{4}-\h{4}-\h{4}-\h{12}\z/, uuid)
|
|
end
|
|
|
|
def assert_uuid_v7(**opts)
|
|
t1 = current_uuid7_time(**opts)
|
|
uuid = @it.uuid_v7(**opts)
|
|
t3 = current_uuid7_time(**opts)
|
|
|
|
assert_match(/\A\h{8}-\h{4}-7\h{3}-[89ab]\h{3}-\h{12}\z/, uuid)
|
|
|
|
t2 = get_uuid7_time(uuid, **opts)
|
|
assert_operator(t1, :<=, t2)
|
|
assert_operator(t2, :<=, t3)
|
|
end
|
|
|
|
def test_uuid_v7
|
|
assert_uuid_v7
|
|
0.upto(12) do |extra_timestamp_bits|
|
|
assert_uuid_v7 extra_timestamp_bits: extra_timestamp_bits
|
|
end
|
|
end
|
|
|
|
# It would be nice to simply use Time#floor here. But that is problematic
|
|
# due to the difference between decimal vs binary fractions.
|
|
def current_uuid7_time(extra_timestamp_bits: 0)
|
|
denominator = (1 << extra_timestamp_bits).to_r
|
|
Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
|
|
.then {|ns| ((ns / 1_000_000r) * denominator).floor / denominator }
|
|
.then {|ms| Time.at(ms / 1000r, in: "+00:00") }
|
|
end
|
|
|
|
def get_uuid7_time(uuid, extra_timestamp_bits: 0)
|
|
denominator = (1 << extra_timestamp_bits) * 1000r
|
|
extra_chars = extra_timestamp_bits / 4
|
|
last_char_bits = extra_timestamp_bits % 4
|
|
extra_chars += 1 if last_char_bits != 0
|
|
timestamp_re = /\A(\h{8})-(\h{4})-7(\h{#{extra_chars}})/
|
|
timestamp_chars = uuid.match(timestamp_re).captures.join
|
|
timestamp = timestamp_chars.to_i(16)
|
|
timestamp >>= 4 - last_char_bits unless last_char_bits == 0
|
|
timestamp /= denominator
|
|
Time.at timestamp, in: "+00:00"
|
|
end
|
|
|
|
def test_alphanumeric
|
|
65.times do |n|
|
|
an = @it.alphanumeric(n)
|
|
assert_match(/\A[0-9a-zA-Z]*\z/, an)
|
|
assert_equal(n, an.length)
|
|
end
|
|
end
|
|
|
|
def test_alphanumeric_chars
|
|
[
|
|
[[*"0".."9"], /\A\d*\z/],
|
|
[[*"a".."t"], /\A[a-t]*\z/],
|
|
["一二三四五六七八九十".chars, /\A[一二三四五六七八九十]*\z/],
|
|
].each do |chars, pattern|
|
|
10.times do |n|
|
|
an = @it.alphanumeric(n, chars: chars)
|
|
assert_match(pattern, an)
|
|
assert_equal(n, an.length)
|
|
end
|
|
end
|
|
end
|
|
|
|
def assert_in_range(range, result, mesg = nil)
|
|
assert(range.cover?(result), build_message(mesg, "Expected #{result} to be in #{range}"))
|
|
end
|
|
end
|
|
|
|
module NotDefaultTest
|
|
def test_random_number_not_default
|
|
msg = "random_number should not be affected by srand"
|
|
seed = srand(0)
|
|
x = @it.random_number(1000)
|
|
10.times do|i|
|
|
srand(0)
|
|
return unless @it.random_number(1000) == x
|
|
end
|
|
srand(0)
|
|
assert_not_equal(x, @it.random_number(1000), msg)
|
|
ensure
|
|
srand(seed) if seed
|
|
end
|
|
end
|
|
|
|
class TestClassMethods < Test::Unit::TestCase
|
|
include FormatterTest
|
|
|
|
def setup
|
|
@it = Random
|
|
end
|
|
end
|
|
|
|
class TestInstanceMethods < Test::Unit::TestCase
|
|
include FormatterTest
|
|
include NotDefaultTest
|
|
|
|
def setup
|
|
@it = Random.new
|
|
end
|
|
end
|
|
end
|