diff --git a/engine.go b/engine.go index f1b89c9..86a1ffa 100644 --- a/engine.go +++ b/engine.go @@ -113,6 +113,13 @@ func WithDebug() Opt { } } +// WithRandSource sets the random source to use in the engine. +func WithRandSource(randSource func() float64) Opt { + return func(e *Engine) { + e.randSource = randSource + } +} + // Engine provides the templating engine. type Engine struct { searchLocations []string @@ -125,6 +132,8 @@ type Engine struct { tracer trace.Tracer + randSource vm.RandSource + vm *vm.VM } @@ -248,7 +257,7 @@ func (e *Engine) init(ctx context.Context, data any) (*vm.VM, error) { return nil, ErrAlreadyInitialized } - v, err := vm.New() + v, err := vm.New(e.randSource) if err != nil { return nil, fmt.Errorf("failed to create vm: %w", err) } diff --git a/internal/vm/vm.go b/internal/vm/vm.go index 136ecac..7f2f027 100644 --- a/internal/vm/vm.go +++ b/internal/vm/vm.go @@ -50,6 +50,9 @@ type Options struct { // Option represents an option for running a script. type Option func(*Options) +// RandSource is a function that returns a seeded float64 value. +type RandSource func() float64 + // WithStartingLineNumber sets the starting line number for the script. func WithStartingLineNumber(lineNumber int) Option { return func(o *Options) { @@ -63,7 +66,7 @@ type program struct { } // New creates a new VM. -func New() (*VM, error) { +func New(randSource RandSource) (*VM, error) { g := goja.New() _, err := g.RunString(underscore.JS) if err != nil { @@ -73,6 +76,12 @@ func New() (*VM, error) { new(require.Registry).Enable(g) console.Enable(g) + if randSource != nil { + g.SetRandSource(func() float64 { + return randSource() + }) + } + return &VM{Runtime: g, globalSourceMapCache: make(map[string]*sourcemap.Consumer)}, nil } diff --git a/internal/vm/vm_test.go b/internal/vm/vm_test.go index d3e41ab..d1819bf 100644 --- a/internal/vm/vm_test.go +++ b/internal/vm/vm_test.go @@ -9,8 +9,30 @@ import ( "github.com/stretchr/testify/require" ) +func TestVM_Run_Runtime_Success(t *testing.T) { + v, err := vm.New(nil) + require.NoError(t, err) + + typeScript := `console.log("hello world");` + + _, err = v.Run(context.Background(), "test", typeScript) + assert.NoError(t, err) +} + +func TestVM_Run_Runtime_WithRandSource_Success(t *testing.T) { + v, err := vm.New(func() float64 { + return 0 + }) + require.NoError(t, err) + + typeScript := `console.log("hello world");` + + _, err = v.Run(context.Background(), "test", typeScript) + assert.NoError(t, err) +} + func TestVM_Run_Runtime_Errors(t *testing.T) { - v, err := vm.New() + v, err := vm.New(nil) require.NoError(t, err) typeScript := `type Test = {