fuzzyworld

template / windows / files / profile_test.go

Branch windows · default branch · all branches

profile_test.go

10.7 KB · history · blame

1package main
2
3import (
4 "io/fs"
5 "os"
6 "os/exec"
7 "os/user"
8 "path/filepath"
9 "runtime"
10 "testing"
11
12 "github.com/stretchr/testify/assert"
13)
14
15func TestValidateProfile(t *testing.T) {
16 testSuccess := func(profile Profile) {
17 err := validateProfile(&profile)
18 if err != nil {
19 t.Errorf("Expected to validate profile '%v', but failed: %v", profile.Name, err)
20 }
21 }
22 testFailure := func(profile Profile, expectedErrStr string) {
23 err := validateProfile(&profile)
24 assert.NotNil(t, err, "Expected to fail to validate profile '%v', but succeeded")
25 assert.Contains(t, err.Error(), expectedErrStr, "Expected error to contain '%v', but it didn't", expectedErrStr)
26 }
27
28 testSuccess(Profile{
29 Type: FileType,
30 Name: "daily",
31 NamePatterns: []ParameterizedText{"{{.Date}}"},
32 Path: "~/test/dir",
33 })
34 testSuccess(Profile{
35 Type: FileType,
36 Name: "daily",
37 NamePatterns: []ParameterizedText{"{{.Date}}"},
38 File: File{
39 Template: "foo",
40 },
41 Path: "~/test/dir",
42 })
43
44 testFailure(Profile{
45 Name: "",
46 }, "Profile name is required")
47 testFailure(Profile{
48 Name: "list",
49 }, "forbidden profile name 'list'")
50 testFailure(Profile{
51 Name: "get",
52 }, "forbidden profile name 'get'")
53 testFailure(Profile{
54 Type: FileType,
55 Name: "daily",
56 }, "namePatterns is required")
57 testFailure(Profile{
58 Type: FileType,
59 Name: "daily",
60 NamePatterns: []ParameterizedText{"blah"},
61 }, "path is not specified for profile daily, which has Type=file")
62
63 testFailure(Profile{
64 Type: FolderType,
65 Name: "daily",
66 NamePatterns: []ParameterizedText{"test"},
67 }, "path is required for profile daily, which has Type=folder")
68 testFailure(Profile{
69 Type: FolderType,
70 Name: "daily",
71 NamePatterns: []ParameterizedText{"test"},
72 File: File{
73 Template: "bar",
74 },
75 }, "file template is not supported for profile daily, which has Type=folder")
76 testFailure(Profile{
77 Type: ScriptType,
78 Name: "daily",
79 NamePatterns: []ParameterizedText{"test", "test2"},
80 }, "multiple name patterns are not supported for profile daily, which has Type=script")
81 testFailure(Profile{
82 Type: FileType,
83 Name: "daily",
84 NamePatterns: []ParameterizedText{"test", "test2"},
85 }, "path is not specified for profile daily, which has Type=file")
86 testFailure(Profile{
87 Type: FileType,
88 Name: "daily",
89 NamePatterns: []ParameterizedText{"test", ""},
90 }, "name pattern is required for pattern index 1 of profile daily")
91
92 for _, profile := range defaultConfig().Profiles {
93 testSuccess(profile)
94 }
95}
96
97func TestFindProfileIndex(t *testing.T) {
98 config := Config{
99 Profiles: []Profile{
100 {
101 Name: "daily",
102 },
103 {
104 IsDefault: true,
105 Name: "notes",
106 },
107 },
108 }
109 testSuccess := func(profileName string, expectedProfileName string) {
110 index, err := findProfileIndex(config.Profiles, profileName)
111 if err != nil {
112 t.Errorf("Failed to find profile '%v': %v", profileName, err)
113 }
114 profile := config.Profiles[index]
115 if profile.Name != expectedProfileName {
116 t.Errorf("Asked for profile '%v', expected '%v', got '%v'", profileName, expectedProfileName, profile.Name)
117 }
118 }
119 testFailure := func(profileName string) {
120 _, err := findProfileIndex(config.Profiles, profileName)
121 if err == nil {
122 t.Errorf("Expected to fail to find profile '%v', but succeeded", profileName)
123 }
124 }
125
126 testSuccess("daily", "daily")
127 testSuccess("notes", "notes")
128
129 testFailure("")
130 testFailure("non-existent")
131
132 config.Profiles[1].IsDefault = false
133 testFailure("")
134 testFailure("non-default")
135}
136
137func TestFindDefaultProfile(t *testing.T) {
138 _, err := findDefaultProfile(defaultConfig().Profiles)
139 assert.Nil(t, err, "Expected to find default profile, but failed")
140
141 _, err = findDefaultProfile([]Profile{})
142 assert.NotNil(t, err, "Expected to fail to find default profile, but succeeded")
143}
144
145func TestCreateEntity(t *testing.T) {
146 // setup
147 now := testNow()
148 cwd := "~/test/dir"
149 projectName := "project-name"
150 extras := map[string]string{
151 "foo": "bar",
152 }
153 patternData := testPrePatternData()
154
155 testFolder := func() {
156 monkeyPatchCalls := applyTestMonkeyPatch(t, monkeyPatch{
157 OSMkdir: func(path string, perm os.FileMode) error { return nil },
158 OSChdir: func(dir string) error { return nil },
159 OSWriteFile: func(filename string, data []byte, perm os.FileMode) error { return nil },
160 })
161
162 profile := Profile{
163 Type: FolderType,
164 Files: []FileInFolder{
165 {
166 Name: "readme.md",
167 File: File{
168 Template: "blah",
169 },
170 },
171 {
172 Name: "test.txt",
173 File: File{
174 Template: "foo",
175 },
176 },
177 },
178 }
179
180 newName := "new-name"
181 expectedFullPath := filepath.Clean("~/test/dir/" + newName)
182 fullPath, err := createEntity(now, profile, cwd, newName, projectName, extras, patternData)
183 assert.Nil(t, err)
184 assert.Equal(t, expectedFullPath, fullPath)
185 assert.Equal(t, 1, len(monkeyPatchCalls.OSChdirCalls))
186 assert.Equal(t, expectedFullPath, monkeyPatchCalls.OSChdirCalls[0].dir)
187 assert.Equal(t, 3, len(monkeyPatchCalls.OSMkdirCalls))
188 assert.Equal(t, expectedFullPath, monkeyPatchCalls.OSMkdirCalls[0].path)
189 assert.Equal(t, 2, len(monkeyPatchCalls.OSWriteFileCalls))
190 assert.Equal(t, filepath.Clean(expectedFullPath+"/readme.md"), monkeyPatchCalls.OSWriteFileCalls[0].filename)
191 assert.Equal(t, []byte("blah"), monkeyPatchCalls.OSWriteFileCalls[0].data)
192 assert.Equal(t, filepath.Clean(expectedFullPath+"/test.txt"), monkeyPatchCalls.OSWriteFileCalls[1].filename)
193 assert.Equal(t, []byte("foo"), monkeyPatchCalls.OSWriteFileCalls[1].data)
194 }
195
196 testFile := func() {
197 monkeyPatchCalls := applyTestMonkeyPatch(t, monkeyPatch{
198 OSWriteFile: func(filename string, data []byte, perm os.FileMode) error { return nil },
199 })
200
201 profile := Profile{
202 Type: FileType,
203 File: File{
204 Template: "blah",
205 },
206 }
207 newName := "new-name.md"
208 expectedFullPath := filepath.Clean("~/test/dir/" + newName)
209 fullPath, err := createEntity(now, profile, cwd, newName, projectName, extras, patternData)
210 assert.Nil(t, err)
211 assert.Equal(t, expectedFullPath, fullPath)
212 assert.Equal(t, 1, len(monkeyPatchCalls.OSWriteFileCalls))
213 assert.Equal(t, expectedFullPath, monkeyPatchCalls.OSWriteFileCalls[0].filename)
214 assert.Equal(t, []byte("blah"), monkeyPatchCalls.OSWriteFileCalls[0].data)
215 }
216
217 testScript := func() {
218 profile := Profile{
219 Type: ScriptType,
220 PostScripts: []ParameterizedText{
221 "{{.ProjectName}}-{{.Year}}-{{.Month}}-{{.Day}}-{{.Hour}}-{{.Minute}}-{{.Second}}-{{.Extras.key1}}",
222 },
223 }
224 newName := "new-name.md"
225 expectedFullPath := filepath.Clean("~/test/dir/" + newName)
226 fullPath, err := createEntity(now, profile, cwd, newName, projectName, extras, patternData)
227 assert.Nil(t, err)
228 assert.Equal(t, expectedFullPath, fullPath)
229 }
230
231 testFolder()
232
233 testFile()
234
235 testScript()
236}
237
238type testFile struct {
239 name string
240 isDir bool
241}
242
243func (f testFile) Name() string { return f.name }
244func (f testFile) IsDir() bool { return f.isDir }
245func (f testFile) Type() fs.FileMode { return 0 }
246func (f testFile) Info() (fs.FileInfo, error) { return nil, nil }
247
248func TestProcessProfile(t *testing.T) {
249 cwd := filepath.Clean("~/test/dir")
250 createDirEntry := func(name string, isDir bool) os.DirEntry {
251 entry := testFile{name: name, isDir: isDir}
252 return entry
253 }
254 var monkeyPatchCalls *monkeyPatchCalls
255 configureMonkeyPatching := func() {
256 monkeyPatchCalls = applyTestMonkeyPatch(t, monkeyPatch{
257 ExecCommand: func(command string, args ...string) *exec.Cmd {
258 return exec.Command("echo")
259 },
260 OSChdir: func(dir string) error { return nil },
261 OSGetwd: func() (dir string, err error) { return cwd, nil },
262 OSReadDir: func(dirname string) ([]os.DirEntry, error) {
263 return []os.DirEntry{
264 createDirEntry("dir1", true),
265 createDirEntry("dir2", true),
266 createDirEntry("file1", false),
267 createDirEntry("file2", false),
268 }, nil
269 },
270 OSWriteFile: func(filename string, data []byte, perm os.FileMode) error {
271 return nil
272 },
273 })
274 }
275
276 projectName := "project-name"
277 extras := map[string]string{
278 "foo": "bar",
279 }
280
281 usr, err := user.Current()
282 assert.Nil(t, err)
283 assert.NotNil(t, usr)
284
285 testSuccess := func(profile Profile) {
286 configureMonkeyPatching()
287 errors := processProfile(profile, projectName, extras, *usr)
288 assert.Equal(t, 0, len(errors))
289 for _, error := range errors {
290 assert.Nil(t, error)
291 }
292 }
293 testFailure := func(profile Profile, errorCount int, errorStr string) {
294 configureMonkeyPatching()
295 errors := processProfile(profile, projectName, extras, *usr)
296 assert.Equal(t, errorCount, len(errors))
297 allErrorsText := ""
298 for _, err := range errors {
299 allErrorsText += err.Error()
300 }
301 assert.Contains(t, allErrorsText, errorStr)
302 }
303 testSingleFailure := func(profile Profile, errorStr string) {
304 testFailure(profile, 1, errorStr)
305 }
306
307 // this profile will be built up from failing to eventually passing
308 currentOS := getCurrentOs()
309 profile := Profile{
310 IsDisabled: true,
311 }
312 testSingleFailure(profile, "Profile is disabled, doing nothing")
313 profile.IsDisabled = false
314 profile.OS = getOtherOs(currentOS)
315 testSingleFailure(profile, "This profile is not supported on this OS, doing nothing.")
316 profile.OS = currentOS
317 // testSingleFailure(profile, "unable to create post scripts: no post scripts specified")
318
319 profile.NamePatterns = []ParameterizedText{}
320 profile.Type = FileType
321 testSingleFailure(profile, "couldn't find a good new name")
322
323 profile.NamePatterns = []ParameterizedText{"file1"}
324 profile.RunPostscriptOnFailure = true
325 testSingleFailure(profile, "couldn't find a good new name")
326
327 profile.NamePatterns = []ParameterizedText{"file3"}
328 profile.PostScripts = []ParameterizedText{"echo {{.ProjectName}}-{{.Year}}"}
329 profile.Path = "~/test/dir"
330 testSuccess(profile)
331 assert.Equal(t, 1, len(monkeyPatchCalls.ExecCommandCalls), "calls to ExecCommand")
332 assert.Equal(t, 1, len(monkeyPatchCalls.OSChdirCalls), "calls to OSChdir")
333 assert.Equal(t, 1, len(monkeyPatchCalls.OSGetwdCalls), "calls to OSGetwd")
334 assert.Equal(t, 1, len(monkeyPatchCalls.OSReadDirCalls), "calls to OSReadDir")
335 assert.Equal(t, 1, len(monkeyPatchCalls.OSWriteFileCalls), "calls to OSWriteFile")
336
337 profile.PostScripts = []ParameterizedText{"echo ''"}
338 testSuccess(profile)
339 assert.Equal(t, 1, len(monkeyPatchCalls.ExecCommandCalls), "calls to ExecCommand")
340 assert.Equal(t, 1, len(monkeyPatchCalls.OSChdirCalls), "calls to OSChdir")
341 assert.Equal(t, 1, len(monkeyPatchCalls.OSGetwdCalls), "calls to OSGetwd")
342 assert.Equal(t, 1, len(monkeyPatchCalls.OSReadDirCalls), "calls to OSReadDir")
343 assert.Equal(t, 1, len(monkeyPatchCalls.OSWriteFileCalls), "calls to OSWriteFile")
344}
345
346func getCurrentOs() OSType {
347 os := runtime.GOOS
348 if os == "windows" {
349 return "Windows"
350 } else {
351 return "Mac"
352 }
353}
354func getOtherOs(currentOs OSType) OSType {
355 if currentOs == "Windows" {
356 return "Mac"
357 }
358 return "Windows"
359}