github.com/bananabytelabs/wazero@v0.0.0-20240105073314-54b22a776da8/config_test.go (about)

     1  package wazero
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	_ "embed"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/bananabytelabs/wazero/api"
    11  	experimentalsys "github.com/bananabytelabs/wazero/experimental/sys"
    12  	"github.com/bananabytelabs/wazero/internal/fstest"
    13  	"github.com/bananabytelabs/wazero/internal/platform"
    14  	internalsys "github.com/bananabytelabs/wazero/internal/sys"
    15  	"github.com/bananabytelabs/wazero/internal/sysfs"
    16  	testfs "github.com/bananabytelabs/wazero/internal/testing/fs"
    17  	"github.com/bananabytelabs/wazero/internal/testing/require"
    18  	"github.com/bananabytelabs/wazero/internal/wasm"
    19  	"github.com/bananabytelabs/wazero/sys"
    20  )
    21  
    22  func TestRuntimeConfig(t *testing.T) {
    23  	tests := []struct {
    24  		name     string
    25  		with     func(RuntimeConfig) RuntimeConfig
    26  		expected RuntimeConfig
    27  	}{
    28  		{
    29  			name: "features",
    30  			with: func(c RuntimeConfig) RuntimeConfig {
    31  				return c.WithCoreFeatures(api.CoreFeaturesV1)
    32  			},
    33  			expected: &runtimeConfig{
    34  				enabledFeatures: api.CoreFeaturesV1,
    35  			},
    36  		},
    37  		{
    38  			name: "memoryLimitPages",
    39  			with: func(c RuntimeConfig) RuntimeConfig {
    40  				return c.WithMemoryLimitPages(10)
    41  			},
    42  			expected: &runtimeConfig{
    43  				memoryLimitPages: 10,
    44  			},
    45  		},
    46  		{
    47  			name: "memoryCapacityFromMax",
    48  			with: func(c RuntimeConfig) RuntimeConfig {
    49  				return c.WithMemoryCapacityFromMax(true)
    50  			},
    51  			expected: &runtimeConfig{
    52  				memoryCapacityFromMax: true,
    53  			},
    54  		},
    55  		{
    56  			name: "WithDebugInfoEnabled",
    57  			with: func(c RuntimeConfig) RuntimeConfig {
    58  				return c.WithDebugInfoEnabled(false)
    59  			},
    60  			expected: &runtimeConfig{
    61  				dwarfDisabled: true, // dwarf is a more technical name and ok here.
    62  			},
    63  		},
    64  		{
    65  			name: "WithCustomSections",
    66  			with: func(c RuntimeConfig) RuntimeConfig {
    67  				return c.WithCustomSections(true)
    68  			},
    69  			expected: &runtimeConfig{
    70  				storeCustomSections: true,
    71  			},
    72  		},
    73  		{
    74  			name:     "WithCloseOnContextDone",
    75  			with:     func(c RuntimeConfig) RuntimeConfig { return c.WithCloseOnContextDone(true) },
    76  			expected: &runtimeConfig{ensureTermination: true},
    77  		},
    78  	}
    79  
    80  	for _, tt := range tests {
    81  		tc := tt
    82  
    83  		t.Run(tc.name, func(t *testing.T) {
    84  			input := &runtimeConfig{}
    85  			rc := tc.with(input)
    86  			require.Equal(t, tc.expected, rc)
    87  			// The source wasn't modified
    88  			require.Equal(t, &runtimeConfig{}, input)
    89  		})
    90  	}
    91  
    92  	t.Run("memoryLimitPages invalid panics", func(t *testing.T) {
    93  		err := require.CapturePanic(func() {
    94  			input := &runtimeConfig{}
    95  			input.WithMemoryLimitPages(wasm.MemoryLimitPages + 1)
    96  		})
    97  		require.EqualError(t, err, "memoryLimitPages invalid: 65537 > 65536")
    98  	})
    99  }
   100  
   101  func TestModuleConfig(t *testing.T) {
   102  	tests := []struct {
   103  		name          string
   104  		with          func(ModuleConfig) ModuleConfig
   105  		expectNameSet bool
   106  		expectedName  string
   107  	}{
   108  		{
   109  			name: "WithName default",
   110  			with: func(c ModuleConfig) ModuleConfig {
   111  				return c
   112  			},
   113  			expectNameSet: false,
   114  			expectedName:  "",
   115  		},
   116  		{
   117  			name: "WithName",
   118  			with: func(c ModuleConfig) ModuleConfig {
   119  				return c.WithName("wazero")
   120  			},
   121  			expectNameSet: true,
   122  			expectedName:  "wazero",
   123  		},
   124  		{
   125  			name: "WithName empty",
   126  			with: func(c ModuleConfig) ModuleConfig {
   127  				return c.WithName("")
   128  			},
   129  			expectNameSet: true,
   130  			expectedName:  "",
   131  		},
   132  		{
   133  			name: "WithName twice",
   134  			with: func(c ModuleConfig) ModuleConfig {
   135  				return c.WithName("wazero").WithName("wa0")
   136  			},
   137  			expectNameSet: true,
   138  			expectedName:  "wa0",
   139  		},
   140  		{
   141  			name: "WithName can clear",
   142  			with: func(c ModuleConfig) ModuleConfig {
   143  				return c.WithName("wazero").WithName("")
   144  			},
   145  			expectNameSet: true,
   146  			expectedName:  "",
   147  		},
   148  	}
   149  	for _, tt := range tests {
   150  		tc := tt
   151  
   152  		t.Run(tc.name, func(t *testing.T) {
   153  			input := NewModuleConfig()
   154  			rc := tc.with(input)
   155  			require.Equal(t, tc.expectNameSet, rc.(*moduleConfig).nameSet)
   156  			require.Equal(t, tc.expectedName, rc.(*moduleConfig).name)
   157  			// The source wasn't modified
   158  			require.Equal(t, NewModuleConfig(), input)
   159  		})
   160  	}
   161  }
   162  
   163  // TestModuleConfig_toSysContext only tests the cases that change the inputs to
   164  // sys.NewContext.
   165  func TestModuleConfig_toSysContext(t *testing.T) {
   166  	base := NewModuleConfig()
   167  
   168  	tests := []struct {
   169  		name  string
   170  		input func() (mc ModuleConfig, verify func(t *testing.T, sys *internalsys.Context))
   171  	}{
   172  		{
   173  			name: "empty",
   174  			input: func() (ModuleConfig, func(t *testing.T, sys *internalsys.Context)) {
   175  				return base, func(t *testing.T, sys *internalsys.Context) { require.NotNil(t, sys) }
   176  			},
   177  		},
   178  		{
   179  			name: "WithNanotime",
   180  			input: func() (ModuleConfig, func(t *testing.T, sys *internalsys.Context)) {
   181  				config := base.WithNanotime(func() int64 { return 1234567 }, 54321)
   182  				return config, func(t *testing.T, sys *internalsys.Context) {
   183  					require.Equal(t, 1234567, int(sys.Nanotime()))
   184  					require.Equal(t, 54321, int(sys.NanotimeResolution()))
   185  				}
   186  			},
   187  		},
   188  		{
   189  			name: "WithSysNanotime",
   190  			input: func() (ModuleConfig, func(t *testing.T, sys *internalsys.Context)) {
   191  				config := base.WithSysNanotime()
   192  				return config, func(t *testing.T, sys *internalsys.Context) {
   193  					require.Equal(t, int(1), int(sys.NanotimeResolution()))
   194  				}
   195  			},
   196  		},
   197  		{
   198  			name: "WithWalltime",
   199  			input: func() (ModuleConfig, func(t *testing.T, sys *internalsys.Context)) {
   200  				config := base.WithWalltime(func() (sec int64, nsec int32) { return 5, 10 }, 54321)
   201  				return config, func(t *testing.T, sys *internalsys.Context) {
   202  					actualSec, actualNano := sys.Walltime()
   203  					require.Equal(t, 5, int(actualSec))
   204  					require.Equal(t, 10, int(actualNano))
   205  					require.Equal(t, 54321, int(sys.WalltimeResolution()))
   206  				}
   207  			},
   208  		},
   209  		{
   210  			name: "WithSysWalltime",
   211  			input: func() (ModuleConfig, func(t *testing.T, sys *internalsys.Context)) {
   212  				config := base.WithSysWalltime()
   213  				return config, func(t *testing.T, sys *internalsys.Context) {
   214  					require.Equal(t, int(time.Microsecond.Nanoseconds()), int(sys.WalltimeResolution()))
   215  				}
   216  			},
   217  		},
   218  		{
   219  			name: "WithArgs empty",
   220  			input: func() (ModuleConfig, func(t *testing.T, sys *internalsys.Context)) {
   221  				config := base.WithArgs()
   222  				return config, func(t *testing.T, sys *internalsys.Context) {
   223  					args := sys.Args()
   224  					require.Equal(t, 0, len(args))
   225  				}
   226  			},
   227  		},
   228  		{
   229  			name: "WithArgs",
   230  			input: func() (ModuleConfig, func(t *testing.T, sys *internalsys.Context)) {
   231  				config := base.WithArgs("a", "bc")
   232  				return config, func(t *testing.T, sys *internalsys.Context) {
   233  					args := sys.Args()
   234  					require.Equal(t, 2, len(args))
   235  					require.Equal(t, "a", string(args[0]))
   236  					require.Equal(t, "bc", string(args[1]))
   237  				}
   238  			},
   239  		},
   240  		{
   241  			name: "WithArgs empty ok", // Particularly argv[0] can be empty, and we have no rules about others.
   242  			input: func() (ModuleConfig, func(t *testing.T, sys *internalsys.Context)) {
   243  				config := base.WithArgs("", "bc")
   244  				return config, func(t *testing.T, sys *internalsys.Context) {
   245  					args := sys.Args()
   246  					require.Equal(t, 2, len(args))
   247  					require.Equal(t, "", string(args[0]))
   248  					require.Equal(t, "bc", string(args[1]))
   249  				}
   250  			},
   251  		},
   252  		{
   253  			name: "WithArgs second call overwrites",
   254  			input: func() (ModuleConfig, func(t *testing.T, sys *internalsys.Context)) {
   255  				config := base.WithArgs("a", "bc").WithArgs("bc", "a")
   256  				return config, func(t *testing.T, sys *internalsys.Context) {
   257  					args := sys.Args()
   258  					require.Equal(t, 2, len(args))
   259  					require.Equal(t, "bc", string(args[0]))
   260  					require.Equal(t, "a", string(args[1]))
   261  				}
   262  			},
   263  		},
   264  		{
   265  			name: "WithEnv",
   266  			input: func() (ModuleConfig, func(t *testing.T, sys *internalsys.Context)) {
   267  				config := base.WithEnv("a", "b")
   268  				return config, func(t *testing.T, sys *internalsys.Context) {
   269  					envs := sys.Environ()
   270  					require.Equal(t, 1, len(envs))
   271  					require.Equal(t, "a=b", string(envs[0]))
   272  				}
   273  			},
   274  		},
   275  		{
   276  			name: "WithEnv empty value",
   277  			input: func() (ModuleConfig, func(t *testing.T, sys *internalsys.Context)) {
   278  				config := base.WithEnv("a", "")
   279  				return config, func(t *testing.T, sys *internalsys.Context) {
   280  					envs := sys.Environ()
   281  					require.Equal(t, 1, len(envs))
   282  					require.Equal(t, "a=", string(envs[0]))
   283  				}
   284  			},
   285  		},
   286  		{
   287  			name: "WithEnv twice",
   288  			input: func() (ModuleConfig, func(t *testing.T, sys *internalsys.Context)) {
   289  				config := base.WithEnv("a", "b").WithEnv("c", "de")
   290  				return config, func(t *testing.T, sys *internalsys.Context) {
   291  					envs := sys.Environ()
   292  					require.Equal(t, 2, len(envs))
   293  					require.Equal(t, "a=b", string(envs[0]))
   294  					require.Equal(t, "c=de", string(envs[1]))
   295  				}
   296  			},
   297  		},
   298  		{
   299  			name: "WithEnv overwrites",
   300  			input: func() (ModuleConfig, func(t *testing.T, sys *internalsys.Context)) {
   301  				config := base.WithEnv("a", "bc").WithEnv("c", "de").WithEnv("a", "ff")
   302  				return config, func(t *testing.T, sys *internalsys.Context) {
   303  					envs := sys.Environ()
   304  					require.Equal(t, 2, len(envs))
   305  					require.Equal(t, "a=ff", string(envs[0]))
   306  					require.Equal(t, "c=de", string(envs[1]))
   307  				}
   308  			},
   309  		},
   310  		{
   311  			name: "WithEnv twice",
   312  			input: func() (ModuleConfig, func(t *testing.T, sys *internalsys.Context)) {
   313  				config := base.WithEnv("a", "b").WithEnv("c", "de")
   314  				return config, func(t *testing.T, sys *internalsys.Context) {
   315  					envs := sys.Environ()
   316  					require.Equal(t, 2, len(envs))
   317  					require.Equal(t, "a=b", string(envs[0]))
   318  					require.Equal(t, "c=de", string(envs[1]))
   319  				}
   320  			},
   321  		},
   322  		{
   323  			name: "WithFS",
   324  			input: func() (ModuleConfig, func(t *testing.T, sys *internalsys.Context)) {
   325  				testFS := &testfs.FS{}
   326  				config := base.WithFS(testFS)
   327  				return config, func(t *testing.T, sys *internalsys.Context) {
   328  					rootfs := sys.FS().RootFS()
   329  					require.Equal(t, &sysfs.AdaptFS{FS: testFS}, rootfs)
   330  				}
   331  			},
   332  		},
   333  		{
   334  			name: "WithFS overwrites",
   335  			input: func() (ModuleConfig, func(t *testing.T, sys *internalsys.Context)) {
   336  				testFS, testFS2 := &testfs.FS{}, &testfs.FS{}
   337  				config := base.WithFS(testFS).WithFS(testFS2)
   338  				return config, func(t *testing.T, sys *internalsys.Context) {
   339  					rootfs := sys.FS().RootFS()
   340  					require.Equal(t, &sysfs.AdaptFS{FS: testFS2}, rootfs)
   341  				}
   342  			},
   343  		},
   344  		{
   345  			name: "WithFS nil",
   346  			input: func() (ModuleConfig, func(t *testing.T, sys *internalsys.Context)) {
   347  				config := base.WithFS(nil)
   348  				return config, func(t *testing.T, sys *internalsys.Context) {
   349  					rootfs := sys.FS().RootFS()
   350  					require.Equal(t, experimentalsys.UnimplementedFS{}, rootfs)
   351  				}
   352  			},
   353  		},
   354  		{
   355  			name: "WithRandSource",
   356  			input: func() (ModuleConfig, func(t *testing.T, sys *internalsys.Context)) {
   357  				r := bytes.NewReader([]byte{1, 2, 3, 4})
   358  				config := base.WithRandSource(r)
   359  				return config, func(t *testing.T, sys *internalsys.Context) {
   360  					actual := sys.RandSource()
   361  					require.Equal(t, r, actual)
   362  				}
   363  			},
   364  		},
   365  		{
   366  			name: "WithRandSource nil",
   367  			input: func() (ModuleConfig, func(t *testing.T, sys *internalsys.Context)) {
   368  				config := base.WithRandSource(nil)
   369  				return config, func(t *testing.T, sys *internalsys.Context) {
   370  					actual := sys.RandSource()
   371  					require.Equal(t, platform.NewFakeRandSource(), actual)
   372  				}
   373  			},
   374  		},
   375  	}
   376  
   377  	for _, tt := range tests {
   378  		tc := tt
   379  
   380  		t.Run(tc.name, func(t *testing.T) {
   381  			config, verify := tc.input()
   382  			actual, err := config.(*moduleConfig).toSysContext()
   383  			require.NoError(t, err)
   384  			verify(t, actual)
   385  		})
   386  	}
   387  }
   388  
   389  // TestModuleConfig_toSysContext_WithWalltime has to test differently because we can't
   390  // compare function pointers when functions are passed by value.
   391  func TestModuleConfig_toSysContext_WithWalltime(t *testing.T) {
   392  	tests := []struct {
   393  		name               string
   394  		input              ModuleConfig
   395  		expectedSec        int64
   396  		expectedNsec       int32
   397  		expectedResolution sys.ClockResolution
   398  		expectedErr        string
   399  	}{
   400  		{
   401  			name: "ok",
   402  			input: NewModuleConfig().
   403  				WithWalltime(func() (sec int64, nsec int32) {
   404  					return 1, 2
   405  				}, 3),
   406  			expectedSec:        1,
   407  			expectedNsec:       2,
   408  			expectedResolution: 3,
   409  		},
   410  		{
   411  			name: "overwrites",
   412  			input: NewModuleConfig().
   413  				WithWalltime(func() (sec int64, nsec int32) {
   414  					return 3, 4
   415  				}, 5).
   416  				WithWalltime(func() (sec int64, nsec int32) {
   417  					return 1, 2
   418  				}, 3),
   419  			expectedSec:        1,
   420  			expectedNsec:       2,
   421  			expectedResolution: 3,
   422  		},
   423  		{
   424  			name: "invalid resolution",
   425  			input: NewModuleConfig().
   426  				WithWalltime(func() (sec int64, nsec int32) {
   427  					return 1, 2
   428  				}, 0),
   429  			expectedErr: "invalid Walltime resolution: 0",
   430  		},
   431  	}
   432  
   433  	for _, tt := range tests {
   434  		tc := tt
   435  
   436  		t.Run(tc.name, func(t *testing.T) {
   437  			sysCtx, err := tc.input.(*moduleConfig).toSysContext()
   438  			if tc.expectedErr == "" {
   439  				require.Nil(t, err)
   440  				sec, nsec := sysCtx.Walltime()
   441  				require.Equal(t, tc.expectedSec, sec)
   442  				require.Equal(t, tc.expectedNsec, nsec)
   443  				require.Equal(t, tc.expectedResolution, sysCtx.WalltimeResolution())
   444  			} else {
   445  				require.EqualError(t, err, tc.expectedErr)
   446  			}
   447  		})
   448  	}
   449  
   450  	t.Run("context", func(t *testing.T) {
   451  		sysCtx, err := NewModuleConfig().
   452  			WithWalltime(func() (sec int64, nsec int32) {
   453  				return 1, 2
   454  			}, 3).(*moduleConfig).toSysContext()
   455  		require.NoError(t, err)
   456  		sec, nsec := sysCtx.Walltime()
   457  		// If below pass, the context was correct!
   458  		require.Equal(t, int64(1), sec)
   459  		require.Equal(t, int32(2), nsec)
   460  	})
   461  }
   462  
   463  // TestModuleConfig_toSysContext_WithNanotime has to test differently because we can't
   464  // compare function pointers when functions are passed by value.
   465  func TestModuleConfig_toSysContext_WithNanotime(t *testing.T) {
   466  	tests := []struct {
   467  		name               string
   468  		input              ModuleConfig
   469  		expectedNanos      int64
   470  		expectedResolution sys.ClockResolution
   471  		expectedErr        string
   472  	}{
   473  		{
   474  			name: "ok",
   475  			input: NewModuleConfig().
   476  				WithNanotime(func() int64 {
   477  					return 1
   478  				}, 2),
   479  			expectedNanos:      1,
   480  			expectedResolution: 2,
   481  		},
   482  		{
   483  			name: "overwrites",
   484  			input: NewModuleConfig().
   485  				WithNanotime(func() int64 {
   486  					return 3
   487  				}, 4).
   488  				WithNanotime(func() int64 {
   489  					return 1
   490  				}, 2),
   491  			expectedNanos:      1,
   492  			expectedResolution: 2,
   493  		},
   494  		{
   495  			name: "invalid resolution",
   496  			input: NewModuleConfig().
   497  				WithNanotime(func() int64 {
   498  					return 1
   499  				}, 0),
   500  			expectedErr: "invalid Nanotime resolution: 0",
   501  		},
   502  	}
   503  
   504  	for _, tt := range tests {
   505  		tc := tt
   506  
   507  		t.Run(tc.name, func(t *testing.T) {
   508  			sysCtx, err := tc.input.(*moduleConfig).toSysContext()
   509  			if tc.expectedErr == "" {
   510  				require.Nil(t, err)
   511  				nanos := sysCtx.Nanotime()
   512  				require.Equal(t, tc.expectedNanos, nanos)
   513  				require.Equal(t, tc.expectedResolution, sysCtx.NanotimeResolution())
   514  			} else {
   515  				require.EqualError(t, err, tc.expectedErr)
   516  			}
   517  		})
   518  	}
   519  }
   520  
   521  // TestModuleConfig_toSysContext_WithNanosleep has to test differently because
   522  // we can't compare function pointers when functions are passed by value.
   523  func TestModuleConfig_toSysContext_WithNanosleep(t *testing.T) {
   524  	sysCtx, err := NewModuleConfig().
   525  		WithNanosleep(func(ns int64) {
   526  			require.Equal(t, int64(2), ns)
   527  		}).(*moduleConfig).toSysContext()
   528  	require.NoError(t, err)
   529  	sysCtx.Nanosleep(2)
   530  }
   531  
   532  // TestModuleConfig_toSysContext_WithOsyield has to test differently because
   533  // we can't compare function pointers when functions are passed by value.
   534  func TestModuleConfig_toSysContext_WithOsyield(t *testing.T) {
   535  	var yielded bool
   536  	sysCtx, err := NewModuleConfig().
   537  		WithOsyield(func() {
   538  			yielded = true
   539  		}).(*moduleConfig).toSysContext()
   540  	require.NoError(t, err)
   541  	sysCtx.Osyield()
   542  	require.True(t, yielded)
   543  }
   544  
   545  func TestModuleConfig_toSysContext_Errors(t *testing.T) {
   546  	tests := []struct {
   547  		name        string
   548  		input       ModuleConfig
   549  		expectedErr string
   550  	}{
   551  		{
   552  			name:        "WithArgs arg contains NUL",
   553  			input:       NewModuleConfig().WithArgs("", string([]byte{'a', 0})),
   554  			expectedErr: "args invalid: contains NUL character",
   555  		},
   556  		{
   557  			name:        "WithEnv key contains NUL",
   558  			input:       NewModuleConfig().WithEnv(string([]byte{'a', 0}), "a"),
   559  			expectedErr: "environ invalid: contains NUL character",
   560  		},
   561  		{
   562  			name:        "WithEnv value contains NUL",
   563  			input:       NewModuleConfig().WithEnv("a", string([]byte{'a', 0})),
   564  			expectedErr: "environ invalid: contains NUL character",
   565  		},
   566  		{
   567  			name:        "WithEnv key contains equals",
   568  			input:       NewModuleConfig().WithEnv("a=", "a"),
   569  			expectedErr: "environ invalid: key contains '=' character",
   570  		},
   571  		{
   572  			name:        "WithEnv empty key",
   573  			input:       NewModuleConfig().WithEnv("", "a"),
   574  			expectedErr: "environ invalid: empty key",
   575  		},
   576  	}
   577  	for _, tt := range tests {
   578  		tc := tt
   579  
   580  		t.Run(tc.name, func(t *testing.T) {
   581  			_, err := tc.input.(*moduleConfig).toSysContext()
   582  			require.EqualError(t, err, tc.expectedErr)
   583  		})
   584  	}
   585  }
   586  
   587  func TestModuleConfig_clone(t *testing.T) {
   588  	mc := NewModuleConfig().(*moduleConfig)
   589  	cloned := mc.clone()
   590  
   591  	// Make post-clone changes
   592  	mc.fsConfig = NewFSConfig().WithFSMount(fstest.FS, "/")
   593  	mc.environKeys["2"] = 2
   594  
   595  	cloned.environKeys["1"] = 1
   596  
   597  	// Ensure the maps are not shared
   598  	require.Equal(t, map[string]int{"2": 2}, mc.environKeys)
   599  	require.Equal(t, map[string]int{"1": 1}, cloned.environKeys)
   600  
   601  	// Ensure the fs is not shared
   602  	require.Nil(t, cloned.fsConfig)
   603  }
   604  
   605  func Test_compiledModule_Name(t *testing.T) {
   606  	tests := []struct {
   607  		name     string
   608  		input    *compiledModule
   609  		expected string
   610  	}{
   611  		{
   612  			name:  "no name section",
   613  			input: &compiledModule{module: &wasm.Module{}},
   614  		},
   615  		{
   616  			name:  "empty name",
   617  			input: &compiledModule{module: &wasm.Module{NameSection: &wasm.NameSection{}}},
   618  		},
   619  		{
   620  			name:     "name",
   621  			input:    &compiledModule{module: &wasm.Module{NameSection: &wasm.NameSection{ModuleName: "foo"}}},
   622  			expected: "foo",
   623  		},
   624  	}
   625  
   626  	for _, tt := range tests {
   627  		tc := tt
   628  
   629  		t.Run(tc.name, func(t *testing.T) {
   630  			require.Equal(t, tc.expected, tc.input.Name())
   631  		})
   632  	}
   633  }
   634  
   635  func Test_compiledModule_CustomSections(t *testing.T) {
   636  	tests := []struct {
   637  		name     string
   638  		input    *compiledModule
   639  		expected []string
   640  	}{
   641  		{
   642  			name:     "no custom section",
   643  			input:    &compiledModule{module: &wasm.Module{}},
   644  			expected: []string{},
   645  		},
   646  		{
   647  			name: "name",
   648  			input: &compiledModule{module: &wasm.Module{
   649  				CustomSections: []*wasm.CustomSection{
   650  					{Name: "custom1"},
   651  					{Name: "custom2"},
   652  					{Name: "customDup"},
   653  					{Name: "customDup"},
   654  				},
   655  			}},
   656  			expected: []string{
   657  				"custom1",
   658  				"custom2",
   659  				"customDup",
   660  				"customDup",
   661  			},
   662  		},
   663  	}
   664  
   665  	for _, tt := range tests {
   666  		tc := tt
   667  
   668  		t.Run(tc.name, func(t *testing.T) {
   669  			customSections := tc.input.CustomSections()
   670  			require.Equal(t, len(tc.expected), len(customSections))
   671  			for i := 0; i < len(tc.expected); i++ {
   672  				require.Equal(t, tc.expected[i], customSections[i].Name())
   673  			}
   674  		})
   675  	}
   676  }
   677  
   678  func Test_compiledModule_Close(t *testing.T) {
   679  	for _, ctx := range []context.Context{nil, testCtx} { // Ensure it doesn't crash on nil!
   680  		e := &mockEngine{name: "1", cachedModules: map[*wasm.Module]struct{}{}}
   681  
   682  		var cs []*compiledModule
   683  		for i := 0; i < 10; i++ {
   684  			m := &wasm.Module{}
   685  			err := e.CompileModule(ctx, m, nil, false)
   686  			require.NoError(t, err)
   687  			cs = append(cs, &compiledModule{module: m, compiledEngine: e})
   688  		}
   689  
   690  		// Before Close.
   691  		require.Equal(t, 10, len(e.cachedModules))
   692  
   693  		for _, c := range cs {
   694  			require.NoError(t, c.Close(ctx))
   695  		}
   696  
   697  		// After Close.
   698  		require.Zero(t, len(e.cachedModules))
   699  	}
   700  }
   701  
   702  func TestNewRuntimeConfig(t *testing.T) {
   703  	c, ok := NewRuntimeConfig().(*runtimeConfig)
   704  	require.True(t, ok)
   705  	// Should be cloned from the source.
   706  	require.NotEqual(t, engineLessConfig, c)
   707  	// Ensures if the correct engine is selected.
   708  	if platform.CompilerSupported() {
   709  		require.Equal(t, engineKindCompiler, c.engineKind)
   710  	} else {
   711  		require.Equal(t, engineKindInterpreter, c.engineKind)
   712  	}
   713  }