160a5143cb
The TestExpandConfigPath() method checks a number of conditions under which the ExpandConfigPath() method might operate, including when the $XDG_CONFIG_HOME environment variable is set. However, if the variable happens to already be set in the test execution environment, that trips up the "expanded default path" test condition as ExpandConfigPath() finds the $XDG_CONFIG_HOME variable and (correctly) uses it in constructing the output path. So we want to run the test method with a clean environment, since it will simulate the $XDG_CONFIG_HOME variable being set itself for the relevant test condition. Therefore we just unset the variable at the start of the test method in case $XDG_CONFIG_HOME is already set.
337 lines
8.5 KiB
Go
337 lines
8.5 KiB
Go
package tools
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"os/user"
|
|
"path/filepath"
|
|
"runtime"
|
|
"sort"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestCleanPathsCleansPaths(t *testing.T) {
|
|
cleaned := CleanPaths("/foo/bar/,/foo/bar/baz", ",")
|
|
assert.Equal(t, []string{"/foo/bar", "/foo/bar/baz"}, cleaned)
|
|
}
|
|
|
|
func TestCleanPathsReturnsNoResultsWhenGivenNoPaths(t *testing.T) {
|
|
cleaned := CleanPaths("", ",")
|
|
assert.Empty(t, cleaned)
|
|
}
|
|
|
|
type ExpandPathTestCase struct {
|
|
Path string
|
|
Expand bool
|
|
|
|
Want string
|
|
WantErr string
|
|
|
|
currentUser func() (*user.User, error)
|
|
lookupUser func(who string) (*user.User, error)
|
|
}
|
|
|
|
func (c *ExpandPathTestCase) Assert(t *testing.T) {
|
|
if c.currentUser != nil {
|
|
oldCurrentUser := currentUser
|
|
currentUser = c.currentUser
|
|
defer func() { currentUser = oldCurrentUser }()
|
|
}
|
|
|
|
if c.lookupUser != nil {
|
|
oldLookupUser := lookupUser
|
|
lookupUser = c.lookupUser
|
|
defer func() { lookupUser = oldLookupUser }()
|
|
}
|
|
|
|
got, err := ExpandPath(c.Path, c.Expand)
|
|
if err != nil || len(c.WantErr) > 0 {
|
|
assert.EqualError(t, err, c.WantErr)
|
|
}
|
|
assert.Equal(t, filepath.ToSlash(c.Want), filepath.ToSlash(got))
|
|
}
|
|
|
|
func TestExpandPath(t *testing.T) {
|
|
for desc, c := range map[string]*ExpandPathTestCase{
|
|
"no expand": {
|
|
Path: "/path/to/hooks",
|
|
Want: "/path/to/hooks",
|
|
},
|
|
"current": {
|
|
Path: "~/path/to/hooks",
|
|
Want: "/home/jane/path/to/hooks",
|
|
currentUser: func() (*user.User, error) {
|
|
return &user.User{
|
|
HomeDir: "/home/jane",
|
|
}, nil
|
|
},
|
|
},
|
|
"current, slash": {
|
|
Path: "~/",
|
|
Want: "/home/jane",
|
|
currentUser: func() (*user.User, error) {
|
|
return &user.User{
|
|
HomeDir: "/home/jane",
|
|
}, nil
|
|
},
|
|
},
|
|
"current, no slash": {
|
|
Path: "~",
|
|
Want: "/home/jane",
|
|
currentUser: func() (*user.User, error) {
|
|
return &user.User{
|
|
HomeDir: "/home/jane",
|
|
}, nil
|
|
},
|
|
},
|
|
"non-current": {
|
|
Path: "~other/path/to/hooks",
|
|
Want: "/home/special/path/to/hooks",
|
|
lookupUser: func(who string) (*user.User, error) {
|
|
assert.Equal(t, "other", who)
|
|
return &user.User{
|
|
HomeDir: "/home/special",
|
|
}, nil
|
|
},
|
|
},
|
|
"non-current, no slash": {
|
|
Path: "~other",
|
|
Want: "/home/special",
|
|
lookupUser: func(who string) (*user.User, error) {
|
|
assert.Equal(t, "other", who)
|
|
return &user.User{
|
|
HomeDir: "/home/special",
|
|
}, nil
|
|
},
|
|
},
|
|
"non-current (missing)": {
|
|
Path: "~other/path/to/hooks",
|
|
WantErr: "could not find user other: missing",
|
|
lookupUser: func(who string) (*user.User, error) {
|
|
assert.Equal(t, "other", who)
|
|
return nil, fmt.Errorf("missing")
|
|
},
|
|
},
|
|
} {
|
|
t.Run(desc, c.Assert)
|
|
}
|
|
}
|
|
|
|
type ExpandConfigPathTestCase struct {
|
|
Path string
|
|
DefaultPath string
|
|
|
|
Want string
|
|
WantErr string
|
|
|
|
currentUser func() (*user.User, error)
|
|
lookupConfigHome func() string
|
|
}
|
|
|
|
func (c *ExpandConfigPathTestCase) Assert(t *testing.T) {
|
|
if c.currentUser != nil {
|
|
oldCurrentUser := currentUser
|
|
currentUser = c.currentUser
|
|
defer func() { currentUser = oldCurrentUser }()
|
|
}
|
|
|
|
if c.lookupConfigHome != nil {
|
|
oldLookupConfigHome := lookupConfigHome
|
|
lookupConfigHome = c.lookupConfigHome
|
|
defer func() { lookupConfigHome = oldLookupConfigHome }()
|
|
}
|
|
|
|
got, err := ExpandConfigPath(c.Path, c.DefaultPath)
|
|
if err != nil || len(c.WantErr) > 0 {
|
|
assert.EqualError(t, err, c.WantErr)
|
|
}
|
|
assert.Equal(t, filepath.ToSlash(c.Want), filepath.ToSlash(got))
|
|
}
|
|
|
|
func TestExpandConfigPath(t *testing.T) {
|
|
os.Unsetenv("XDG_CONFIG_HOME")
|
|
for desc, c := range map[string]*ExpandConfigPathTestCase{
|
|
"unexpanded full path": {
|
|
Path: "/path/to/attributes",
|
|
Want: "/path/to/attributes",
|
|
},
|
|
"expanded full path": {
|
|
Path: "~/path/to/attributes",
|
|
Want: "/home/pat/path/to/attributes",
|
|
currentUser: func() (*user.User, error) {
|
|
return &user.User{
|
|
HomeDir: "/home/pat",
|
|
}, nil
|
|
},
|
|
},
|
|
"expanded default path": {
|
|
DefaultPath: "git/attributes",
|
|
Want: "/home/pat/.config/git/attributes",
|
|
currentUser: func() (*user.User, error) {
|
|
return &user.User{
|
|
HomeDir: "/home/pat",
|
|
}, nil
|
|
},
|
|
},
|
|
"XDG_CONFIG_HOME set": {
|
|
DefaultPath: "git/attributes",
|
|
Want: "/home/pat/configpath/git/attributes",
|
|
lookupConfigHome: func() string {
|
|
return "/home/pat/configpath"
|
|
},
|
|
},
|
|
} {
|
|
t.Run(desc, c.Assert)
|
|
}
|
|
}
|
|
|
|
func TestFastWalkBasic(t *testing.T) {
|
|
rootDir, err := ioutil.TempDir(os.TempDir(), "GitLfsTestFastWalkBasic")
|
|
if err != nil {
|
|
assert.FailNow(t, "Unable to get temp dir: %v", err)
|
|
}
|
|
defer os.RemoveAll(rootDir)
|
|
os.Chdir(rootDir)
|
|
|
|
expectedEntries := createFastWalkInputData(10, 160)
|
|
|
|
walker := fastWalkWithExcludeFiles(expectedEntries[0])
|
|
gotEntries, gotErrors := collectFastWalkResults(walker.ch)
|
|
|
|
assert.Empty(t, gotErrors)
|
|
|
|
sort.Strings(expectedEntries)
|
|
sort.Strings(gotEntries)
|
|
assert.Equal(t, expectedEntries, gotEntries)
|
|
}
|
|
|
|
// Make test data - ensure you've Chdir'ed into a temp dir first
|
|
// Returns list of files/dirs that are created
|
|
// First entry is the parent dir of all others
|
|
func createFastWalkInputData(smallFolder, largeFolder int) []string {
|
|
dirs := []string{
|
|
"testroot",
|
|
"testroot/folder1",
|
|
"testroot/folder2",
|
|
"testroot/folder2/subfolder1",
|
|
"testroot/folder2/subfolder2",
|
|
"testroot/folder2/subfolder3",
|
|
"testroot/folder2/subfolder4",
|
|
"testroot/folder2/subfolder4/subsub",
|
|
}
|
|
expectedEntries := make([]string, 0, 250)
|
|
|
|
for i, dir := range dirs {
|
|
os.MkdirAll(dir, 0755)
|
|
numFiles := smallFolder
|
|
expectedEntries = append(expectedEntries, dir)
|
|
if i >= 3 && i <= 5 {
|
|
// Bulk test to ensure works with > 1 batch
|
|
numFiles = largeFolder
|
|
}
|
|
for f := 0; f < numFiles; f++ {
|
|
filename := join(dir, fmt.Sprintf("file%d.txt", f))
|
|
ioutil.WriteFile(filename, []byte("TEST"), 0644)
|
|
expectedEntries = append(expectedEntries, filename)
|
|
}
|
|
}
|
|
|
|
return expectedEntries
|
|
}
|
|
|
|
func collectFastWalkResults(fchan <-chan fastWalkInfo) ([]string, []error) {
|
|
gotEntries := make([]string, 0, 1000)
|
|
gotErrors := make([]error, 0, 5)
|
|
for o := range fchan {
|
|
if o.Err != nil {
|
|
gotErrors = append(gotErrors, o.Err)
|
|
} else {
|
|
if len(o.ParentDir) == 0 {
|
|
gotEntries = append(gotEntries, o.Info.Name())
|
|
} else {
|
|
gotEntries = append(gotEntries, join(o.ParentDir, o.Info.Name()))
|
|
}
|
|
}
|
|
}
|
|
|
|
return gotEntries, gotErrors
|
|
}
|
|
|
|
func getFileMode(filename string) os.FileMode {
|
|
s, err := os.Stat(filename)
|
|
if err != nil {
|
|
return 0000
|
|
}
|
|
return s.Mode()
|
|
}
|
|
|
|
// uniq creates an element-wise copy of "xs" containing only unique elements in
|
|
// the same order.
|
|
func uniq(xs []string) []string {
|
|
seen := make(map[string]struct{})
|
|
uniq := make([]string, 0, len(xs))
|
|
|
|
for _, x := range xs {
|
|
if _, ok := seen[x]; !ok {
|
|
seen[x] = struct{}{}
|
|
uniq = append(uniq, x)
|
|
}
|
|
}
|
|
|
|
return uniq
|
|
}
|
|
|
|
func TestSetWriteFlag(t *testing.T) {
|
|
f, err := ioutil.TempFile("", "lfstestwriteflag")
|
|
assert.Nil(t, err)
|
|
filename := f.Name()
|
|
defer os.Remove(filename)
|
|
f.Close()
|
|
// Set up with read/write bit for all but no execute
|
|
assert.Nil(t, os.Chmod(filename, 0666))
|
|
|
|
assert.Nil(t, SetFileWriteFlag(filename, false))
|
|
// should turn off all write
|
|
assert.EqualValues(t, 0444, getFileMode(filename))
|
|
assert.Nil(t, SetFileWriteFlag(filename, true))
|
|
// should only add back user write (on Mac/Linux)
|
|
if runtime.GOOS == "windows" {
|
|
assert.EqualValues(t, 0666, getFileMode(filename))
|
|
} else {
|
|
assert.EqualValues(t, 0644, getFileMode(filename))
|
|
}
|
|
|
|
// Can't run selective UGO tests on Windows as doesn't support separate roles
|
|
// Also Golang only supports read/write but not execute on Windows
|
|
if runtime.GOOS != "windows" {
|
|
// Set up with read/write/execute bit for all but no execute
|
|
assert.Nil(t, os.Chmod(filename, 0777))
|
|
assert.Nil(t, SetFileWriteFlag(filename, false))
|
|
// should turn off all write but not execute
|
|
assert.EqualValues(t, 0555, getFileMode(filename))
|
|
assert.Nil(t, SetFileWriteFlag(filename, true))
|
|
// should only add back user write (on Mac/Linux)
|
|
if runtime.GOOS == "windows" {
|
|
assert.EqualValues(t, 0777, getFileMode(filename))
|
|
} else {
|
|
assert.EqualValues(t, 0755, getFileMode(filename))
|
|
}
|
|
|
|
assert.Nil(t, os.Chmod(filename, 0440))
|
|
assert.Nil(t, SetFileWriteFlag(filename, false))
|
|
assert.EqualValues(t, 0440, getFileMode(filename))
|
|
assert.Nil(t, SetFileWriteFlag(filename, true))
|
|
// should only add back user write
|
|
assert.EqualValues(t, 0640, getFileMode(filename))
|
|
}
|
|
}
|
|
|
|
func TestExecutablePermissions(t *testing.T) {
|
|
assert.EqualValues(t, os.FileMode(0755), ExecutablePermissions(0644))
|
|
assert.EqualValues(t, os.FileMode(0750), ExecutablePermissions(0640))
|
|
assert.EqualValues(t, os.FileMode(0700), ExecutablePermissions(0600))
|
|
}
|