cuelang.org/go@v0.13.0/cue/interpreter/wasm/exe_test.go (about)

     1  // Copyright 2023 CUE Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // TestExe expects cmd/cue to be configured with wasm support,
    16  // which it only is with the cuewasm build tag enabled.
    17  
    18  //go:build cuewasm
    19  
    20  package wasm_test
    21  
    22  import (
    23  	"io/fs"
    24  	"os"
    25  	"path/filepath"
    26  	stdruntime "runtime"
    27  	"strings"
    28  	"testing"
    29  
    30  	"cuelang.org/go/cmd/cue/cmd"
    31  	"cuelang.org/go/cue"
    32  	"cuelang.org/go/cue/ast"
    33  	"cuelang.org/go/cue/build"
    34  	"cuelang.org/go/cue/cuecontext"
    35  	"cuelang.org/go/cue/interpreter/wasm"
    36  	"cuelang.org/go/cue/parser"
    37  	"cuelang.org/go/internal"
    38  	"cuelang.org/go/internal/core/runtime"
    39  	"cuelang.org/go/internal/cuetest"
    40  
    41  	"github.com/rogpeppe/go-internal/gotooltest"
    42  	"github.com/rogpeppe/go-internal/testscript"
    43  )
    44  
    45  // We are using TestMain because we want to ensure Wasm is enabled and
    46  // works as expected with the command-line tool.
    47  func TestMain(m *testing.M) {
    48  	testscript.Main(m, map[string]func(){
    49  		"cue": func() { os.Exit(cmd.Main()) },
    50  	})
    51  }
    52  
    53  // TestExe tests Wasm using the command-line tool.
    54  func TestExe(t *testing.T) {
    55  	if version, _ := (*runtime.Runtime)(cuecontext.New()).Settings(); version == internal.EvalV3 {
    56  		t.Skip("TODO: fix these tests on evalv3")
    57  	}
    58  	root := must(filepath.Abs("testdata"))(t)
    59  	wasmFiles := filepath.Join(root, "cue")
    60  	p := testscript.Params{
    61  		Dir:                 "testdata/cue",
    62  		UpdateScripts:       cuetest.UpdateGoldenFiles,
    63  		RequireExplicitExec: true,
    64  		RequireUniqueNames:  true,
    65  		Setup: func(e *testscript.Env) error {
    66  			copyWasmFiles(t, e.WorkDir, wasmFiles)
    67  			e.Vars = append(e.Vars, "CUE_CACHE_DIR="+filepath.Join(e.WorkDir, ".tmp/cache"))
    68  			return nil
    69  		},
    70  		Condition: cuetest.Condition,
    71  	}
    72  	if err := gotooltest.Setup(&p); err != nil {
    73  		t.Fatal(err)
    74  	}
    75  	testscript.Run(t, p)
    76  }
    77  
    78  func copyWasmFiles(t *testing.T, dstDir, srcDir string) {
    79  	filepath.WalkDir(dstDir, func(path string, d fs.DirEntry, err error) error {
    80  		if filepath.Ext(path) != ".wasm" {
    81  			return nil
    82  		}
    83  		relPath := must(filepath.Rel(dstDir, path))(t)
    84  		from := filepath.Join(srcDir, relPath)
    85  		copyFile(t, path, from)
    86  		return nil
    87  	})
    88  }
    89  
    90  func copyFile(t *testing.T, dst, src string) {
    91  	buf := must(os.ReadFile(src))(t)
    92  	err := os.WriteFile(dst, buf, 0664)
    93  	if err != nil {
    94  		t.Fatal(err)
    95  	}
    96  }
    97  
    98  func check(t *testing.T, dir string, got string) {
    99  	golden := filepath.Join("testdata", dir) + ".golden"
   100  
   101  	if cuetest.UpdateGoldenFiles {
   102  		os.WriteFile(golden, []byte(got), 0666)
   103  	}
   104  
   105  	want := string(must(os.ReadFile(golden))(t))
   106  	if got != want {
   107  		t.Errorf("want %v, got %v", want, got)
   108  	}
   109  }
   110  
   111  func loadDir(t *testing.T, name string) cue.Value {
   112  	ctx := cuecontext.New(cuecontext.Interpreter(wasm.New()))
   113  	bi := dirInstance(t, name)
   114  	return ctx.BuildInstance(bi)
   115  }
   116  
   117  func dirInstance(t *testing.T, name string) *build.Instance {
   118  	ctx := build.NewContext(build.ParseFile(loadFile))
   119  	inst := ctx.NewInstance(name, nil)
   120  
   121  	files := must(os.ReadDir(name))(t)
   122  	for _, f := range files {
   123  		if strings.HasSuffix(f.Name(), "cue") {
   124  			inst.AddFile(filepath.Join(name, f.Name()), nil)
   125  		}
   126  		if strings.HasSuffix(f.Name(), "wasm") {
   127  			f := &build.File{
   128  				Filename: f.Name(),
   129  			}
   130  			inst.UnknownFiles = append(inst.UnknownFiles, f)
   131  		}
   132  	}
   133  	inst.Complete()
   134  	return inst
   135  }
   136  
   137  func loadFile(filename string, src any) (*ast.File, error) {
   138  	return parser.ParseFile(filename, src, parser.ParseFuncs)
   139  }
   140  
   141  func must[T any](v T, err error) func(t *testing.T) T {
   142  	fail := false
   143  	if err != nil {
   144  		fail = true
   145  	}
   146  	return func(t *testing.T) T {
   147  		if fail {
   148  			_, file, line, _ := stdruntime.Caller(1)
   149  			file = filepath.Base(file)
   150  			t.Fatalf("unexpected error at %v:%v: %v", file, line, err)
   151  		}
   152  		return v
   153  	}
   154  }