787 lines
18 KiB
Go
787 lines
18 KiB
Go
/*
|
|
Copyright 2015 The Kubernetes Authors All rights reserved.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package main
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"go.uber.org/goleak"
|
|
)
|
|
|
|
const (
|
|
testKey = "KEY"
|
|
)
|
|
|
|
func TestEnvBool(t *testing.T) {
|
|
cases := []struct {
|
|
value string
|
|
def bool
|
|
exp bool
|
|
err bool
|
|
}{
|
|
{"true", true, true, false},
|
|
{"true", false, true, false},
|
|
{"", true, true, false},
|
|
{"", false, false, false},
|
|
{"false", true, false, false},
|
|
{"false", false, false, false},
|
|
{"", true, true, false},
|
|
{"", false, false, false},
|
|
{"no true", false, false, true},
|
|
{"no false", false, false, true},
|
|
}
|
|
|
|
for _, testCase := range cases {
|
|
os.Setenv(testKey, testCase.value)
|
|
val, err := envBoolOrError(testCase.def, testKey)
|
|
if err != nil && !testCase.err {
|
|
t.Fatalf("%q: unexpected error: %v", testCase.value, err)
|
|
}
|
|
if err == nil && testCase.err {
|
|
t.Fatalf("%q: unexpected success", testCase.value)
|
|
}
|
|
if val != testCase.exp {
|
|
t.Fatalf("%q: expected %v but %v returned", testCase.value, testCase.exp, val)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestEnvString(t *testing.T) {
|
|
cases := []struct {
|
|
value string
|
|
def string
|
|
exp string
|
|
}{
|
|
{"true", "true", "true"},
|
|
{"true", "false", "true"},
|
|
{"", "true", "true"},
|
|
{"", "false", "false"},
|
|
{"false", "true", "false"},
|
|
{"false", "false", "false"},
|
|
{"", "true", "true"},
|
|
{"", "false", "false"},
|
|
}
|
|
|
|
for _, testCase := range cases {
|
|
os.Setenv(testKey, testCase.value)
|
|
val := envString(testCase.def, testKey)
|
|
if val != testCase.exp {
|
|
t.Fatalf("%q: expected %v but %v returned", testCase.value, testCase.exp, val)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestEnvInt(t *testing.T) {
|
|
cases := []struct {
|
|
value string
|
|
def int
|
|
exp int
|
|
err bool
|
|
}{
|
|
{"0", 1, 0, false},
|
|
{"", 0, 0, false},
|
|
{"-1", 0, -1, false},
|
|
{"abcd", 0, 0, true},
|
|
{"abcd", 0, 0, true},
|
|
}
|
|
|
|
for _, testCase := range cases {
|
|
os.Setenv(testKey, testCase.value)
|
|
val, err := envIntOrError(testCase.def, testKey)
|
|
if err != nil && !testCase.err {
|
|
t.Fatalf("%q: unexpected error: %v", testCase.value, err)
|
|
}
|
|
if err == nil && testCase.err {
|
|
t.Fatalf("%q: unexpected success", testCase.value)
|
|
}
|
|
if val != testCase.exp {
|
|
t.Fatalf("%q: expected %v but %v returned", testCase.value, testCase.exp, val)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestEnvFloat(t *testing.T) {
|
|
cases := []struct {
|
|
value string
|
|
def float64
|
|
exp float64
|
|
err bool
|
|
}{
|
|
{"0.5", 0, 0.5, false},
|
|
{"", 0.5, 0.5, false},
|
|
{"-0.5", 0, -0.5, false},
|
|
{"abcd", 0, 0, true},
|
|
}
|
|
|
|
for _, testCase := range cases {
|
|
os.Setenv(testKey, testCase.value)
|
|
val, err := envFloatOrError(testCase.def, testKey)
|
|
if err != nil && !testCase.err {
|
|
t.Fatalf("%q: unexpected error: %v", testCase.value, err)
|
|
}
|
|
if err == nil && testCase.err {
|
|
t.Fatalf("%q: unexpected success", testCase.value)
|
|
}
|
|
if val != testCase.exp {
|
|
t.Fatalf("%q: expected %v but %v returned", testCase.value, testCase.exp, val)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestEnvDuration(t *testing.T) {
|
|
cases := []struct {
|
|
value string
|
|
def time.Duration
|
|
exp time.Duration
|
|
err bool
|
|
}{
|
|
{"1s", 0, time.Second, false},
|
|
{"", time.Minute, time.Minute, false},
|
|
{"1h", 0, time.Hour, false},
|
|
{"abcd", 0, 0, true},
|
|
}
|
|
|
|
for _, testCase := range cases {
|
|
os.Setenv(testKey, testCase.value)
|
|
val, err := envDurationOrError(testCase.def, testKey)
|
|
if err != nil && !testCase.err {
|
|
t.Fatalf("%q: unexpected error: %v", testCase.value, err)
|
|
}
|
|
if err == nil && testCase.err {
|
|
t.Fatalf("%q: unexpected success", testCase.value)
|
|
}
|
|
if val != testCase.exp {
|
|
t.Fatalf("%q: expected %v but %v returned", testCase.value, testCase.exp, val)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMakeAbsPath(t *testing.T) {
|
|
cases := []struct {
|
|
path string
|
|
root string
|
|
exp string
|
|
}{{
|
|
path: "", root: "", exp: "",
|
|
}, {
|
|
path: "", root: "/root", exp: "",
|
|
}, {
|
|
path: "path", root: "/root", exp: "/root/path",
|
|
}, {
|
|
path: "p/a/t/h", root: "/root", exp: "/root/p/a/t/h",
|
|
}, {
|
|
path: "/path", root: "/root", exp: "/path",
|
|
}, {
|
|
path: "/p/a/t/h", root: "/root", exp: "/p/a/t/h",
|
|
}}
|
|
|
|
for _, tc := range cases {
|
|
res := makeAbsPath(tc.path, absPath(tc.root))
|
|
if res.String() != tc.exp {
|
|
t.Errorf("expected: %q, got: %q", tc.exp, res)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestWorktreePath(t *testing.T) {
|
|
testCases := []absPath{
|
|
"",
|
|
"/",
|
|
"//",
|
|
"/dir",
|
|
"/dir/",
|
|
"/dir//",
|
|
"/dir/sub",
|
|
"/dir/sub/",
|
|
"/dir//sub",
|
|
"/dir//sub/",
|
|
"dir",
|
|
"dir/sub",
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
if want, got := tc, worktree(tc).Path(); want != got {
|
|
t.Errorf("expected %q, got %q", want, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestWorktreeHash(t *testing.T) {
|
|
testCases := []struct {
|
|
in worktree
|
|
exp string
|
|
}{{
|
|
in: "",
|
|
exp: "",
|
|
}, {
|
|
in: "/",
|
|
exp: "",
|
|
}, {
|
|
in: "/one",
|
|
exp: "one",
|
|
}, {
|
|
in: "/one/two",
|
|
exp: "two",
|
|
}, {
|
|
in: "/one/two/",
|
|
exp: "two",
|
|
}, {
|
|
in: "/one//two",
|
|
exp: "two",
|
|
}}
|
|
|
|
for _, tc := range testCases {
|
|
if want, got := tc.exp, tc.in.Hash(); want != got {
|
|
t.Errorf("%q: expected %q, got %q", tc.in, want, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestManualHasNoTabs(t *testing.T) {
|
|
if strings.Contains(manual, "\t") {
|
|
t.Fatal("the manual text contains a tab")
|
|
}
|
|
}
|
|
|
|
func TestParseGitConfigs(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
input string
|
|
expect []keyVal
|
|
fail bool
|
|
}{{
|
|
name: "empty",
|
|
input: ``,
|
|
expect: []keyVal{},
|
|
}, {
|
|
name: "one-pair",
|
|
input: `k:v`,
|
|
expect: []keyVal{keyVal{"k", "v"}},
|
|
}, {
|
|
name: "one-pair-qkey",
|
|
input: `"k":v`,
|
|
expect: []keyVal{keyVal{"k", "v"}},
|
|
}, {
|
|
name: "one-pair-qval",
|
|
input: `k:"v"`,
|
|
expect: []keyVal{keyVal{"k", "v"}},
|
|
}, {
|
|
name: "one-pair-qkey-qval",
|
|
input: `"k":"v"`,
|
|
expect: []keyVal{keyVal{"k", "v"}},
|
|
}, {
|
|
name: "multi-pair",
|
|
input: `k1:v1,"k2":v2,k3:"v3","k4":"v4"`,
|
|
expect: []keyVal{{"k1", "v1"}, {"k2", "v2"}, {"k3", "v3"}, {"k4", "v4"}},
|
|
}, {
|
|
name: "garbage",
|
|
input: `abc123`,
|
|
fail: true,
|
|
}, {
|
|
name: "key-section-var",
|
|
input: `sect.var:v`,
|
|
expect: []keyVal{keyVal{"sect.var", "v"}},
|
|
}, {
|
|
name: "key-section-subsection-var",
|
|
input: `sect.sub.var:v`,
|
|
expect: []keyVal{keyVal{"sect.sub.var", "v"}},
|
|
}, {
|
|
name: "key-subsection-with-space",
|
|
input: `k.sect.sub section:v`,
|
|
expect: []keyVal{keyVal{"k.sect.sub section", "v"}},
|
|
}, {
|
|
name: "key-subsection-with-escape",
|
|
input: `k.sect.sub\tsection:v`,
|
|
expect: []keyVal{keyVal{"k.sect.sub\\tsection", "v"}},
|
|
}, {
|
|
name: "key-subsection-with-comma",
|
|
input: `k.sect.sub,section:v`,
|
|
expect: []keyVal{keyVal{"k.sect.sub,section", "v"}},
|
|
}, {
|
|
name: "qkey-subsection-with-space",
|
|
input: `"k.sect.sub section":v`,
|
|
expect: []keyVal{keyVal{"k.sect.sub section", "v"}},
|
|
}, {
|
|
name: "qkey-subsection-with-escapes",
|
|
input: `"k.sect.sub\t\n\\section":v`,
|
|
expect: []keyVal{keyVal{"k.sect.sub\t\n\\section", "v"}},
|
|
}, {
|
|
name: "qkey-subsection-with-comma",
|
|
input: `"k.sect.sub,section":v`,
|
|
expect: []keyVal{keyVal{"k.sect.sub,section", "v"}},
|
|
}, {
|
|
name: "qkey-subsection-with-colon",
|
|
input: `"k.sect.sub:section":v`,
|
|
expect: []keyVal{keyVal{"k.sect.sub:section", "v"}},
|
|
}, {
|
|
name: "invalid-qkey",
|
|
input: `"k\xk":v"`,
|
|
fail: true,
|
|
}, {
|
|
name: "val-spaces",
|
|
input: `k1:v 1,k2:v 2`,
|
|
expect: []keyVal{{"k1", "v 1"}, {"k2", "v 2"}},
|
|
}, {
|
|
name: "qval-spaces",
|
|
input: `k1:" v 1 ",k2:" v 2 "`,
|
|
expect: []keyVal{{"k1", " v 1 "}, {"k2", " v 2 "}},
|
|
}, {
|
|
name: "mix-val-qval",
|
|
input: `k1:v 1,k2:" v 2 "`,
|
|
expect: []keyVal{{"k1", "v 1"}, {"k2", " v 2 "}},
|
|
}, {
|
|
name: "garbage-after-qval",
|
|
input: `k1:"v1"x,k2:"v2"`,
|
|
fail: true,
|
|
}, {
|
|
name: "dangling-comma",
|
|
input: `k1:"v1",k2:"v2",`,
|
|
expect: []keyVal{{"k1", "v1"}, {"k2", "v2"}},
|
|
}, {
|
|
name: "val-with-escapes",
|
|
input: `k1:v\n\t\\\"\,1`,
|
|
expect: []keyVal{{"k1", "v\n\t\\\",1"}},
|
|
}, {
|
|
name: "qval-with-escapes",
|
|
input: `k1:"v\n\t\\\"\,1"`,
|
|
expect: []keyVal{{"k1", "v\n\t\\\",1"}},
|
|
}, {
|
|
name: "qval-with-comma",
|
|
input: `k1:"v,1"`,
|
|
expect: []keyVal{{"k1", "v,1"}},
|
|
}, {
|
|
name: "qkey-missing-close",
|
|
input: `"k1:v1`,
|
|
fail: true,
|
|
}, {
|
|
name: "qval-missing-close",
|
|
input: `k1:"v1`,
|
|
fail: true,
|
|
}}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
defer goleak.VerifyNone(t)
|
|
|
|
kvs, err := parseGitConfigs(tc.input)
|
|
if err != nil && !tc.fail {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
if err == nil && tc.fail {
|
|
t.Errorf("unexpected success")
|
|
}
|
|
if !reflect.DeepEqual(kvs, tc.expect) {
|
|
t.Errorf("bad result:\n\texpected: %#v\n\t got: %#v", tc.expect, kvs)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAbsPathString(t *testing.T) {
|
|
testCases := []string{
|
|
"",
|
|
"/",
|
|
"//",
|
|
"/dir",
|
|
"/dir/",
|
|
"/dir//",
|
|
"/dir/sub",
|
|
"/dir/sub/",
|
|
"/dir//sub",
|
|
"/dir//sub/",
|
|
"dir",
|
|
"dir/sub",
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
if want, got := tc, absPath(tc).String(); want != got {
|
|
t.Errorf("expected %q, got %q", want, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAbsPathCanonical(t *testing.T) {
|
|
testCases := []struct {
|
|
in absPath
|
|
exp absPath
|
|
}{{
|
|
in: "",
|
|
exp: "",
|
|
}, {
|
|
in: "/",
|
|
exp: "/",
|
|
}, {
|
|
in: "/one",
|
|
exp: "/one",
|
|
}, {
|
|
in: "/one/two",
|
|
exp: "/one/two",
|
|
}, {
|
|
in: "/one/two/",
|
|
exp: "/one/two",
|
|
}, {
|
|
in: "/one//two",
|
|
exp: "/one/two",
|
|
}, {
|
|
in: "/one/two/../three",
|
|
exp: "/one/three",
|
|
}}
|
|
|
|
for _, tc := range testCases {
|
|
want := tc.exp
|
|
got, err := tc.in.Canonical()
|
|
if err != nil {
|
|
t.Errorf("%q: unexpected error: %v", tc.in, err)
|
|
} else if want != got {
|
|
t.Errorf("%q: expected %q, got %q", tc.in, want, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAbsPathJoin(t *testing.T) {
|
|
testCases := []struct {
|
|
base absPath
|
|
more []string
|
|
expect absPath
|
|
}{{
|
|
base: "/dir",
|
|
more: nil,
|
|
expect: "/dir",
|
|
}, {
|
|
base: "/dir",
|
|
more: []string{"one"},
|
|
expect: "/dir/one",
|
|
}, {
|
|
base: "/dir",
|
|
more: []string{"one", "two"},
|
|
expect: "/dir/one/two",
|
|
}, {
|
|
base: "/dir",
|
|
more: []string{"one", "two", "three"},
|
|
expect: "/dir/one/two/three",
|
|
}, {
|
|
base: "/dir",
|
|
more: []string{"with/slash"},
|
|
expect: "/dir/with/slash",
|
|
}, {
|
|
base: "/dir",
|
|
more: []string{"with/trailingslash/"},
|
|
expect: "/dir/with/trailingslash",
|
|
}, {
|
|
base: "/dir",
|
|
more: []string{"with//twoslash"},
|
|
expect: "/dir/with/twoslash",
|
|
}, {
|
|
base: "/dir",
|
|
more: []string{"one/1", "two/2", "three/3"},
|
|
expect: "/dir/one/1/two/2/three/3",
|
|
}}
|
|
|
|
for _, tc := range testCases {
|
|
if want, got := tc.expect, tc.base.Join(tc.more...); want != got {
|
|
t.Errorf("(%q, %q): expected %q, got %q", tc.base, tc.more, want, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAbsPathSplit(t *testing.T) {
|
|
testCases := []struct {
|
|
in absPath
|
|
expDir string
|
|
expBase string
|
|
}{{
|
|
in: "",
|
|
expDir: "",
|
|
expBase: "",
|
|
}, {
|
|
in: "/",
|
|
expDir: "/",
|
|
expBase: "",
|
|
}, {
|
|
in: "//",
|
|
expDir: "/",
|
|
expBase: "",
|
|
}, {
|
|
in: "/one",
|
|
expDir: "/",
|
|
expBase: "one",
|
|
}, {
|
|
in: "/one/two",
|
|
expDir: "/one",
|
|
expBase: "two",
|
|
}, {
|
|
in: "/one/two/",
|
|
expDir: "/one",
|
|
expBase: "two",
|
|
}, {
|
|
in: "/one//two",
|
|
expDir: "/one",
|
|
expBase: "two",
|
|
}}
|
|
|
|
for _, tc := range testCases {
|
|
wantDir, wantBase := tc.expDir, tc.expBase
|
|
if gotDir, gotBase := tc.in.Split(); wantDir != gotDir || wantBase != gotBase {
|
|
t.Errorf("%q: expected (%q, %q), got (%q, %q)", tc.in, wantDir, wantBase, gotDir, gotBase)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAbsPathDir(t *testing.T) {
|
|
testCases := []struct {
|
|
in absPath
|
|
exp string
|
|
}{{
|
|
in: "",
|
|
exp: "",
|
|
}, {
|
|
in: "/",
|
|
exp: "/",
|
|
}, {
|
|
in: "/one",
|
|
exp: "/",
|
|
}, {
|
|
in: "/one/two",
|
|
exp: "/one",
|
|
}, {
|
|
in: "/one/two/",
|
|
exp: "/one",
|
|
}, {
|
|
in: "/one//two",
|
|
exp: "/one",
|
|
}}
|
|
|
|
for _, tc := range testCases {
|
|
if want, got := tc.exp, tc.in.Dir(); want != got {
|
|
t.Errorf("%q: expected %q, got %q", tc.in, want, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAbsPathBase(t *testing.T) {
|
|
testCases := []struct {
|
|
in absPath
|
|
exp string
|
|
}{{
|
|
in: "",
|
|
exp: "",
|
|
}, {
|
|
in: "/",
|
|
exp: "",
|
|
}, {
|
|
in: "/one",
|
|
exp: "one",
|
|
}, {
|
|
in: "/one/two",
|
|
exp: "two",
|
|
}, {
|
|
in: "/one/two/",
|
|
exp: "two",
|
|
}, {
|
|
in: "/one//two",
|
|
exp: "two",
|
|
}}
|
|
|
|
for _, tc := range testCases {
|
|
if want, got := tc.exp, tc.in.Base(); want != got {
|
|
t.Errorf("%q: expected %q, got %q", tc.in, want, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDirIsEmpty(t *testing.T) {
|
|
root := absPath(t.TempDir())
|
|
|
|
// Brand new should be empty.
|
|
if empty, err := dirIsEmpty(root); err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
} else if !empty {
|
|
t.Errorf("expected %q to be deemed empty", root)
|
|
}
|
|
|
|
// Holding normal files should not be empty.
|
|
dir := root.Join("files")
|
|
if err := os.Mkdir(dir.String(), 0755); err != nil {
|
|
t.Fatalf("failed to make a temp subdir: %v", err)
|
|
}
|
|
for _, file := range []string{"a", "b", "c"} {
|
|
path := filepath.Join(dir.String(), file)
|
|
if err := os.WriteFile(path, []byte{}, 0755); err != nil {
|
|
t.Fatalf("failed to write a file: %v", err)
|
|
}
|
|
if empty, err := dirIsEmpty(dir); err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
} else if empty {
|
|
t.Errorf("expected %q to be deemed not-empty", dir)
|
|
}
|
|
}
|
|
|
|
// Holding dot-files should not be empty.
|
|
dir = root.Join("dot-files")
|
|
if err := os.Mkdir(dir.String(), 0755); err != nil {
|
|
t.Fatalf("failed to make a temp subdir: %v", err)
|
|
}
|
|
for _, file := range []string{".a", ".b", ".c"} {
|
|
path := dir.Join(file)
|
|
if err := os.WriteFile(path.String(), []byte{}, 0755); err != nil {
|
|
t.Fatalf("failed to write a file: %v", err)
|
|
}
|
|
if empty, err := dirIsEmpty(dir); err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
} else if empty {
|
|
t.Errorf("expected %q to be deemed not-empty", dir)
|
|
}
|
|
}
|
|
|
|
// Holding dirs should not be empty.
|
|
dir = root.Join("dirs")
|
|
if err := os.Mkdir(dir.String(), 0755); err != nil {
|
|
t.Fatalf("failed to make a temp subdir: %v", err)
|
|
}
|
|
for _, subdir := range []string{"a", "b", "c"} {
|
|
path := filepath.Join(dir.String(), subdir)
|
|
if err := os.Mkdir(path, 0755); err != nil {
|
|
t.Fatalf("failed to make a subdir: %v", err)
|
|
}
|
|
if empty, err := dirIsEmpty(dir); err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
} else if empty {
|
|
t.Errorf("expected %q to be deemed not-empty", dir)
|
|
}
|
|
}
|
|
|
|
// Test error path.
|
|
if _, err := dirIsEmpty(root.Join("does-not-exist")); err == nil {
|
|
t.Errorf("unexpected success for non-existent dir")
|
|
}
|
|
}
|
|
|
|
func TestRemoveDirContents(t *testing.T) {
|
|
root := absPath(t.TempDir())
|
|
|
|
// Brand new should be empty.
|
|
if empty, err := dirIsEmpty(root); err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
} else if !empty {
|
|
t.Errorf("expected %q to be deemed empty", root)
|
|
}
|
|
|
|
// Test removal.
|
|
if err := removeDirContents(root, nil); err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
|
|
// Populate the dir.
|
|
for _, file := range []string{"f1", "f2", ".f3", ".f4"} {
|
|
path := root.Join(file)
|
|
if err := os.WriteFile(path.String(), []byte{}, 0755); err != nil {
|
|
t.Fatalf("failed to write a file: %v", err)
|
|
}
|
|
}
|
|
for _, subdir := range []string{"d1", "d2", "d3"} {
|
|
path := root.Join(subdir)
|
|
if err := os.Mkdir(path.String(), 0755); err != nil {
|
|
t.Fatalf("failed to make a subdir: %v", err)
|
|
}
|
|
}
|
|
|
|
// It should be deemed not-empty
|
|
if empty, err := dirIsEmpty(root); err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
} else if empty {
|
|
t.Errorf("expected %q to be deemed not-empty", root)
|
|
}
|
|
|
|
// Test removal.
|
|
if err := removeDirContents(root, nil); err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
|
|
// Test error path.
|
|
if err := removeDirContents(root.Join("does-not-exist"), nil); err == nil {
|
|
t.Errorf("unexpected success for non-existent dir")
|
|
}
|
|
}
|
|
|
|
func TestTouch(t *testing.T) {
|
|
root := absPath(t.TempDir())
|
|
|
|
// Make a dir and get info.
|
|
dirPath := root.Join("dir")
|
|
if err := os.MkdirAll(dirPath.String(), 0755); err != nil {
|
|
t.Fatalf("can't create dir: %v", err)
|
|
}
|
|
|
|
// Make a file and get info.
|
|
filePath := root.Join("file")
|
|
if file, err := os.Create(filePath.String()); err != nil {
|
|
t.Fatalf("can't create file: %v", err)
|
|
} else {
|
|
file.Close()
|
|
}
|
|
|
|
// Make sure a newfile does not exist.
|
|
newfilePath := root.Join("newfile")
|
|
if fi, err := os.Stat(newfilePath.String()); err == nil {
|
|
t.Fatalf("unexpected newfile: %v", fi)
|
|
} else if !os.IsNotExist(err) {
|
|
t.Fatalf("can't stat newfile: %v", err)
|
|
}
|
|
|
|
time.Sleep(500 * time.Millisecond)
|
|
stamp := time.Now()
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
if err := touch(dirPath); err != nil {
|
|
t.Fatalf("touch(dir) failed: %v", err)
|
|
}
|
|
if dirInfo, err := os.Stat(dirPath.String()); err != nil {
|
|
t.Fatalf("can't stat dir: %v", err)
|
|
} else if !dirInfo.IsDir() {
|
|
t.Errorf("touch(dir) is no longer a dir: %v", dirInfo)
|
|
} else if !dirInfo.ModTime().After(stamp) {
|
|
t.Errorf("touch(dir) mtime %v is not after %v", dirInfo.ModTime(), stamp)
|
|
}
|
|
|
|
if err := touch(filePath); err != nil {
|
|
t.Fatalf("touch(file) failed: %v", err)
|
|
}
|
|
if fileInfo, err := os.Stat(filePath.String()); err != nil {
|
|
t.Fatalf("can't stat file: %v", err)
|
|
} else if fileInfo.IsDir() {
|
|
t.Errorf("touch(file) is no longer a file: %v", fileInfo)
|
|
} else if !fileInfo.ModTime().After(stamp) {
|
|
t.Errorf("touch(file) mtime %v is not after %v", fileInfo.ModTime(), stamp)
|
|
}
|
|
|
|
if err := touch(newfilePath); err != nil {
|
|
t.Fatalf("touch(newfile) failed: %v", err)
|
|
}
|
|
if newfileInfo, err := os.Stat(newfilePath.String()); err != nil {
|
|
t.Fatalf("can't stat newfile: %v", err)
|
|
} else if newfileInfo.IsDir() {
|
|
t.Errorf("touch(newfile) is not a file: %v", newfileInfo)
|
|
} else if !newfileInfo.ModTime().After(stamp) {
|
|
t.Errorf("touch(newfile) mtime %v is not after %v", newfileInfo.ModTime(), stamp)
|
|
}
|
|
}
|