cuelang.org/go@v0.10.1/pkg/tool/file/file_test.go (about) 1 // Copyright 2019 CUE Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package file 16 17 import ( 18 "fmt" 19 "os" 20 "path/filepath" 21 "reflect" 22 "runtime" 23 "testing" 24 25 "cuelang.org/go/cue" 26 "cuelang.org/go/cue/parser" 27 "cuelang.org/go/internal/task" 28 "cuelang.org/go/internal/value" 29 "cuelang.org/go/pkg/internal" 30 "github.com/go-quicktest/qt" 31 ) 32 33 func parse(t *testing.T, kind, expr string) cue.Value { 34 t.Helper() 35 36 x, err := parser.ParseExpr("test", expr) 37 if err != nil { 38 t.Fatal(err) 39 } 40 v := internal.NewContext().BuildExpr(x) 41 if err := v.Err(); err != nil { 42 t.Fatal(err) 43 } 44 return value.UnifyBuiltin(v, kind) 45 } 46 47 func TestRead(t *testing.T) { 48 v := parse(t, "tool/file.Read", `{filename: "testdata/input.foo"}`) 49 got, err := (*cmdRead).Run(nil, &task.Context{Obj: v}) 50 if err != nil { 51 t.Fatal(err) 52 } 53 want := map[string]interface{}{"contents": []byte("This is a test.")} 54 if !reflect.DeepEqual(got, want) { 55 t.Errorf("got %v; want %v", got, want) 56 } 57 58 v = parse(t, "tool/file.Read", `{ 59 filename: "testdata/input.foo" 60 contents: string 61 }`) 62 got, err = (*cmdRead).Run(nil, &task.Context{Obj: v}) 63 if err != nil { 64 t.Fatal(err) 65 } 66 want = map[string]interface{}{"contents": "This is a test."} 67 if !reflect.DeepEqual(got, want) { 68 t.Errorf("got %v; want %v", got, want) 69 } 70 } 71 72 func TestAppend(t *testing.T) { 73 name := filepath.Join(t.TempDir(), "file") 74 name = filepath.ToSlash(name) 75 76 v := parse(t, "tool/file.Append", fmt.Sprintf(`{ 77 filename: "%s" 78 contents: "This is a test." 79 }`, name)) 80 _, err := (*cmdAppend).Run(nil, &task.Context{Obj: v}) 81 if err != nil { 82 t.Fatal(err) 83 } 84 85 b, err := os.ReadFile(name) 86 if err != nil { 87 t.Fatal(err) 88 } 89 90 if got, want := string(b), "This is a test."; got != want { 91 t.Errorf("got %v; want %v", got, want) 92 } 93 } 94 95 func TestCreate(t *testing.T) { 96 name := filepath.Join(t.TempDir(), "file") 97 name = filepath.ToSlash(name) 98 99 v := parse(t, "tool/file.Create", fmt.Sprintf(`{ 100 filename: "%s" 101 contents: "This is a test." 102 }`, name)) 103 _, err := (*cmdCreate).Run(nil, &task.Context{Obj: v}) 104 if err != nil { 105 t.Fatal(err) 106 } 107 108 b, err := os.ReadFile(name) 109 if err != nil { 110 t.Fatal(err) 111 } 112 113 if got, want := string(b), "This is a test."; got != want { 114 t.Errorf("got %v; want %v", got, want) 115 } 116 } 117 118 func TestGlob(t *testing.T) { 119 // Simple globbing against testdata. 120 v := parse(t, "tool/file.Glob", `{ 121 glob: "testdata/input.*" 122 }`) 123 got, err := (*cmdGlob).Run(nil, &task.Context{Obj: v}) 124 qt.Assert(t, qt.IsNil(err)) 125 qt.Assert(t, qt.DeepEquals(got, any(map[string]any{"files": []string{"testdata/input.foo"}}))) 126 127 // globstar or recursive globbing is not supported. 128 v = parse(t, "tool/file.Glob", `{ 129 glob: "testdata/**/glob.leaf" 130 }`) 131 got, err = (*cmdGlob).Run(nil, &task.Context{Obj: v}) 132 qt.Assert(t, qt.IsNotNil(err)) 133 qt.Assert(t, qt.IsNil(got)) 134 } 135 136 func TestGlobEscapeStar(t *testing.T) { 137 // `\**` is disallowed in a pattern on Windows, as the backslash is a path separator, 138 // hence `**` is treated as a globstar which is not yet supported. 139 // `\**` is allowed on other OSes as the first star is escaped, and only the second 140 // is treated as a wildcard. Thus such a pattern should match a file like `*.test`. 141 dir := t.TempDir() 142 leafFile := filepath.Join(dir, "*.test") 143 if runtime.GOOS != "windows" { 144 err := os.WriteFile(leafFile, nil, 0o666) 145 qt.Assert(t, qt.IsNil(err)) 146 } 147 148 v := parse(t, "tool/file.Glob", `{ 149 glob: "`+filepath.ToSlash(dir)+`/\\**" 150 }`) 151 got, err := (*cmdGlob).Run(nil, &task.Context{Obj: v}) 152 if runtime.GOOS == "windows" { 153 qt.Assert(t, qt.IsNotNil(err)) 154 qt.Assert(t, qt.Equals(got, nil)) 155 } else { 156 qt.Assert(t, qt.IsNil(err)) 157 qt.Assert(t, qt.DeepEquals(got, any(map[string]any{"files": []string{leafFile}}))) 158 } 159 } 160 161 func TestMkdir(t *testing.T) { 162 baseDir := t.TempDir() 163 164 // simple dir creation 165 d1 := filepath.Join(baseDir, "foo") 166 v := parse(t, "tool/file.Mkdir", fmt.Sprintf(`{path: #"%s"#}`, d1)) 167 _, err := (*cmdMkdir).Run(nil, &task.Context{Obj: v}) 168 if err != nil { 169 t.Fatal(err) 170 } 171 fi1, err := os.Stat(d1) 172 if err != nil { 173 t.Fatal(err) 174 } 175 if !fi1.IsDir() { 176 t.Fatal("not a directory") 177 } 178 179 // dir already exists 180 v = parse(t, "tool/file.Mkdir", fmt.Sprintf(`{path: #"%s"#}`, d1)) 181 _, err = (*cmdMkdir).Run(nil, &task.Context{Obj: v}) 182 if err != nil { 183 t.Fatal(err) 184 } 185 186 // create parents 187 // set permissions 188 d2 := filepath.Join(baseDir, "bar/x") 189 v = parse(t, "tool/file.MkdirAll", fmt.Sprintf(`{path: #"%s"#, permissions: 0o700}`, d2)) 190 _, err = (*cmdMkdir).Run(nil, &task.Context{Obj: v}) 191 if err != nil { 192 t.Fatal(err) 193 } 194 fi2, err := os.Stat(d2) 195 if err != nil { 196 t.Fatal(err) 197 } 198 if !fi2.IsDir() { 199 t.Fatal("not a directory") 200 } 201 202 // file at same path 203 f, err := os.CreateTemp(baseDir, "") 204 if err != nil { 205 t.Fatal(err) 206 } 207 f.Close() 208 v = parse(t, "tool/file.Mkdir", fmt.Sprintf(`{path: #"%s"#}`, f.Name())) 209 _, err = (*cmdMkdir).Run(nil, &task.Context{Obj: v}) 210 if err == nil { 211 t.Fatal("should not create directory at existing filepath") 212 } 213 } 214 215 func TestMkdirTemp(t *testing.T) { 216 // create temp dir 217 v := parse(t, "tool/file.MkdirTemp", "{}") 218 r, err := (*cmdMkdirTemp).Run(nil, &task.Context{Obj: v}) 219 if err != nil { 220 t.Fatal(err) 221 } 222 if _, exists := r.(map[string]interface{})["path"]; !exists { 223 t.Fatal("no directory path returned") 224 } 225 path := r.(map[string]interface{})["path"].(string) 226 t.Cleanup(func() { os.RemoveAll(path) }) 227 fi, err := os.Stat(path) 228 if err != nil { 229 t.Fatal(err) 230 } 231 if !fi.IsDir() { 232 t.Fatal("not a directory") 233 } 234 235 // removes temp dir 236 v2 := parse(t, "tool/file.RemoveAll", fmt.Sprintf(`{path: #"%s"#}`, path)) 237 _, err = (*cmdRemoveAll).Run(nil, &task.Context{Obj: v2}) 238 if err != nil { 239 t.Fatal(err) 240 } 241 _, err = os.Stat(path) 242 if err == nil { 243 t.Fatal(err) 244 } 245 246 }