refactor(tui): use strconv.Atoi in parseIntClamp, drop spurious error return
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/charmbracelet/huh"
|
"github.com/charmbracelet/huh"
|
||||||
@@ -88,12 +89,13 @@ func Run(ctx context.Context, reg *module.Registry, initial tui.WizardState) (tu
|
|||||||
return s, false, err
|
return s, false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Redundant-but-safe: the DescriptionFunc closure on the plan-review
|
||||||
|
// screen already kept s.Modules in sync. The MultiSelect group is
|
||||||
|
// frozen by the time we reach here, so this is idempotent. Kept for
|
||||||
|
// the case where the form is exited via a path that bypasses the
|
||||||
|
// plan-review screen in future revisions.
|
||||||
s.Modules = syncSelected(s.Modules, selectedModules)
|
s.Modules = syncSelected(s.Modules, selectedModules)
|
||||||
// Parse parallelism: clamp to 1 on any parse failure, since the wizard
|
s.Parallelism = parseIntClamp(parallelismStr, 1)
|
||||||
// uses a free-form Input; a stricter schema can come later.
|
|
||||||
if n, perr := parseIntClamp(parallelismStr, 1); perr == nil {
|
|
||||||
s.Parallelism = n
|
|
||||||
}
|
|
||||||
s.Confirmed = proceed
|
s.Confirmed = proceed
|
||||||
return s, proceed, nil
|
return s, proceed, nil
|
||||||
}
|
}
|
||||||
@@ -149,15 +151,18 @@ func renderPlan(ctx context.Context, reg *module.Registry, selectedIDs []string)
|
|||||||
return b.String()
|
return b.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseIntClamp parses s as int. Empty or invalid input returns fallback.
|
// parseIntClamp parses s as a positive int. Empty, non-numeric (including
|
||||||
func parseIntClamp(s string, fallback int) (int, error) {
|
// partial matches like "3abc"), negative, zero, or overflowing input all
|
||||||
|
// return fallback. strconv.Atoi (not fmt.Sscanf) is used so partial matches
|
||||||
|
// are rejected and overflow surfaces as an error.
|
||||||
|
func parseIntClamp(s string, fallback int) int {
|
||||||
s = strings.TrimSpace(s)
|
s = strings.TrimSpace(s)
|
||||||
if s == "" {
|
if s == "" {
|
||||||
return fallback, nil
|
return fallback
|
||||||
}
|
}
|
||||||
var n int
|
n, err := strconv.Atoi(s)
|
||||||
if _, err := fmt.Sscanf(s, "%d", &n); err != nil || n < 1 {
|
if err != nil || n < 1 {
|
||||||
return fallback, nil
|
return fallback
|
||||||
}
|
}
|
||||||
return n, nil
|
return n
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,13 +48,15 @@ func TestParseIntClamp(t *testing.T) {
|
|||||||
"": 1,
|
"": 1,
|
||||||
" ": 1,
|
" ": 1,
|
||||||
"abc": 1,
|
"abc": 1,
|
||||||
|
"3abc": 1, // partial match is rejected (strconv.Atoi, not Sscanf)
|
||||||
"0": 1,
|
"0": 1,
|
||||||
"-5": 1,
|
"-5": 1,
|
||||||
"3": 3,
|
"3": 3,
|
||||||
"12": 12,
|
"12": 12,
|
||||||
|
"99999999999999999999": 1, // overflow → fallback
|
||||||
}
|
}
|
||||||
for in, want := range cases {
|
for in, want := range cases {
|
||||||
got, _ := parseIntClamp(in, 1)
|
got := parseIntClamp(in, 1)
|
||||||
if got != want {
|
if got != want {
|
||||||
t.Errorf("parseIntClamp(%q) = %d, want %d", in, got, want)
|
t.Errorf("parseIntClamp(%q) = %d, want %d", in, got, want)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user