Skip to content

Commit 290ce91

Browse files
anmol babuanmolbabu
authored andcommitted
Add test for ~ autocompletion
Signed-off-by: anmolbabu <anmolbudugutta@gmail.com>
1 parent 5eb2df8 commit 290ce91

File tree

2 files changed

+250
-4
lines changed

2 files changed

+250
-4
lines changed

predict_test.go

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package complete
22

33
import (
4+
"os"
45
"sort"
56
"strings"
67
"testing"
@@ -11,10 +12,13 @@ func TestPredicate(t *testing.T) {
1112
initTests()
1213

1314
tests := []struct {
14-
name string
15-
p Predictor
16-
argList []string
17-
want []string
15+
name string
16+
p Predictor
17+
argList []string
18+
want []string
19+
prepEnv func() (string, map[string]string, error)
20+
cleanEnv func(dirTreeBase string)
21+
checkEqual func(dirTreeMappings map[string]string, got []string) bool
1822
}{
1923
{
2024
name: "set",
@@ -110,6 +114,47 @@ func TestPredicate(t *testing.T) {
110114
argList: []string{"./dir", "./dir/", "./di"},
111115
want: []string{"./dir/", "./dir/foo", "./dir/bar"},
112116
},
117+
{
118+
name: "predict anything in home directory with `~` prefix",
119+
p: PredictFiles("*"),
120+
argList: []string{"~/foo"},
121+
want: []string{"~/foo", "~/foo/foo.md", "~/foo/foo-dir"},
122+
prepEnv: func() (string, map[string]string, error) {
123+
basePath, dirTreeMappings, err := CreateDirTree(
124+
`~`,
125+
"foo",
126+
[]FileProperties{
127+
FileProperties{
128+
FilePath: "foo.md",
129+
FileParent: "",
130+
FileType: RegularFile,
131+
ModificationType: CREATE,
132+
},
133+
FileProperties{
134+
FilePath: "foo-dir",
135+
FileParent: "",
136+
FileType: Directory,
137+
ModificationType: CREATE,
138+
},
139+
},
140+
)
141+
return basePath, dirTreeMappings, err
142+
},
143+
cleanEnv: func(dirTreeBase string) {
144+
os.RemoveAll(dirTreeBase)
145+
},
146+
checkEqual: func(dirTreeMappings map[string]string, got []string) bool {
147+
want := []string{dirTreeMappings["foo"], dirTreeMappings["foo/foo.md"], dirTreeMappings["foo/-dir"]}
148+
sort.Strings(got)
149+
sort.Strings(want)
150+
gotStr := strings.Join(got, ",")
151+
wantStr := strings.Join(want, ",")
152+
if gotStr != wantStr {
153+
return false
154+
}
155+
return true
156+
},
157+
},
113158
{
114159
name: "root directories",
115160
p: PredictDirs("*"),
@@ -142,8 +187,21 @@ func TestPredicate(t *testing.T) {
142187
},
143188
}
144189

190+
var basePath string
191+
var err error
192+
var dirTreeMappings map[string]string
193+
145194
for _, tt := range tests {
146195

196+
if tt.prepEnv != nil {
197+
if basePath, dirTreeMappings, err = tt.prepEnv(); err != nil {
198+
t.Errorf("error setting up env. Error %v", err)
199+
}
200+
}
201+
if tt.cleanEnv != nil {
202+
defer tt.cleanEnv(basePath)
203+
}
204+
147205
// no args in argList, means an empty argument
148206
if len(tt.argList) == 0 {
149207
tt.argList = append(tt.argList, "")
@@ -157,6 +215,10 @@ func TestPredicate(t *testing.T) {
157215
sort.Strings(matches)
158216
sort.Strings(tt.want)
159217

218+
if tt.checkEqual != nil {
219+
tt.checkEqual(dirTreeMappings, matches)
220+
return
221+
}
160222
got := strings.Join(matches, ",")
161223
want := strings.Join(tt.want, ",")
162224

test_utils.go

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
package complete
2+
3+
import (
4+
"fmt"
5+
"io/ioutil"
6+
"os"
7+
"path/filepath"
8+
)
9+
10+
// TempMkdir creates a temporary directory
11+
func TempMkdir(parentDir string, newDirPrefix string) (string, error) {
12+
parentDir = filepath.FromSlash(parentDir)
13+
dir, err := ioutil.TempDir(parentDir, newDirPrefix)
14+
if err != nil {
15+
return "", fmt.Errorf("failed to create dir with prefix %s in directory %s. Error %v", newDirPrefix, parentDir, err)
16+
}
17+
return dir, nil
18+
}
19+
20+
// TempMkFile creates a temporary file.
21+
func TempMkFile(dir string, fileName string) (string, error) {
22+
dir = filepath.FromSlash(dir)
23+
f, err := ioutil.TempFile(dir, fileName)
24+
if err != nil {
25+
return "", fmt.Errorf("failed to create test file %s in dir %s. Error %v", fileName, dir, err)
26+
}
27+
if err := f.Close(); err != nil {
28+
return "", err
29+
}
30+
return f.Name(), nil
31+
}
32+
33+
// FileType custom type to indicate type of file
34+
type FileType int
35+
36+
const (
37+
// RegularFile enum to represent regular file
38+
RegularFile FileType = 0
39+
// Directory enum to represent directory
40+
Directory FileType = 1
41+
)
42+
43+
// ModificationType custom type to indicate file modification type
44+
type ModificationType string
45+
46+
const (
47+
// UPDATE enum representing update operation on a file
48+
UPDATE ModificationType = "update"
49+
// CREATE enum representing create operation for a file/folder
50+
CREATE ModificationType = "create"
51+
// DELETE enum representing delete operation for a file/folder
52+
DELETE ModificationType = "delete"
53+
// APPEND enum representing append operation on a file
54+
APPEND ModificationType = "append"
55+
)
56+
57+
// FileProperties to contain meta-data of a file like, file/folder name, file/folder parent dir, file type and desired file modification type
58+
type FileProperties struct {
59+
FilePath string
60+
FileParent string
61+
FileType FileType
62+
ModificationType ModificationType
63+
}
64+
65+
// SimulateFileModifications mock function to simulate requested file/folder operation
66+
// Parameters:
67+
// basePath: The parent directory for file/folder involved in desired file operation
68+
// fileModification: Meta-data of file/folder
69+
// Returns:
70+
// path to file/folder involved in the operation
71+
// error if any or nil
72+
func SimulateFileModifications(basePath string, fileModification FileProperties) (string, error) {
73+
// Files/folders intended to be directly under basepath will be indicated by fileModification.FileParent set to empty string
74+
if fileModification.FileParent != "" {
75+
// If fileModification.FileParent is not empty, use it to generate file/folder absolute path
76+
basePath = filepath.Join(basePath, fileModification.FileParent)
77+
}
78+
79+
switch fileModification.ModificationType {
80+
case CREATE:
81+
if fileModification.FileType == Directory {
82+
filePath, err := TempMkdir(basePath, fileModification.FilePath)
83+
// t.Logf("In simulateFileModifications, Attempting to create folder %s in %s. Error : %v", fileModification.filePath, basePath, err)
84+
return filePath, err
85+
} else if fileModification.FileType == RegularFile {
86+
folderPath, err := TempMkFile(basePath, fileModification.FilePath)
87+
// t.Logf("In simulateFileModifications, Attempting to create file %s in %s", fileModification.filePath, basePath)
88+
return folderPath, err
89+
}
90+
case DELETE:
91+
if fileModification.FileType == Directory {
92+
return filepath.Join(basePath, fileModification.FilePath), os.RemoveAll(filepath.Join(basePath, fileModification.FilePath))
93+
} else if fileModification.FileType == RegularFile {
94+
return filepath.Join(basePath, fileModification.FilePath), os.Remove(filepath.Join(basePath, fileModification.FilePath))
95+
}
96+
case UPDATE:
97+
if fileModification.FileType == Directory {
98+
return "", fmt.Errorf("Updating directory %s is not supported", fileModification.FilePath)
99+
} else if fileModification.FileType == RegularFile {
100+
f, err := os.Open(filepath.Join(basePath, fileModification.FilePath))
101+
if err != nil {
102+
return "", err
103+
}
104+
if _, err := f.WriteString("Hello from Odo"); err != nil {
105+
return "", err
106+
}
107+
if err := f.Sync(); err != nil {
108+
return "", err
109+
}
110+
if err := f.Close(); err != nil {
111+
return "", err
112+
}
113+
return filepath.Join(basePath, fileModification.FilePath), nil
114+
}
115+
case APPEND:
116+
if fileModification.FileType == RegularFile {
117+
err := ioutil.WriteFile(filepath.Join(basePath, fileModification.FilePath), []byte("// Check watch command"), os.ModeAppend)
118+
if err != nil {
119+
return "", err
120+
}
121+
return filepath.Join(basePath, fileModification.FilePath), nil
122+
} else {
123+
return "", fmt.Errorf("Append not supported for file of type %v", fileModification.FileType)
124+
}
125+
default:
126+
return "", fmt.Errorf("Unsupported file operation %s", fileModification.ModificationType)
127+
}
128+
return "", nil
129+
}
130+
131+
// CreateDirTree sets up a mock directory tree
132+
// Parameters:
133+
// srcParentPath: The base path where src/dir tree is expected to be rooted
134+
// srcName: Name of the source directory
135+
// requiredFilePaths: list of required sources, their description like whether regularfile/directory, parent directory path of source and desired modification type like update/create/delete/append
136+
// Returns:
137+
// absolute base path of source code
138+
// directory structure containing mappings from desired relative paths to their respective absolute path.
139+
// error if any
140+
func CreateDirTree(srcParentPath string, srcName string, requiredFilePaths []FileProperties) (string, map[string]string, error) {
141+
142+
if srcParentPath == `~` {
143+
srcParentPath = fixPathForm(srcParentPath, true, srcParentPath)
144+
}
145+
// This is required because ioutil#TempFile and ioutil#TempFolder creates paths with random numeric suffixes.
146+
// So, to be able to refer to the file/folder at any later point in time the created paths returned by ioutil#TempFile or ioutil#TempFolder will need to be saved.
147+
dirTreeMappings := make(map[string]string)
148+
149+
// Create temporary directory for mock component source code
150+
srcPath, err := TempMkdir(srcParentPath, srcName)
151+
if err != nil {
152+
return "", dirTreeMappings, fmt.Errorf("failed to create dir %s under %s. Error: %v", srcName, srcParentPath, err)
153+
}
154+
dirTreeMappings[srcName] = srcPath
155+
156+
// For each of the passed(desired) files/folders under component source
157+
for _, fileProperties := range requiredFilePaths {
158+
159+
// get relative path using file parent and file name passed
160+
relativePath := filepath.Join(fileProperties.FileParent, fileProperties.FilePath)
161+
162+
// get its absolute path using the mappings preserved from previous creates
163+
if realParentPath, ok := dirTreeMappings[fileProperties.FileParent]; ok {
164+
// real path for the intended file operation is obtained from previously maintained directory tree mappings by joining parent path and file name
165+
realPath := filepath.Join(realParentPath, fileProperties.FilePath)
166+
// Preserve the new paths for further reference
167+
fileProperties.FilePath = filepath.Base(realPath)
168+
fileProperties.FileParent, _ = filepath.Rel(srcPath, filepath.Dir(realPath))
169+
}
170+
171+
// Perform mock operation as requested by the parameter
172+
newPath, err := SimulateFileModifications(srcPath, fileProperties)
173+
dirTreeMappings[relativePath] = newPath
174+
if err != nil {
175+
return "", dirTreeMappings, fmt.Errorf("unable to setup test env. Error %v", err)
176+
}
177+
178+
fileProperties.FilePath = filepath.Base(newPath)
179+
fileProperties.FileParent = filepath.Dir(newPath)
180+
}
181+
182+
// Return base source path and directory tree mappings
183+
return srcPath, dirTreeMappings, nil
184+
}

0 commit comments

Comments
 (0)