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  }