diff --git a/lib/securerandom.cpp b/lib/securerandom.cpp index a7686eca6..24ed7688e 100644 --- a/lib/securerandom.cpp +++ b/lib/securerandom.cpp @@ -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); diff --git a/spec/library/securerandom/random_number_spec.rb b/spec/library/securerandom/random_number_spec.rb index 12c511da0..b0a2963ee 100644 --- a/spec/library/securerandom/random_number_spec.rb +++ b/spec/library/securerandom/random_number_spec.rb @@ -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 diff --git a/src/random.rb b/src/random.rb index 9a177a27a..44ff76968 100644 --- a/src/random.rb +++ b/src/random.rb @@ -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 diff --git a/src/random_object.cpp b/src/random_object.cpp index de0ca5880..f246f5e5c 100644 --- a/src/random_object.cpp +++ b/src/random_object.cpp @@ -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)); diff --git a/test/natalie/random_test.rb b/test/natalie/random_test.rb index 8f1888647..5465b667c 100644 --- a/test/natalie/random_test.rb +++ b/test/natalie/random_test.rb @@ -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) @@ -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