fuzzyworld

template / ci-testing / files / profile_test.go

Branch ci-testing · default branch · all branches

profile_test.go

10.8 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 shell, shellArgs := shellCommandAndArgs("echo")
259 return exec.Command(shell, shellArgs...)
260 },
261 OSChdir: func(dir string) error { return nil },
262 OSGetwd: func() (dir string, err error) { return cwd, nil },
263 OSReadDir: func(dirname string) ([]os.DirEntry, error) {
264 return []os.DirEntry{
265 createDirEntry("dir1", true),
266 createDirEntry("dir2", true),
267 createDirEntry("file1", false),
268 createDirEntry("file2", false),
269 }, nil
270 },
271 OSWriteFile: func(filename string, data []byte, perm os.FileMode) error {
272 return nil
273 },
274 })
275 }
276
277 projectName := "project-name"
278 extras := map[string]string{
279 "foo": "bar",
280 }
281
282 usr, err := user.Current()
283 assert.Nil(t, err)
284 assert.NotNil(t, usr)
285
286 testSuccess := func(profile Profile) {
287 configureMonkeyPatching()
288 errors := processProfile(profile, projectName, extras, *usr)
289 assert.Equal(t, 0, len(errors))
290 for _, error := range errors {
291 assert.Nil(t, error)
292 }
293 }
294 testFailure := func(profile Profile, errorCount int, errorStr string) {
295 configureMonkeyPatching()
296 errors := processProfile(profile, projectName, extras, *usr)
297 assert.Equal(t, errorCount, len(errors))
298 allErrorsText := ""
299 for _, err := range errors {
300 allErrorsText += err.Error()
301 }
302 assert.Contains(t, allErrorsText, errorStr)
303 }
304 testSingleFailure := func(profile Profile, errorStr string) {
305 testFailure(profile, 1, errorStr)
306 }
307
308 // this profile will be built up from failing to eventually passing
309 currentOS := getCurrentOs()
310 profile := Profile{
311 IsDisabled: true,
312 }
313 testSingleFailure(profile, "Profile is disabled, doing nothing")
314 profile.IsDisabled = false
315 profile.OS = getOtherOs(currentOS)
316 testSingleFailure(profile, "This profile is not supported on this OS, doing nothing.")
317 profile.OS = currentOS
318 // testSingleFailure(profile, "unable to create post scripts: no post scripts specified")
319
320 profile.NamePatterns = []ParameterizedText{}
321 profile.Type = FileType
322 testSingleFailure(profile, "couldn't find a good new name")
323
324 profile.NamePatterns = []ParameterizedText{"file1"}
325 profile.RunPostscriptOnFailure = true
326 testSingleFailure(profile, "couldn't find a good new name")
327
328 profile.NamePatterns = []ParameterizedText{"file3"}
329 profile.PostScripts = []ParameterizedText{"echo {{.ProjectName}}-{{.Year}}"}
330 profile.Path = "~/test/dir"
331 testSuccess(profile)
332 assert.Equal(t, 1, len(monkeyPatchCalls.ExecCommandCalls), "calls to ExecCommand")
333 assert.Equal(t, 1, len(monkeyPatchCalls.OSChdirCalls), "calls to OSChdir")
334 assert.Equal(t, 1, len(monkeyPatchCalls.OSGetwdCalls), "calls to OSGetwd")
335 assert.Equal(t, 1, len(monkeyPatchCalls.OSReadDirCalls), "calls to OSReadDir")
336 assert.Equal(t, 1, len(monkeyPatchCalls.OSWriteFileCalls), "calls to OSWriteFile")
337
338 profile.PostScripts = []ParameterizedText{"echo ''"}
339 testSuccess(profile)
340 assert.Equal(t, 1, len(monkeyPatchCalls.ExecCommandCalls), "calls to ExecCommand")
341 assert.Equal(t, 1, len(monkeyPatchCalls.OSChdirCalls), "calls to OSChdir")
342 assert.Equal(t, 1, len(monkeyPatchCalls.OSGetwdCalls), "calls to OSGetwd")
343 assert.Equal(t, 1, len(monkeyPatchCalls.OSReadDirCalls), "calls to OSReadDir")
344 assert.Equal(t, 1, len(monkeyPatchCalls.OSWriteFileCalls), "calls to OSWriteFile")
345}
346
347func getCurrentOs() OSType {
348 os := runtime.GOOS
349 if os == "windows" {
350 return "Windows"
351 } else {
352 return "Mac"
353 }
354}
355func getOtherOs(currentOs OSType) OSType {
356 if currentOs == "Windows" {
357 return "Mac"
358 }
359 return "Windows"
360}