Skip to content

Commit

Permalink
Merge pull request #2375 from herwinw/random_number_arg_nog_numeric
Browse files Browse the repository at this point in the history
More fixes to argument types of Random.rand and
(Secure)Random.random_number
  • Loading branch information
herwinw committed Dec 6, 2024
2 parents eaab765 + 193b9b0 commit 2f594e1
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 7 deletions.
4 changes: 4 additions & 0 deletions lib/securerandom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ Value SecureRandom_random_number(Env *env, Value self, Args &&args, Block *) {
env->raise("ArgumentError", "bad value for range");
}

auto Numeric = GlobalEnv::the()->Object()->const_get("Numeric"_s);
if (!arg->is_a(env, Numeric))
env->raise("ArgumentError", "No implicit conversion of {} into Integer", arg->klass()->inspect_str());

nat_int_t max = IntegerObject::convert_to_nat_int_t(env, arg);
if (max <= 0)
return generate_random(0.0, 1.0);
Expand Down
8 changes: 3 additions & 5 deletions spec/library/securerandom/random_number_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,8 @@
end

it "raises ArgumentError if the argument is non-numeric" do
NATFIXME 'it raises ArgumentError if the argument is non-numeric', exception: SpecFailedException do
-> {
SecureRandom.random_number(Object.new)
}.should raise_error(ArgumentError)
end
-> {
SecureRandom.random_number(Object.new)
}.should raise_error(ArgumentError)
end
end
8 changes: 6 additions & 2 deletions src/random.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@ def bytes(...)
end

def random_number(*args)
if args.size == 1 && args[0].is_a?(Numeric) && args[0].negative?
args[0] = 1.0
if args.size == 1
if args[0].nil? || ((args[0].is_a?(Integer) || args[0].is_a?(Float)) && args[0].negative?)
args[0] = 1.0
elsif !args[0].is_a?(Numeric)
raise ArgumentError, "invalid argument - #{args[0]}"
end
end
rand(*args)
end
Expand Down
3 changes: 3 additions & 0 deletions src/random_object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ Value RandomObject::rand(Env *env, Value arg) {
env->raise("ArgumentError", "bad value for range");
}

if (arg->is_nil())
env->raise("ArgumentError", "invalid argument - {}", arg->to_s(env)->string());

nat_int_t max = IntegerObject::convert_to_nat_int_t(env, arg);
if (max <= 0) {
env->raise("ArgumentError", "invalid argument - {}", arg->inspect_str(env));
Expand Down
89 changes: 89 additions & 0 deletions test/natalie/random_test.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
require_relative '../spec_helper'

require 'securerandom'

describe 'Random' do
it 'should extend Random::Formatter' do
Random.should be_kind_of(Random::Formatter)
Expand All @@ -19,5 +21,92 @@
0.0.should <= num
num.should < 1.0
end

it "generates a random float number between 0.0 and 1.0 if argument is nil" do
num = Random.random_number(nil)
num.should be_kind_of(Float)
0.0.should <= num
num.should < 1.0
end

it "raises ArgumentError if the argument is non-numeric" do
obj = Object.new
-> {
Random.random_number(obj)
}.should raise_error(ArgumentError, "invalid argument - #{obj}")
end

it "raises Random if the argument is imaginary" do
-> {
Random.random_number(1 + 2i)
}.should raise_error(RangeError)
end

it "raises RangeError if the argument is complex" do
-> {
Random.random_number(Complex(1, 2))
}.should raise_error(RangeError)
end
end

describe 'Random.rand' do
it "raises ArgumentError if argument is negative" do
-> {
Random.rand(-10)
}.should raise_error(ArgumentError, 'invalid argument - -10')
end

it "raises ArgumentError if argument is negative float" do
-> {
Random.rand(-11.1)
}.should raise_error(ArgumentError, 'invalid argument - -11.1')
end

it "raises ArgumentError if the argument is nil" do
-> {
Random.rand(nil)
}.should raise_error(ArgumentError, 'invalid argument - ')
end

it "raises TypeError if the argument is non-numeric" do
-> {
Random.rand(Object.new)
}.should raise_error(TypeError, 'no implicit conversion of Object into Integer')
end

it "raises RangeError if the argument is imaginary" do
-> {
Random.rand(1 + 2i)
}.should raise_error(RangeError)
end

it "raises RangeError if the argument is complex" do
-> {
Random.rand(Complex(1, 2))
}.should raise_error(RangeError)
end
end
end

describe 'SecureRandom' do
describe 'SecureRandom.random_number' do
it "generates a random float number between 0.0 and 1.0 if argument is nil" do
num = SecureRandom.random_number(nil)
num.should be_kind_of(Float)
0.0.should <= num
num.should < 1.0
end

it "raises RangeError if the argument is imaginary" do
-> {
SecureRandom.random_number(1 + 2i)
}.should raise_error(RangeError)
end

it "raises RangeError if the argument is complex" do
-> {
SecureRandom.random_number(Complex(1, 2))
}.should raise_error(RangeError)
end
end
end

0 comments on commit 2f594e1

Please sign in to comment.