wa-lang.org/wazero@v1.0.2/internal/wasm/binary/decoder_test.go (about)

     1  package binary
     2  
     3  import (
     4  	"testing"
     5  
     6  	"wa-lang.org/wazero/api"
     7  	"wa-lang.org/wazero/internal/testing/require"
     8  	"wa-lang.org/wazero/internal/wasm"
     9  )
    10  
    11  // TestDecodeModule relies on unit tests for Module.Encode, specifically that the encoding is both known and correct.
    12  // This avoids having to copy/paste or share variables to assert against byte arrays.
    13  func TestDecodeModule(t *testing.T) {
    14  	i32, f32 := wasm.ValueTypeI32, wasm.ValueTypeF32
    15  	zero := uint32(0)
    16  
    17  	tests := []struct {
    18  		name  string
    19  		input *wasm.Module // round trip test!
    20  	}{
    21  		{
    22  			name:  "empty",
    23  			input: &wasm.Module{},
    24  		},
    25  		{
    26  			name:  "only name section",
    27  			input: &wasm.Module{NameSection: &wasm.NameSection{ModuleName: "simple"}},
    28  		},
    29  		{
    30  			name: "type section",
    31  			input: &wasm.Module{
    32  				TypeSection: []*wasm.FunctionType{
    33  					{},
    34  					{Params: []wasm.ValueType{i32, i32}, Results: []wasm.ValueType{i32}},
    35  					{Params: []wasm.ValueType{i32, i32, i32, i32}, Results: []wasm.ValueType{i32}},
    36  				},
    37  			},
    38  		},
    39  		{
    40  			name: "type and import section",
    41  			input: &wasm.Module{
    42  				TypeSection: []*wasm.FunctionType{
    43  					{Params: []wasm.ValueType{i32, i32}, Results: []wasm.ValueType{i32}},
    44  					{Params: []wasm.ValueType{f32, f32}, Results: []wasm.ValueType{f32}},
    45  				},
    46  				ImportSection: []*wasm.Import{
    47  					{
    48  						Module: "Math", Name: "Mul",
    49  						Type:     wasm.ExternTypeFunc,
    50  						DescFunc: 1,
    51  					}, {
    52  						Module: "Math", Name: "Add",
    53  						Type:     wasm.ExternTypeFunc,
    54  						DescFunc: 0,
    55  					},
    56  				},
    57  			},
    58  		},
    59  		{
    60  			name: "table and memory section",
    61  			input: &wasm.Module{
    62  				TableSection:  []*wasm.Table{{Min: 3, Type: wasm.RefTypeFuncref}},
    63  				MemorySection: &wasm.Memory{Min: 1, Cap: 1, Max: 1, IsMaxEncoded: true},
    64  			},
    65  		},
    66  		{
    67  			name: "type function and start section",
    68  			input: &wasm.Module{
    69  				TypeSection: []*wasm.FunctionType{{}},
    70  				ImportSection: []*wasm.Import{{
    71  					Module: "", Name: "hello",
    72  					Type:     wasm.ExternTypeFunc,
    73  					DescFunc: 0,
    74  				}},
    75  				StartSection: &zero,
    76  			},
    77  		},
    78  	}
    79  
    80  	for _, tt := range tests {
    81  		tc := tt
    82  
    83  		t.Run(tc.name, func(t *testing.T) {
    84  			m, e := DecodeModule(EncodeModule(tc.input), api.CoreFeaturesV1, wasm.MemoryLimitPages, false)
    85  			require.NoError(t, e)
    86  			require.Equal(t, tc.input, m)
    87  		})
    88  	}
    89  
    90  	t.Run("skips custom section", func(t *testing.T) {
    91  		input := append(append(Magic, version...),
    92  			wasm.SectionIDCustom, 0xf, // 15 bytes in this section
    93  			0x04, 'm', 'e', 'm', 'e',
    94  			1, 2, 3, 4, 5, 6, 7, 8, 9, 0)
    95  		m, e := DecodeModule(input, api.CoreFeaturesV1, wasm.MemoryLimitPages, false)
    96  		require.NoError(t, e)
    97  		require.Equal(t, &wasm.Module{}, m)
    98  	})
    99  
   100  	t.Run("skips custom section, but not name", func(t *testing.T) {
   101  		input := append(append(Magic, version...),
   102  			wasm.SectionIDCustom, 0xf, // 15 bytes in this section
   103  			0x04, 'm', 'e', 'm', 'e',
   104  			1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
   105  			wasm.SectionIDCustom, 0x0e, // 14 bytes in this section
   106  			0x04, 'n', 'a', 'm', 'e',
   107  			subsectionIDModuleName, 0x07, // 7 bytes in this subsection
   108  			0x06, // the Module name simple is 6 bytes long
   109  			's', 'i', 'm', 'p', 'l', 'e')
   110  		m, e := DecodeModule(input, api.CoreFeaturesV1, wasm.MemoryLimitPages, false)
   111  		require.NoError(t, e)
   112  		require.Equal(t, &wasm.Module{NameSection: &wasm.NameSection{ModuleName: "simple"}}, m)
   113  	})
   114  	t.Run("data count section disabled", func(t *testing.T) {
   115  		input := append(append(Magic, version...),
   116  			wasm.SectionIDDataCount, 1, 0)
   117  		_, e := DecodeModule(input, api.CoreFeaturesV1, wasm.MemoryLimitPages, false)
   118  		require.EqualError(t, e, `data count section not supported as feature "bulk-memory-operations" is disabled`)
   119  	})
   120  }
   121  
   122  func TestDecodeModule_Errors(t *testing.T) {
   123  	tests := []struct {
   124  		name        string
   125  		input       []byte
   126  		expectedErr string
   127  	}{
   128  		{
   129  			name:        "wrong magic",
   130  			input:       []byte("wasm\x01\x00\x00\x00"),
   131  			expectedErr: "invalid magic number",
   132  		},
   133  		{
   134  			name:        "wrong version",
   135  			input:       []byte("\x00asm\x01\x00\x00\x01"),
   136  			expectedErr: "invalid version header",
   137  		},
   138  		{
   139  			name: "multiple start sections",
   140  			input: append(append(Magic, version...),
   141  				wasm.SectionIDType, 4, 1, 0x60, 0, 0,
   142  				wasm.SectionIDFunction, 2, 1, 0,
   143  				wasm.SectionIDCode, 4, 1,
   144  				2, 0, wasm.OpcodeEnd,
   145  				wasm.SectionIDStart, 1, 0,
   146  				wasm.SectionIDStart, 1, 0,
   147  			),
   148  			expectedErr: `multiple start sections are invalid`,
   149  		},
   150  		{
   151  			name: "redundant name section",
   152  			input: append(append(Magic, version...),
   153  				wasm.SectionIDCustom, 0x09, // 9 bytes in this section
   154  				0x04, 'n', 'a', 'm', 'e',
   155  				subsectionIDModuleName, 0x02, 0x01, 'x',
   156  				wasm.SectionIDCustom, 0x09, // 9 bytes in this section
   157  				0x04, 'n', 'a', 'm', 'e',
   158  				subsectionIDModuleName, 0x02, 0x01, 'x'),
   159  			expectedErr: "section custom: redundant custom section name",
   160  		},
   161  	}
   162  
   163  	for _, tt := range tests {
   164  		tc := tt
   165  
   166  		t.Run(tc.name, func(t *testing.T) {
   167  			_, e := DecodeModule(tc.input, api.CoreFeaturesV1, wasm.MemoryLimitPages, false)
   168  			require.EqualError(t, e, tc.expectedErr)
   169  		})
   170  	}
   171  }