fuzzyworld

template / files / internal / core / profile_test.go

profile_test.go

Blame: the commit that last changed each line · file · history

37160b89 2026-05-01 Pavel Safronov1package core
c62570e2 2022-09-23 Pavel Safronov2
3import (
ecad2935 2026-05-01 Pavel Safronov4 "bufio"
5 "fmt"
9573ca02 2022-11-16 Pavel Safronov6 "io/fs"
c3fc7a22 2022-10-30 Pavel Safronov7 "os"
8 "os/exec"
9 "os/user"
10 "path/filepath"
9573ca02 2022-11-16 Pavel Safronov11 "runtime"
ecad2935 2026-05-01 Pavel Safronov12 "strings"
c62570e2 2022-09-23 Pavel Safronov13 "testing"
6543e947 2022-12-29 Pavel Safronov14 "time"
c3fc7a22 2022-10-30 Pavel Safronov15
16 "github.com/stretchr/testify/assert"
c62570e2 2022-09-23 Pavel Safronov17)
18
763c260d 2022-10-06 Pavel Safronov19func TestValidateProfile(t *testing.T) {
20 testSuccess := func(profile Profile) {
b0586433 2022-10-21 Pavel Safronov21 err := validateProfile(&profile)
763c260d 2022-10-06 Pavel Safronov22 if err != nil {
23 t.Errorf("Expected to validate profile '%v', but failed: %v", profile.Name, err)
24 }
25 }
9573ca02 2022-11-16 Pavel Safronov26 testFailure := func(profile Profile, expectedErrStr string) {
b0586433 2022-10-21 Pavel Safronov27 err := validateProfile(&profile)
9573ca02 2022-11-16 Pavel Safronov28 assert.NotNil(t, err, "Expected to fail to validate profile '%v', but succeeded")
29 assert.Contains(t, err.Error(), expectedErrStr, "Expected error to contain '%v', but it didn't", expectedErrStr)
763c260d 2022-10-06 Pavel Safronov30 }
31
32 testSuccess(Profile{
873846b9 2022-12-09 Pavel Safronov33 Type: FileType,
34 Name: "daily",
35 NamePatterns: []ParameterizedText{"{{.Date}}"},
36 TargetDirectory: "~/test/dir",
763c260d 2022-10-06 Pavel Safronov37 })
05f9e8ef 2022-10-06 Pavel Safronov38 testSuccess(Profile{
873846b9 2022-12-09 Pavel Safronov39 Type: FileType,
40 Name: "daily",
41 NamePatterns: []ParameterizedText{"{{.Date}}"},
42 FileTemplate: "foo",
43 TargetDirectory: "~/test/dir",
05f9e8ef 2022-10-06 Pavel Safronov44 })
763c260d 2022-10-06 Pavel Safronov45
46 testFailure(Profile{
47 Name: "",
873846b9 2022-12-09 Pavel Safronov48 }, "profile name is required")
763c260d 2022-10-06 Pavel Safronov49 testFailure(Profile{
50 Name: "list",
9573ca02 2022-11-16 Pavel Safronov51 }, "forbidden profile name 'list'")
763c260d 2022-10-06 Pavel Safronov52 testFailure(Profile{
53 Name: "get",
9573ca02 2022-11-16 Pavel Safronov54 }, "forbidden profile name 'get'")
763c260d 2022-10-06 Pavel Safronov55 testFailure(Profile{
56 Type: FileType,
57 Name: "daily",
9573ca02 2022-11-16 Pavel Safronov58 }, "namePatterns is required")
763c260d 2022-10-06 Pavel Safronov59 testFailure(Profile{
9573ca02 2022-11-16 Pavel Safronov60 Type: FileType,
61 Name: "daily",
62 NamePatterns: []ParameterizedText{"blah"},
873846b9 2022-12-09 Pavel Safronov63 }, "targetDirectory is not specified for profile daily, which has Type=file")
8c15a714 2022-11-04 Pavel Safronov64
9573ca02 2022-11-16 Pavel Safronov65 testFailure(Profile{
66 Type: FolderType,
67 Name: "daily",
68 NamePatterns: []ParameterizedText{"test"},
873846b9 2022-12-09 Pavel Safronov69 }, "targetDirectory is not specified for profile daily, which has Type=folder")
05f9e8ef 2022-10-06 Pavel Safronov70 testFailure(Profile{
71 Type: FolderType,
72 Name: "daily",
1a02ef4e 2022-10-21 Pavel Safronov73 NamePatterns: []ParameterizedText{"test"},
873846b9 2022-12-09 Pavel Safronov74 FileTemplate: "bar",
75 }, "targetDirectory is not specified for profile daily, which has Type=folder")
05f9e8ef 2022-10-06 Pavel Safronov76 testFailure(Profile{
77 Type: ScriptType,
78 Name: "daily",
1a02ef4e 2022-10-21 Pavel Safronov79 NamePatterns: []ParameterizedText{"test", "test2"},
9573ca02 2022-11-16 Pavel Safronov80 }, "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"},
873846b9 2022-12-09 Pavel Safronov85 }, "targetDirectory is not specified for profile daily, which has Type=file")
9573ca02 2022-11-16 Pavel Safronov86 testFailure(Profile{
87 Type: FileType,
88 Name: "daily",
89 NamePatterns: []ParameterizedText{"test", ""},
90 }, "name pattern is required for pattern index 1 of profile daily")
763c260d 2022-10-06 Pavel Safronov91
92 for _, profile := range defaultConfig().Profiles {
93 testSuccess(profile)
94 }
95}
96
ae89a42a 2022-11-02 Pavel Safronov97func TestFindProfileIndex(t *testing.T) {
c62570e2 2022-09-23 Pavel Safronov98 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) {
ae89a42a 2022-11-02 Pavel Safronov110 index, err := findProfileIndex(config.Profiles, profileName)
c62570e2 2022-09-23 Pavel Safronov111 if err != nil {
112 t.Errorf("Failed to find profile '%v': %v", profileName, err)
113 }
ae89a42a 2022-11-02 Pavel Safronov114 profile := config.Profiles[index]
c62570e2 2022-09-23 Pavel Safronov115 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) {
ae89a42a 2022-11-02 Pavel Safronov120 _, err := findProfileIndex(config.Profiles, profileName)
c62570e2 2022-09-23 Pavel Safronov121 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
ae89a42a 2022-11-02 Pavel Safronov129 testFailure("")
c62570e2 2022-09-23 Pavel Safronov130 testFailure("non-existent")
05f9e8ef 2022-10-06 Pavel Safronov131
132 config.Profiles[1].IsDefault = false
133 testFailure("")
134 testFailure("non-default")
c62570e2 2022-09-23 Pavel Safronov135}
c3fc7a22 2022-10-30 Pavel Safronov136
ae89a42a 2022-11-02 Pavel Safronov137func 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
c3fc7a22 2022-10-30 Pavel Safronov145func 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 {
873846b9 2022-12-09 Pavel Safronov166 Name: "readme.md",
167 FileTemplate: "blah",
c3fc7a22 2022-10-30 Pavel Safronov168 },
169 {
873846b9 2022-12-09 Pavel Safronov170 Name: "test.txt",
171 FileTemplate: "foo",
c3fc7a22 2022-10-30 Pavel Safronov172 },
173 },
174 }
175
176 newName := "new-name"
177 expectedFullPath := filepath.Clean("~/test/dir/" + newName)
bbd011d0 2022-12-10 Pavel Safronov178 fullPath, err := createEntity(now, profile, cwd, newName, projectName, extras, patternData, nil)
c3fc7a22 2022-10-30 Pavel Safronov179 assert.Nil(t, err)
180 assert.Equal(t, expectedFullPath, fullPath)
181 assert.Equal(t, 1, len(monkeyPatchCalls.OSChdirCalls))
182 assert.Equal(t, expectedFullPath, monkeyPatchCalls.OSChdirCalls[0].dir)
5e424f1b 2022-11-12 Pavel Safronov183 assert.Equal(t, 3, len(monkeyPatchCalls.OSMkdirCalls))
c3fc7a22 2022-10-30 Pavel Safronov184 assert.Equal(t, expectedFullPath, monkeyPatchCalls.OSMkdirCalls[0].path)
185 assert.Equal(t, 2, len(monkeyPatchCalls.OSWriteFileCalls))
186 assert.Equal(t, filepath.Clean(expectedFullPath+"/readme.md"), monkeyPatchCalls.OSWriteFileCalls[0].filename)
187 assert.Equal(t, []byte("blah"), monkeyPatchCalls.OSWriteFileCalls[0].data)
188 assert.Equal(t, filepath.Clean(expectedFullPath+"/test.txt"), monkeyPatchCalls.OSWriteFileCalls[1].filename)
189 assert.Equal(t, []byte("foo"), monkeyPatchCalls.OSWriteFileCalls[1].data)
190 }
191
192 testFile := func() {
193 monkeyPatchCalls := applyTestMonkeyPatch(t, monkeyPatch{
194 OSWriteFile: func(filename string, data []byte, perm os.FileMode) error { return nil },
195 })
196
197 profile := Profile{
873846b9 2022-12-09 Pavel Safronov198 Type: FileType,
199 FileTemplate: "blah",
c3fc7a22 2022-10-30 Pavel Safronov200 }
201 newName := "new-name.md"
202 expectedFullPath := filepath.Clean("~/test/dir/" + newName)
bbd011d0 2022-12-10 Pavel Safronov203 fullPath, err := createEntity(now, profile, cwd, newName, projectName, extras, patternData, nil)
c3fc7a22 2022-10-30 Pavel Safronov204 assert.Nil(t, err)
205 assert.Equal(t, expectedFullPath, fullPath)
206 assert.Equal(t, 1, len(monkeyPatchCalls.OSWriteFileCalls))
207 assert.Equal(t, expectedFullPath, monkeyPatchCalls.OSWriteFileCalls[0].filename)
208 assert.Equal(t, []byte("blah"), monkeyPatchCalls.OSWriteFileCalls[0].data)
209 }
210
211 testScript := func() {
212 profile := Profile{
213 Type: ScriptType,
214 PostScripts: []ParameterizedText{
215 "{{.ProjectName}}-{{.Year}}-{{.Month}}-{{.Day}}-{{.Hour}}-{{.Minute}}-{{.Second}}-{{.Extras.key1}}",
216 },
217 }
218 newName := "new-name.md"
219 expectedFullPath := filepath.Clean("~/test/dir/" + newName)
bbd011d0 2022-12-10 Pavel Safronov220 fullPath, err := createEntity(now, profile, cwd, newName, projectName, extras, patternData, nil)
c3fc7a22 2022-10-30 Pavel Safronov221 assert.Nil(t, err)
222 assert.Equal(t, expectedFullPath, fullPath)
223 }
224
225 testFolder()
226
227 testFile()
228
229 testScript()
ecad2935 2026-05-01 Pavel Safronov230
231 // OSMkdir failure for folder type
232 applyTestMonkeyPatch(t, monkeyPatch{
233 OSMkdir: func(path string, perm os.FileMode) error { return fmt.Errorf("mkdir failed") },
234 })
235 _, err := createEntity(now, Profile{Type: FolderType}, cwd, "new-name", projectName, extras, patternData, nil)
236 assert.NotNil(t, err)
237 assert.Contains(t, err.Error(), "error creating directory")
238
239 // OSChdir failure after successful OSMkdir
240 applyTestMonkeyPatch(t, monkeyPatch{
241 OSMkdir: func(path string, perm os.FileMode) error { return nil },
242 OSChdir: func(dir string) error { return fmt.Errorf("chdir failed") },
243 })
244 _, err = createEntity(now, Profile{Type: FolderType}, cwd, "new-name", projectName, extras, patternData, nil)
245 assert.NotNil(t, err)
246 assert.Contains(t, err.Error(), "unable to change directory")
247
248 // createFile failure inside folder (FolderType)
249 applyTestMonkeyPatch(t, monkeyPatch{
250 OSMkdir: func(path string, perm os.FileMode) error { return nil },
251 OSChdir: func(dir string) error { return nil },
252 OSWriteFile: func(filename string, data []byte, perm os.FileMode) error { return fmt.Errorf("write failed") },
253 })
254 _, err = createEntity(now, Profile{
255 Type: FolderType,
256 Files: []FileInFolder{{Name: "f.md", FileTemplate: "tmpl"}},
257 }, cwd, "new-name", projectName, extras, patternData, nil)
258 assert.NotNil(t, err)
259 assert.Contains(t, err.Error(), "error creating file")
260
261 // invalid file name pattern inside folder triggers createNewNameForPatterns failure
262 applyTestMonkeyPatch(t, monkeyPatch{
263 OSMkdir: func(path string, perm os.FileMode) error { return nil },
264 OSChdir: func(dir string) error { return nil },
265 })
266 _, err = createEntity(now, Profile{
267 Type: FolderType,
268 Files: []FileInFolder{{Name: ParameterizedText("{{.Bad"), FileTemplate: "tmpl"}},
269 }, cwd, "new-name", projectName, extras, patternData, nil)
270 assert.NotNil(t, err)
271 assert.Contains(t, err.Error(), "error creating file name for file index")
272
273 // subdir OSMkdir failure inside folder
274 mkdirCount := 0
275 applyTestMonkeyPatch(t, monkeyPatch{
276 OSMkdir: func(path string, perm os.FileMode) error {
277 mkdirCount++
278 if mkdirCount > 1 {
279 return fmt.Errorf("subdir mkdir failed")
280 }
281 return nil
282 },
283 OSChdir: func(dir string) error { return nil },
284 })
285 _, err = createEntity(now, Profile{
286 Type: FolderType,
287 Files: []FileInFolder{{Name: "f.md", FileTemplate: "tmpl"}},
288 }, cwd, "new-name", projectName, extras, patternData, nil)
289 assert.NotNil(t, err)
290 assert.Contains(t, err.Error(), "error creating sub directory")
291
292 // FileType createFile failure
293 applyTestMonkeyPatch(t, monkeyPatch{
294 OSWriteFile: func(filename string, data []byte, perm os.FileMode) error { return fmt.Errorf("write failed") },
295 })
296 _, err = createEntity(now, Profile{Type: FileType, FileTemplate: "tmpl"}, cwd, "new-name.md", projectName, extras, patternData, nil)
297 assert.NotNil(t, err)
298 assert.Contains(t, err.Error(), "error writing file")
c3fc7a22 2022-10-30 Pavel Safronov299}
300
9573ca02 2022-11-16 Pavel Safronov301type testFile struct {
302 name string
303 isDir bool
304}
305
306func (f testFile) Name() string { return f.name }
307func (f testFile) IsDir() bool { return f.isDir }
308func (f testFile) Type() fs.FileMode { return 0 }
309func (f testFile) Info() (fs.FileInfo, error) { return nil, nil }
6543e947 2022-12-29 Pavel Safronov310func (f testFile) ModTime() time.Time { return time.Time{} }
311func (f testFile) Mode() fs.FileMode { return 0 }
312func (f testFile) Size() int64 { return 0 }
313func (f testFile) Sys() any { return nil }
314
315var _ os.DirEntry = testFile{}
316var _ os.FileInfo = testFile{}
317
318func createDirEntry(name string, isDir bool) testFile {
319 entry := testFile{name: name, isDir: isDir}
320 return entry
321}
9573ca02 2022-11-16 Pavel Safronov322
c3fc7a22 2022-10-30 Pavel Safronov323func TestProcessProfile(t *testing.T) {
324 cwd := filepath.Clean("~/test/dir")
9573ca02 2022-11-16 Pavel Safronov325 var monkeyPatchCalls *monkeyPatchCalls
326 configureMonkeyPatching := func() {
327 monkeyPatchCalls = applyTestMonkeyPatch(t, monkeyPatch{
328 ExecCommand: func(command string, args ...string) *exec.Cmd {
748e3056 2022-11-19 Pavel Safronov329 shell, shellArgs := shellCommandAndArgs("echo")
330 return exec.Command(shell, shellArgs...)
9573ca02 2022-11-16 Pavel Safronov331 },
bbd011d0 2022-12-10 Pavel Safronov332 OSCreate: func(name string) (file *os.File, err error) {
333 dir := os.TempDir()
334 return os.CreateTemp(dir, "test")
335 },
9573ca02 2022-11-16 Pavel Safronov336 OSChdir: func(dir string) error { return nil },
337 OSGetwd: func() (dir string, err error) { return cwd, nil },
338 OSReadDir: func(dirname string) ([]os.DirEntry, error) {
339 return []os.DirEntry{
340 createDirEntry("dir1", true),
341 createDirEntry("dir2", true),
342 createDirEntry("file1", false),
343 createDirEntry("file2", false),
344 }, nil
345 },
6543e947 2022-12-29 Pavel Safronov346 OSStat: func(name string) (os.FileInfo, error) {
347 return createDirEntry("dir1", true), nil
348 },
9573ca02 2022-11-16 Pavel Safronov349 OSWriteFile: func(filename string, data []byte, perm os.FileMode) error {
350 return nil
351 },
352 })
353 }
c3fc7a22 2022-10-30 Pavel Safronov354
355 projectName := "project-name"
356 extras := map[string]string{
357 "foo": "bar",
358 }
a5ad914b 2022-10-30 Pavel Safronov359
9573ca02 2022-11-16 Pavel Safronov360 usr, err := user.Current()
361 assert.Nil(t, err)
362 assert.NotNil(t, usr)
a5ad914b 2022-10-30 Pavel Safronov363
9573ca02 2022-11-16 Pavel Safronov364 testSuccess := func(profile Profile) {
365 configureMonkeyPatching()
bbd011d0 2022-12-10 Pavel Safronov366 errors := processProfile(profile, projectName, extras, *usr, nil)
a5ad914b 2022-10-30 Pavel Safronov367 assert.Equal(t, 0, len(errors))
9573ca02 2022-11-16 Pavel Safronov368 for _, error := range errors {
369 assert.Nil(t, error)
370 }
a5ad914b 2022-10-30 Pavel Safronov371 }
9573ca02 2022-11-16 Pavel Safronov372 testFailure := func(profile Profile, errorCount int, errorStr string) {
373 configureMonkeyPatching()
bbd011d0 2022-12-10 Pavel Safronov374 errors := processProfile(profile, projectName, extras, *usr, nil)
9573ca02 2022-11-16 Pavel Safronov375 assert.Equal(t, errorCount, len(errors))
376 allErrorsText := ""
377 for _, err := range errors {
378 allErrorsText += err.Error()
a5ad914b 2022-10-30 Pavel Safronov379 }
9573ca02 2022-11-16 Pavel Safronov380 assert.Contains(t, allErrorsText, errorStr)
381 }
382 testSingleFailure := func(profile Profile, errorStr string) {
383 testFailure(profile, 1, errorStr)
384 }
a5ad914b 2022-10-30 Pavel Safronov385
9573ca02 2022-11-16 Pavel Safronov386 // this profile will be built up from failing to eventually passing
387 currentOS := getCurrentOs()
388 profile := Profile{
389 IsDisabled: true,
a5ad914b 2022-10-30 Pavel Safronov390 }
9573ca02 2022-11-16 Pavel Safronov391 testSingleFailure(profile, "Profile is disabled, doing nothing")
392 profile.IsDisabled = false
393 profile.OS = getOtherOs(currentOS)
873846b9 2022-12-09 Pavel Safronov394 testSingleFailure(profile, "this profile is not supported on this OS, doing nothing.")
9573ca02 2022-11-16 Pavel Safronov395 profile.OS = currentOS
396 // testSingleFailure(profile, "unable to create post scripts: no post scripts specified")
a5ad914b 2022-10-30 Pavel Safronov397
9573ca02 2022-11-16 Pavel Safronov398 profile.NamePatterns = []ParameterizedText{}
399 profile.Type = FileType
400 testSingleFailure(profile, "couldn't find a good new name")
a5ad914b 2022-10-30 Pavel Safronov401
9573ca02 2022-11-16 Pavel Safronov402 profile.NamePatterns = []ParameterizedText{"file1"}
403 profile.RunPostscriptOnFailure = true
404 testSingleFailure(profile, "couldn't find a good new name")
405
406 profile.NamePatterns = []ParameterizedText{"file3"}
407 profile.PostScripts = []ParameterizedText{"echo {{.ProjectName}}-{{.Year}}"}
6543e947 2022-12-29 Pavel Safronov408 profile.TargetDirectory = "./test/dir"
9573ca02 2022-11-16 Pavel Safronov409 testSuccess(profile)
410 assert.Equal(t, 1, len(monkeyPatchCalls.ExecCommandCalls), "calls to ExecCommand")
411 assert.Equal(t, 1, len(monkeyPatchCalls.OSChdirCalls), "calls to OSChdir")
412 assert.Equal(t, 1, len(monkeyPatchCalls.OSGetwdCalls), "calls to OSGetwd")
413 assert.Equal(t, 1, len(monkeyPatchCalls.OSReadDirCalls), "calls to OSReadDir")
414 assert.Equal(t, 1, len(monkeyPatchCalls.OSWriteFileCalls), "calls to OSWriteFile")
415
416 profile.PostScripts = []ParameterizedText{"echo ''"}
417 testSuccess(profile)
418 assert.Equal(t, 1, len(monkeyPatchCalls.ExecCommandCalls), "calls to ExecCommand")
419 assert.Equal(t, 1, len(monkeyPatchCalls.OSChdirCalls), "calls to OSChdir")
420 assert.Equal(t, 1, len(monkeyPatchCalls.OSGetwdCalls), "calls to OSGetwd")
421 assert.Equal(t, 1, len(monkeyPatchCalls.OSReadDirCalls), "calls to OSReadDir")
422 assert.Equal(t, 1, len(monkeyPatchCalls.OSWriteFileCalls), "calls to OSWriteFile")
ecad2935 2026-05-01 Pavel Safronov423
424 // script-type profile runs a post-script and creates no files
425 scriptProfile := Profile{
426 Type: ScriptType,
427 Name: "my-script",
428 PostScripts: []ParameterizedText{"echo hello"},
429 }
430 testSuccess(scriptProfile)
431 assert.Equal(t, 1, len(monkeyPatchCalls.ExecCommandCalls), "script profile should run one command")
432 assert.Equal(t, 0, len(monkeyPatchCalls.OSWriteFileCalls), "script profile should not write files")
433
434 // pipe input with a folder-type profile is an error
435 folderProfile := Profile{
436 Type: FolderType,
437 Name: "folder",
438 NamePatterns: []ParameterizedText{"newfolder"},
439 TargetDirectory: "./test/dir",
440 }
441 scanner := bufio.NewScanner(strings.NewReader("some input"))
442 configureMonkeyPatching()
443 errs := processProfile(folderProfile, projectName, extras, *usr, scanner)
444 assert.Equal(t, 1, len(errs))
445 assert.Contains(t, errs[0].Error(), "cannot use pipe input with non-file type profile")
446
447 // OSGetwd failure
448 applyTestMonkeyPatch(t, monkeyPatch{
449 OSGetwd: func() (string, error) { return "", fmt.Errorf("getwd failed") },
450 })
451 errs = processProfile(Profile{Type: FileType, NamePatterns: []ParameterizedText{"f"}}, projectName, extras, *usr, nil)
452 assert.Equal(t, 1, len(errs))
453 assert.Contains(t, errs[0].Error(), "unable to get current working directory")
454
455 // OSReadDir failure
456 applyTestMonkeyPatch(t, monkeyPatch{
457 OSGetwd: func() (string, error) { return cwd, nil },
458 OSReadDir: func(dirname string) ([]os.DirEntry, error) { return nil, fmt.Errorf("readdir failed") },
459 OSStat: func(name string) (os.FileInfo, error) { return createDirEntry("d", true), nil },
460 OSChdir: func(dir string) error { return nil },
461 })
462 errs = processProfile(Profile{Type: FileType, NamePatterns: []ParameterizedText{"f"}, TargetDirectory: "./test/dir"}, projectName, extras, *usr, nil)
463 assert.Equal(t, 1, len(errs))
464 assert.Contains(t, errs[0].Error(), "readdir failed")
465
466 // OSStat returns ErrNotExist → OSMkdir fails
467 applyTestMonkeyPatch(t, monkeyPatch{
468 OSGetwd: func() (string, error) { return cwd, nil },
469 OSStat: func(name string) (os.FileInfo, error) { return nil, os.ErrNotExist },
470 OSMkdir: func(path string, perm os.FileMode) error { return fmt.Errorf("mkdir target failed") },
471 })
472 errs = processProfile(Profile{Type: FileType, NamePatterns: []ParameterizedText{"f"}, TargetDirectory: "./test/dir"}, projectName, extras, *usr, nil)
473 assert.Equal(t, 1, len(errs))
474 assert.Contains(t, errs[0].Error(), "unable to create target directory")
475
476 // OSChdir fails after mkdir succeeds
477 applyTestMonkeyPatch(t, monkeyPatch{
478 OSGetwd: func() (string, error) { return cwd, nil },
479 OSStat: func(name string) (os.FileInfo, error) { return nil, os.ErrNotExist },
480 OSMkdir: func(path string, perm os.FileMode) error { return nil },
481 OSChdir: func(dir string) error { return fmt.Errorf("chdir target failed") },
482 })
483 errs = processProfile(Profile{Type: FileType, NamePatterns: []ParameterizedText{"f"}, TargetDirectory: "./test/dir"}, projectName, extras, *usr, nil)
484 assert.Equal(t, 1, len(errs))
485 assert.Contains(t, errs[0].Error(), "unable to change directory (1)")
486
487 // RunPostscriptOnFailure=true, no good name, still runs post script
488 applyTestMonkeyPatch(t, monkeyPatch{
489 OSGetwd: func() (string, error) { return cwd, nil },
490 OSStat: func(name string) (os.FileInfo, error) { return createDirEntry("d", true), nil },
491 OSReadDir: func(dirname string) ([]os.DirEntry, error) {
492 return []os.DirEntry{createDirEntry("file1", false)}, nil
493 },
494 ExecCommand: func(command string, args ...string) *exec.Cmd {
495 shell, shellArgs := shellCommandAndArgs("echo")
496 return exec.Command(shell, shellArgs...)
497 },
498 })
499 errs = processProfile(Profile{
500 Type: FileType,
501 NamePatterns: []ParameterizedText{"file1"},
502 RunPostscriptOnFailure: true,
503 PostScripts: []ParameterizedText{"echo hi"},
504 }, projectName, extras, *usr, nil)
505 assert.Equal(t, 0, len(errs))
506
507 // createEntity error without swallow → "unable to create entity"
508 applyTestMonkeyPatch(t, monkeyPatch{
509 OSGetwd: func() (string, error) { return cwd, nil },
510 OSStat: func(name string) (os.FileInfo, error) { return createDirEntry("d", true), nil },
511 OSReadDir: func(dirname string) ([]os.DirEntry, error) { return []os.DirEntry{}, nil },
512 OSWriteFile: func(filename string, data []byte, perm os.FileMode) error {
513 return fmt.Errorf("write failed")
514 },
515 })
516 errs = processProfile(Profile{
517 Type: FileType,
518 NamePatterns: []ParameterizedText{"newfile"},
519 }, projectName, extras, *usr, nil)
520 assert.Equal(t, 1, len(errs))
521 assert.Contains(t, errs[0].Error(), "unable to create entity")
522
523 // createEntity error with swallow → continues to post scripts
524 applyTestMonkeyPatch(t, monkeyPatch{
525 OSGetwd: func() (string, error) { return cwd, nil },
526 OSStat: func(name string) (os.FileInfo, error) { return createDirEntry("d", true), nil },
527 OSReadDir: func(dirname string) ([]os.DirEntry, error) { return []os.DirEntry{}, nil },
528 OSWriteFile: func(filename string, data []byte, perm os.FileMode) error {
529 return fmt.Errorf("write failed")
530 },
531 ExecCommand: func(command string, args ...string) *exec.Cmd {
532 shell, shellArgs := shellCommandAndArgs("echo")
533 return exec.Command(shell, shellArgs...)
534 },
535 })
536 errs = processProfile(Profile{
537 Type: FileType,
538 NamePatterns: []ParameterizedText{"newfile"},
539 RunPostscriptOnFailure: true,
540 PostScripts: []ParameterizedText{"echo hi"},
541 }, projectName, extras, *usr, nil)
542 assert.Equal(t, 0, len(errs))
543
544 // invalid post script template → createPostScriptArrays failure
545 configureMonkeyPatching()
546 errs = processProfile(Profile{
547 Type: FileType,
548 NamePatterns: []ParameterizedText{"file3"},
549 TargetDirectory: "./test/dir",
550 PostScripts: []ParameterizedText{"{{.Bad"},
551 }, projectName, extras, *usr, nil)
552 assert.Equal(t, 1, len(errs))
553 assert.Contains(t, errs[0].Error(), "unable to create post scripts")
554
555 // post script with no output → "Post script had no output"
556 applyTestMonkeyPatch(t, monkeyPatch{
557 OSGetwd: func() (string, error) { return cwd, nil },
558 OSStat: func(name string) (os.FileInfo, error) { return createDirEntry("d", true), nil },
559 OSReadDir: func(dirname string) ([]os.DirEntry, error) { return []os.DirEntry{}, nil },
560 OSWriteFile: func(filename string, data []byte, perm os.FileMode) error { return nil },
561 ExecCommand: func(command string, args ...string) *exec.Cmd {
562 return exec.Command("sh", "-c", "true") // exits 0, no stdout output
563 },
564 })
565 errs = processProfile(Profile{
566 Type: FileType,
567 NamePatterns: []ParameterizedText{"newfile"},
568 PostScripts: []ParameterizedText{"true"},
569 }, projectName, extras, *usr, nil)
570 assert.Equal(t, 0, len(errs))
571
572 // post script that exits non-zero → logs error but does not fail
573 applyTestMonkeyPatch(t, monkeyPatch{
574 OSGetwd: func() (string, error) { return cwd, nil },
575 OSStat: func(name string) (os.FileInfo, error) { return createDirEntry("d", true), nil },
576 OSReadDir: func(dirname string) ([]os.DirEntry, error) { return []os.DirEntry{}, nil },
577 OSWriteFile: func(filename string, data []byte, perm os.FileMode) error { return nil },
578 ExecCommand: func(command string, args ...string) *exec.Cmd {
579 return exec.Command("sh", "-c", "false") // exits 1
580 },
581 })
582 errs = processProfile(Profile{
583 Type: FileType,
584 NamePatterns: []ParameterizedText{"newfile"},
585 PostScripts: []ParameterizedText{"false"},
586 }, projectName, extras, *usr, nil)
587 assert.Equal(t, 0, len(errs))
588}
589
590func TestCreateNewNameForPatternsGetVersionError(t *testing.T) {
591 now := testNow()
592 patternData := testPrePatternData()
593 // getVersion used in a non-last pattern is an error
594 _, err := createNewNameForPatterns(now, patternData, "proj",
595 []ParameterizedText{"{{getVersion}}-name", "fallback"},
596 nil,
597 func(newName string) bool { return false }, // always reject
598 )
599 assert.NotNil(t, err)
600 assert.Contains(t, err.Error(), "cannot use function getVersion in a pattern that is not the last pattern")
9573ca02 2022-11-16 Pavel Safronov601}
602
603func getCurrentOs() OSType {
604 os := runtime.GOOS
605 if os == "windows" {
606 return "Windows"
607 } else {
608 return "Mac"
609 }
610}
611func getOtherOs(currentOs OSType) OSType {
9b0177be 2022-11-19 Pavel Safronov612 if currentOs == "Windows" {
9573ca02 2022-11-16 Pavel Safronov613 return "Mac"
614 }
615 return "Windows"
c3fc7a22 2022-10-30 Pavel Safronov616}