wa-lang.org/wazero@v1.0.2/internal/sys/sys_test.go (about) 1 package sys 2 3 import ( 4 "bytes" 5 "context" 6 "io" 7 "testing" 8 "time" 9 10 "wa-lang.org/wazero/internal/platform" 11 testfs "wa-lang.org/wazero/internal/testing/fs" 12 "wa-lang.org/wazero/internal/testing/require" 13 "wa-lang.org/wazero/sys" 14 ) 15 16 func TestContext_FS(t *testing.T) { 17 sysCtx := DefaultContext(testfs.FS{}) 18 19 require.Equal(t, NewFSContext(testfs.FS{}), sysCtx.FS(testCtx)) 20 21 // can override to something else 22 fsc := NewFSContext(testfs.FS{"foo": &testfs.File{}}) 23 require.Equal(t, fsc, sysCtx.FS(context.WithValue(testCtx, FSKey{}, fsc))) 24 } 25 26 func TestDefaultSysContext(t *testing.T) { 27 sysCtx, err := NewContext( 28 0, // max 29 nil, // args 30 nil, // environ 31 nil, // stdin 32 nil, // stdout 33 nil, // stderr 34 nil, // randSource 35 nil, 0, // walltime, walltimeResolution 36 nil, 0, // nanotime, nanotimeResolution 37 nil, // nanosleep 38 testfs.FS{}, // fs 39 ) 40 require.NoError(t, err) 41 42 require.Nil(t, sysCtx.Args()) 43 require.Zero(t, sysCtx.ArgsSize()) 44 require.Nil(t, sysCtx.Environ()) 45 require.Zero(t, sysCtx.EnvironSize()) 46 require.Equal(t, eofReader{}, sysCtx.Stdin()) 47 require.Equal(t, io.Discard, sysCtx.Stdout()) 48 require.Equal(t, io.Discard, sysCtx.Stderr()) 49 // To compare functions, we can only compare pointers, but the pointer will 50 // change. Hence, we have to compare the results instead. 51 sec, _ := sysCtx.Walltime(testCtx) 52 require.Equal(t, platform.FakeEpochNanos/time.Second.Nanoseconds(), sec) 53 require.Equal(t, sys.ClockResolution(1_000), sysCtx.WalltimeResolution()) 54 require.Zero(t, sysCtx.Nanotime(testCtx)) // See above on functions. 55 require.Equal(t, sys.ClockResolution(1), sysCtx.NanotimeResolution()) 56 require.Equal(t, &ns, sysCtx.nanosleep) 57 require.Equal(t, platform.NewFakeRandSource(), sysCtx.RandSource()) 58 require.Equal(t, NewFSContext(testfs.FS{}), sysCtx.FS(testCtx)) 59 } 60 61 func TestNewContext_Args(t *testing.T) { 62 tests := []struct { 63 name string 64 args []string 65 maxSize uint32 66 expectedSize uint32 67 expectedErr string 68 }{ 69 { 70 name: "ok", 71 maxSize: 10, 72 args: []string{"a", "bc"}, 73 expectedSize: 5, 74 }, 75 { 76 name: "exceeds max count", 77 maxSize: 1, 78 args: []string{"a", "bc"}, 79 expectedErr: "args invalid: exceeds maximum count", 80 }, 81 { 82 name: "exceeds max size", 83 maxSize: 4, 84 args: []string{"a", "bc"}, 85 expectedErr: "args invalid: exceeds maximum size", 86 }, 87 { 88 name: "null character", 89 maxSize: 10, 90 args: []string{"a", string([]byte{'b', 0})}, 91 expectedErr: "args invalid: contains NUL character", 92 }, 93 } 94 95 for _, tt := range tests { 96 tc := tt 97 98 t.Run(tc.name, func(t *testing.T) { 99 sysCtx, err := NewContext( 100 tc.maxSize, // max 101 tc.args, 102 nil, // environ 103 bytes.NewReader(make([]byte, 0)), // stdin 104 nil, // stdout 105 nil, // stderr 106 nil, // randSource 107 nil, 0, // walltime, walltimeResolution 108 nil, 0, // nanotime, nanotimeResolution 109 nil, // nanosleep 110 nil, // fs 111 ) 112 if tc.expectedErr == "" { 113 require.Nil(t, err) 114 require.Equal(t, tc.args, sysCtx.Args()) 115 require.Equal(t, tc.expectedSize, sysCtx.ArgsSize()) 116 } else { 117 require.EqualError(t, err, tc.expectedErr) 118 } 119 }) 120 } 121 } 122 123 func TestNewContext_Environ(t *testing.T) { 124 tests := []struct { 125 name string 126 environ []string 127 maxSize uint32 128 expectedSize uint32 129 expectedErr string 130 }{ 131 { 132 name: "ok", 133 maxSize: 10, 134 environ: []string{"a=b", "c=de"}, 135 expectedSize: 9, 136 }, 137 { 138 name: "exceeds max count", 139 maxSize: 1, 140 environ: []string{"a=b", "c=de"}, 141 expectedErr: "environ invalid: exceeds maximum count", 142 }, 143 { 144 name: "exceeds max size", 145 maxSize: 4, 146 environ: []string{"a=b", "c=de"}, 147 expectedErr: "environ invalid: exceeds maximum size", 148 }, 149 { 150 name: "null character", 151 maxSize: 10, 152 environ: []string{"a=b", string(append([]byte("c=d"), 0))}, 153 expectedErr: "environ invalid: contains NUL character", 154 }, 155 } 156 157 for _, tt := range tests { 158 tc := tt 159 160 t.Run(tc.name, func(t *testing.T) { 161 sysCtx, err := NewContext( 162 tc.maxSize, // max 163 nil, // args 164 tc.environ, 165 bytes.NewReader(make([]byte, 0)), // stdin 166 nil, // stdout 167 nil, // stderr 168 nil, // randSource 169 nil, 0, // walltime, walltimeResolution 170 nil, 0, // nanotime, nanotimeResolution 171 nil, // nanosleep 172 nil, // fs 173 ) 174 if tc.expectedErr == "" { 175 require.Nil(t, err) 176 require.Equal(t, tc.environ, sysCtx.Environ()) 177 require.Equal(t, tc.expectedSize, sysCtx.EnvironSize()) 178 } else { 179 require.EqualError(t, err, tc.expectedErr) 180 } 181 }) 182 } 183 } 184 185 func TestNewContext_Walltime(t *testing.T) { 186 tests := []struct { 187 name string 188 time *sys.Walltime 189 resolution sys.ClockResolution 190 expectedErr string 191 }{ 192 { 193 name: "ok", 194 time: platform.NewFakeWalltime(), 195 resolution: 3, 196 }, 197 { 198 name: "invalid resolution", 199 time: platform.NewFakeWalltime(), 200 resolution: 0, 201 expectedErr: "invalid Walltime resolution: 0", 202 }, 203 } 204 205 for _, tt := range tests { 206 tc := tt 207 208 t.Run(tc.name, func(t *testing.T) { 209 sysCtx, err := NewContext( 210 0, // max 211 nil, // args 212 nil, 213 nil, // stdin 214 nil, // stdout 215 nil, // stderr 216 nil, // randSource 217 tc.time, tc.resolution, // walltime, walltimeResolution 218 nil, 0, // nanotime, nanotimeResolution 219 nil, // nanosleep 220 nil, // fs 221 ) 222 if tc.expectedErr == "" { 223 require.Nil(t, err) 224 require.Equal(t, tc.time, sysCtx.walltime) 225 require.Equal(t, tc.resolution, sysCtx.WalltimeResolution()) 226 } else { 227 require.EqualError(t, err, tc.expectedErr) 228 } 229 }) 230 } 231 } 232 233 func TestNewContext_Nanotime(t *testing.T) { 234 tests := []struct { 235 name string 236 time *sys.Nanotime 237 resolution sys.ClockResolution 238 expectedErr string 239 }{ 240 { 241 name: "ok", 242 time: platform.NewFakeNanotime(), 243 resolution: 3, 244 }, 245 { 246 name: "invalid resolution", 247 time: platform.NewFakeNanotime(), 248 resolution: 0, 249 expectedErr: "invalid Nanotime resolution: 0", 250 }, 251 } 252 253 for _, tt := range tests { 254 tc := tt 255 256 t.Run(tc.name, func(t *testing.T) { 257 sysCtx, err := NewContext( 258 0, // max 259 nil, // args 260 nil, 261 nil, // stdin 262 nil, // stdout 263 nil, // stderr 264 nil, // randSource 265 nil, 0, // nanotime, nanotimeResolution 266 tc.time, tc.resolution, // nanotime, nanotimeResolution 267 nil, // nanosleep 268 nil, // fs 269 ) 270 if tc.expectedErr == "" { 271 require.Nil(t, err) 272 require.Equal(t, tc.time, sysCtx.nanotime) 273 require.Equal(t, tc.resolution, sysCtx.NanotimeResolution()) 274 } else { 275 require.EqualError(t, err, tc.expectedErr) 276 } 277 }) 278 } 279 } 280 281 func Test_clockResolutionInvalid(t *testing.T) { 282 tests := []struct { 283 name string 284 resolution sys.ClockResolution 285 expected bool 286 }{ 287 { 288 name: "ok", 289 resolution: 1, 290 }, 291 { 292 name: "zero", 293 resolution: 0, 294 expected: true, 295 }, 296 { 297 name: "too big", 298 resolution: sys.ClockResolution(time.Hour.Nanoseconds() * 2), 299 expected: true, 300 }, 301 } 302 303 for _, tt := range tests { 304 tc := tt 305 306 t.Run(tc.name, func(t *testing.T) { 307 require.Equal(t, tc.expected, clockResolutionInvalid(tc.resolution)) 308 }) 309 } 310 } 311 312 func TestNewContext_Nanosleep(t *testing.T) { 313 var aNs sys.Nanosleep = func(context.Context, int64) { 314 } 315 sysCtx, err := NewContext( 316 0, // max 317 nil, // args 318 nil, 319 nil, // stdin 320 nil, // stdout 321 nil, // stderr 322 nil, // randSource 323 nil, 0, // Nanosleep, NanosleepResolution 324 nil, 0, // Nanosleep, NanosleepResolution 325 &aNs, // nanosleep 326 nil, // fs 327 ) 328 require.Nil(t, err) 329 require.Equal(t, &aNs, sysCtx.nanosleep) 330 }