/
path_test.go
172 lines (160 loc) · 5.13 KB
/
path_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
package explicitfilepath
import (
"fmt"
"os"
"path/filepath"
"testing"
_ "github.com/containers/image/v5/internal/testing/explicitfilepath-tmpdir"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type pathResolvingTestCase struct {
setup func(*testing.T, string) string
expected string
}
var testCases = []pathResolvingTestCase{
{ // A straightforward subdirectory hierarchy
func(t *testing.T, top string) string {
err := os.MkdirAll(filepath.Join(top, "dir1/dir2/dir3"), 0755)
require.NoError(t, err)
return "dir1/dir2/dir3"
},
"dir1/dir2/dir3",
},
{ // Missing component
func(t *testing.T, top string) string {
return "thisismissing/dir2"
},
"",
},
{ // Symlink on the path
func(t *testing.T, top string) string {
err := os.MkdirAll(filepath.Join(top, "dir1/dir2"), 0755)
require.NoError(t, err)
err = os.Symlink("dir1", filepath.Join(top, "link1"))
require.NoError(t, err)
return "link1/dir2"
},
"dir1/dir2",
},
{ // Trailing symlink
func(t *testing.T, top string) string {
err := os.MkdirAll(filepath.Join(top, "dir1/dir2"), 0755)
require.NoError(t, err)
err = os.Symlink("dir2", filepath.Join(top, "dir1/link2"))
require.NoError(t, err)
return "dir1/link2"
},
"dir1/dir2",
},
{ // Symlink pointing nowhere, as a non-final component
func(t *testing.T, top string) string {
err := os.Symlink("thisismissing", filepath.Join(top, "link1"))
require.NoError(t, err)
return "link1/dir2"
},
"",
},
{ // Trailing symlink pointing nowhere (but note that a missing non-symlink would be accepted)
func(t *testing.T, top string) string {
err := os.Symlink("thisismissing", filepath.Join(top, "link1"))
require.NoError(t, err)
return "link1"
},
"",
},
{ // Relative components in a path
func(t *testing.T, top string) string {
err := os.MkdirAll(filepath.Join(top, "dir1/dir2/dir3"), 0755)
require.NoError(t, err)
return "dir1/./dir2/../dir2/dir3"
},
"dir1/dir2/dir3",
},
{ // Trailing relative components
func(t *testing.T, top string) string {
err := os.MkdirAll(filepath.Join(top, "dir1/dir2"), 0755)
require.NoError(t, err)
return "dir1/dir2/.."
},
"dir1",
},
{ // Relative components in symlink
func(t *testing.T, top string) string {
err := os.MkdirAll(filepath.Join(top, "dir1/dir2"), 0755)
require.NoError(t, err)
err = os.Symlink("../dir1/dir2", filepath.Join(top, "dir1/link2"))
require.NoError(t, err)
return "dir1/link2"
},
"dir1/dir2",
},
{ // Relative component pointing "into" a symlink
func(t *testing.T, top string) string {
err := os.MkdirAll(filepath.Join(top, "dir1/dir2/dir3"), 0755)
require.NoError(t, err)
err = os.Symlink("dir3", filepath.Join(top, "dir1/dir2/link3"))
require.NoError(t, err)
return "dir1/dir2/link3/../.."
},
"dir1",
},
{ // Unreadable directory
func(t *testing.T, top string) string {
err := os.MkdirAll(filepath.Join(top, "unreadable/dir2"), 0755)
require.NoError(t, err)
err = os.Chmod(filepath.Join(top, "unreadable"), 000)
require.NoError(t, err)
return "unreadable/dir2"
},
"",
},
}
func testPathsAreSameFile(t *testing.T, path1, path2, description string) {
fi1, err := os.Stat(path1)
require.NoError(t, err)
fi2, err := os.Stat(path2)
require.NoError(t, err)
assert.True(t, os.SameFile(fi1, fi2), description)
}
func runPathResolvingTestCase(t *testing.T, f func(string) (string, error), c pathResolvingTestCase, suffix string) {
topDir := t.TempDir()
defer func() {
// Clean up after the "Unreadable directory" case; os.RemoveAll just fails without this.
_ = os.Chmod(filepath.Join(topDir, "unreadable"), 0755) // Ignore errors, especially if this does not exist.
}()
input := c.setup(t, topDir) + suffix // Do not call filepath.Join() on input, it calls filepath.Clean() internally!
description := fmt.Sprintf("%s vs. %s%s", input, c.expected, suffix)
fullOutput, err := ResolvePathToFullyExplicit(topDir + "/" + input)
if c.expected == "" {
assert.Error(t, err, description)
} else {
require.NoError(t, err, input)
fullExpected := topDir + "/" + c.expected + suffix
assert.Equal(t, fullExpected, fullOutput)
// Either the two paths resolve to the same existing file, or to the same name in the same existing parent.
if _, err := os.Lstat(fullExpected); err == nil {
testPathsAreSameFile(t, fullOutput, fullExpected, description)
} else {
require.True(t, os.IsNotExist(err))
_, err := os.Stat(fullOutput)
require.Error(t, err)
require.True(t, os.IsNotExist(err))
parentExpected, fileExpected := filepath.Split(fullExpected)
parentOutput, fileOutput := filepath.Split(fullOutput)
assert.Equal(t, fileExpected, fileOutput)
testPathsAreSameFile(t, parentOutput, parentExpected, description)
}
}
}
func TestResolvePathToFullyExplicit(t *testing.T) {
for _, c := range testCases {
runPathResolvingTestCase(t, ResolvePathToFullyExplicit, c, "")
runPathResolvingTestCase(t, ResolvePathToFullyExplicit, c, "/trailing")
}
}
func TestResolveExistingPathToFullyExplicit(t *testing.T) {
for _, c := range testCases {
runPathResolvingTestCase(t, resolveExistingPathToFullyExplicit, c, "")
}
}