github.com/beauknowssoftware/makehcl@v0.0.0-20200322000747-1b9bb1e1c008/internal/plan/plan_test.go (about) 1 package plan_test 2 3 import ( 4 "io" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 "testing" 9 10 "github.com/beauknowssoftware/makehcl/internal/plan" 11 "github.com/google/go-cmp/cmp" 12 "github.com/pkg/errors" 13 ) 14 15 const ( 16 local = false 17 ) 18 19 type filename = string 20 type fileContents = []byte 21 22 func createFile(t *testing.T, f filename, data fileContents) { 23 dir := filepath.Dir(f) 24 if err := os.MkdirAll(dir, os.ModePerm); err != nil { 25 err = errors.Wrapf(err, "failed to create directory %v", dir) 26 t.Fatal(err) 27 } 28 29 if err := ioutil.WriteFile(f, data, os.ModePerm); err != nil { 30 err = errors.Wrapf(err, "failed to write file %v", f) 31 t.Fatal(err) 32 } 33 } 34 35 func copyFile(t *testing.T, src, dest string) { 36 out, err := os.Create(dest) 37 if err != nil { 38 err = errors.Wrapf(err, "failed to create %v", dest) 39 t.Fatal(err) 40 } 41 defer out.Close() 42 43 in, err := os.Open(src) 44 if err != nil { 45 err = errors.Wrapf(err, "failed to open %v", src) 46 t.Fatal(err) 47 } 48 defer in.Close() 49 50 if _, err := io.Copy(out, in); err != nil { 51 err = errors.Wrapf(err, "failed to copy from %v to %v", src, dest) 52 t.Fatal(err) 53 } 54 } 55 56 func safeDo(t *testing.T, o plan.DoOptions) plan.Plan { 57 p, err := plan.Do(o) 58 if err != nil { 59 err = errors.Wrap(err, "failed to plan") 60 t.Fatal(err) 61 } 62 63 return p 64 } 65 66 func copyDir(t *testing.T, src, dest string) { 67 entries, err := ioutil.ReadDir(src) 68 if err != nil { 69 err = errors.Wrapf(err, "failed to list %v", src) 70 t.Fatal(err) 71 } 72 73 for _, entry := range entries { 74 srcFile := filepath.Join(src, entry.Name()) 75 destFile := filepath.Join(dest, entry.Name()) 76 copyFile(t, srcFile, destFile) 77 } 78 } 79 80 func copyToTemp(t *testing.T, src string) string { 81 tempDir, err := ioutil.TempDir("", "makehcl") 82 if err != nil { 83 err = errors.Wrap(err, "failed to create temporary directory") 84 t.Fatal(err) 85 } 86 87 copyDir(t, src, tempDir) 88 89 return tempDir 90 } 91 92 func pushd(t *testing.T, dir string) func() { 93 originalDir, err := os.Getwd() 94 if err != nil { 95 err = errors.Wrap(err, "failed to get working directory") 96 t.Fatal(err) 97 } 98 99 if !local { 100 dir = copyToTemp(t, dir) 101 } 102 103 if err := os.Chdir(dir); err != nil { 104 err = errors.Wrapf(err, "failed to pushd to %v", dir) 105 t.Fatal(err) 106 } 107 108 return func() { 109 if err := os.Chdir(originalDir); err != nil { 110 err = errors.Wrapf(err, "failed to popd directories to %v", originalDir) 111 t.Fatal(err) 112 } 113 114 if !local { 115 if err := os.RemoveAll(dir); err != nil { 116 err = errors.Wrapf(err, "failed to remove %v", dir) 117 t.Fatal(err) 118 } 119 } 120 } 121 } 122 123 func TestRun(t *testing.T) { 124 tests := map[string]struct { 125 folder string 126 existing []map[filename]fileContents 127 expected plan.Plan 128 options plan.DoOptions 129 }{ 130 "simple": { 131 folder: "testdata/simple", 132 expected: plan.Plan{ 133 plan.Item{ 134 Target: "test.txt", 135 Reasons: []plan.Reason{ 136 { 137 Target: "test.txt", 138 ReasonType: plan.DoesNotExist, 139 }, 140 }, 141 }, 142 }, 143 }, 144 "dependencies": { 145 folder: "testdata/dependencies", 146 expected: plan.Plan{ 147 plan.Item{ 148 Target: "test2.txt", 149 Reasons: []plan.Reason{ 150 { 151 Target: "test2.txt", 152 ReasonType: plan.DoesNotExist, 153 }, 154 }, 155 }, 156 plan.Item{ 157 Target: "test.txt", 158 Reasons: []plan.Reason{ 159 { 160 Target: "test.txt", 161 ReasonType: plan.DoesNotExist, 162 }, 163 }, 164 }, 165 plan.Item{ 166 Target: "test3.txt", 167 Reasons: []plan.Reason{ 168 { 169 Target: "test3.txt", 170 ReasonType: plan.DoesNotExist, 171 }, 172 }, 173 }, 174 }, 175 }, 176 "existing files": { 177 folder: "testdata/dependencies", 178 existing: []map[filename]fileContents{ 179 {"test2.txt": {}}, 180 }, 181 expected: plan.Plan{ 182 plan.Item{ 183 Target: "test.txt", 184 Reasons: []plan.Reason{ 185 { 186 Target: "test.txt", 187 ReasonType: plan.DoesNotExist, 188 }, 189 }, 190 }, 191 plan.Item{ 192 Target: "test3.txt", 193 Reasons: []plan.Reason{ 194 { 195 Target: "test3.txt", 196 ReasonType: plan.DoesNotExist, 197 }, 198 }, 199 }, 200 }, 201 }, 202 "ignore last modified": { 203 folder: "testdata/ignore_last_modified", 204 options: plan.DoOptions{ 205 Options: plan.Options{ 206 IgnoreLastModified: true, 207 }, 208 }, 209 existing: []map[filename]fileContents{ 210 {"test2.txt": {}}, 211 {"test.txt": {}}, 212 {"test3.txt": {}}, 213 }, 214 expected: plan.Plan{ 215 plan.Item{Target: "test2.txt"}, 216 plan.Item{Target: "test.txt"}, 217 plan.Item{Target: "test3.txt"}, 218 }, 219 }, 220 "out of date": { 221 folder: "testdata/out_of_date", 222 existing: []map[filename]fileContents{ 223 {"test2.txt": {}}, 224 {"test.txt": {}}, 225 {"test3.txt": {}}, 226 {"test2.txt": {}}, 227 }, 228 expected: plan.Plan{ 229 plan.Item{ 230 Target: "test.txt", 231 Reasons: []plan.Reason{ 232 { 233 Target: "test2.txt", 234 ReasonType: plan.OlderThanDependency, 235 }, 236 }, 237 }, 238 plan.Item{ 239 Target: "test3.txt", 240 Reasons: []plan.Reason{ 241 { 242 Target: "test.txt", 243 ReasonType: plan.DependencyPlanned, 244 }, 245 }, 246 }, 247 }, 248 }, 249 "multiple reasons": { 250 folder: "testdata/multiple_reasons", 251 existing: []map[filename]fileContents{ 252 {"test3.txt": {}}, 253 {"test2.txt": {}}, 254 {"test.txt": {}}, 255 {"test3.txt": {}}, 256 {"test2.txt": {}}, 257 }, 258 expected: plan.Plan{ 259 plan.Item{ 260 Target: "test.txt", 261 Reasons: []plan.Reason{ 262 { 263 Target: "test2.txt", 264 ReasonType: plan.OlderThanDependency, 265 }, 266 { 267 Target: "test3.txt", 268 ReasonType: plan.OlderThanDependency, 269 }, 270 }, 271 }, 272 }, 273 }, 274 } 275 276 for name, test := range tests { 277 t.Run(name, func(t *testing.T) { 278 popd := pushd(t, test.folder) 279 defer popd() 280 281 for _, batch := range test.existing { 282 for f, d := range batch { 283 createFile(t, f, d) 284 } 285 } 286 287 actual := safeDo(t, test.options) 288 289 if diff := cmp.Diff(test.expected, actual); diff != "" { 290 t.Fatalf("plan mismatch (-want,+got):\n%s", diff) 291 } 292 }) 293 } 294 }