168 lines
4.6 KiB
Go
168 lines
4.6 KiB
Go
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")
|
|
}
|
|
}
|