github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/sys/stdio_test.go (about) 1 package sys 2 3 import ( 4 "io/fs" 5 "os" 6 "testing" 7 8 "github.com/wasilibs/wazerox/internal/testing/require" 9 ) 10 11 func TestStdio(t *testing.T) { 12 // simulate regular file attached to stdin 13 f, err := os.CreateTemp(t.TempDir(), "somefile") 14 require.NoError(t, err) 15 defer f.Close() 16 17 stdin, err := stdinFileEntry(os.Stdin) 18 require.NoError(t, err) 19 stdinStat, err := os.Stdin.Stat() 20 require.NoError(t, err) 21 22 stdinNil, err := stdinFileEntry(nil) 23 require.NoError(t, err) 24 25 stdinFile, err := stdinFileEntry(f) 26 require.NoError(t, err) 27 28 stdout, err := stdioWriterFileEntry("stdout", os.Stdout) 29 require.NoError(t, err) 30 stdoutStat, err := os.Stdout.Stat() 31 require.NoError(t, err) 32 33 stdoutNil, err := stdioWriterFileEntry("stdout", nil) 34 require.NoError(t, err) 35 36 stdoutFile, err := stdioWriterFileEntry("stdout", f) 37 require.NoError(t, err) 38 39 stderr, err := stdioWriterFileEntry("stderr", os.Stderr) 40 require.NoError(t, err) 41 stderrStat, err := os.Stderr.Stat() 42 require.NoError(t, err) 43 44 stderrNil, err := stdioWriterFileEntry("stderr", nil) 45 require.NoError(t, err) 46 47 stderrFile, err := stdioWriterFileEntry("stderr", f) 48 require.NoError(t, err) 49 50 tests := []struct { 51 name string 52 f *FileEntry 53 // Depending on how the tests run, os.Stdin won't necessarily be a char 54 // device. We compare against an os.File, to account for this. 55 expectedType fs.FileMode 56 }{ 57 { 58 name: "stdin", 59 f: stdin, 60 expectedType: stdinStat.Mode().Type(), 61 }, 62 { 63 name: "stdin noop", 64 f: stdinNil, 65 expectedType: fs.ModeDevice, 66 }, 67 { 68 name: "stdin file", 69 f: stdinFile, 70 expectedType: 0, // normal file 71 }, 72 { 73 name: "stdout", 74 f: stdout, 75 expectedType: stdoutStat.Mode().Type(), 76 }, 77 { 78 name: "stdout noop", 79 f: stdoutNil, 80 expectedType: fs.ModeDevice, 81 }, 82 { 83 name: "stdout file", 84 f: stdoutFile, 85 expectedType: 0, // normal file 86 }, 87 { 88 name: "stderr", 89 f: stderr, 90 expectedType: stderrStat.Mode().Type(), 91 }, 92 { 93 name: "stderr noop", 94 f: stderrNil, 95 expectedType: fs.ModeDevice, 96 }, 97 { 98 name: "stderr file", 99 f: stderrFile, 100 expectedType: 0, // normal file 101 }, 102 } 103 104 for _, tt := range tests { 105 tc := tt 106 107 t.Run(tc.name+" Stat", func(t *testing.T) { 108 st, errno := tc.f.File.Stat() 109 require.EqualErrno(t, 0, errno) 110 require.Equal(t, tc.expectedType, st.Mode&fs.ModeType) 111 require.Equal(t, uint64(1), st.Nlink) 112 113 // Fake times are needed to pass wasi-testsuite. 114 // See https://github.com/WebAssembly/wasi-testsuite/blob/af57727/tests/rust/src/bin/fd_filestat_get.rs#L1-L19 115 require.Zero(t, st.Ctim) 116 require.Zero(t, st.Mtim) 117 require.Zero(t, st.Atim) 118 }) 119 120 buf := make([]byte, 5) 121 switch tc.f { 122 case stdinNil: 123 t.Run(tc.name+" returns zero on Read", func(t *testing.T) { 124 n, errno := tc.f.File.Read(buf) 125 require.EqualErrno(t, 0, errno) 126 require.Zero(t, n) // like reading io.EOF 127 }) 128 case stdoutNil, stderrNil: 129 // This is important because some code will loop forever attempting 130 // to write data. This happened in TestShortHash. 131 t.Run(tc.name+" returns length on Write", func(t *testing.T) { 132 n, errno := tc.f.File.Write(buf) 133 require.EqualErrno(t, 0, errno) 134 require.Equal(t, len(buf), n) // like io.Discard 135 }) 136 } 137 } 138 }