github.com/bananabytelabs/wazero@v0.0.0-20240105073314-54b22a776da8/internal/sysfs/futimens_test.go (about)

     1  //go:build windows || linux || darwin
     2  
     3  package sysfs
     4  
     5  import (
     6  	"os"
     7  	"path"
     8  	"runtime"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/bananabytelabs/wazero/experimental/sys"
    13  	"github.com/bananabytelabs/wazero/internal/platform"
    14  	"github.com/bananabytelabs/wazero/internal/testing/require"
    15  )
    16  
    17  func TestUtimens(t *testing.T) {
    18  	t.Run("doesn't exist", func(t *testing.T) {
    19  		err := utimens("nope", 0, 0)
    20  		require.EqualErrno(t, sys.ENOENT, err)
    21  	})
    22  	testUtimens(t, false)
    23  }
    24  
    25  func testUtimens(t *testing.T, futimes bool) {
    26  	// Note: This sets microsecond granularity because Windows doesn't support
    27  	// nanosecond.
    28  	//
    29  	// Negative isn't tested as most platforms don't return consistent results.
    30  	tests := []struct {
    31  		name       string
    32  		atim, mtim int64
    33  	}{
    34  		{
    35  			name: "nil",
    36  		},
    37  		{
    38  			name: "a=omit,m=omit",
    39  			atim: sys.UTIME_OMIT,
    40  			mtim: sys.UTIME_OMIT,
    41  		},
    42  		{
    43  			name: "a=set,m=omit",
    44  			atim: int64(123*time.Second + 4*time.Microsecond),
    45  			mtim: sys.UTIME_OMIT,
    46  		},
    47  		{
    48  			name: "a=omit,m=set",
    49  			atim: sys.UTIME_OMIT,
    50  			mtim: int64(123*time.Second + 4*time.Microsecond),
    51  		},
    52  		{
    53  			name: "a=set,m=set",
    54  			atim: int64(123*time.Second + 4*time.Microsecond),
    55  			mtim: int64(223*time.Second + 5*time.Microsecond),
    56  		},
    57  	}
    58  	for _, fileType := range []string{"dir", "file", "link"} {
    59  		for _, tt := range tests {
    60  			tc := tt
    61  			fileType := fileType
    62  			name := fileType + " " + tc.name
    63  
    64  			t.Run(name, func(t *testing.T) {
    65  				tmpDir := t.TempDir()
    66  				file := path.Join(tmpDir, "file")
    67  				err := os.WriteFile(file, []byte{}, 0o700)
    68  				require.NoError(t, err)
    69  
    70  				link := file + "-link"
    71  				require.NoError(t, os.Symlink(file, link))
    72  
    73  				dir := path.Join(tmpDir, "dir")
    74  				err = os.Mkdir(dir, 0o700)
    75  				require.NoError(t, err)
    76  
    77  				var path, statPath string
    78  				switch fileType {
    79  				case "dir":
    80  					path = dir
    81  					statPath = dir
    82  				case "file":
    83  					path = file
    84  					statPath = file
    85  				case "link":
    86  					path = link
    87  					statPath = file
    88  				default:
    89  					panic(tc)
    90  				}
    91  
    92  				oldSt, errno := lstat(statPath)
    93  				require.EqualErrno(t, 0, errno)
    94  
    95  				if !futimes {
    96  					errno = utimens(path, tc.atim, tc.mtim)
    97  					require.EqualErrno(t, 0, errno)
    98  				} else {
    99  					flag := sys.O_RDWR
   100  					if path == dir {
   101  						flag = sys.O_RDONLY
   102  						if runtime.GOOS == "windows" {
   103  							// windows requires O_RDWR, which is invalid for directories
   104  							t.Skip("windows cannot update timestamps on a dir")
   105  						}
   106  					}
   107  
   108  					f := requireOpenFile(t, path, flag, 0)
   109  
   110  					errno = f.Utimens(tc.atim, tc.mtim)
   111  					require.EqualErrno(t, 0, f.Close())
   112  					require.EqualErrno(t, 0, errno)
   113  				}
   114  
   115  				newSt, errno := lstat(statPath)
   116  				require.EqualErrno(t, 0, errno)
   117  
   118  				if platform.CompilerSupported() {
   119  					if tc.atim == sys.UTIME_OMIT {
   120  						require.Equal(t, oldSt.Atim, newSt.Atim)
   121  					} else {
   122  						require.Equal(t, tc.atim, newSt.Atim)
   123  					}
   124  				}
   125  
   126  				// When compiler isn't supported, we can still check mtim.
   127  				if tc.mtim == sys.UTIME_OMIT {
   128  					require.Equal(t, oldSt.Mtim, newSt.Mtim)
   129  				} else {
   130  					require.Equal(t, tc.mtim, newSt.Mtim)
   131  				}
   132  			})
   133  		}
   134  	}
   135  }