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

     1  package binary
     2  
     3  import (
     4  	"bytes"
     5  	"testing"
     6  
     7  	"wa-lang.org/wazero/api"
     8  	"wa-lang.org/wazero/internal/testing/require"
     9  	"wa-lang.org/wazero/internal/wasm"
    10  )
    11  
    12  func TestTableSection(t *testing.T) {
    13  	three := uint32(3)
    14  	tests := []struct {
    15  		name     string
    16  		input    []byte
    17  		expected []*wasm.Table
    18  	}{
    19  		{
    20  			name: "min and min with max",
    21  			input: []byte{
    22  				0x01,                            // 1 table
    23  				wasm.RefTypeFuncref, 0x01, 2, 3, // (table 2 3)
    24  			},
    25  			expected: []*wasm.Table{{Min: 2, Max: &three, Type: wasm.RefTypeFuncref}},
    26  		},
    27  		{
    28  			name: "min and min with max - three tables",
    29  			input: []byte{
    30  				0x03,                            // 3 table
    31  				wasm.RefTypeFuncref, 0x01, 2, 3, // (table 2 3)
    32  				wasm.RefTypeExternref, 0x01, 2, 3, // (table 2 3)
    33  				wasm.RefTypeFuncref, 0x01, 2, 3, // (table 2 3)
    34  			},
    35  			expected: []*wasm.Table{
    36  				{Min: 2, Max: &three, Type: wasm.RefTypeFuncref},
    37  				{Min: 2, Max: &three, Type: wasm.RefTypeExternref},
    38  				{Min: 2, Max: &three, Type: wasm.RefTypeFuncref},
    39  			},
    40  		},
    41  	}
    42  
    43  	for _, tt := range tests {
    44  		tc := tt
    45  
    46  		t.Run(tc.name, func(t *testing.T) {
    47  			tables, err := decodeTableSection(bytes.NewReader(tc.input), api.CoreFeatureReferenceTypes)
    48  			require.NoError(t, err)
    49  			require.Equal(t, tc.expected, tables)
    50  		})
    51  	}
    52  }
    53  
    54  func TestTableSection_Errors(t *testing.T) {
    55  	tests := []struct {
    56  		name        string
    57  		input       []byte
    58  		expectedErr string
    59  		features    api.CoreFeatures
    60  	}{
    61  		{
    62  			name: "min and min with max",
    63  			input: []byte{
    64  				0x02,                            // 2 tables
    65  				wasm.RefTypeFuncref, 0x00, 0x01, // (table 1)
    66  				wasm.RefTypeFuncref, 0x01, 0x02, 0x03, // (table 2 3)
    67  			},
    68  			expectedErr: "at most one table allowed in module as feature \"reference-types\" is disabled",
    69  			features:    api.CoreFeaturesV1,
    70  		},
    71  	}
    72  
    73  	for _, tt := range tests {
    74  		tc := tt
    75  
    76  		t.Run(tc.name, func(t *testing.T) {
    77  			_, err := decodeTableSection(bytes.NewReader(tc.input), tc.features)
    78  			require.EqualError(t, err, tc.expectedErr)
    79  		})
    80  	}
    81  }
    82  
    83  func TestMemorySection(t *testing.T) {
    84  	max := wasm.MemoryLimitPages
    85  
    86  	three := uint32(3)
    87  	tests := []struct {
    88  		name     string
    89  		input    []byte
    90  		expected *wasm.Memory
    91  	}{
    92  		{
    93  			name: "min and min with max",
    94  			input: []byte{
    95  				0x01,             // 1 memory
    96  				0x01, 0x02, 0x03, // (memory 2 3)
    97  			},
    98  			expected: &wasm.Memory{Min: 2, Cap: 2, Max: three, IsMaxEncoded: true},
    99  		},
   100  	}
   101  
   102  	for _, tt := range tests {
   103  		tc := tt
   104  
   105  		t.Run(tc.name, func(t *testing.T) {
   106  			memories, err := decodeMemorySection(bytes.NewReader(tc.input), newMemorySizer(max, false), max)
   107  			require.NoError(t, err)
   108  			require.Equal(t, tc.expected, memories)
   109  		})
   110  	}
   111  }
   112  
   113  func TestMemorySection_Errors(t *testing.T) {
   114  	max := wasm.MemoryLimitPages
   115  
   116  	tests := []struct {
   117  		name        string
   118  		input       []byte
   119  		expectedErr string
   120  	}{
   121  		{
   122  			name: "min and min with max",
   123  			input: []byte{
   124  				0x02,       // 2 memories
   125  				0x01,       // (memory 1)
   126  				0x02, 0x03, // (memory 2 3)
   127  			},
   128  			expectedErr: "at most one memory allowed in module, but read 2",
   129  		},
   130  	}
   131  
   132  	for _, tt := range tests {
   133  		tc := tt
   134  
   135  		t.Run(tc.name, func(t *testing.T) {
   136  			_, err := decodeMemorySection(bytes.NewReader(tc.input), newMemorySizer(max, false), max)
   137  			require.EqualError(t, err, tc.expectedErr)
   138  		})
   139  	}
   140  }
   141  
   142  func TestDecodeExportSection(t *testing.T) {
   143  	tests := []struct {
   144  		name     string
   145  		input    []byte
   146  		expected []*wasm.Export
   147  	}{
   148  		{
   149  			name: "empty and non-empty name",
   150  			input: []byte{
   151  				0x02,                      // 2 exports
   152  				0x00,                      // Size of empty name
   153  				wasm.ExternTypeFunc, 0x02, // func[2]
   154  				0x01, 'a', // Size of name, name
   155  				wasm.ExternTypeFunc, 0x01, // func[1]
   156  			},
   157  			expected: []*wasm.Export{
   158  				{Name: "", Type: wasm.ExternTypeFunc, Index: wasm.Index(2)},
   159  				{Name: "a", Type: wasm.ExternTypeFunc, Index: wasm.Index(1)},
   160  			},
   161  		},
   162  	}
   163  
   164  	for _, tt := range tests {
   165  		tc := tt
   166  
   167  		t.Run(tc.name, func(t *testing.T) {
   168  			exports, err := decodeExportSection(bytes.NewReader(tc.input))
   169  			require.NoError(t, err)
   170  			require.Equal(t, tc.expected, exports)
   171  		})
   172  	}
   173  }
   174  
   175  func TestDecodeExportSection_Errors(t *testing.T) {
   176  	tests := []struct {
   177  		name        string
   178  		input       []byte
   179  		expectedErr string
   180  	}{
   181  		{
   182  			name: "duplicates empty name",
   183  			input: []byte{
   184  				0x02,                      // 2 exports
   185  				0x00,                      // Size of empty name
   186  				wasm.ExternTypeFunc, 0x00, // func[0]
   187  				0x00,                      // Size of empty name
   188  				wasm.ExternTypeFunc, 0x00, // func[0]
   189  			},
   190  			expectedErr: "export[1] duplicates name \"\"",
   191  		},
   192  		{
   193  			name: "duplicates name",
   194  			input: []byte{
   195  				0x02,      // 2 exports
   196  				0x01, 'a', // Size of name, name
   197  				wasm.ExternTypeFunc, 0x00, // func[0]
   198  				0x01, 'a', // Size of name, name
   199  				wasm.ExternTypeFunc, 0x00, // func[0]
   200  			},
   201  			expectedErr: "export[1] duplicates name \"a\"",
   202  		},
   203  	}
   204  
   205  	for _, tt := range tests {
   206  		tc := tt
   207  
   208  		t.Run(tc.name, func(t *testing.T) {
   209  			_, err := decodeExportSection(bytes.NewReader(tc.input))
   210  			require.EqualError(t, err, tc.expectedErr)
   211  		})
   212  	}
   213  }
   214  
   215  func TestEncodeFunctionSection(t *testing.T) {
   216  	require.Equal(t, []byte{wasm.SectionIDFunction, 0x2, 0x01, 0x05}, encodeFunctionSection([]wasm.Index{5}))
   217  }
   218  
   219  // TestEncodeStartSection uses the same index as TestEncodeFunctionSection to highlight the encoding is different.
   220  func TestEncodeStartSection(t *testing.T) {
   221  	require.Equal(t, []byte{wasm.SectionIDStart, 0x01, 0x05}, encodeStartSection(5))
   222  }
   223  
   224  func TestDecodeDataCountSection(t *testing.T) {
   225  	t.Run("ok", func(t *testing.T) {
   226  		v, err := decodeDataCountSection(bytes.NewReader([]byte{0x1}))
   227  		require.NoError(t, err)
   228  		require.Equal(t, uint32(1), *v)
   229  	})
   230  	t.Run("eof", func(t *testing.T) {
   231  		// EOF is fine as the datacount is optional.
   232  		_, err := decodeDataCountSection(bytes.NewReader([]byte{}))
   233  		require.NoError(t, err)
   234  	})
   235  }