github.com/goplus/llgo@v0.8.3/cl/cltest/cltest.go (about) 1 /* 2 * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package cltest 18 19 import ( 20 "archive/zip" 21 "go/ast" 22 "go/parser" 23 "go/token" 24 "go/types" 25 "io" 26 "log" 27 "os" 28 "path" 29 "strings" 30 "testing" 31 32 "github.com/goplus/gogen/packages" 33 "github.com/goplus/llgo/cl" 34 "github.com/goplus/llgo/internal/llgen" 35 "golang.org/x/tools/go/ssa" 36 "golang.org/x/tools/go/ssa/ssautil" 37 38 llssa "github.com/goplus/llgo/ssa" 39 ) 40 41 func init() { 42 cl.SetDebug(cl.DbgFlagAll) 43 llssa.Initialize(llssa.InitAll | llssa.InitNative) 44 llssa.SetDebug(llssa.DbgFlagAll) 45 } 46 47 func FromDir(t *testing.T, sel, relDir string, byLLGen bool) { 48 dir, err := os.Getwd() 49 if err != nil { 50 t.Fatal("Getwd failed:", err) 51 } 52 dir = path.Join(dir, relDir) 53 fis, err := os.ReadDir(dir) 54 if err != nil { 55 t.Fatal("ReadDir failed:", err) 56 } 57 for _, fi := range fis { 58 name := fi.Name() 59 if !fi.IsDir() || strings.HasPrefix(name, "_") { 60 continue 61 } 62 t.Run(name, func(t *testing.T) { 63 testFrom(t, dir+"/"+name, sel, byLLGen) 64 }) 65 } 66 } 67 68 // *.ll => *.lla 69 func decodeLinkFile(llFile string) (data []byte, err error) { 70 zipFile := llFile + "a" 71 zipf, err := zip.OpenReader(zipFile) 72 if err != nil { 73 return 74 } 75 defer zipf.Close() 76 f, err := zipf.Open("llgo_autogen.ll") 77 if err != nil { 78 return 79 } 80 defer f.Close() 81 data, err = io.ReadAll(f) 82 if err == nil { 83 os.WriteFile(llFile, data, 0644) 84 } 85 return 86 } 87 88 func Pkg(t *testing.T, pkgPath, outFile string) { 89 b, err := os.ReadFile(outFile) 90 if err != nil { 91 if !os.IsNotExist(err) { 92 t.Fatal("ReadFile failed:", err) 93 } 94 if b, err = decodeLinkFile(outFile); err != nil { 95 t.Fatal("decodeLinkFile failed:", err) 96 } 97 } 98 expected := string(b) 99 if v := llgen.GenFrom(pkgPath); v != expected { 100 t.Fatalf("\n==> got:\n%s\n==> expected:\n%s\n", v, expected) 101 } 102 } 103 104 func testFrom(t *testing.T, pkgDir, sel string, byLLGen bool) { 105 if sel != "" && !strings.Contains(pkgDir, sel) { 106 return 107 } 108 log.Println("Parsing", pkgDir) 109 in := pkgDir + "/in.go" 110 out := pkgDir + "/out.ll" 111 b, err := os.ReadFile(out) 112 if err != nil { 113 t.Fatal("ReadFile failed:", err) 114 } 115 expected := string(b) 116 if byLLGen { 117 if v := llgen.GenFrom(in); v != expected { 118 t.Fatalf("\n==> got:\n%s\n==> expected:\n%s\n", v, expected) 119 } 120 } else { 121 TestCompileEx(t, nil, in, expected) 122 } 123 } 124 125 func TestCompileEx(t *testing.T, src any, fname, expected string) { 126 t.Helper() 127 fset := token.NewFileSet() 128 f, err := parser.ParseFile(fset, fname, src, parser.ParseComments) 129 if err != nil { 130 t.Fatal("ParseFile failed:", err) 131 } 132 files := []*ast.File{f} 133 name := f.Name.Name 134 pkg := types.NewPackage(name, name) 135 imp := packages.NewImporter(fset) 136 foo, _, err := ssautil.BuildPackage( 137 &types.Config{Importer: imp}, fset, pkg, files, ssa.SanityCheckFunctions) 138 if err != nil { 139 t.Fatal("BuildPackage failed:", err) 140 } 141 foo.WriteTo(os.Stderr) 142 prog := llssa.NewProgram(nil) 143 prog.SetRuntime(func() *types.Package { 144 rt, err := imp.Import(llssa.PkgRuntime) 145 if err != nil { 146 t.Fatal("load runtime failed:", err) 147 } 148 return rt 149 }) 150 prog.SetPython(func() *types.Package { 151 rt, err := imp.Import(llssa.PkgPython) 152 if err != nil { 153 t.Fatal("load python failed:", err) 154 } 155 return rt 156 }) 157 158 ret, err := cl.NewPackage(prog, foo, files) 159 if err != nil { 160 t.Fatal("cl.NewPackage failed:", err) 161 } 162 163 if prog.NeedPyInit { // call PyInit if needed 164 ret.PyInit() 165 } 166 167 if v := ret.String(); v != expected { 168 t.Fatalf("\n==> got:\n%s\n==> expected:\n%s\n", v, expected) 169 } 170 }