Skip to content
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions internal/driver/interactive.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ func interactive(p *profile.Profile, o *plugin.Options) error {
value = strings.TrimSpace(value)
}
if v := pprofVariables[name]; v != nil {
// All non-bool options require inputs
if v.kind != boolKind && value == "" {
o.UI.PrintErr(fmt.Errorf("please input a value, e.g. %v", name+"=<val>"))
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit:
Here, I think %s would be more idiomatic than %v.
The following would be standard for Golang:

o.UI.PrintErr(fmt.Errorf("please input a value, e.g. %s=<val>", name))

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.
Really appreciate those comments to help me write better Go code. Thanks!

continue
}
if name == "sample_index" {
// Error check sample_index=xxx to ensure xxx is a valid sample type.
index, err := p.SampleIndexByName(value)
Expand Down Expand Up @@ -267,6 +272,9 @@ func parseCommandLine(input []string) ([]string, variables, error) {
}
}
if c == nil {
if v := pprofVariables[name]; v != nil {
return nil, nil, fmt.Errorf(`did you mean: %s?`, name+"="+args[0])
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: Same as above.
Also nit: I don't think back ticks have added benefit here, so I'd reccomend quotes,
So, following is more idiomatic (assuming args is a slice of strings):

fmt.Errorf("did you mean: %s=%s", name, args[0])

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

}
return nil, nil, fmt.Errorf("unrecognized command: %q", name)
}

Expand Down
100 changes: 42 additions & 58 deletions internal/driver/interactive_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,62 +40,53 @@ func TestShell(t *testing.T) {
savedVariables := pprofVariables
defer func() { pprofVariables = savedVariables }()

// Random interleave of independent scripts
pprofVariables = testVariables(savedVariables)
shortcuts1, scScript1 := makeShortcuts(interleave(script, 2), 1)
shortcuts2, scScript2 := makeShortcuts(interleave(script, 1), 2)

// pass in HTTPTransport when setting defaults, because otherwise default
// transport will try to add flags to the default flag set.
o := setDefaults(&plugin.Options{HTTPTransport: transport.New(nil)})
o.UI = newUI(t, interleave(script, 0))
if err := interactive(p, o); err != nil {
t.Error("first attempt:", err)
}
// Random interleave of independent scripts
pprofVariables = testVariables(savedVariables)
o.UI = newUI(t, interleave(script, 1))
if err := interactive(p, o); err != nil {
t.Error("second attempt:", err)
var testcases = []struct {
name string
input []string
shortcuts shortcuts
allowRx string
numAllowRxMatches int
propagateError bool
Copy link
Collaborator

Choose a reason for hiding this comment

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

This flag seems to be false in all test cases, is this expected?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Now fixed.
The conditional logic on line 79 was incorrect and is fixed now.

}{
{"Random interleave of independent scripts 1", interleave(script, 0), pprofShortcuts, "", 0, false},
{"Random interleave of independent scripts 2", interleave(script, 1), pprofShortcuts, "", 0, false},
{"Random interleave of independent scripts with shortcuts 1", scScript1, shortcuts1, "", 0, false},
{"Random interleave of independent scripts with shortcuts 2", scScript2, shortcuts2, "", 0, false},
{"Group with invalid vale", []string{"cumulative=this"}, pprofShortcuts, `unrecognized value for cumulative: "this". Use one of cum, flat`, 1, false},
Copy link
Contributor

Choose a reason for hiding this comment

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

(super nit) I think this is a typo: vale => value

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

{"No special value provided for the option", []string{"sample_index"}, pprofShortcuts, `please input a value, e.g. sample_index=<val>`, 1, false},
{"No string value provided for the option", []string{"focus="}, pprofShortcuts, `please input a value, e.g. focus=<val>`, 1, false},
{"No float value provided for the option", []string{"divide_by"}, pprofShortcuts, `please input a value, e.g. divide_by=<val>`, 1, false},
{"Helpful input format reminder", []string{"sample_index 0"}, pprofShortcuts, `did you mean: sample_index=0`, 1, false},
{"Verify propagation of IO errors", []string{"**error**"}, pprofShortcuts, "", 0, false},
}

// Random interleave of independent scripts with shortcuts
pprofVariables = testVariables(savedVariables)
var scScript []string
pprofShortcuts, scScript = makeShortcuts(interleave(script, 2), 1)
o.UI = newUI(t, scScript)
if err := interactive(p, o); err != nil {
t.Error("first shortcut attempt:", err)
}
o := setDefaults(&plugin.Options{HTTPTransport: transport.New(nil)})
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
pprofVariables = testVariables(savedVariables)
pprofShortcuts = tc.shortcuts
ui := &proftest.TestUI{
T: t,
Input: tc.input,
AllowRx: tc.allowRx,
}
o.UI = ui

// Random interleave of independent scripts with shortcuts
pprofVariables = testVariables(savedVariables)
pprofShortcuts, scScript = makeShortcuts(interleave(script, 1), 2)
o.UI = newUI(t, scScript)
if err := interactive(p, o); err != nil {
t.Error("second shortcut attempt:", err)
}
err := interactive(p, o)
if (tc.propagateError && err == nil) || (tc.propagateError && err != nil) {
t.Errorf("%v: %v", tc.name, err)
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: use %s when possible

t.Errorf("%s: %v", tc.name, err)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

}

// Group with invalid value
pprofVariables = testVariables(savedVariables)
ui := &proftest.TestUI{
T: t,
Input: []string{"cumulative=this"},
AllowRx: `unrecognized value for cumulative: "this". Use one of cum, flat`,
}
o.UI = ui
if err := interactive(p, o); err != nil {
t.Error("invalid group value:", err)
}
// Confirm error message written out once.
if ui.NumAllowRxMatches != 1 {
t.Errorf("want error message to be printed 1 time, got %v", ui.NumAllowRxMatches)
}
// Verify propagation of IO errors
pprofVariables = testVariables(savedVariables)
o.UI = newUI(t, []string{"**error**"})
if err := interactive(p, o); err == nil {
t.Error("expected IO error, got nil")
// Confirm error message written out once.
if tc.numAllowRxMatches != ui.NumAllowRxMatches {
t.Errorf("want error message to be printed %v time(s), got %v",
Copy link
Contributor

Choose a reason for hiding this comment

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

Use %d instead of %v?
(I know this line already existed, but nice to be able to make it a bit more idiomatic.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

tc.numAllowRxMatches, ui.NumAllowRxMatches)
}
})
}

}

var testCommands = commands{
Expand Down Expand Up @@ -132,7 +123,7 @@ var script = []string{
"f=-1;f=-2.5;check f=-2.5;f=0.0001;check f=0.0001",
"check ff=0;ff=-1.01;check ff=-1.01;ff=100;check ff=100",
"s=one;s=two;check s=two",
"ss=tree;check ss=tree;ss=;check ss;ss=forest;check ss=forest",
"ss=tree;check ss=tree;ss=forest;check ss=forest",
"ta=true;check ta=true;check tb=false;check tc=false;tb=1;check tb=true;check ta=false;check tc=false;tc=yes;check tb=false;check ta=false;check tc=true",
}

Expand Down Expand Up @@ -162,13 +153,6 @@ func makeShortcuts(input []string, seed int) (shortcuts, []string) {
return s, output
}

func newUI(t *testing.T, input []string) plugin.UI {
return &proftest.TestUI{
T: t,
Input: input,
}
}

func checkValue(p *profile.Profile, cmd []string, vars variables, o *plugin.Options) error {
if len(cmd) != 2 {
return fmt.Errorf("expected len(cmd)==2, got %v", cmd)
Expand Down