github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/os/os_anyos_test.go (about) 1 //go:build windows || darwin || (linux && !baremetal) || wasip1 2 3 package os_test 4 5 import ( 6 "io/fs" 7 "os" 8 . "os" 9 "path/filepath" 10 "runtime" 11 "strconv" 12 "strings" 13 "testing" 14 "testing/fstest" 15 "time" 16 ) 17 18 var dot = []string{ 19 "dir.go", 20 "env.go", 21 "errors.go", 22 "file.go", 23 "os_test.go", 24 "types.go", 25 "stat_darwin.go", 26 } 27 28 func randomName() string { 29 // fastrand() does not seem available here, so fake it 30 ns := time.Now().Nanosecond() 31 pid := Getpid() 32 return strconv.FormatUint(uint64(ns^pid), 10) 33 } 34 35 func TestMkdir(t *testing.T) { 36 dir := TempDir() + "/TestMkdir" + randomName() 37 Remove(dir) 38 err := Mkdir(dir, 0755) 39 defer Remove(dir) 40 if err != nil { 41 t.Errorf("Mkdir(%s, 0755) returned %v", dir, err) 42 } 43 // tests the "directory" branch of Remove 44 err = Remove(dir) 45 if err != nil { 46 t.Errorf("Remove(%s) returned %v", dir, err) 47 } 48 } 49 50 func TestStatBadDir(t *testing.T) { 51 if runtime.GOOS == "windows" { 52 t.Log("TODO: TestStatBadDir: IsNotExist fails on Windows, skipping") 53 return 54 } 55 dir := TempDir() 56 badDir := filepath.Join(dir, "not-exist/really-not-exist") 57 _, err := Stat(badDir) 58 if pe, ok := err.(*fs.PathError); !ok || !IsNotExist(err) || pe.Path != badDir { 59 t.Errorf("Mkdir error = %#v; want PathError for path %q satisifying IsNotExist", err, badDir) 60 } 61 } 62 63 func equal(name1, name2 string) (r bool) { 64 switch runtime.GOOS { 65 case "windows": 66 r = strings.ToLower(name1) == strings.ToLower(name2) 67 default: 68 r = name1 == name2 69 } 70 return 71 } 72 73 func TestFstat(t *testing.T) { 74 if runtime.GOARCH == "386" || runtime.GOARCH == "arm" { 75 t.Log("TODO: implement fstat for 386 and arm") 76 return 77 } 78 sfname := "TestFstat" 79 path := TempDir() + "/" + sfname 80 payload := writeFile(t, path, O_CREATE|O_TRUNC|O_RDWR, "Hello") 81 defer Remove(path) 82 83 file, err1 := Open(path) 84 if err1 != nil { 85 t.Fatal("open failed:", err1) 86 } 87 defer file.Close() 88 dir, err2 := file.Stat() 89 if err2 != nil { 90 t.Fatal("fstat failed:", err2) 91 } 92 if !equal(sfname, dir.Name()) { 93 t.Error("name should be ", sfname, "; is", dir.Name()) 94 } 95 filesize := len(payload) 96 if dir.Size() != int64(filesize) { 97 t.Error("size should be", filesize, "; is", dir.Size()) 98 } 99 } 100 101 func writeFile(t *testing.T, fname string, flag int, text string) string { 102 f, err := OpenFile(fname, flag, 0666) 103 if err != nil { 104 t.Fatalf("Open: %v", err) 105 } 106 n, err := f.WriteString(text) 107 if err != nil { 108 t.Fatalf("WriteString: %d, %v", n, err) 109 } 110 f.Close() 111 data, err := ReadFile(f.Name()) 112 if err != nil { 113 t.Fatalf("ReadFile: %v", err) 114 } 115 return string(data) 116 } 117 118 func TestRemove(t *testing.T) { 119 f := TempDir() + "/TestRemove" + randomName() 120 121 err := Remove(f) 122 if err == nil { 123 t.Errorf("TestRemove: remove of nonexistent file did not fail") 124 } else { 125 if pe, ok := err.(*fs.PathError); !ok { 126 t.Errorf("TestRemove: expected PathError, got err %q", err.Error()) 127 } else { 128 if pe.Path != f { 129 t.Errorf("TestRemove: PathError returned path %q, expected %q", pe.Path, f) 130 } 131 } 132 if !IsNotExist(err) { 133 t.Errorf("TestRemove: expected IsNotExist(err) true, got false; err %q", err.Error()) 134 } 135 } 136 137 s := writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new") 138 if s != "new" { 139 t.Fatalf("writeFile: have %q want %q", s, "new") 140 } 141 // tests the "file" branch of Remove 142 err = Remove(f) 143 if err != nil { 144 t.Fatalf("Remove: %v", err) 145 } 146 } 147 148 // chtmpdir changes the working directory to a new temporary directory and 149 // provides a cleanup function. 150 func chtmpdir(t *testing.T) func() { 151 oldwd, err := Getwd() 152 if err != nil { 153 t.Fatalf("chtmpdir: %v", err) 154 } 155 d, err := MkdirTemp("", "test") 156 if err != nil { 157 t.Fatalf("chtmpdir: %v", err) 158 } 159 if err := Chdir(d); err != nil { 160 t.Fatalf("chtmpdir: %v", err) 161 } 162 return func() { 163 if err := Chdir(oldwd); err != nil { 164 t.Fatalf("chtmpdir: %v", err) 165 } 166 RemoveAll(d) 167 } 168 } 169 170 func TestRename(t *testing.T) { 171 // TODO: use t.TempDir() 172 from, to := TempDir()+"/"+"TestRename-from", TempDir()+"/"+"TestRename-to" 173 174 file, err := Create(from) 175 defer Remove(from) // TODO: switch to t.Tempdir, remove this line 176 if err != nil { 177 t.Fatalf("open %q failed: %v", from, err) 178 } 179 defer Remove(to) // TODO: switch to t.Tempdir, remove this line 180 if err = file.Close(); err != nil { 181 t.Errorf("close %q failed: %v", from, err) 182 } 183 err = Rename(from, to) 184 if err != nil { 185 t.Fatalf("rename %q, %q failed: %v", to, from, err) 186 } 187 _, err = Stat(to) 188 if err != nil { 189 t.Errorf("stat %q failed: %v", to, err) 190 } 191 } 192 193 func TestRenameOverwriteDest(t *testing.T) { 194 from, to := TempDir()+"/"+"TestRenameOverwrite-from", TempDir()+"/"+"TestRenameOverwrite-to" 195 196 toData := []byte("to") 197 fromData := []byte("from") 198 199 err := os.WriteFile(to, toData, 0777) 200 defer Remove(to) // TODO: switch to t.Tempdir, remove this line 201 if err != nil { 202 t.Fatalf("write file %q failed: %v", to, err) 203 } 204 205 err = os.WriteFile(from, fromData, 0777) 206 defer Remove(from) // TODO: switch to t.Tempdir, remove this line 207 if err != nil { 208 t.Fatalf("write file %q failed: %v", from, err) 209 } 210 err = Rename(from, to) 211 if err != nil { 212 t.Fatalf("rename %q, %q failed: %v", to, from, err) 213 } 214 215 _, err = Stat(from) 216 if err == nil { 217 t.Errorf("from file %q still exists", from) 218 } 219 if runtime.GOOS == "windows" { 220 t.Log("TODO: TestRenameOverwriteDest: IsNotExist fails on Windows, skipping") 221 } else if err != nil && !IsNotExist(err) { 222 t.Fatalf("stat from: %v", err) 223 } 224 toFi, err := Stat(to) 225 if err != nil { 226 t.Fatalf("stat %q failed: %v", to, err) 227 } 228 if toFi.Size() != int64(len(fromData)) { 229 t.Errorf(`"to" size = %d; want %d (old "from" size)`, toFi.Size(), len(fromData)) 230 } 231 } 232 233 func TestRenameFailed(t *testing.T) { 234 from, to := TempDir()+"/"+"RenameFailed-from", TempDir()+"/"+"RenameFailed-to" 235 236 err := Rename(from, to) 237 switch err := err.(type) { 238 case *LinkError: 239 if err.Op != "rename" { 240 t.Errorf("rename %q, %q: err.Op: want %q, got %q", from, to, "rename", err.Op) 241 } 242 if err.Old != from { 243 t.Errorf("rename %q, %q: err.Old: want %q, got %q", from, to, from, err.Old) 244 } 245 if err.New != to { 246 t.Errorf("rename %q, %q: err.New: want %q, got %q", from, to, to, err.New) 247 } 248 case nil: 249 t.Errorf("rename %q, %q: expected error, got nil", from, to) 250 default: 251 t.Errorf("rename %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err) 252 } 253 } 254 255 func TestUserHomeDir(t *testing.T) { 256 dir, err := UserHomeDir() 257 if dir == "" && err == nil { 258 t.Fatal("UserHomeDir returned an empty string but no error") 259 } 260 if err != nil { 261 t.Logf("UserHomeDir failed: %v", err) 262 return 263 } 264 fi, err := Stat(dir) 265 if err != nil { 266 t.Fatal(err) 267 } 268 if !fi.IsDir() { 269 t.Fatalf("dir %s is not directory; type = %v", dir, fi.Mode()) 270 } 271 } 272 273 func TestDirFS(t *testing.T) { 274 if runtime.GOOS == "windows" { 275 t.Log("TODO: implement Readdir for Windows") 276 return 277 } 278 if runtime.GOOS == "wasip1" { 279 t.Log("TODO: allow foo/bar/. as synonym for path foo/bar on wasi?") 280 return 281 } 282 if err := fstest.TestFS(DirFS("./testdata/dirfs"), "a", "b", "dir/x"); err != nil { 283 t.Fatal(err) 284 } 285 286 // Test that Open does not accept backslash as separator. 287 d := DirFS(".") 288 _, err := d.Open(`testdata\dirfs`) 289 if err == nil { 290 t.Fatalf(`Open testdata\dirfs succeeded`) 291 } 292 } 293 294 func TestDirFSPathsValid(t *testing.T) { 295 if runtime.GOOS == "windows" { 296 t.Log("skipping on Windows") 297 return 298 } 299 if runtime.GOOS == "wasip1" { 300 t.Log("skipping on wasi because it fails on wasi on windows") 301 return 302 } 303 304 // TODO: switch back to t.TempDir once it's implemented 305 d, err := MkdirTemp("", "TestDirFSPathsValid") 306 if err != nil { 307 t.Fatal(err) 308 } 309 defer Remove(d) 310 if err := WriteFile(filepath.Join(d, "control.txt"), []byte(string("Hello, world!")), 0644); err != nil { 311 t.Fatal(err) 312 } 313 defer Remove(filepath.Join(d, "control.txt")) 314 if err := WriteFile(filepath.Join(d, `e:xperi\ment.txt`), []byte(string("Hello, colon and backslash!")), 0644); err != nil { 315 t.Fatal(err) 316 } 317 defer Remove(filepath.Join(d, `e:xperi\ment.txt`)) 318 319 fsys := DirFS(d) 320 err = fs.WalkDir(fsys, ".", func(path string, e fs.DirEntry, err error) error { 321 if fs.ValidPath(e.Name()) { 322 t.Logf("%q ok", e.Name()) 323 } else { 324 t.Errorf("%q INVALID", e.Name()) 325 } 326 return nil 327 }) 328 if err != nil { 329 t.Fatal(err) 330 } 331 }