diff --git a/cmd/apply.go b/cmd/apply.go index 126ceba..c22c1c8 100644 --- a/cmd/apply.go +++ b/cmd/apply.go @@ -41,6 +41,6 @@ func (ac *ApplyCmd) Run() error { if err != nil { return err } - return ac.importsGroomer.RemoveUnusedImportFromDirectory(path, map[string]string{"fmt":"", "runtime":"rt", "rand":""}) // TODO: flag for import aliases + return ac.importsGroomer.RemoveUnusedImportFromDirectory(path, map[string]string{"fmt": "", "runtime": "rt", "rand": ""}) // TODO: flag for import aliases }) } diff --git a/cmd/revert.go b/cmd/revert.go index b69222b..a1bee42 100644 --- a/cmd/revert.go +++ b/cmd/revert.go @@ -41,6 +41,6 @@ func (rc *RevertCmd) Run() error { if err != nil { return err } - return rc.importsGroomer.RemoveUnusedImportFromDirectory(path, map[string]string{"fmt":"", "runtime":"rt", "crypto/rand":""}) // TODO: flag for import aliases + return rc.importsGroomer.RemoveUnusedImportFromDirectory(path, map[string]string{"fmt": "", "runtime": "rt", "crypto/rand": ""}) // TODO: flag for import aliases }) } diff --git a/parser/parser.go b/parser/parser.go index b149a53..3524261 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -19,24 +19,46 @@ const ( ) type FuncEvent interface { - FuncName() string + GetCaller() string + GetCallee() string + GetCallID() string } type InvocationEvent struct { - Name string - Args string + Caller string + Callee string + CallID string + Args string } -func (ie *InvocationEvent) FuncName() string { - return ie.Name +func (ie *InvocationEvent) GetCaller() string { + return ie.Caller +} + +func (ie *InvocationEvent) GetCallee() string { + return ie.Callee +} + +func (ie *InvocationEvent) GetCallID() string { + return ie.CallID } type ReturningEvent struct { - Name string + Caller string + Callee string + CallID string +} + +func (re *ReturningEvent) GetCaller() string { + return re.Caller +} + +func (re *ReturningEvent) GetCallee() string { + return re.Callee } -func (ie *ReturningEvent) FuncName() string { - return ie.Name +func (re *ReturningEvent) GetCallID() string { + return re.CallID } type parser struct { @@ -50,19 +72,25 @@ func (p *parser) Parse(in io.Reader) ([]FuncEvent, error) { var events []FuncEvent scanner := bufio.NewScanner(in) for scanner.Scan() { - row := scanner.Text() - if strings.HasPrefix(row, "Entering function") { - words := strings.Split(row, " ") + halfs := strings.Split(scanner.Text(), ";") + callID := strings.Split(halfs[1], "=")[1] + msg := halfs[0] + if strings.HasPrefix(msg, "Function") { + words := strings.Split(msg, " ") events = append(events, &InvocationEvent{ - Name: words[2], - Args: strings.Join(words[3:], " "), + Callee: words[1], + Caller: words[4], + Args: strings.Join(words[5:], " "), + CallID: callID, }) } - if strings.HasPrefix(row, "Exiting function") { - split := strings.Split(row, " ") + if strings.HasPrefix(msg, "Exiting function") { + words := strings.Split(msg, " ") events = append(events, &ReturningEvent{ - Name: split[2], + Callee: words[2], + Caller: words[5], + CallID: callID, }) } } diff --git a/parser/parser_test.go b/parser/parser_test.go index 91d2f9a..a509b10 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -7,34 +7,58 @@ import ( ) func TestParser_Parse(t *testing.T) { - input := `Entering function main -Entering function foo with args (1) (true) -Entering function bar with args (test string) -Entering function baz -Exiting function baz -Exiting function bar -Exiting function foo -Exiting function main` + input := `Function main.main called by runtime.main; callID=1d8ca74e-c860-8a75-fc36-fe6d34350f0c +Function main.foo called by main.main with args (5) (false); callID=973355a9-2ec6-095c-9137-7a1081ac0a5f +Function main.bar called by main.foo with args (test string); callID=6c294dfd-4c6a-39b1-474e-314bee73f514 +Function main.baz called by main.bar; callID=a019a297-0a6e-a792-0e3f-23c33a44622f +Exiting function main.baz called by main.bar; callID=a019a297-0a6e-a792-0e3f-23c33a44622f +Exiting function main.bar called by main.foo; callID=6c294dfd-4c6a-39b1-474e-314bee73f514 +Exiting function main.foo called by main.main; callID=973355a9-2ec6-095c-9137-7a1081ac0a5f +Exiting function main.main called by runtime.main; callID=1d8ca74e-c860-8a75-fc36-fe6d34350f0c` expected := []FuncEvent{ &InvocationEvent{ - Name: "main", + Caller: "runtime.main", + Callee: "main.main", + CallID: "1d8ca74e-c860-8a75-fc36-fe6d34350f0c", }, &InvocationEvent{ - Name: "foo", - Args: "with args (1) (true)", + Caller: "main.main", + Callee: "main.foo", + CallID: "973355a9-2ec6-095c-9137-7a1081ac0a5f", + Args: "with args (5) (false)", }, &InvocationEvent{ - Name: "bar", - Args: "with args (test string)", + Caller: "main.foo", + Callee: "main.bar", + CallID: "6c294dfd-4c6a-39b1-474e-314bee73f514", + Args: "with args (test string)", }, &InvocationEvent{ - Name: "baz", + Caller: "main.bar", + Callee: "main.baz", + CallID: "a019a297-0a6e-a792-0e3f-23c33a44622f", + }, + &ReturningEvent{ + Caller: "main.bar", + Callee: "main.baz", + CallID: "a019a297-0a6e-a792-0e3f-23c33a44622f", + }, + &ReturningEvent{ + Caller: "main.foo", + Callee: "main.bar", + CallID: "6c294dfd-4c6a-39b1-474e-314bee73f514", + }, + &ReturningEvent{ + Caller: "main.main", + Callee: "main.foo", + CallID: "973355a9-2ec6-095c-9137-7a1081ac0a5f", + }, + &ReturningEvent{ + Caller: "runtime.main", + Callee: "main.main", + CallID: "1d8ca74e-c860-8a75-fc36-fe6d34350f0c", }, - &ReturningEvent{Name: "baz"}, - &ReturningEvent{Name: "bar"}, - &ReturningEvent{Name: "foo"}, - &ReturningEvent{Name: "main"}, } actual, err := NewParser().Parse(bytes.NewBufferString(input)) diff --git a/tracing/deinstrument_test.go b/tracing/deinstrument_test.go index dd5409e..761041e 100644 --- a/tracing/deinstrument_test.go +++ b/tracing/deinstrument_test.go @@ -43,7 +43,7 @@ func TestDeinstrumentFile(t *testing.T) { } var buff2 bytes.Buffer - if err := NewImportsGroomer().RemoveUnusedImportFromFile(fset, file, &buff2, map[string]string{"fmt":"", "runtime":"rt", "crypto/rand":""}); err != nil { + if err := NewImportsGroomer().RemoveUnusedImportFromFile(fset, file, &buff2, map[string]string{"fmt": "", "runtime": "rt", "crypto/rand": ""}); err != nil { t.Fatal(err) } @@ -87,7 +87,7 @@ func TestDeinstrumentDirectory(t *testing.T) { t.Fatal(err) } - if err := NewImportsGroomer().RemoveUnusedImportFromDirectory("test", map[string]string{"fmt":"", "runtime":"rt", "crypto/rand":""}); err != nil { + if err := NewImportsGroomer().RemoveUnusedImportFromDirectory("test", map[string]string{"fmt": "", "runtime": "rt", "crypto/rand": ""}); err != nil { t.Fatal(err) } diff --git a/tracing/unused_imports_test.go b/tracing/unused_imports_test.go index c980dd3..9df91e6 100644 --- a/tracing/unused_imports_test.go +++ b/tracing/unused_imports_test.go @@ -27,7 +27,7 @@ func TestRemoveUnusedImportsFromFile(t *testing.T) { t.Fatal(err) } var buff bytes.Buffer - if err := NewImportsGroomer().RemoveUnusedImportFromFile(fset, file, &buff, map[string]string{"fmt":"", "runtime":"rt", "crypto/rand":""}); err != nil { + if err := NewImportsGroomer().RemoveUnusedImportFromFile(fset, file, &buff, map[string]string{"fmt": "", "runtime": "rt", "crypto/rand": ""}); err != nil { t.Fatal(err) } @@ -63,7 +63,7 @@ func TestRemoveUnusedImportsFromDirectory(t *testing.T) { i++ } - if err := NewImportsGroomer().RemoveUnusedImportFromDirectory("test", map[string]string{"fmt":"", "runtime":"rt", "crypto/rand":""}); err != nil { + if err := NewImportsGroomer().RemoveUnusedImportFromDirectory("test", map[string]string{"fmt": "", "runtime": "rt", "crypto/rand": ""}); err != nil { t.Fatal(err) } diff --git a/vis/vis.go b/vis/vis.go index 3714063..617da07 100644 --- a/vis/vis.go +++ b/vis/vis.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/DimitarPetrov/printracer/parser" "html/template" + "math" "os" ) @@ -43,15 +44,19 @@ const reportTemplate = ` # Arguments + Call ID - {{ range $i, $e := .Args }} + {{ range $i, $e := .TableRows }} {{ inc $i }} -
{{ $e }}
+
{{ $e.Args }}
+ +
{{ $e.CallID }}
+ {{ end }} @@ -138,10 +143,15 @@ func (s *stack) Empty() bool { return s.Length() == 0 } +type TableRow struct { + Args string + CallID string +} + type templateData struct { - Args []string - Diagram string - MetaJSON template.JS + TableRows []TableRow + Diagram string + MetaJSON template.JS } type sequenceDiagramData struct { @@ -149,15 +159,15 @@ type sequenceDiagramData struct { count int } -func (r *sequenceDiagramData) addFunctionInvocation(source string, target string) { +func (r *sequenceDiagramData) addFunctionInvocation(source, target string) { r.addRecord(source, "->", target) } -func (r *sequenceDiagramData) addFunctionReturn(source string, target string) { +func (r *sequenceDiagramData) addFunctionReturn(source, target string) { r.addRecord(source, "-->", target) } -func (r *sequenceDiagramData) addRecord(source string, operation string, target string) { +func (r *sequenceDiagramData) addRecord(source, operation, target string) { r.count++ r.data.WriteString(fmt.Sprintf("%s%s%s: (%d)\n", source, operation, target, r.count)) } @@ -167,18 +177,54 @@ func (r *sequenceDiagramData) String() string { } func (v *visualizer) constructTemplateData(events []parser.FuncEvent, maxDepth int, startingFunc string) (templateData, error) { + if maxDepth == math.MaxInt32 && len(startingFunc) == 0 { + return v.constructTemplateDataGraph(events) + } + return v.constructTemplateDataLinearly(events, maxDepth, startingFunc) +} + +func (v *visualizer) constructTemplateDataGraph(events []parser.FuncEvent) (templateData, error) { + diagramData := &sequenceDiagramData{} + + var tableRows []TableRow + + for i := 0; i < len(events); i++ { + event := events[i] + switch event := event.(type) { + case *parser.InvocationEvent: + diagramData.addFunctionInvocation(event.GetCaller(), event.GetCallee()) + tableRows = append(tableRows, TableRow{ + Args: fmt.Sprintf("calling %s", event.Args), + CallID: event.GetCallID(), + }) + case *parser.ReturningEvent: + diagramData.addFunctionReturn(event.GetCallee(), event.GetCaller()) + tableRows = append(tableRows, TableRow{ + Args: "returning", + CallID: event.GetCallID(), + }) + } + } + + return templateData{ + Diagram: diagramData.String(), + TableRows: tableRows, + }, nil +} + +func (v *visualizer) constructTemplateDataLinearly(events []parser.FuncEvent, maxDepth int, startingFunc string) (templateData, error) { diagramData := &sequenceDiagramData{} if len(startingFunc) > 0 { for i := 0; i < len(events); i++ { - if events[i].FuncName() == startingFunc { + if _, ok := events[i].(*parser.InvocationEvent); ok && events[i].GetCaller() == startingFunc { events = events[i:] break } } for i := 1; i < len(events); i++ { - if events[i].FuncName() == startingFunc { + if _, ok := events[i].(*parser.ReturningEvent); ok && events[i].GetCaller() == startingFunc { events = events[:i+1] break } @@ -186,36 +232,47 @@ func (v *visualizer) constructTemplateData(events []parser.FuncEvent, maxDepth i } stack := stack(make([]parser.FuncEvent, 0, len(events))) + var tableRows []TableRow - var args []string + diagramData.addFunctionInvocation(events[0].GetCaller(), events[0].GetCallee()) + stack.Push(events[0]) + tableRows = append(tableRows, TableRow{ + Args: fmt.Sprintf("calling %s", events[0].(*parser.InvocationEvent).Args), + CallID: events[0].GetCallID(), + }) - for i := 0; i < len(events); i++ { + for i := 1; i < len(events); i++ { + if stack.Empty() { + break + } event := events[i] switch event := event.(type) { case *parser.InvocationEvent: if stack.Length() < maxDepth { - prev := event - if !stack.Empty() { - prev = stack.Peek().(*parser.InvocationEvent) + prev := stack.Peek().(*parser.InvocationEvent) + if prev.GetCallee() == event.GetCaller() { + diagramData.addFunctionInvocation(event.GetCaller(), event.GetCallee()) + tableRows = append(tableRows, TableRow{ + Args: fmt.Sprintf("calling %s", event.Args), + CallID: event.GetCallID(), + }) + stack.Push(event) } - diagramData.addFunctionInvocation(prev.Name, event.FuncName()) - args = append(args, fmt.Sprintf("calling %s", event.Args)) - stack.Push(event) } case *parser.ReturningEvent: - if stack.Peek().FuncName() == event.FuncName() { - prev := stack.Pop() - if !stack.Empty() { - prev = stack.Peek() - } - diagramData.addFunctionReturn(event.FuncName(), prev.FuncName()) - args = append(args, "returning") + if stack.Peek().GetCallee() == event.GetCallee() { + _ = stack.Pop() + diagramData.addFunctionReturn(event.GetCallee(), event.GetCaller()) + tableRows = append(tableRows, TableRow{ + Args: "returning", + CallID: event.GetCallID(), + }) } } } return templateData{ - Diagram: diagramData.String(), - Args: args, + Diagram: diagramData.String(), + TableRows: tableRows, }, nil } diff --git a/vis/vis_test.go b/vis/vis_test.go index 8372321..b608c5a 100644 --- a/vis/vis_test.go +++ b/vis/vis_test.go @@ -13,83 +13,99 @@ import ( var inputEvents = []parser.FuncEvent{ &parser.InvocationEvent{ - Name: "main", + Caller: "runtime.main", + Callee: "main.main", + CallID: "1d8ca74e-c860-8a75-fc36-fe6d34350f0c", }, &parser.InvocationEvent{ - Name: "foo", - Args: "with args (1) (true)", + Caller: "main.main", + Callee: "main.foo", + CallID: "973355a9-2ec6-095c-9137-7a1081ac0a5f", + Args: "with args (5) (false)", }, &parser.InvocationEvent{ - Name: "bar", - Args: "with args (test string)", + Caller: "main.foo", + Callee: "main.bar", + CallID: "6c294dfd-4c6a-39b1-474e-314bee73f514", + Args: "with args (test string)", }, &parser.InvocationEvent{ - Name: "baz", + Caller: "main.bar", + Callee: "main.baz", + CallID: "a019a297-0a6e-a792-0e3f-23c33a44622f", + }, + &parser.ReturningEvent{ + Caller: "main.bar", + Callee: "main.baz", + CallID: "a019a297-0a6e-a792-0e3f-23c33a44622f", + }, + &parser.ReturningEvent{ + Caller: "main.foo", + Callee: "main.bar", + CallID: "6c294dfd-4c6a-39b1-474e-314bee73f514", + }, + &parser.ReturningEvent{ + Caller: "main.main", + Callee: "main.foo", + CallID: "973355a9-2ec6-095c-9137-7a1081ac0a5f", + }, + &parser.ReturningEvent{ + Caller: "runtime.main", + Callee: "main.main", + CallID: "1d8ca74e-c860-8a75-fc36-fe6d34350f0c", }, - &parser.ReturningEvent{Name: "baz"}, - &parser.ReturningEvent{Name: "bar"}, - &parser.ReturningEvent{Name: "foo"}, - &parser.ReturningEvent{Name: "main"}, } -var fullDiagram = `main->main: (1) -main->foo: (2) -foo->bar: (3) -bar->baz: (4) -baz-->bar: (5) -bar-->foo: (6) -foo-->main: (7) -main-->main: (8) +var fullDiagram = `runtime.main->main.main: (1) +main.main->main.foo: (2) +main.foo->main.bar: (3) +main.bar->main.baz: (4) +main.baz-->main.bar: (5) +main.bar-->main.foo: (6) +main.foo-->main.main: (7) +main.main-->runtime.main: (8) ` -var fullArgs = []string{ - "calling ", - "calling with args (1) (true)", - "calling with args (test string)", - "calling ", - "returning", - "returning", - "returning", - "returning", +var fullTableRows = []TableRow{ + {Args: "calling ", CallID: "1d8ca74e-c860-8a75-fc36-fe6d34350f0c"}, + {Args: "calling with args (5) (false)", CallID: "973355a9-2ec6-095c-9137-7a1081ac0a5f"}, + {Args: "calling with args (test string)", CallID: "6c294dfd-4c6a-39b1-474e-314bee73f514"}, + {Args: "calling ", CallID: "a019a297-0a6e-a792-0e3f-23c33a44622f"}, + {Args: "returning", CallID: "a019a297-0a6e-a792-0e3f-23c33a44622f"}, + {Args: "returning", CallID: "6c294dfd-4c6a-39b1-474e-314bee73f514"}, + {Args: "returning", CallID: "973355a9-2ec6-095c-9137-7a1081ac0a5f"}, + {Args: "returning", CallID: "1d8ca74e-c860-8a75-fc36-fe6d34350f0c"}, } -var diagramWith2DepthLimit = `main->main: (1) -main->foo: (2) -foo-->main: (3) -main-->main: (4) +var diagramWith2DepthLimit = `runtime.main->main.main: (1) +main.main->main.foo: (2) +main.foo-->main.main: (3) +main.main-->runtime.main: (4) ` -var argsWith2DepthLimit = []string{ - "calling ", - "calling with args (1) (true)", - "returning", - "returning", +var tableRowsWith2DepthLimit = []TableRow{ + {Args: "calling ", CallID: "1d8ca74e-c860-8a75-fc36-fe6d34350f0c"}, + {Args: "calling with args (5) (false)", CallID: "973355a9-2ec6-095c-9137-7a1081ac0a5f"}, + {Args: "returning", CallID: "973355a9-2ec6-095c-9137-7a1081ac0a5f"}, + {Args: "returning", CallID: "1d8ca74e-c860-8a75-fc36-fe6d34350f0c"}, } -var diagramWithFooStartingFunc = `foo->foo: (1) -foo->bar: (2) -bar->baz: (3) -baz-->bar: (4) -bar-->foo: (5) -foo-->foo: (6) +var diagramWithFooStartingFunc = `main.foo->main.bar: (1) +main.bar->main.baz: (2) +main.baz-->main.bar: (3) +main.bar-->main.foo: (4) ` -var argsWithFooStartingFunc = []string{ - "calling with args (1) (true)", - "calling with args (test string)", - "calling ", - "returning", - "returning", - "returning", +var tableRowsWithFooStartingFunc = []TableRow{ + {Args: "calling with args (test string)", CallID: "6c294dfd-4c6a-39b1-474e-314bee73f514"}, + {Args: "calling ", CallID: "a019a297-0a6e-a792-0e3f-23c33a44622f"}, + {Args: "returning", CallID: "a019a297-0a6e-a792-0e3f-23c33a44622f"}, + {Args: "returning", CallID: "6c294dfd-4c6a-39b1-474e-314bee73f514"}, } -var diagramWithFooStartingFuncAnd2DepthLimit = `foo->foo: (1) -foo->bar: (2) -bar-->foo: (3) -foo-->foo: (4) +var diagramWithFooStartingFuncAnd2DepthLimit = `main.foo->main.bar: (1) +main.bar-->main.foo: (2) ` -var argsWithFooStartingFuncAnd2DepthLimit = []string{ - "calling with args (1) (true)", - "calling with args (test string)", - "returning", - "returning", +var tableRowsWithFooStartingFuncAnd2DepthLimit = []TableRow{ + {Args: "calling with args (test string)", CallID: "6c294dfd-4c6a-39b1-474e-314bee73f514"}, + {Args: "returning", CallID: "6c294dfd-4c6a-39b1-474e-314bee73f514"}, } func TestVisualizerConstructTemplateData(t *testing.T) { @@ -98,12 +114,12 @@ func TestVisualizerConstructTemplateData(t *testing.T) { MaxDepth int StartingFunc string Diagram string - Args []string + TableRows []TableRow }{ - {Name: "ConstructTemplateData", MaxDepth: math.MaxInt32, Diagram: fullDiagram, Args: fullArgs}, - {Name: "ConstructTemplateDataWithDepthLimit", MaxDepth: 2, Diagram: diagramWith2DepthLimit, Args: argsWith2DepthLimit}, - {Name: "ConstructTemplateDataWithFooStartingFunc", MaxDepth: math.MaxInt32, StartingFunc: "foo", Diagram: diagramWithFooStartingFunc, Args: argsWithFooStartingFunc}, - {Name: "ConstructTemplateDataWithFooStartingFuncAndDepthLimit", MaxDepth: 2, StartingFunc: "foo", Diagram: diagramWithFooStartingFuncAnd2DepthLimit, Args: argsWithFooStartingFuncAnd2DepthLimit}, + {Name: "ConstructTemplateData", MaxDepth: math.MaxInt32, Diagram: fullDiagram, TableRows: fullTableRows}, + {Name: "ConstructTemplateDataWithDepthLimit", MaxDepth: 2, Diagram: diagramWith2DepthLimit, TableRows: tableRowsWith2DepthLimit}, + {Name: "ConstructTemplateDataWithFooStartingFunc", MaxDepth: math.MaxInt32, StartingFunc: "main.foo", Diagram: diagramWithFooStartingFunc, TableRows: tableRowsWithFooStartingFunc}, + {Name: "ConstructTemplateDataWithFooStartingFuncAndDepthLimit", MaxDepth: 1, StartingFunc: "main.foo", Diagram: diagramWithFooStartingFuncAnd2DepthLimit, TableRows: tableRowsWithFooStartingFuncAnd2DepthLimit}, } visualizer := visualizer{} @@ -117,8 +133,8 @@ func TestVisualizerConstructTemplateData(t *testing.T) { if diagramData.Diagram != test.Diagram { t.Errorf("Assertion failed! Expected diagram data: %s bug got: %s", test.Diagram, diagramData.Diagram) } - if !reflect.DeepEqual(diagramData.Args, test.Args) { - t.Errorf("Assertion failed! Expected args: %v bug got: %v", test.Args, diagramData.Args) + if !reflect.DeepEqual(diagramData.TableRows, test.TableRows) { + t.Errorf("Assertion failed! Expected args: %v bug got: %v", test.TableRows, diagramData.TableRows) } }) } @@ -130,12 +146,12 @@ func TestVisualize(t *testing.T) { MaxDepth int StartingFunc string Diagram string - Args []string + TableRows []TableRow }{ - {Name: "ConstructTemplateData", MaxDepth: math.MaxInt32, Diagram: fullDiagram, Args: fullArgs}, - {Name: "ConstructTemplateDataWithDepthLimit", MaxDepth: 2, Diagram: diagramWith2DepthLimit, Args: argsWith2DepthLimit}, - {Name: "ConstructTemplateDataWithFooStartingFunc", MaxDepth: math.MaxInt32, StartingFunc: "foo", Diagram: diagramWithFooStartingFunc, Args: argsWithFooStartingFunc}, - {Name: "ConstructTemplateDataWithFooStartingFuncAndDepthLimit", MaxDepth: 2, StartingFunc: "foo", Diagram: diagramWithFooStartingFuncAnd2DepthLimit, Args: argsWithFooStartingFuncAnd2DepthLimit}, + {Name: "ConstructTemplateData", MaxDepth: math.MaxInt32, Diagram: fullDiagram, TableRows: fullTableRows}, + {Name: "ConstructTemplateDataWithDepthLimit", MaxDepth: 2, Diagram: diagramWith2DepthLimit, TableRows: tableRowsWith2DepthLimit}, + {Name: "ConstructTemplateDataWithFooStartingFunc", MaxDepth: math.MaxInt32, StartingFunc: "foo", Diagram: diagramWithFooStartingFunc, TableRows: tableRowsWithFooStartingFunc}, + {Name: "ConstructTemplateDataWithFooStartingFuncAndDepthLimit", MaxDepth: 2, StartingFunc: "foo", Diagram: diagramWithFooStartingFuncAnd2DepthLimit, TableRows: tableRowsWithFooStartingFuncAnd2DepthLimit}, } for _, test := range tests { @@ -159,9 +175,12 @@ func TestVisualize(t *testing.T) { if !bytes.Contains(html, []byte(encodedDiagram)) { t.Error("Assertion failed! Expected html file to contain diagram data") } - for _, arg := range test.Args { - if !bytes.Contains(html, []byte(arg)) { - t.Errorf("Assertion failed! Expected html file to contain arg %s", arg) + for _, row := range test.TableRows { + if !bytes.Contains(html, []byte(row.Args)) { + t.Errorf("Assertion failed! Expected html file to contain arg %s", row.Args) + } + if !bytes.Contains(html, []byte(row.CallID)) { + t.Errorf("Assertion failed! Expected html file to contain callID %s", row.CallID) } } })