416 lines
10 KiB
Go
416 lines
10 KiB
Go
package generate
|
|
|
|
import (
|
|
"bytes"
|
|
"code.squareroundforest.org/arpio/notation"
|
|
"fmt"
|
|
"os"
|
|
"path"
|
|
"runtime"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func check(c ...string) map[string]string {
|
|
m := make(map[string]string)
|
|
for i := 0; i < len(c); i += 2 {
|
|
name := c[i]
|
|
|
|
var value string
|
|
if i < len(c)-1 {
|
|
value = c[i+1]
|
|
}
|
|
|
|
m[name] = value
|
|
}
|
|
|
|
return m
|
|
}
|
|
|
|
func testGenerate(check map[string]string, errstr string, o options, gopath ...string) func(t *testing.T) {
|
|
return func(t *testing.T) {
|
|
d, err := generate(o, gopath...)
|
|
if errstr != "" {
|
|
if err == nil {
|
|
t.Fatal("failed to fail")
|
|
}
|
|
|
|
if !strings.Contains(err.Error(), errstr) {
|
|
t.Fatal("unexpected error", err)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var failed bool
|
|
for name, expect := range check {
|
|
dn, ok := d[name]
|
|
if !ok {
|
|
failed = true
|
|
break
|
|
}
|
|
|
|
if !strings.Contains(dn, expect) {
|
|
failed = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if failed {
|
|
t.Log("failed to get the right documentation")
|
|
t.Log("expected matches:")
|
|
t.Log(notation.Sprintw(check))
|
|
t.Log("documetation got:")
|
|
t.Log(notation.Sprintw(d))
|
|
t.Fatal()
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGenerate(t *testing.T) {
|
|
wd := path.Clean(path.Join(os.Getenv("PWD"), ".."))
|
|
h := os.Getenv("HOME")
|
|
o := options{
|
|
wd: wd,
|
|
goroot: runtime.GOROOT(),
|
|
gomod: "code.squareroundforest.org/arpio/docreflect",
|
|
modules: map[string]string{
|
|
"golang.org/x/mod@v0.27.0": path.Join(h, "go", "pkg/mod", "golang.org/x/mod@v0.27.0"),
|
|
"code.squareroundforest.org/arpio/notation@v0.0.0-20241225183158-af3bd591a174": path.Join(
|
|
h, "go", "pkg/mod", "code.squareroundforest.org/arpio/notation@v0.0.0-20241225183158-af3bd591a174",
|
|
),
|
|
"code.squareroundforest.org/arpio/docreflect": wd,
|
|
},
|
|
}
|
|
|
|
t.Run("generate", func(t *testing.T) {
|
|
t.Run(
|
|
"stdlib",
|
|
testGenerate(check("strings.Join", "Join concatenates", "strings.Join", "func(elems, sep)"), "", o, "strings.Join"),
|
|
)
|
|
|
|
notationPrintln := "code.squareroundforest.org/arpio/notation.Println"
|
|
t.Run(
|
|
"imported module",
|
|
testGenerate(
|
|
check(
|
|
notationPrintln,
|
|
"Println prints",
|
|
notationPrintln,
|
|
"func(v)",
|
|
),
|
|
"",
|
|
o,
|
|
notationPrintln,
|
|
),
|
|
)
|
|
|
|
localDocs := "code.squareroundforest.org/arpio/docreflect.Docs"
|
|
t.Run(
|
|
"local",
|
|
testGenerate(check(localDocs, "Docs returns the documentation for"), "", o, localDocs),
|
|
)
|
|
|
|
packagePath := "code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage"
|
|
t.Run(
|
|
"package",
|
|
testGenerate(
|
|
check(
|
|
packagePath, "Package testpackage is a test package",
|
|
fmt.Sprintf("%s.ExportedType", packagePath), "ExportedType has docs",
|
|
fmt.Sprintf("%s.ExportedType.Bar.Baz", packagePath), "Baz is another field",
|
|
),
|
|
"",
|
|
o,
|
|
packagePath,
|
|
),
|
|
)
|
|
|
|
t.Run("symbol", func(t *testing.T) {
|
|
t.Run("type", testGenerate(
|
|
check(
|
|
"code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.ExportedType",
|
|
"ExportedType has docs",
|
|
"code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.ExportedType2",
|
|
"",
|
|
),
|
|
"",
|
|
o,
|
|
"code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.ExportedType",
|
|
"code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.ExportedType2",
|
|
))
|
|
|
|
t.Run("const", testGenerate(
|
|
check(
|
|
"code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.C1",
|
|
"C1 is a const",
|
|
),
|
|
"",
|
|
o,
|
|
"code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.C1",
|
|
))
|
|
|
|
t.Run("const grouped", testGenerate(
|
|
check(
|
|
"code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.C3",
|
|
"Cx is a const",
|
|
),
|
|
"",
|
|
o,
|
|
"code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.C3",
|
|
))
|
|
|
|
t.Run("var", testGenerate(
|
|
check(
|
|
"code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.V1",
|
|
"V1 is a var",
|
|
),
|
|
"",
|
|
o,
|
|
"code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.V1",
|
|
))
|
|
|
|
t.Run("var grouped", testGenerate(
|
|
check(
|
|
"code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.V3",
|
|
"Vx is a var",
|
|
),
|
|
"",
|
|
o,
|
|
"code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.V3",
|
|
))
|
|
|
|
t.Run("func", testGenerate(
|
|
check(
|
|
"code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.ExportedFunc",
|
|
"ExportedFunc has documentation",
|
|
"code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.New",
|
|
"New create a new instance of ExportedType",
|
|
),
|
|
"",
|
|
o,
|
|
"code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.New",
|
|
"code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.ExportedFunc",
|
|
))
|
|
})
|
|
|
|
t.Run("field", testGenerate(
|
|
check(
|
|
"code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.ExportedType.Foo",
|
|
"Foo is a field",
|
|
),
|
|
"",
|
|
o,
|
|
"code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.ExportedType.Foo",
|
|
))
|
|
|
|
t.Run("method", testGenerate(
|
|
check(
|
|
"code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.ExportedType.Method",
|
|
"Method is a method of ExportedType",
|
|
),
|
|
"",
|
|
o,
|
|
"code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.ExportedType.Method",
|
|
))
|
|
|
|
t.Run("inline struct type expression", testGenerate(
|
|
check(
|
|
"code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.ExportedType.Bar",
|
|
"Bar is an inline struct type expression",
|
|
"code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.ExportedType.Bar.Baz",
|
|
"Baz is another field",
|
|
),
|
|
"",
|
|
o,
|
|
"code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.ExportedType.Bar",
|
|
"code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.ExportedType.Bar.Baz",
|
|
))
|
|
|
|
t.Run("unexported symbol", testGenerate(
|
|
check(
|
|
"code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.unexportedFunc",
|
|
"unexportedFunc can have documentation",
|
|
),
|
|
"",
|
|
o,
|
|
"code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.unexportedFunc",
|
|
))
|
|
|
|
mainFunc := "code.squareroundforest.org/arpio/docreflect/internal/tests/src/command.main"
|
|
t.Run("main package", testGenerate(check(mainFunc, "main func"), "", o, mainFunc))
|
|
|
|
anum := fmt.Sprintf("%s.A", packagePath)
|
|
bnum := fmt.Sprintf("%s.B", packagePath)
|
|
cnum := fmt.Sprintf("%s.C", packagePath)
|
|
t.Run(
|
|
"grouped types",
|
|
testGenerate(
|
|
check(anum, "A is a number", bnum, "B is another number", cnum, "C is a third number"),
|
|
"",
|
|
o,
|
|
packagePath,
|
|
),
|
|
)
|
|
|
|
t.Run(
|
|
"grouped types as symbol",
|
|
testGenerate(check(anum, "A is a number"), "", o, anum),
|
|
)
|
|
|
|
pfoo := fmt.Sprintf("%s.ExportedType.PFoo", packagePath)
|
|
barPBaz := fmt.Sprintf("%s.ExportedType.Bar.PBaz", packagePath)
|
|
t.Run(
|
|
"pointer field",
|
|
testGenerate(
|
|
check(pfoo, "PFoo is a pointer field", barPBaz, "PBaz is another pointer field"),
|
|
"",
|
|
o,
|
|
packagePath,
|
|
),
|
|
)
|
|
|
|
t.Run(
|
|
"pointer field as symbol",
|
|
testGenerate(
|
|
check(pfoo, "PFoo is a pointer field", barPBaz, "PBaz is another pointer field"),
|
|
"",
|
|
o,
|
|
pfoo,
|
|
barPBaz,
|
|
),
|
|
)
|
|
|
|
quxQuux := fmt.Sprintf("%s.ExportedType.Qux.Quux", packagePath)
|
|
t.Run(
|
|
"anonymous pointer struct field",
|
|
testGenerate(
|
|
check(quxQuux, "Quux is a number"),
|
|
"",
|
|
o,
|
|
packagePath,
|
|
),
|
|
)
|
|
|
|
t.Run(
|
|
"anonymous pointer struct field as symbol",
|
|
testGenerate(
|
|
check(quxQuux, "Quux is a number"),
|
|
"",
|
|
o,
|
|
quxQuux,
|
|
),
|
|
)
|
|
})
|
|
|
|
t.Run("errors", func(t *testing.T) {
|
|
t.Run("package not found", testGenerate(nil, "package", o, "foo.bar.baz/qux"))
|
|
t.Run(
|
|
"symbol not found",
|
|
testGenerate(nil, "symbol", o, "code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.Qux"),
|
|
)
|
|
|
|
t.Run(
|
|
"field not found",
|
|
testGenerate(
|
|
nil,
|
|
"symbol",
|
|
o,
|
|
"code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.ExportedType.Corge",
|
|
),
|
|
)
|
|
|
|
t.Run(
|
|
"field not found, second level",
|
|
testGenerate(
|
|
nil,
|
|
"symbol",
|
|
o,
|
|
"code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.ExportedType.Foo.Qux",
|
|
),
|
|
)
|
|
|
|
t.Run(
|
|
"method not found",
|
|
testGenerate(nil, "symbol", o, "code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.ExportedType2.Qux"),
|
|
)
|
|
|
|
t.Run(
|
|
"invalid path",
|
|
testGenerate(nil, "foo", o, "./foo/bar"),
|
|
)
|
|
|
|
t.Run(
|
|
"non-existent module path",
|
|
testGenerate(nil, "package", o, "code.squareroundforest.org/arpio/notation/foo.Foo"),
|
|
)
|
|
|
|
t.Run(
|
|
"parse failed, syntax error",
|
|
testGenerate(nil, "package", o, "code.squareroundforest.org/arpio/docreflect/internal/tests/src/syntaxerror"),
|
|
)
|
|
|
|
t.Run(
|
|
"no type spec",
|
|
testGenerate(nil, "symbol", o, "code.squareroundforest.org/arpio/docreflect/internal/tests/src/testpackage.Foo.Qux"),
|
|
)
|
|
})
|
|
|
|
t.Run("init options", func(t *testing.T) {
|
|
o := initOptions()
|
|
if o.wd != os.Getenv("PWD") {
|
|
t.Fatal("wd")
|
|
}
|
|
|
|
if o.goroot != runtime.GOROOT() {
|
|
t.Fatal("goroot")
|
|
}
|
|
|
|
if o.gomod != "code.squareroundforest.org/arpio/docreflect" {
|
|
t.Fatal("gomod")
|
|
}
|
|
|
|
for _, module := range []string{
|
|
"code.squareroundforest.org/arpio/notation",
|
|
"golang.org/x/mod",
|
|
} {
|
|
var found bool
|
|
for key := range o.modules {
|
|
if strings.Contains(key, module) {
|
|
found = true
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
t.Fatal("gomod")
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestFormat(t *testing.T) {
|
|
b := bytes.NewBuffer(nil)
|
|
d := map[string]string{
|
|
"foo": "bar",
|
|
"baz": "qux",
|
|
}
|
|
|
|
if err := format(b, "testpackage", d); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
o := b.String()
|
|
if o != `package testpackage
|
|
import "code.squareroundforest.org/arpio/docreflect"
|
|
func init() {
|
|
docreflect.Register("baz", "qux")
|
|
docreflect.Register("foo", "bar")
|
|
}` {
|
|
t.Fatal()
|
|
}
|
|
}
|