Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: redirect console output #542

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

OutOfBedlam
Copy link

Add ability to re-direct console.log() to io.Writer instead of os.Stdout.

example

var buf = &bytes.Buffer{}
vm := otto.New(otto.WithStdoutWriter(buf))
vm.Run(`console.log('hello', 'world');`)

fmt.Println(buf.String())

Copy link
Collaborator

@stevenh stevenh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice addition thanks for the PR.

I've put some suggestions of how we could improve it a little.

o := &Otto{
runtime: newContext(),
}
o.runtime.otto = o
o.runtime.traceLimit = 10
for _, opt := range opts {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: lets set the default so we can simplify the use after.

Suggested change
for _, opt := range opts {
o.runtime.console = os.Stdout
for _, opt := range opts {

Comment on lines +19 to +25
var w io.Writer
if call.runtime.stdoutWriter != nil {
w = call.runtime.stdoutWriter
} else {
w = os.Stdout
}
fmt.Fprintln(w, formatForConsole(call.ArgumentList)) //nolint:errcheck // Nothing we can do if this fails.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: with the use of a default we can simply this.

Suggested change
var w io.Writer
if call.runtime.stdoutWriter != nil {
w = call.runtime.stdoutWriter
} else {
w = os.Stdout
}
fmt.Fprintln(w, formatForConsole(call.ArgumentList)) //nolint:errcheck // Nothing we can do if this fails.
fmt.Fprintln(call.runtime.console, formatForConsole(call.ArgumentList)) //nolint:errcheck // Nothing we can do if this fails.

Comment on lines +30 to +36
var w io.Writer
if call.runtime.stdoutWriter != nil {
w = call.runtime.stdoutWriter
} else {
w = os.Stdout
}
fmt.Fprintln(w, formatForConsole(call.ArgumentList)) //nolint:errcheck // Nothing we can do if this fails.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: simplify as above.

Suggested change
var w io.Writer
if call.runtime.stdoutWriter != nil {
w = call.runtime.stdoutWriter
} else {
w = os.Stdout
}
fmt.Fprintln(w, formatForConsole(call.ArgumentList)) //nolint:errcheck // Nothing we can do if this fails.
fmt.Fprintln(call.runtime.console, formatForConsole(call.ArgumentList)) //nolint:errcheck // Nothing we can do if this fails.

@@ -775,3 +779,11 @@ func (o Object) MarshalJSON() ([]byte, error) {
}
return json.Marshal(goValue)
}

type Option func(*Otto)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: lets document the type.

Comment on lines +785 to +787
func WithStdoutWriter(w io.Writer) Option {
return func(o *Otto) {
o.runtime.stdoutWriter = w
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: lets document the type and change the naming so it easier for the user to understand the impact of using this option.

Suggested change
func WithStdoutWriter(w io.Writer) Option {
return func(o *Otto) {
o.runtime.stdoutWriter = w
// WithConsoleOutput sets the target for console output.
// Default: Stdout.
func WithConsoleOutput(w io.Writer) Option {
return func(o *Otto) {
o.runtime.console = w

Comment on lines +1806 to +1833
func TestOtterStdoutWriter(t *testing.T) {
tests := []struct {
name string
script string
expect string
}{
{
name: "console.log",
script: "console.log('hello', 'world')",
expect: "hello world\n",
},
{
name: "console.err",
script: "console.error('error', 'world')",
expect: "error world\n",
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
var buf = &bytes.Buffer{}
vm := New(WithStdoutWriter(buf))
_, err := vm.Run(tc.script)
require.NoError(t, err)
require.Equal(t, tc.expect, buf.String())
})
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: can we use sub tests vs table driven as its more concise and allows developers to run specific tests directly from their editor e.g. VS Code.

Also the use of just a declared buffer vs instantiated is more idiomatic.

Not tested the below, so there might be typos, but you get the idea 😃

Suggested change
func TestOtterStdoutWriter(t *testing.T) {
tests := []struct {
name string
script string
expect string
}{
{
name: "console.log",
script: "console.log('hello', 'world')",
expect: "hello world\n",
},
{
name: "console.err",
script: "console.error('error', 'world')",
expect: "error world\n",
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
var buf = &bytes.Buffer{}
vm := New(WithStdoutWriter(buf))
_, err := vm.Run(tc.script)
require.NoError(t, err)
require.Equal(t, tc.expect, buf.String())
})
}
}
func TestOtto_WithConsoleOutput(t *testing.T) {
t.Run('console.log', func(t *testing.T) {
var buf bytes.Buffer
vm := New(WithConsoleOutput(&buf))
_, err := vm.Run("console.log('hello', 'world')")
require.NoError(t, err)
require.Equal(t, "hello world\n", buf.String())
})
t.Run('console.err', func(t *testing.T) {
var buf bytes.Buffer
vm := New(WithConsoleOutput(&buf))
_, err := vm.Run("console.error('world')")
require.NoError(t, err)
require.Equal(t, "error world\n", buf.String())
})
}

@@ -66,6 +67,7 @@ type runtime struct {
stackLimit int
traceLimit int
lck sync.Mutex
stdoutWriter io.Writer
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: make it clear the use vs the value

Suggested change
stdoutWriter io.Writer
console io.Writer

@stevenh stevenh changed the title Redirect console output to io.Writer feat: redirect console output Nov 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants