Nav apraksta

source_test.go 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. package report
  2. import (
  3. "bytes"
  4. "io/ioutil"
  5. "os"
  6. "path/filepath"
  7. "regexp"
  8. "runtime"
  9. "strings"
  10. "testing"
  11. "github.com/google/pprof/internal/binutils"
  12. "github.com/google/pprof/profile"
  13. )
  14. func TestWebList(t *testing.T) {
  15. if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
  16. t.Skip("weblist only tested on x86-64 linux")
  17. }
  18. cpu := readProfile(filepath.Join("testdata", "sample.cpu"), t)
  19. rpt := New(cpu, &Options{
  20. OutputFormat: WebList,
  21. Symbol: regexp.MustCompile("busyLoop"),
  22. SampleValue: func(v []int64) int64 { return v[1] },
  23. SampleUnit: cpu.SampleType[1].Unit,
  24. })
  25. var buf bytes.Buffer
  26. if err := Generate(&buf, rpt, &binutils.Binutils{}); err != nil {
  27. t.Fatalf("could not generate weblist: %v", err)
  28. }
  29. output := buf.String()
  30. for _, expect := range []string{"func busyLoop", "callq", "math.Abs"} {
  31. if !strings.Contains(output, expect) {
  32. t.Errorf("weblist output does not contain '%s':\n%s", expect, output)
  33. }
  34. }
  35. }
  36. func TestOpenSourceFile(t *testing.T) {
  37. tempdir, err := ioutil.TempDir("", "")
  38. if err != nil {
  39. t.Fatalf("failed to create temp dir: %v", err)
  40. }
  41. const lsep = string(filepath.ListSeparator)
  42. for _, tc := range []struct {
  43. desc string
  44. searchPath string
  45. trimPath string
  46. fs []string
  47. path string
  48. wantPath string // If empty, error is wanted.
  49. }{
  50. {
  51. desc: "exact absolute path is found",
  52. fs: []string{"foo/bar.cc"},
  53. path: "$dir/foo/bar.cc",
  54. wantPath: "$dir/foo/bar.cc",
  55. },
  56. {
  57. desc: "exact relative path is found",
  58. searchPath: "$dir",
  59. fs: []string{"foo/bar.cc"},
  60. path: "foo/bar.cc",
  61. wantPath: "$dir/foo/bar.cc",
  62. },
  63. {
  64. desc: "multiple search path",
  65. searchPath: "some/path" + lsep + "$dir",
  66. fs: []string{"foo/bar.cc"},
  67. path: "foo/bar.cc",
  68. wantPath: "$dir/foo/bar.cc",
  69. },
  70. {
  71. desc: "relative path is found in parent dir",
  72. searchPath: "$dir/foo/bar",
  73. fs: []string{"bar.cc", "foo/bar/baz.cc"},
  74. path: "bar.cc",
  75. wantPath: "$dir/bar.cc",
  76. },
  77. {
  78. desc: "trims configured prefix",
  79. searchPath: "$dir",
  80. trimPath: "some-path" + lsep + "/some/remote/path",
  81. fs: []string{"my-project/foo/bar.cc"},
  82. path: "/some/remote/path/my-project/foo/bar.cc",
  83. wantPath: "$dir/my-project/foo/bar.cc",
  84. },
  85. {
  86. desc: "trims heuristically",
  87. searchPath: "$dir/my-project",
  88. fs: []string{"my-project/foo/bar.cc"},
  89. path: "/some/remote/path/my-project/foo/bar.cc",
  90. wantPath: "$dir/my-project/foo/bar.cc",
  91. },
  92. {
  93. desc: "error when not found",
  94. path: "foo.cc",
  95. },
  96. } {
  97. t.Run(tc.desc, func(t *testing.T) {
  98. defer func() {
  99. if err := os.RemoveAll(tempdir); err != nil {
  100. t.Fatalf("failed to remove dir %q: %v", tempdir, err)
  101. }
  102. }()
  103. for _, f := range tc.fs {
  104. path := filepath.Join(tempdir, filepath.FromSlash(f))
  105. dir := filepath.Dir(path)
  106. if err := os.MkdirAll(dir, 0755); err != nil {
  107. t.Fatalf("failed to create dir %q: %v", dir, err)
  108. }
  109. if err := ioutil.WriteFile(path, nil, 0644); err != nil {
  110. t.Fatalf("failed to create file %q: %v", path, err)
  111. }
  112. }
  113. tc.searchPath = filepath.FromSlash(strings.Replace(tc.searchPath, "$dir", tempdir, -1))
  114. tc.path = filepath.FromSlash(strings.Replace(tc.path, "$dir", tempdir, 1))
  115. tc.wantPath = filepath.FromSlash(strings.Replace(tc.wantPath, "$dir", tempdir, 1))
  116. if file, err := openSourceFile(tc.path, tc.searchPath, tc.trimPath); err != nil && tc.wantPath != "" {
  117. t.Errorf("openSourceFile(%q, %q, %q) = err %v, want path %q", tc.path, tc.searchPath, tc.trimPath, err, tc.wantPath)
  118. } else if err == nil {
  119. defer file.Close()
  120. gotPath := file.Name()
  121. if tc.wantPath == "" {
  122. t.Errorf("openSourceFile(%q, %q, %q) = %q, want error", tc.path, tc.searchPath, tc.trimPath, gotPath)
  123. } else if gotPath != tc.wantPath {
  124. t.Errorf("openSourceFile(%q, %q, %q) = %q, want path %q", tc.path, tc.searchPath, tc.trimPath, gotPath, tc.wantPath)
  125. }
  126. }
  127. })
  128. }
  129. }
  130. func TestIndentation(t *testing.T) {
  131. for _, c := range []struct {
  132. str string
  133. wantIndent int
  134. }{
  135. {"", 0},
  136. {"foobar", 0},
  137. {" foo", 2},
  138. {"\tfoo", 8},
  139. {"\t foo", 9},
  140. {" \tfoo", 8},
  141. {" \tfoo", 8},
  142. {" \tfoo", 16},
  143. } {
  144. if n := indentation(c.str); n != c.wantIndent {
  145. t.Errorf("indentation(%v): got %d, want %d", c.str, n, c.wantIndent)
  146. }
  147. }
  148. }
  149. func readProfile(fname string, t *testing.T) *profile.Profile {
  150. file, err := os.Open(fname)
  151. if err != nil {
  152. t.Fatalf("%s: could not open profile: %v", fname, err)
  153. }
  154. defer file.Close()
  155. p, err := profile.Parse(file)
  156. if err != nil {
  157. t.Fatalf("%s: could not parse profile: %v", fname, err)
  158. }
  159. // Fix file names so they do not include absolute path names.
  160. fix := func(s string) string {
  161. const testdir = "/internal/report/"
  162. pos := strings.Index(s, testdir)
  163. if pos == -1 {
  164. return s
  165. }
  166. return s[pos+len(testdir):]
  167. }
  168. for _, m := range p.Mapping {
  169. m.File = fix(m.File)
  170. }
  171. for _, f := range p.Function {
  172. f.Filename = fix(f.Filename)
  173. }
  174. return p
  175. }