diff --git a/lang/func_test.go b/lang/func_test.go index a7a76ac..9cd3e9f 100644 --- a/lang/func_test.go +++ b/lang/func_test.go @@ -1,6 +1,8 @@ package lang_test import ( + "errors" + "strings" "testing" "github.com/matryer/is" @@ -8,6 +10,114 @@ import ( "github.com/princjef/gomarkdoc/logger" ) +func TestFunc_Level_standalone(t *testing.T) { + is := is.New(t) + + fn, err := loadFunc("../testData/lang/function", "Standalone") + is.NoErr(err) + + is.Equal(fn.Level(), 2) +} + +func TestFunc_Level_receiver(t *testing.T) { + is := is.New(t) + + fn, err := loadFunc("../testData/lang/function", "WithReceiver") + is.NoErr(err) + + is.Equal(fn.Level(), 3) +} + +func TestFunc_Level_initializer(t *testing.T) { + is := is.New(t) + + fn, err := loadFunc("../testData/lang/function", "New") + is.NoErr(err) + + is.Equal(fn.Level(), 3) +} + +func TestFunc_Name_standalone(t *testing.T) { + is := is.New(t) + + fn, err := loadFunc("../testData/lang/function", "Standalone") + is.NoErr(err) + + is.Equal(fn.Name(), "Standalone") +} + +func TestFunc_Name_receiver(t *testing.T) { + is := is.New(t) + + fn, err := loadFunc("../testData/lang/function", "WithReceiver") + is.NoErr(err) + + is.Equal(fn.Name(), "WithReceiver") +} + +func TestFunc_Receiver_standalone(t *testing.T) { + is := is.New(t) + + fn, err := loadFunc("../testData/lang/function", "Standalone") + is.NoErr(err) + + is.Equal(fn.Receiver(), "") +} + +func TestFunc_Receiver_receiver(t *testing.T) { + is := is.New(t) + + fn, err := loadFunc("../testData/lang/function", "WithReceiver") + is.NoErr(err) + + is.Equal(fn.Receiver(), "Receiver") +} + +func TestFunc_Doc(t *testing.T) { + is := is.New(t) + + fn, err := loadFunc("../testData/lang/function", "Standalone") + is.NoErr(err) + + doc := fn.Doc() + blocks := doc.Blocks() + is.Equal(len(blocks), 5) + + is.Equal(blocks[0].Kind(), lang.ParagraphBlock) + is.Equal(blocks[0].Level(), 3) + is.Equal(blocks[0].Text(), "Standalone provides a function that is not part of a type.") + + is.Equal(blocks[1].Kind(), lang.ParagraphBlock) + is.Equal(blocks[1].Level(), 3) + is.Equal(blocks[1].Text(), "Additional description can be provided in subsequent paragraphs, including code blocks and headers") + + is.Equal(blocks[2].Kind(), lang.HeaderBlock) + is.Equal(blocks[2].Level(), 3) + is.Equal(blocks[2].Text(), "Header A") + + is.Equal(blocks[3].Kind(), lang.ParagraphBlock) + is.Equal(blocks[3].Level(), 3) + is.Equal(blocks[3].Text(), "This section contains a code block.") + + is.Equal(blocks[4].Kind(), lang.CodeBlock) + is.Equal(blocks[4].Level(), 3) + is.Equal(blocks[4].Text(), "Code Block\nMore of Code Block\n") +} + +func TestFunc_Location(t *testing.T) { + is := is.New(t) + + fn, err := loadFunc("../testData/lang/function", "Standalone") + is.NoErr(err) + + loc := fn.Location() + is.Equal(loc.Start.Line, 14) + is.Equal(loc.Start.Col, 1) + is.Equal(loc.End.Line, 14) + is.Equal(loc.End.Col, 48) + is.True(strings.HasSuffix(loc.Filepath, "func.go")) +} + func TestFunc_stringsCompare(t *testing.T) { is := is.New(t) @@ -109,3 +219,38 @@ func TestFunc_ioIoutilTempFile(t *testing.T) { is.Equal(sig, "func TempFile(dir, pattern string) (f *os.File, err error)") is.Equal(len(fn.Examples()), 2) } + +func loadFunc(dir, name string) (*lang.Func, error) { + buildPkg, err := getBuildPackage(dir) + if err != nil { + return nil, err + } + + log := logger.New(logger.ErrorLevel) + pkg, err := lang.NewPackageFromBuild(log, buildPkg) + if err != nil { + return nil, err + } + + for _, f := range pkg.Funcs() { + if f.Name() == name { + return f, nil + } + } + + for _, t := range pkg.Types() { + for _, f := range t.Funcs() { + if f.Name() == name { + return f, nil + } + } + + for _, f := range t.Methods() { + if f.Name() == name { + return f, nil + } + } + } + + return nil, errors.New("func not found") +} diff --git a/lang/package_test.go b/lang/package_test.go index a9b0951..c9d922e 100644 --- a/lang/package_test.go +++ b/lang/package_test.go @@ -12,6 +12,53 @@ import ( "github.com/princjef/gomarkdoc/logger" ) +func TestPackage_Consts(t *testing.T) { + is := is.New(t) + + pkg, err := loadPackage("../testData/lang/function") + is.NoErr(err) + + consts := pkg.Consts() + is.Equal(len(consts), 1) + + decl, err := consts[0].Decl() + is.NoErr(err) + is.Equal(decl, `const ( + ConstA = "string" + ConstB = true +)`) +} + +func TestPackage_Vars(t *testing.T) { + is := is.New(t) + + pkg, err := loadPackage("../testData/lang/function") + is.NoErr(err) + + vars := pkg.Vars() + is.Equal(len(vars), 1) + + decl, err := vars[0].Decl() + is.NoErr(err) + is.Equal(decl, `var Variable = 5`) +} + +func TestPackage_dotImport(t *testing.T) { + is := is.New(t) + + err := os.Chdir("../testData/lang/function") + is.NoErr(err) + + defer func() { + _ = os.Chdir("../../../lang") + }() + + pkg, err := loadPackage(".") + is.NoErr(err) + + is.Equal(pkg.Import(), `import "github.com/princjef/gomarkdoc/testData/lang/function"`) +} + func TestPackage_strings(t *testing.T) { is := is.New(t) @@ -112,3 +159,18 @@ func getBuildPackage(path string) (*build.Package, error) { return build.Import(path, wd, build.ImportComment) } + +func loadPackage(dir string) (*lang.Package, error) { + buildPkg, err := getBuildPackage(dir) + if err != nil { + return nil, err + } + + log := logger.New(logger.ErrorLevel) + pkg, err := lang.NewPackageFromBuild(log, buildPkg) + if err != nil { + return nil, err + } + + return pkg, nil +} diff --git a/lang/type_test.go b/lang/type_test.go index 73efc7e..8a8b193 100644 --- a/lang/type_test.go +++ b/lang/type_test.go @@ -1,6 +1,7 @@ package lang_test import ( + "errors" "testing" "github.com/matryer/is" @@ -8,6 +9,19 @@ import ( "github.com/princjef/gomarkdoc/logger" ) +func TestType_Examples(t *testing.T) { + is := is.New(t) + + typ, err := loadType("../testData/lang/function", "Receiver") + is.NoErr(err) + + ex := typ.Examples() + is.Equal(len(ex), 2) + + is.Equal(ex[0].Name(), "") + is.Equal(ex[1].Name(), "Sub Test") +} + func TestFunc_netHttpResponseWriter(t *testing.T) { is := is.New(t) @@ -220,3 +234,24 @@ func TestFunc_netHttpResponse(t *testing.T) { is.True(len(typ.Funcs()) > 0) is.True(len(typ.Methods()) > 0) } + +func loadType(dir, name string) (*lang.Type, error) { + buildPkg, err := getBuildPackage(dir) + if err != nil { + return nil, err + } + + log := logger.New(logger.ErrorLevel) + pkg, err := lang.NewPackageFromBuild(log, buildPkg) + if err != nil { + return nil, err + } + + for _, t := range pkg.Types() { + if t.Name() == name { + return t, nil + } + } + + return nil, errors.New("type not found") +} diff --git a/lang/value_test.go b/lang/value_test.go new file mode 100644 index 0000000..d6c9bd7 --- /dev/null +++ b/lang/value_test.go @@ -0,0 +1,98 @@ +package lang_test + +import ( + "errors" + "strings" + "testing" + + "github.com/matryer/is" + "github.com/princjef/gomarkdoc/lang" + "github.com/princjef/gomarkdoc/logger" +) + +func TestValue_Level(t *testing.T) { + is := is.New(t) + + val, err := loadValue("../testData/lang/function", "Variable") + is.NoErr(err) + + is.Equal(val.Level(), 2) +} + +func TestValue_Summary(t *testing.T) { + is := is.New(t) + + val, err := loadValue("../testData/lang/function", "Variable") + is.NoErr(err) + + is.Equal(val.Summary(), "Variable is a package-level variable.") +} + +func TestValue_Doc(t *testing.T) { + is := is.New(t) + + val, err := loadValue("../testData/lang/function", "Variable") + is.NoErr(err) + + doc := val.Doc() + is.Equal(doc.Level(), 3) + is.Equal(len(doc.Blocks()), 1) + is.Equal(doc.Blocks()[0].Kind(), lang.ParagraphBlock) + is.Equal(doc.Blocks()[0].Level(), 3) + is.Equal(doc.Blocks()[0].Text(), "Variable is a package-level variable.") +} + +func TestValue_Decl(t *testing.T) { + is := is.New(t) + + val, err := loadValue("../testData/lang/function", "Variable") + is.NoErr(err) + + decl, err := val.Decl() + is.NoErr(err) + + is.Equal(decl, "var Variable = 5") +} + +func TestValue_Location(t *testing.T) { + is := is.New(t) + + val, err := loadValue("../testData/lang/function", "Variable") + is.NoErr(err) + + loc := val.Location() + is.Equal(loc.Start.Line, 4) + is.Equal(loc.Start.Col, 1) + is.Equal(loc.End.Line, 4) + is.Equal(loc.End.Col, 17) + is.True(strings.HasSuffix(loc.Filepath, "value.go")) +} + +func loadValue(dir, name string) (*lang.Value, error) { + buildPkg, err := getBuildPackage(dir) + if err != nil { + return nil, err + } + + log := logger.New(logger.ErrorLevel) + pkg, err := lang.NewPackageFromBuild(log, buildPkg) + if err != nil { + return nil, err + } + + for _, v := range pkg.Vars() { + d, err := v.Decl() + if err == nil && strings.Contains(d, name) { + return v, nil + } + } + + for _, v := range pkg.Consts() { + d, err := v.Decl() + if err == nil && strings.Contains(d, name) { + return v, nil + } + } + + return nil, errors.New("value not found") +} diff --git a/testData/lang/function/func.go b/testData/lang/function/func.go new file mode 100644 index 0000000..f5d18fd --- /dev/null +++ b/testData/lang/function/func.go @@ -0,0 +1,30 @@ +package function + +// Standalone provides a function that is not part of a type. +// +// Additional description can be provided in subsequent paragraphs, including +// code blocks and headers +// +// Header A +// +// This section contains a code block. +// +// Code Block +// More of Code Block +func Standalone(p1 int, p2 string) (int, error) { + return p1, nil +} + +// Receiver is a type used to demonstrate functions with receivers. +type Receiver struct{} + +// New is an initializer for Receiver. +func New() Receiver { + return Receiver{} +} + +// WithReceiver has a receiver. +func (r Receiver) WithReceiver() {} + +// WithPtrReceiver has a pointer receiver. +func (r *Receiver) WithPtrReceiver() {} diff --git a/testData/lang/function/func_test.go b/testData/lang/function/func_test.go new file mode 100644 index 0000000..9bcdc5d --- /dev/null +++ b/testData/lang/function/func_test.go @@ -0,0 +1,29 @@ +package function_test + +import ( + "fmt" + + "github.com/princjef/gomarkdoc/testData/lang/function" +) + +func ExampleStandalone() { + res, _ := function.Standalone(2, "abc") + fmt.Println(res) + // Output: 2 +} + +func ExampleStandalone_zero() { + res, _ := function.Standalone(0, "def") + fmt.Println(res) + // Output: 0 +} + +func ExampleReceiver() { + r := &function.Receiver{} + fmt.Println(r) +} + +func ExampleReceiver_subTest() { + var r function.Receiver + r.WithReceiver() +} diff --git a/testData/lang/function/value.go b/testData/lang/function/value.go new file mode 100644 index 0000000..96af9e6 --- /dev/null +++ b/testData/lang/function/value.go @@ -0,0 +1,10 @@ +package function + +// Variable is a package-level variable. +var Variable = 5 + +// Set of constants for this package. +const ( + ConstA = "string" + ConstB = true +)