wa-lang.org/wazero@v1.0.2/cmd/wazero/wazero_test.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	_ "embed"
     6  	"flag"
     7  	"fmt"
     8  	"os"
     9  	"path/filepath"
    10  	"testing"
    11  
    12  	"wa-lang.org/wazero/internal/testing/require"
    13  )
    14  
    15  //go:embed testdata/wasi_arg.wasm
    16  var wasmWasiArg []byte
    17  
    18  //go:embed testdata/wasi_env.wasm
    19  var wasmWasiEnv []byte
    20  
    21  //go:embed testdata/wasi_fd.wasm
    22  var wasmWasiFd []byte
    23  
    24  //go:embed testdata/fs/bear.txt
    25  var bearTxt []byte
    26  
    27  func TestRun(t *testing.T) {
    28  	bearPath := filepath.Join(t.TempDir(), "bear.txt")
    29  	require.NoError(t, os.WriteFile(bearPath, bearTxt, 0o755))
    30  
    31  	tests := []struct {
    32  		name       string
    33  		wazeroOpts []string
    34  		wasm       []byte
    35  		wasmArgs   []string
    36  		stdOut     string
    37  		stdErr     string
    38  	}{
    39  		{
    40  			name:     "args",
    41  			wasm:     wasmWasiArg,
    42  			wasmArgs: []string{"hello world"},
    43  			// Executable name is first arg so is printed.
    44  			stdOut: "test.wasm\x00hello world\x00",
    45  		},
    46  		{
    47  			name:     "-- args",
    48  			wasm:     wasmWasiArg,
    49  			wasmArgs: []string{"--", "hello world"},
    50  			// Executable name is first arg so is printed.
    51  			stdOut: "test.wasm\x00hello world\x00",
    52  		},
    53  		{
    54  			name:       "env",
    55  			wasm:       wasmWasiEnv,
    56  			wazeroOpts: []string{"--env=ANIMAL=bear", "--env=FOOD=sushi"},
    57  			stdOut:     "ANIMAL=bear\x00FOOD=sushi\x00",
    58  		},
    59  		{
    60  			name:       "fd",
    61  			wasm:       wasmWasiFd,
    62  			wazeroOpts: []string{fmt.Sprintf("--mount=%s:/", filepath.Dir(bearPath))},
    63  			stdOut:     "pooh\n",
    64  		},
    65  	}
    66  
    67  	for _, tc := range tests {
    68  		tt := tc
    69  		t.Run(tt.name, func(t *testing.T) {
    70  			wasmPath := filepath.Join(t.TempDir(), "test.wasm")
    71  			require.NoError(t, os.WriteFile(wasmPath, tt.wasm, 0o755))
    72  
    73  			args := append([]string{"run"}, tt.wazeroOpts...)
    74  			args = append(args, wasmPath)
    75  			args = append(args, tt.wasmArgs...)
    76  			exitCode, stdOut, stdErr := runMain(t, args)
    77  			require.Equal(t, 0, exitCode, stdErr)
    78  			require.Equal(t, tt.stdOut, stdOut)
    79  			require.Equal(t, tt.stdErr, stdErr)
    80  		})
    81  	}
    82  }
    83  
    84  func TestHelp(t *testing.T) {
    85  	exitCode, _, stdErr := runMain(t, []string{"-h"})
    86  	require.Equal(t, 0, exitCode)
    87  	require.Contains(t, stdErr, "wazero CLI\n\nUsage:")
    88  }
    89  
    90  func TestErrors(t *testing.T) {
    91  	notWasmPath := filepath.Join(t.TempDir(), "bears.wasm")
    92  	require.NoError(t, os.WriteFile(notWasmPath, []byte("pooh"), 0o755))
    93  
    94  	tests := []struct {
    95  		message string
    96  		args    []string
    97  	}{
    98  		{
    99  			message: "missing path to wasm file",
   100  			args:    []string{},
   101  		},
   102  		{
   103  			message: "error reading wasm binary",
   104  			args:    []string{"non-existent.wasm"},
   105  		},
   106  		{
   107  			message: "error compiling wasm binary",
   108  			args:    []string{notWasmPath},
   109  		},
   110  		{
   111  			message: "invalid environment variable",
   112  			args:    []string{"--env=ANIMAL", "testdata/wasi_env.wasm"},
   113  		},
   114  		{
   115  			message: "invalid mount",
   116  			args:    []string{"--mount=.", "testdata/wasi_env.wasm"},
   117  		},
   118  	}
   119  
   120  	for _, tc := range tests {
   121  		tt := tc
   122  		t.Run(tt.message, func(t *testing.T) {
   123  			exitCode, _, stdErr := runMain(t, append([]string{"run"}, tt.args...))
   124  
   125  			require.Equal(t, 1, exitCode)
   126  			require.Contains(t, stdErr, tt.message)
   127  		})
   128  	}
   129  }
   130  
   131  func runMain(t *testing.T, args []string) (int, string, string) {
   132  	t.Helper()
   133  	oldArgs := os.Args
   134  	t.Cleanup(func() {
   135  		os.Args = oldArgs
   136  	})
   137  	os.Args = append([]string{"wazero"}, args...)
   138  
   139  	var exitCode int
   140  	stdOut := &bytes.Buffer{}
   141  	stdErr := &bytes.Buffer{}
   142  	var exited bool
   143  	func() {
   144  		defer func() {
   145  			if r := recover(); r != nil {
   146  				exited = true
   147  			}
   148  		}()
   149  		flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
   150  		doMain(stdOut, stdErr, func(code int) {
   151  			exitCode = code
   152  			panic(code)
   153  		})
   154  	}()
   155  
   156  	require.True(t, exited)
   157  
   158  	return exitCode, stdOut.String(), stdErr.String()
   159  }