diff --git a/cl/_testmockc/function/in.h b/cl/_testmockc/function/in.h new file mode 100644 index 00000000..98a8f3dd --- /dev/null +++ b/cl/_testmockc/function/in.h @@ -0,0 +1,5 @@ +unsigned f(int a); + +void g(); + +signed int xprintf(const char* fmt, ...); diff --git a/cl/blockctx.go b/cl/blockctx.go index 023e5ce0..147e7197 100644 --- a/cl/blockctx.go +++ b/cl/blockctx.go @@ -49,7 +49,7 @@ func (ctx *blockCtx) goNodePos(v clang.Cursor) token.Pos { return token.Pos(int(rg.Begin.Offset) + base) } return token.NoPos */ - panic("todo") + panic("todo: goNodePos") } func (p *blockCtx) getPubName(pfnName *string) (rewritten bool) { diff --git a/cl/cltest/cltest.go b/cl/cltest/cltest.go new file mode 100644 index 00000000..e2c8fa64 --- /dev/null +++ b/cl/cltest/cltest.go @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2026 The XGo Authors (xgo.dev). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cltest + +import ( + "os" + "path" + "strings" + "testing" +) + +// ----------------------------------------------------------------------------- + +// TestFromDir runs testFunc for each subdirectory of relDir. If sel is not empty, only subdirectories +// whose path contains sel will be tested. +func TestFromDir(t *testing.T, sel, relDir string, testFunc func(t *testing.T, pkgDir string)) { + dir, err := os.Getwd() + if err != nil { + t.Fatal("Getwd failed:", err) + } + dir = path.Join(dir, relDir) + fis, err := os.ReadDir(dir) + if err != nil { + t.Fatal("ReadDir failed:", err) + } + for _, fi := range fis { + name := fi.Name() + if strings.HasPrefix(name, "_") { + continue + } + t.Run(name, func(t *testing.T) { + pkgDir := dir + "/" + name + if sel != "" && !strings.Contains(pkgDir, sel) { + return + } + testFunc(t, pkgDir) + }) + } +} + +// ----------------------------------------------------------------------------- + +// MockNameLookup is a mock implementation of the NameLookup function. It returns a fixed archive +// path and true for any input. +func MockNameLookup(manglingName string) (archivePath string, ok bool) { + return "libfoo.a", true +} + +// ----------------------------------------------------------------------------- diff --git a/cl/compile.go b/cl/compile.go index 4ac5d846..f0baef1c 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -56,7 +56,7 @@ func (p *nodeInterp) Position(start token.Pos) token.Position { } func (p *nodeInterp) LoadExpr(v ast.Node) string { - panic("todo") + panic("todo: nodeInterp.LoadExpr") } // ----------------------------------------------------------------------------- @@ -91,13 +91,16 @@ type Config struct { // Reused specifies to reuse the Package instance between processing multiple C/C++ header files. *Reused + + // NameLookup looks up the archive path for a given mangling name. It returns the archive path and a boolean indicating whether the lookup was successful. + NameLookup func(manglingName string) (archivePath string, ok bool) } // ----------------------------------------------------------------------------- // Source represents a C/C++ header to compile. type Source struct { - clang.TranslationUnit + TU clang.TranslationUnit PresumedFile *c.Char } @@ -139,7 +142,7 @@ func loadFile(p *gogen.Package, conf *Config, file Source) (pi *PkgInfo, err err pkg: p, cb: p.CB(), fset: p.Fset, } _ = conf - clang.VisitChildren(file.Cursor(), func(decl, parent clang.Cursor) clang.ChildVisitResult { + clang.VisitChildren(file.TU.Cursor(), func(decl, parent clang.Cursor) clang.ChildVisitResult { compileDecl(ctx, decl) return clang.Continue }) diff --git a/cl/compile_test.go b/cl/compile_test.go index 6089f847..9ec44369 100644 --- a/cl/compile_test.go +++ b/cl/compile_test.go @@ -14,47 +14,64 @@ * limitations under the License. */ -package cl +package cl_test import ( + "bytes" "os" - "path" - "strings" "testing" + + "github.com/goplus/gogen" + "github.com/goplus/llcppg/cl" + "github.com/goplus/llcppg/cl/cltest" + "github.com/goplus/llcppg/clang" + "github.com/qiniu/x/test" ) // ----------------------------------------------------------------------------- -func DoTestFromDir(t *testing.T, sel, relDir string, testFunc func(t *testing.T, pkgDir string)) { - dir, err := os.Getwd() - if err != nil { - t.Fatal("Getwd failed:", err) +func testDiff(t *testing.T, dir string, outfname string, b *bytes.Buffer, exp any) { + if expected, ok := exp.(string); ok { + result := b.String() + if result != expected { + t.Errorf("\nResult:\n%s\nExpected:\n%s\n", result, expected) + } + } else if test.Diff(t, dir+outfname, b.Bytes(), exp.([]byte)) { + t.Error(dir, ": unexpect result") } - dir = path.Join(dir, relDir) - fis, err := os.ReadDir(dir) +} + +func testGenGo(t *testing.T, pkg *gogen.Package, dir string, exp any) { + var b bytes.Buffer + err := pkg.WriteTo(&b) if err != nil { - t.Fatal("ReadDir failed:", err) - } - for _, fi := range fis { - name := fi.Name() - if strings.HasPrefix(name, "_") { - continue - } - t.Run(name, func(t *testing.T) { - pkgDir := dir + "/" + name - if sel != "" && !strings.Contains(pkgDir, sel) { - return - } - testFunc(t, pkgDir) - }) + t.Fatal("gogen.WriteTo failed:", err) } + testDiff(t, dir, "/result.txt", &b, exp) } -// ----------------------------------------------------------------------------- -/* func testFromDir(t *testing.T, sel, relDir string) { - DoTestFromDir(t, sel, relDir, func(t *testing.T, pkgDir string) { + cltest.TestFromDir(t, sel, relDir, func(t *testing.T, pkgDir string) { + idx := clang.CreateIndex(0, 0) + defer idx.Dispose() + + u := idx.ParseTranslationUnit(0, pkgDir+"/in.h", "-x", "c") + defer u.Dispose() + + pkg, err := cl.NewPackage("", "foo", cl.Source{TU: u}, &cl.Config{ + NameLookup: cltest.MockNameLookup, + }) + if err != nil { + t.Error("cl.NewPackage:", err) + return + } + exp, _ := os.ReadFile(pkgDir + "/out.go") + testGenGo(t, pkg.Package, pkgDir, exp) }) } -*/ + +func _TestMockC(t *testing.T) { + testFromDir(t, "", "./_testmockc") +} + // ----------------------------------------------------------------------------- diff --git a/cl/type_and_var.go b/cl/type_and_var.go index 48bf8cd7..66aa249b 100644 --- a/cl/type_and_var.go +++ b/cl/type_and_var.go @@ -36,7 +36,7 @@ const ( ) func toType(ctx *blockCtx, typ lc.Type, flags int) types.Type { - panic("todo") + panic("todo: toType") } // ----------------------------------------------------------------------------- diff --git a/go.mod b/go.mod index 9556fc18..b31ab324 100644 --- a/go.mod +++ b/go.mod @@ -5,4 +5,5 @@ go 1.27.0 require ( github.com/goplus/gogen v1.23.5 github.com/goplus/lib v0.5.2 + github.com/qiniu/x v1.18.3 ) diff --git a/go.sum b/go.sum index bd55ec31..f5c46251 100644 --- a/go.sum +++ b/go.sum @@ -2,3 +2,5 @@ github.com/goplus/gogen v1.23.5 h1:76w3zmAHI+ECI7bPr0enUd0du9+t1IYyXmp43CbIpSs= github.com/goplus/gogen v1.23.5/go.mod h1:Y7ulYW3wonQ3d9er00b0uGFEV/IUZa6okWJZh892ACQ= github.com/goplus/lib v0.5.2 h1:BUd3mUwTajDRBHVxMfS/y/hDJ6n/Pxwf6z7ikrOXvkE= github.com/goplus/lib v0.5.2/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0= +github.com/qiniu/x v1.18.3 h1:trrBKBNszHGwV8XynnbddJr+A7Vca8/xlWP4F/Z4my8= +github.com/qiniu/x v1.18.3/go.mod h1:Sx3Wy+0GI9OsX4a53mYj6A0o7mHJ94PUvraqGYb4EIs=