github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/wasm/binary/section_test.go (about)

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