fuzzyworld

template / files / internal / core / profile_test.go

profile_test.go

22.1 KB · history · blame

1package core
2
3import (
4 "bufio"
5 "fmt"
6 "io/fs"
7 "os"
8 "os/exec"
9 "os/user"
10 "path/filepath"
11 "runtime"
12 "strings"
13 "testing"
14 "time"
15
16 "github.com/stretchr/testify/assert"
17)
18
19func TestValidateProfile(t *testing.T) {
20 testSuccess := func(profile Profile) {
21 err := validateProfile(&profile)
22 if err != nil {
23 t.Errorf("Expected to validate profile '%v', but failed: %v", profile.Name, err)
24 }
25 }
26 testFailure := func(profile Profile, expectedErrStr string) {
27 err := validateProfile(&profile)
28 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)
30 }
31
32 testSuccess(Profile{
33 Type: FileType,
34 Name: "daily",
35 NamePatterns: []ParameterizedText{"{{.Date}}"},
36 TargetDirectory: "~/test/dir",
37 })
38 testSuccess(Profile{
39 Type: FileType,
40 Name: "daily",
41 NamePatterns: []ParameterizedText{"{{.Date}}"},
42 FileTemplate: "foo",
43 TargetDirectory: "~/test/dir",
44 })
45
46 testFailure(Profile{
47 Name: "",
48 }, "profile name is required")
49 testFailure(Profile{
50 Name: "list",
51 }, "forbidden profile name 'list'")
52 testFailure(Profile{
53 Name: "get",
54 }, "forbidden profile name 'get'")
55 testFailure(Profile{
56 Type: FileType,
57 Name: "daily",
58 }, "namePatterns is required")
59 testFailure(Profile{
60 Type: FileType,
61 Name: "daily",
62 NamePatterns: []ParameterizedText{"blah"},
63 }, "targetDirectory is not specified for profile daily, which has Type=file")
64
65 testFailure(Profile{
66 Type: FolderType,
67 Name: "daily",
68 NamePatterns: []ParameterizedText{"test"},
69 }, "targetDirectory is not specified for profile daily, which has Type=folder")
70 testFailure(Profile{
71 Type: FolderType,
72 Name: "daily",
73 NamePatterns: []ParameterizedText{"test"},
74 FileTemplate: "bar",
75 }, "targetDirectory is not specified 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 }, "targetDirectory 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 FileTemplate: "blah",
168 },
169 {
170 Name: "test.txt",
171 FileTemplate: "foo",
172 },
173 },
174 }
175
176 newName := "new-name"
177 expectedFullPath := filepath.Clean("~/test/dir/" + newName)
178 fullPath, err := createEntity(now, profile, cwd, newName, projectName, extras, patternData, nil)
179 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)
183 assert.Equal(t, 3, len(monkeyPatchCalls.OSMkdirCalls))
184 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{
198 Type: FileType,
199 FileTemplate: "blah",
200 }
201 newName := "new-name.md"
202 expectedFullPath := filepath.Clean("~/test/dir/" + newName)
203 fullPath, err := createEntity(now, profile, cwd, newName, projectName, extras, patternData, nil)
204 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)
220 fullPath, err := createEntity(now, profile, cwd, newName, projectName, extras, patternData, nil)
221 assert.Nil(t, err)
222 assert.Equal(t, expectedFullPath, fullPath)
223 }
224
225 testFolder()
226
227 testFile()
228
229 testScript()
230
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")
299}
300
301type 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 }
310func (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}
322
323func TestProcessProfile(t *testing.T) {
324 cwd := filepath.Clean("~/test/dir")
325 var monkeyPatchCalls *monkeyPatchCalls
326 configureMonkeyPatching := func() {
327 monkeyPatchCalls = applyTestMonkeyPatch(t, monkeyPatch{
328 ExecCommand: func(command string, args ...string) *exec.Cmd {
329 shell, shellArgs := shellCommandAndArgs("echo")
330 return exec.Command(shell, shellArgs...)
331 },
332 OSCreate: func(name string) (file *os.File, err error) {
333 dir := os.TempDir()
334 return os.CreateTemp(dir, "test")
335 },
336 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 },
346 OSStat: func(name string) (os.FileInfo, error) {
347 return createDirEntry("dir1", true), nil
348 },
349 OSWriteFile: func(filename string, data []byte, perm os.FileMode) error {
350 return nil
351 },
352 })
353 }
354
355 projectName := "project-name"
356 extras := map[string]string{
357 "foo": "bar",
358 }
359
360 usr, err := user.Current()
361 assert.Nil(t, err)
362 assert.NotNil(t, usr)
363
364 testSuccess := func(profile Profile) {
365 configureMonkeyPatching()
366 errors := processProfile(profile, projectName, extras, *usr, nil)
367 assert.Equal(t, 0, len(errors))
368 for _, error := range errors {
369 assert.Nil(t, error)
370 }
371 }
372 testFailure := func(profile Profile, errorCount int, errorStr string) {
373 configureMonkeyPatching()
374 errors := processProfile(profile, projectName, extras, *usr, nil)
375 assert.Equal(t, errorCount, len(errors))
376 allErrorsText := ""
377 for _, err := range errors {
378 allErrorsText += err.Error()
379 }
380 assert.Contains(t, allErrorsText, errorStr)
381 }
382 testSingleFailure := func(profile Profile, errorStr string) {
383 testFailure(profile, 1, errorStr)
384 }
385
386 // this profile will be built up from failing to eventually passing
387 currentOS := getCurrentOs()
388 profile := Profile{
389 IsDisabled: true,
390 }
391 testSingleFailure(profile, "Profile is disabled, doing nothing")
392 profile.IsDisabled = false
393 profile.OS = getOtherOs(currentOS)
394 testSingleFailure(profile, "this profile is not supported on this OS, doing nothing.")
395 profile.OS = currentOS
396 // testSingleFailure(profile, "unable to create post scripts: no post scripts specified")
397
398 profile.NamePatterns = []ParameterizedText{}
399 profile.Type = FileType
400 testSingleFailure(profile, "couldn't find a good new name")
401
402 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}}"}
408 profile.TargetDirectory = "./test/dir"
409 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")
423
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")
601}
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 {
612 if currentOs == "Windows" {
613 return "Mac"
614 }
615 return "Windows"
616}