diff --git a/builtin_math.go b/builtin_math.go index a9f4a55..7ce90c3 100644 --- a/builtin_math.go +++ b/builtin_math.go @@ -117,7 +117,13 @@ func builtinMath_pow(call FunctionCall) Value { } func builtinMath_random(call FunctionCall) Value { - return toValue_float64(rand.Float64()) + var v float64 + if call.runtime.random != nil { + v = call.runtime.random() + } else { + v = rand.Float64() + } + return toValue_float64(v) } func builtinMath_round(call FunctionCall) Value { diff --git a/otto.go b/otto.go index 2ec033c..6135330 100644 --- a/otto.go +++ b/otto.go @@ -363,6 +363,10 @@ func (self Otto) SetDebuggerHandler(fn func(vm *Otto)) { self.runtime.debugger = fn } +func (self Otto) SetRandomSource(fn func() float64) { + self.runtime.random = fn +} + // Context is a structure that contains information about the current execution // context. type Context struct { diff --git a/runtime.go b/runtime.go index 168cb1c..a998f7a 100644 --- a/runtime.go +++ b/runtime.go @@ -55,6 +55,7 @@ type _runtime struct { otto *Otto eval *_object // The builtin eval, for determine indirect versus direct invocation debugger func(*Otto) + random func() float64 labels []string // FIXME lck sync.Mutex diff --git a/runtime_test.go b/runtime_test.go index 247ecab..eeb1173 100644 --- a/runtime_test.go +++ b/runtime_test.go @@ -803,3 +803,32 @@ func Test_debugger(t *testing.T) { is(err, nil) }) } + +func Test_random(t *testing.T) { + tt(t, func() { + vm := New() + vm.SetRandomSource(func() float64 { return 1 }) + + r, err := vm.Run(`Math.random()`) + is(err, nil) + f, err := r.ToFloat() + is(err, nil) + is(f, 1) + }) + + tt(t, func() { + vm := New() + + r1, err := vm.Run(`Math.random()`) + is(err, nil) + f1, err := r1.ToFloat() + is(err, nil) + + r2, err := vm.Run(`Math.random()`) + is(err, nil) + f2, err := r2.ToFloat() + is(err, nil) + + is(f1 == f2, false) + }) +}