Skip to content

Commit

Permalink
fixing lint errors and improve test coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
emilwareus committed Mar 11, 2024
1 parent ce8be37 commit 3f56794
Show file tree
Hide file tree
Showing 10 changed files with 265 additions and 28 deletions.
1 change: 1 addition & 0 deletions internal/callgraph/cgexec/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type Command struct {

func NewCommand(osCmd *exec.Cmd) *Command {
var stdoutBuf, stderrBuf bytes.Buffer

return &Command{osCmd, &stdoutBuf, &stderrBuf}
}

Expand Down
52 changes: 34 additions & 18 deletions internal/callgraph/finder/golangfinder/finder.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,36 +18,52 @@ func (f GolangFinder) FindRoots(files []string) ([]string, error) {

for _, file := range files {
if strings.HasSuffix(file, ".go") {
fset := token.NewFileSet()
node, err := parser.ParseFile(fset, file, nil, parser.ParseComments)
isMain, err := f.isMainFile(file)
if err != nil {
return nil, err
}

if node.Name.Name == "main" {
hasMainFunction := false
for _, decl := range node.Decls {
if funcDecl, ok := decl.(*ast.FuncDecl); ok {
if funcDecl.Name.Name == "main" && funcDecl.Recv == nil &&
funcDecl.Type.Params.List == nil {
hasMainFunction = true
break
}
}
}

if hasMainFunction {
mainFiles = append(mainFiles, file)
}
if isMain {
mainFiles = append(mainFiles, file)
}
}
}

return mainFiles, nil
}

func (f GolangFinder) isMainFile(file string) (bool, error) {
fset := token.NewFileSet()
node, err := parser.ParseFile(fset, file, nil, parser.ParseComments)
if err != nil {
return false, err
}

if node.Name.Name != "main" {
return false, nil
}

return f.hasMainFunction(node), nil
}

func (f GolangFinder) hasMainFunction(node *ast.File) bool {
for _, decl := range node.Decls {
if funcDecl, ok := decl.(*ast.FuncDecl); ok {
if f.isMainFunction(funcDecl) {
return true
}
}
}

return false
}

func (f GolangFinder) isMainFunction(funcDecl *ast.FuncDecl) bool {
return funcDecl.Name.Name == "main" && funcDecl.Recv == nil && funcDecl.Type.Params.List == nil
}

// Not needed for golang
func (f GolangFinder) FindDependencyDirs(files []string, findJars bool) ([]string, error) {
// Not needed for golang
return []string{}, nil
}

Expand Down
37 changes: 37 additions & 0 deletions internal/callgraph/finder/golangfinder/finder_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package golanfinder

import (
"os"
"testing"

"github.com/debricked/cli/internal/callgraph/finder"
Expand All @@ -19,6 +20,13 @@ func TestGolangFindEntrypoint(t *testing.T) {
assert.Equal(t, "testdata/app.go", files[0])
}

func TestGolangFindEntrypointNoMain(t *testing.T) {
f := GolangFinder{}
files, err := f.FindRoots([]string{"testdata/extrapackage/extra.go"})
assert.Nil(t, err)
assert.Empty(t, files)
}

func TestFindFiles(t *testing.T) {
f := GolangFinder{}
files, err := f.FindFiles([]string{"testdata"}, nil)
Expand All @@ -28,3 +36,32 @@ func TestFindFiles(t *testing.T) {
assert.Contains(t, files, "testdata/util.go")

}

func TestFindDependencyDirs(t *testing.T) {
f := GolangFinder{}
files, err := f.FindDependencyDirs([]string{"testdata/app.go", "testdata/util.go"}, false)
assert.Nil(t, err)
assert.Empty(t, files)
}

func TestFindFilesWithErrors(t *testing.T) {
finder := GolangFinder{}
_, err := finder.FindFiles([]string{"nonexistent"}, nil)
assert.Error(t, err)

tempDir, err := os.MkdirTemp("", "testdir")
assert.Nil(t, err)
defer os.RemoveAll(tempDir) // clean up
err = os.Chmod(tempDir, 0222) // remove read permissions
assert.Nil(t, err)
_, err = finder.FindFiles([]string{tempDir}, nil)
assert.Error(t, err)

}

func TestFindFilesExclusions(t *testing.T) {
finder := GolangFinder{}
files, err := finder.FindFiles([]string{"testdata"}, []string{"testdata"})
assert.Nil(t, err)
assert.Empty(t, files)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package extra
31 changes: 31 additions & 0 deletions internal/callgraph/finder/refiner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"os"
"path/filepath"
"reflect"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -132,3 +133,33 @@ func TestNoGCDPath(t *testing.T) {

assert.Equal(t, res, "")
}

func TestFilterFiles(t *testing.T) {
tests := []struct {
name string
files []string
pattern string
want []string
}{
{
name: "Test with matching pattern",
files: []string{"file1.txt", "file2.go", "file3.md"},
pattern: `.*\.go`,
want: []string{"file2.go"},
},
{
name: "Test with no matching pattern",
files: []string{"file1.txt", "file2.go", "file3.md"},
pattern: `.*\.js`,
want: []string{},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := FilterFiles(tt.files, tt.pattern); !reflect.DeepEqual(got, tt.want) {
t.Errorf("FilterFiles() = %v, want %v", got, tt.want)
}
})
}
}
9 changes: 8 additions & 1 deletion internal/callgraph/language/golang/callgraph.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ func NewCallgraph(
func cleanSymbol(symbol string) string {
symbol = strings.Replace(symbol, "(*", "", 1)
symbol = strings.Replace(symbol, ").", ".", 1)

return symbol
}

Expand Down Expand Up @@ -100,7 +101,7 @@ func (cg *Callgraph) constructCallGraph() error {

func (cg *Callgraph) createPackageConfig() (*packages.Config, []string) {
cfg := &packages.Config{
Mode: packages.LoadAllSyntax,
Mode: packages.NeedDeps | packages.NeedSyntax | packages.NeedTypesInfo | packages.NeedTypes | packages.NeedTypesSizes | packages.NeedImports | packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles,
Tests: cg.includeTests,
Dir: cg.workingDirectory,
}
Expand Down Expand Up @@ -157,13 +158,15 @@ func (cg *Callgraph) constructRTACallGraph(prog *ssa.Program, pkgs []*ssa.Packag
roots = append(roots, main.Func("init"), main.Func("main"))
}
rtares := rta.Analyze(roots, true)

return rtares.CallGraph, nil
}

func isLibraryNode(filename string, pwd string) bool {
if len(filename) > len(pwd) && filename[:len(pwd)] == pwd {
return false
}

return true
}

Expand Down Expand Up @@ -250,6 +253,7 @@ func setLineStartEndFile(nodes []*model.Node, filename string) error {
node.LineEnd = end
}
}

return true
})

Expand Down Expand Up @@ -289,6 +293,7 @@ func mainPackages(pkgs []*ssa.Package) ([]*ssa.Package, error) {
if len(mains) == 0 {
return nil, fmt.Errorf("no main packages")
}

return mains, nil
}

Expand All @@ -306,13 +311,15 @@ func (e *Edge) pos() *token.Position {
if e.position.Offset == -1 {
e.position = e.fset.Position(e.edge.Pos()) // called lazily
}

return &e.position
}

func (e *Edge) calleePos() *token.Position {
if e.callePosition.Offset == -1 {
e.callePosition = e.fset.Position(e.Callee.Pos()) // called lazily
}

return &e.position
}

Expand Down
29 changes: 22 additions & 7 deletions internal/callgraph/model/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package model
import (
"bytes"
"fmt"
"sort"
"strings"
)

const CURRENT_VERSION = "5"
Expand Down Expand Up @@ -35,10 +37,16 @@ func (n *Node) ToBytes() []byte {

buffer.WriteString(fmt.Sprintf("'%s', '%s', %d, %d, [", n.Name, n.Filename, n.LineStart, n.LineEnd))

for _, parent := range n.Parents {
buffer.WriteString(fmt.Sprintf("['%s', %d, '%s'], ", parent.Parent.Symbol, parent.CallLine, parent.Parent.Filename))
sort.Slice(n.Parents, func(i, j int) bool {
return n.Parents[i].Parent.Symbol < n.Parents[j].Parent.Symbol
})

parents := make([]string, len(n.Parents))
for i, parent := range n.Parents {
parents[i] = fmt.Sprintf("['%s', %d, '%s']", parent.Parent.Symbol, parent.CallLine, parent.Parent.Filename)
}

buffer.WriteString(strings.Join(parents, ", "))
buffer.WriteString("]]")

return buffer.Bytes()
Expand All @@ -58,10 +66,6 @@ func NewCallGraph() *CallGraph {

func (cg *CallGraph) AddNode(filename, name, symbol string, isLibraryNode bool, lineStart, lineEnd int) *Node {

if cg.Nodes == nil {
cg.Nodes = make(map[string]*Node)
}

if node, ok := cg.Nodes[symbol]; ok {
return node
}
Expand Down Expand Up @@ -96,9 +100,19 @@ func (cg *CallGraph) GetNode(symbol string) *Node {
func (cg *CallGraph) ToBytes() ([]byte, error) {
output := []byte{}

// Get the keys of cg.Nodes
keys := make([]string, 0, len(cg.Nodes))
for key := range cg.Nodes {
keys = append(keys, key)
}

// Sort the keys
sort.Strings(keys)

output = append(output, []byte("[")...)

for _, node := range cg.Nodes {
for _, key := range keys {
node := cg.Nodes[key]
output = append(output, node.ToBytes()...)
output = append(output, []byte(",")...)
}
Expand All @@ -124,5 +138,6 @@ func (cg *CallGraph) EdgeCount() int {
for _, node := range cg.Nodes {
count += len(node.Parents)
}

return count
}
Loading

0 comments on commit 3f56794

Please sign in to comment.