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  }