github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/testing/binaryencoding/names_test.go (about)

     1  package binaryencoding
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/wasilibs/wazerox/internal/testing/require"
     7  	"github.com/wasilibs/wazerox/internal/wasm"
     8  )
     9  
    10  func TestEncodeNameSectionData(t *testing.T) {
    11  	tests := []struct {
    12  		name     string
    13  		input    *wasm.NameSection
    14  		expected []byte
    15  	}{
    16  		{
    17  			name:  "empty",
    18  			input: &wasm.NameSection{},
    19  		},
    20  		{
    21  			name: "only module",
    22  			// e.g. (module $simple )
    23  			input: &wasm.NameSection{ModuleName: "simple"},
    24  			expected: []byte{
    25  				subsectionIDModuleName, 0x07, // 7 bytes
    26  				0x06, // the Module name simple is 6 bytes long
    27  				's', 'i', 'm', 'p', 'l', 'e',
    28  			},
    29  		},
    30  		{
    31  			name: "module and function name",
    32  			//	(module $simple
    33  			//		(import "" "Hello" (func $hello))
    34  			//		(start $hello)
    35  			//	)
    36  			input: &wasm.NameSection{
    37  				ModuleName:    "simple",
    38  				FunctionNames: wasm.NameMap{{Index: wasm.Index(0), Name: "hello"}},
    39  			},
    40  			expected: []byte{
    41  				subsectionIDModuleName, 0x07, // 7 bytes
    42  				0x06, // the Module name simple is 6 bytes long
    43  				's', 'i', 'm', 'p', 'l', 'e',
    44  				subsectionIDFunctionNames, 0x08, // 8 bytes
    45  				0x01, // one function name
    46  				0x00, // the function index is zero
    47  				0x05, // the function name hello is 5 bytes long
    48  				'h', 'e', 'l', 'l', 'o',
    49  			},
    50  		},
    51  		{
    52  			name: "two function names", // e.g. TinyGo which at one point didn't set a module name
    53  			//	(module
    54  			//		(import "wasi_snapshot_preview1" "args_sizes_get" (func $wasi.args_sizes_get (param i32, i32) (result i32)))
    55  			//		(import "wasi_snapshot_preview1" "fd_write" (func $wasi.fd_write (param i32, i32, i32, i32) (result i32)))
    56  			//	)
    57  			input: &wasm.NameSection{
    58  				FunctionNames: wasm.NameMap{
    59  					{Index: wasm.Index(0), Name: "wasi.args_sizes_get"},
    60  					{Index: wasm.Index(1), Name: "wasi.fd_write"},
    61  				},
    62  			},
    63  			expected: []byte{
    64  				subsectionIDFunctionNames, 0x25, // 37 bytes
    65  				0x02, // two function names
    66  				0x00, // the function index is zero
    67  				0x13, // the function name wasi.args_sizes_get is 19 bytes long
    68  				'w', 'a', 's', 'i', '.', 'a', 'r', 'g', 's', '_', 's', 'i', 'z', 'e', 's', '_', 'g', 'e', 't',
    69  				0x01, // the function index is one
    70  				0x0d, // the function name wasi.fd_write is 13 bytes long
    71  				'w', 'a', 's', 'i', '.', 'f', 'd', '_', 'w', 'r', 'i', 't', 'e',
    72  			},
    73  		},
    74  		{
    75  			name: "function with local names",
    76  			//	(module
    77  			//		(import "Math" "Mul" (func $mul (param $x f32) (param $y f32) (result f32)))
    78  			//		(import "Math" "Add" (func $add (param $l f32) (param $r f32) (result f32)))
    79  			//	)
    80  			input: &wasm.NameSection{
    81  				FunctionNames: wasm.NameMap{
    82  					{Index: wasm.Index(0), Name: "mul"},
    83  					{Index: wasm.Index(1), Name: "add"},
    84  				},
    85  				LocalNames: wasm.IndirectNameMap{
    86  					{Index: wasm.Index(0), NameMap: wasm.NameMap{
    87  						{Index: wasm.Index(0), Name: "x"},
    88  						{Index: wasm.Index(1), Name: "y"},
    89  					}},
    90  					{Index: wasm.Index(1), NameMap: wasm.NameMap{
    91  						{Index: wasm.Index(0), Name: "l"},
    92  						{Index: wasm.Index(1), Name: "r"},
    93  					}},
    94  				},
    95  			},
    96  			expected: []byte{
    97  				subsectionIDFunctionNames, 0x0b, // 7 bytes
    98  				0x02,                      // two function names
    99  				0x00, 0x03, 'm', 'u', 'l', // index 0, size of "mul", "mul"
   100  				0x01, 0x03, 'a', 'd', 'd', // index 1, size of "add", "add"
   101  				subsectionIDLocalNames, 0x11, // 17 bytes
   102  				0x02,       // two functions
   103  				0x00, 0x02, // index 0 has 2 locals
   104  				0x00, 0x01, 'x', // index 0, size of "x", "x"
   105  				0x01, 0x01, 'y', // index 1, size of "y", "y"
   106  				0x01, 0x02, // index 1 has 2 locals
   107  				0x00, 0x01, 'l', // index 0, size of "l", "l"
   108  				0x01, 0x01, 'r', // index 1, size of "r", "r"
   109  			},
   110  		},
   111  	}
   112  
   113  	for _, tt := range tests {
   114  		tc := tt
   115  
   116  		t.Run(tc.name, func(t *testing.T) {
   117  			bytes := EncodeNameSectionData(tc.input)
   118  			require.Equal(t, tc.expected, bytes)
   119  		})
   120  	}
   121  }
   122  
   123  func TestEncodeNameSubsection(t *testing.T) {
   124  	subsectionID := uint8(1)
   125  	name := []byte("simple")
   126  	require.Equal(t, []byte{
   127  		subsectionID,
   128  		byte(1 + 6), // 1 is the size of 6 in LEB128 encoding
   129  		6, 's', 'i', 'm', 'p', 'l', 'e',
   130  	}, encodeNameSubsection(subsectionID, encodeSizePrefixed(name)))
   131  }
   132  
   133  func TestEncodeNameAssoc(t *testing.T) {
   134  	na := wasm.NameAssoc{Index: 1, Name: "hello"}
   135  	require.Equal(t, []byte{byte(na.Index), 5, 'h', 'e', 'l', 'l', 'o'}, encodeNameAssoc(na))
   136  }
   137  
   138  func TestEncodeNameMap(t *testing.T) {
   139  	na := wasm.NameAssoc{Index: 1, Name: "hello"}
   140  	m := wasm.NameMap{na}
   141  	require.Equal(t, []byte{byte(1), byte(na.Index), 5, 'h', 'e', 'l', 'l', 'o'}, encodeNameMap(m))
   142  }
   143  
   144  func TestEncodeSizePrefixed(t *testing.T) {
   145  	// We expect size in bytes (LEB128 encoded) then the bytes
   146  	require.Equal(t, []byte{5, 'h', 'e', 'l', 'l', 'o'}, encodeSizePrefixed([]byte("hello")))
   147  }