Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions cl/_testmockc/function/in.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
unsigned f(int a);

void g();

signed int xprintf(const char* fmt, ...);
2 changes: 1 addition & 1 deletion cl/blockctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
63 changes: 63 additions & 0 deletions cl/cltest/cltest.go
Original file line number Diff line number Diff line change
@@ -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) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P3] TestFromDir sel filter runs inside t.Run, emitting empty subtests

The sel != "" && !strings.Contains(pkgDir, sel) check is inside the t.Run(name, ...) closure, so every non-matching directory still spawns an (empty, passing) subtest and returns early rather than being skipped. The doc says "only subdirectories whose path contains sel will be tested," which reads as full exclusion. Behavior is unchanged from the original, but now that this is a shared exported helper, consider filtering before t.Run or using t.Skip to avoid noise-level subtests.

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
}

// -----------------------------------------------------------------------------
9 changes: 6 additions & 3 deletions cl/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}

// -----------------------------------------------------------------------------
Expand Down Expand Up @@ -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)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Config.NameLookup is declared but never consumed

The new NameLookup field is added to Config and documented as "looks up the archive path for a given mangling name," but nothing invokes it — loadFile discards the config via _ = conf and NewPackage only reads Reused/Importer/Fset. As a public field this can mislead consumers of the cl package into thinking it takes effect. Acceptable as scaffolding if the consumer lands in a follow-up; otherwise consider marking the doc as "reserved / not yet effective," and decide whether nil is permitted (and validated up front) when the callback is eventually wired in.

}

// -----------------------------------------------------------------------------

// Source represents a C/C++ header to compile.
type Source struct {
clang.TranslationUnit
TU clang.TranslationUnit
PresumedFile *c.Char
}

Expand Down Expand Up @@ -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
})
Expand Down
71 changes: 44 additions & 27 deletions cl/compile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Only test of new path (_TestMockC) is disabled

_TestMockC is underscore-prefixed, so go test never runs it. It is the sole test exercising the new cl.Source{TU:} construction, Config.NameLookup, and cltest.TestFromDir. Combined with toType/goNodePos still being panic("todo"), none of the renamed/added code has enforced CI coverage. Fine as scaffolding, but consider a tracking note or enabling a minimal test once the stub panics are implemented so the refactor doesn't silently regress.

testFromDir(t, "", "./_testmockc")
}

// -----------------------------------------------------------------------------
2 changes: 1 addition & 1 deletion cl/type_and_var.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const (
)

func toType(ctx *blockCtx, typ lc.Type, flags int) types.Type {
panic("todo")
panic("todo: toType")
}

// -----------------------------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Loading