package config import ( "strings" "testing" "time" ) func TestParseSize(t *testing.T) { cases := map[string]int64{ "": Unlimited, "0": Unlimited, "unlimited": Unlimited, "512": 512, "512B": 512, "2GiB": 2 << 30, "2 GiB": 2 << 30, "2G": 2 << 30, "500MB": 500_000_000, "1.5MiB": 1572864, "2gib": 2 << 30, } for in, want := range cases { got, err := ParseSize(in) if err != nil { t.Errorf("ParseSize(%q): %v", in, err) continue } if got != want { t.Errorf("ParseSize(%q) = %d, want %d", in, got, want) } } for _, in := range []string{"-1", "lots", "2XiB", "GiB2"} { if _, err := ParseSize(in); err == nil { t.Errorf("ParseSize(%q) accepted an invalid size", in) } } } func TestParseDuration(t *testing.T) { cases := map[string]time.Duration{ "": Unlimited, "never": Unlimited, "0": Unlimited, "90m": 90 * time.Minute, "72h": 72 * time.Hour, "3d": 72 * time.Hour, "1w": 168 * time.Hour, "1.5d": 36 * time.Hour, } for in, want := range cases { got, err := ParseDuration(in) if err != nil { t.Errorf("ParseDuration(%q): %v", in, err) continue } if got != want { t.Errorf("ParseDuration(%q) = %s, want %s", in, got, want) } } for _, in := range []string{"-3d", "soon", "3days"} { if _, err := ParseDuration(in); err == nil { t.Errorf("ParseDuration(%q) accepted an invalid duration", in) } } } // The formatters are human-facing and round to two decimals, so they only // round-trip exactly for values that land on a unit boundary. Nothing in the // program re-parses their output; this pins the cases that are shown most. func TestFormatRoundTrips(t *testing.T) { for _, n := range []int64{0, 512, 2 << 30, 100 << 20, 1536} { if got, err := ParseSize(FormatSize(n)); err != nil || got != n { t.Errorf("FormatSize(%d) = %q, which parses back to %d (%v)", n, FormatSize(n), got, err) } } for _, d := range []time.Duration{0, time.Hour, 72 * time.Hour, 90 * time.Minute} { if got, err := ParseDuration(FormatDuration(d)); err != nil || got != d { t.Errorf("FormatDuration(%s) = %q, which parses back to %s (%v)", d, FormatDuration(d), got, err) } } } // The convention is: one hyphen for a letter, two for a word. It is enforced // here because the stdlib flag package treats both forms as the same. func TestHyphenConvention(t *testing.T) { newSet := func() (*Set, *string) { var listen string s := NewSet("test", "SEND_TEST_") s.String(&listen, "listen", "l", "default", "ADDR", "listen address") return s, &listen } for _, args := range [][]string{{"--listen", "x"}, {"-l", "x"}, {"--listen=x"}, {"-l=x"}} { s, listen := newSet() if err := s.Parse(args); err != nil { t.Errorf("%v: %v", args, err) continue } if *listen != "x" { t.Errorf("%v: listen = %q", args, *listen) } } for _, args := range [][]string{{"-listen", "x"}, {"--l", "x"}, {"-listen=x"}} { s, _ := newSet() err := s.Parse(args) if err == nil { t.Errorf("%v was accepted; it breaks the hyphen convention", args) continue } if !strings.Contains(err.Error(), "hyphen") { t.Errorf("%v: error does not explain the convention: %v", args, err) } } } func TestEnvFallback(t *testing.T) { t.Setenv("SEND_TEST_MAX_SIZE", "4GiB") var size int64 s := NewSet("test", "SEND_TEST_") s.Size(&size, "max-size", "s", "2GiB", "cap") if err := s.Parse(nil); err != nil { t.Fatal(err) } if size != 4<<30 { t.Errorf("size = %d, want 4GiB from the environment", size) } // An explicit flag still wins over the environment. s = NewSet("test", "SEND_TEST_") s.Size(&size, "max-size", "s", "2GiB", "cap") if err := s.Parse([]string{"--max-size", "1GiB"}); err != nil { t.Fatal(err) } if size != 1<<30 { t.Errorf("size = %d, want the flag to win", size) } } func TestNormalisePath(t *testing.T) { cases := map[string]string{ "": "/", "/": "/", "send": "/send/", "/send": "/send/", "/send/": "/send/", "a/b": "/a/b/", } for in, want := range cases { if got := NormalisePath(in); got != want { t.Errorf("NormalisePath(%q) = %q, want %q", in, got, want) } } } func TestDefaultExpiryMustFitWithinMax(t *testing.T) { c := &Config{BasePath: "/", DataDir: "d", SweepInterval: time.Minute, MaxConcurrent: 1, MaxExpiry: time.Hour, DefaultExpiry: 24 * time.Hour} if err := c.Normalise(); err == nil { t.Error("a default longer than the maximum was accepted") } c.DefaultExpiry = Unlimited if err := c.Normalise(); err == nil { t.Error("an unlimited default under a finite maximum was accepted") } }