cli: parse each option value once
validate() parsed every value to bounds-check it, then the typed getters re-parsed the same string at read time (with a comment admitting the failure was unreachable). A single parseValue() now validates and converts, finalize() runs it once per option after layering, and the getters just read the stored typed value.
This commit is contained in:
@@ -94,79 +94,79 @@ func TestParseSize(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateRange(t *testing.T) {
|
||||
func TestParseValueRange(t *testing.T) {
|
||||
x := byLong["max-connection-per-server"]
|
||||
if err := validate(x, "16"); err != nil {
|
||||
t.Errorf("validate 16: %v", err)
|
||||
if _, err := parseValue(x, "16"); err != nil {
|
||||
t.Errorf("parseValue 16: %v", err)
|
||||
}
|
||||
if err := validate(x, "99"); err == nil {
|
||||
t.Errorf("validate 99: want out-of-range error")
|
||||
if _, err := parseValue(x, "99"); err == nil {
|
||||
t.Errorf("parseValue 99: want out-of-range error")
|
||||
}
|
||||
a := byLong["file-allocation"]
|
||||
if err := validate(a, "bogus"); err == nil {
|
||||
t.Errorf("validate enum bogus: want error")
|
||||
if _, err := parseValue(a, "bogus"); err == nil {
|
||||
t.Errorf("parseValue enum bogus: want error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateIntFloor(t *testing.T) {
|
||||
// Min:0 now enforces a floor of 0: negatives are rejected.
|
||||
func TestParseValueIntFloor(t *testing.T) {
|
||||
// Min:0 enforces a floor of 0: negatives are rejected.
|
||||
m := byLong["max-tries"] // Min 0, "0 = unlimited" runtime meaning preserved
|
||||
if err := validate(m, "0"); err != nil {
|
||||
t.Errorf("validate max-tries 0: %v, want nil (0 stays a valid input)", err)
|
||||
if _, err := parseValue(m, "0"); err != nil {
|
||||
t.Errorf("parseValue max-tries 0: %v, want nil (0 stays a valid input)", err)
|
||||
}
|
||||
if err := validate(m, "-1"); err == nil {
|
||||
t.Errorf("validate max-tries -1: want below-minimum error")
|
||||
if _, err := parseValue(m, "-1"); err == nil {
|
||||
t.Errorf("parseValue max-tries -1: want below-minimum error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateFloatNonNegative(t *testing.T) {
|
||||
func TestParseValueFloatNonNegative(t *testing.T) {
|
||||
// Float options (seed-time, seed-ratio) reject negatives: a negative
|
||||
// SeedTime would fire the seed timer immediately and a negative SeedRatio
|
||||
// is silently ignored, so neither is a meaningful input.
|
||||
for _, name := range []string{"seed-ratio", "seed-time"} {
|
||||
o := byLong[name]
|
||||
if err := validate(o, "-1"); err == nil {
|
||||
t.Errorf("validate %s -1: want below-minimum error", name)
|
||||
if _, err := parseValue(o, "-1"); err == nil {
|
||||
t.Errorf("parseValue %s -1: want below-minimum error", name)
|
||||
}
|
||||
if err := validate(o, "0"); err != nil {
|
||||
t.Errorf("validate %s 0: %v, want nil", name, err)
|
||||
if _, err := parseValue(o, "0"); err != nil {
|
||||
t.Errorf("parseValue %s 0: %v, want nil", name, err)
|
||||
}
|
||||
if err := validate(o, "1.5"); err != nil {
|
||||
t.Errorf("validate %s 1.5: %v, want nil", name, err)
|
||||
if _, err := parseValue(o, "1.5"); err != nil {
|
||||
t.Errorf("parseValue %s 1.5: %v, want nil", name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateBool(t *testing.T) {
|
||||
func TestParseValueBool(t *testing.T) {
|
||||
b := byLong["enable-dht"]
|
||||
// Only literal true/false are accepted (case-sensitive), with surrounding
|
||||
// whitespace trimmed.
|
||||
for _, ok := range []string{"true", "false", " true ", "false\t"} {
|
||||
if err := validate(b, ok); err != nil {
|
||||
t.Errorf("validate bool %q: %v", ok, err)
|
||||
if _, err := parseValue(b, ok); err != nil {
|
||||
t.Errorf("parseValue bool %q: %v", ok, err)
|
||||
}
|
||||
}
|
||||
// The invented spellings and any case variant must now fail.
|
||||
// The invented spellings and any case variant must fail.
|
||||
for _, bad := range []string{"yes", "no", "1", "0", "on", "off", "flase",
|
||||
"True", "TRUE", "tRuE", "False", "FALSE"} {
|
||||
if err := validate(b, bad); err == nil {
|
||||
t.Errorf("validate bool %q: want error (only true/false accepted)", bad)
|
||||
if _, err := parseValue(b, bad); err == nil {
|
||||
t.Errorf("parseValue bool %q: want error (only true/false accepted)", bad)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateSizeBounds(t *testing.T) {
|
||||
func TestParseValueSizeBounds(t *testing.T) {
|
||||
k := byLong["min-split-size"] // 1M..1024M (no G unit)
|
||||
if err := validate(k, "20M"); err != nil {
|
||||
t.Errorf("validate min-split-size 20M: %v", err)
|
||||
if _, err := parseValue(k, "20M"); err != nil {
|
||||
t.Errorf("parseValue min-split-size 20M: %v", err)
|
||||
}
|
||||
if err := validate(k, "512K"); err == nil {
|
||||
t.Errorf("validate min-split-size 512K: want below-minimum error")
|
||||
if _, err := parseValue(k, "512K"); err == nil {
|
||||
t.Errorf("parseValue min-split-size 512K: want below-minimum error")
|
||||
}
|
||||
// 1025M exceeds the 1<<30 cap and still parses, so it tests the bounds path
|
||||
// (where "2G" would have failed earlier as an unknown unit).
|
||||
if err := validate(k, "1025M"); err == nil {
|
||||
t.Errorf("validate min-split-size 1025M: want above-maximum error")
|
||||
if _, err := parseValue(k, "1025M"); err == nil {
|
||||
t.Errorf("parseValue min-split-size 1025M: want above-maximum error")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,6 +207,9 @@ func TestOptionsGetters(t *testing.T) {
|
||||
o.vals["min-split-size"] = "20M"
|
||||
o.vals["continue"] = "true"
|
||||
o.vals["seed-ratio"] = "1.5"
|
||||
if err := o.finalize(); err != nil { // parse the raw values once, as Parse does
|
||||
t.Fatalf("finalize: %v", err)
|
||||
}
|
||||
if o.Int("split") != 8 {
|
||||
t.Errorf("Int split = %d", o.Int("split"))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user