summaryrefslogtreecommitdiff
path: root/pkgtools/pkglint/files/trace
diff options
context:
space:
mode:
Diffstat (limited to 'pkgtools/pkglint/files/trace')
-rw-r--r--pkgtools/pkglint/files/trace/tracing.go79
-rwxr-xr-xpkgtools/pkglint/files/trace/tracing_test.go78
2 files changed, 133 insertions, 24 deletions
diff --git a/pkgtools/pkglint/files/trace/tracing.go b/pkgtools/pkglint/files/trace/tracing.go
index d5bd032f58b..e8ed8b96d14 100644
--- a/pkgtools/pkglint/files/trace/tracing.go
+++ b/pkgtools/pkglint/files/trace/tracing.go
@@ -16,16 +16,6 @@ var (
var traceDepth int
-func Ref(rv interface{}) ref {
- return ref{rv}
-}
-
-func (r ref) String() string {
- ptr := reflect.ValueOf(r.intf)
- ref := reflect.Indirect(ptr)
- return fmt.Sprintf("%v", ref)
-}
-
func Stepf(format string, args ...interface{}) {
if Tracing {
msg := fmt.Sprintf(format, args...)
@@ -53,14 +43,17 @@ func Call2(arg1, arg2 string) func() {
return traceCall(arg1, arg2)
}
+// Call records a function call in the tracing log, both when entering and
+// when leaving the function.
+//
+// Usage:
+// if trace.Tracing {
+// defer trace.Call(arg1, arg2, trace.Result(result1), trace.Result(result2))()
+// }
func Call(args ...interface{}) func() {
return traceCall(args...)
}
-type ref struct {
- intf interface{}
-}
-
// http://stackoverflow.com/questions/13476349/check-for-nil-and-nil-interface-in-go
func isNil(a interface{}) bool {
defer func() {
@@ -69,19 +62,19 @@ func isNil(a interface{}) bool {
return a == nil || reflect.ValueOf(a).IsNil()
}
-func argsStr(args ...interface{}) string {
- argsStr := ""
- for i, arg := range args {
- if i != 0 {
- argsStr += ", "
+func argsStr(args []interface{}) string {
+ rv := ""
+ for _, arg := range args {
+ if rv != "" {
+ rv += ", "
}
if str, ok := arg.(fmt.Stringer); ok && !isNil(str) {
- argsStr += str.String()
+ rv += str.String()
} else {
- argsStr += fmt.Sprintf("%#v", arg)
+ rv += fmt.Sprintf("%#v", arg)
}
}
- return argsStr
+ return rv
}
func traceIndent() string {
@@ -104,11 +97,49 @@ func traceCall(args ...interface{}) func() {
}
}
indent := traceIndent()
- io.WriteString(Out, fmt.Sprintf("TRACE: %s+ %s(%s)\n", indent, funcname, argsStr(args...)))
+ io.WriteString(Out, fmt.Sprintf("TRACE: %s+ %s(%s)\n", indent, funcname, argsStr(withoutResults(args))))
traceDepth++
return func() {
traceDepth--
- io.WriteString(Out, fmt.Sprintf("TRACE: %s- %s(%s)\n", indent, funcname, argsStr(args...)))
+ io.WriteString(Out, fmt.Sprintf("TRACE: %s- %s(%s)\n", indent, funcname, argsStr(withResults(args))))
+ }
+}
+
+type result struct {
+ pointer interface{}
+}
+
+// Result marks an argument as a result and is only logged when the function returns.
+func Result(rv interface{}) result {
+ if reflect.ValueOf(rv).Kind() != reflect.Ptr {
+ panic(fmt.Sprintf("Result must be called with a pointer to the result, not %#v.", rv))
+ }
+ return result{rv}
+}
+
+func withoutResults(args []interface{}) []interface{} {
+ for i, arg := range args {
+ if _, ok := arg.(result); ok {
+ return args[0:i]
+ }
+ }
+ return args
+}
+
+func withResults(args []interface{}) []interface{} {
+ for i, arg := range args {
+ if _, ok := arg.(result); ok {
+ var awr []interface{}
+ awr = append(awr, args[0:i]...)
+ awr = append(awr, "=>")
+ for _, res := range args[i:] {
+ pointer := reflect.ValueOf(res.(result).pointer)
+ actual := reflect.Indirect(pointer).Interface()
+ awr = append(awr, actual)
+ }
+ return awr
+ }
}
+ return args
}
diff --git a/pkgtools/pkglint/files/trace/tracing_test.go b/pkgtools/pkglint/files/trace/tracing_test.go
new file mode 100755
index 00000000000..f63b31e0fa8
--- /dev/null
+++ b/pkgtools/pkglint/files/trace/tracing_test.go
@@ -0,0 +1,78 @@
+package trace
+
+import (
+ "bytes"
+ "gopkg.in/check.v1"
+ "testing"
+)
+
+type Suite struct{}
+
+var _ = check.Suite(new(Suite))
+
+func Test(t *testing.T) { check.TestingT(t) }
+
+func onlyArguments(args ...interface{}) {
+ defer Call(args...)()
+ Stepf("Running %q", "code")
+}
+
+func argumentsAndResult(arg0 string, arg1 int) (result string) {
+ defer Call(arg0, arg1, Result(&result))()
+ Stepf("Running %q", "code")
+ return "the result"
+}
+
+func argumentsAndResultWrong(arg0 string, arg1 int) (result string) {
+ defer Call(arg0, arg1, result)() // "result" is evaluated too early and only once.
+ Stepf("Running %q", "code")
+ return "the result"
+}
+
+func (s *Suite) Test_Call__onlyArguments(c *check.C) {
+
+ output := s.captureTracingOutput(func() {
+ onlyArguments("arg0", 1234)
+ })
+
+ c.Check(output, check.Equals, ""+
+ "TRACE: + netbsd.org/pkglint/trace.onlyArguments(\"arg0\", 1234)\n"+
+ "TRACE: 1 Running \"code\"\n"+
+ "TRACE: - netbsd.org/pkglint/trace.onlyArguments(\"arg0\", 1234)\n")
+}
+
+func (s *Suite) Test_Call__argumentsAndResult(c *check.C) {
+
+ output := s.captureTracingOutput(func() {
+ argumentsAndResult("arg0", 1234)
+ })
+
+ c.Check(output, check.Equals, ""+
+ "TRACE: + netbsd.org/pkglint/trace.argumentsAndResult(\"arg0\", 1234)\n"+
+ "TRACE: 1 Running \"code\"\n"+
+ "TRACE: - netbsd.org/pkglint/trace.argumentsAndResult(\"arg0\", 1234, \"=>\", \"the result\")\n")
+}
+
+func (s *Suite) Test_Call__argumentsAndResultWrong(c *check.C) {
+
+ output := s.captureTracingOutput(func() {
+ argumentsAndResultWrong("arg0", 1234)
+ })
+
+ c.Check(output, check.Equals, ""+
+ "TRACE: + netbsd.org/pkglint/trace.argumentsAndResultWrong(\"arg0\", 1234, \"\")\n"+
+ "TRACE: 1 Running \"code\"\n"+
+ "TRACE: - netbsd.org/pkglint/trace.argumentsAndResultWrong(\"arg0\", 1234, \"\")\n")
+}
+
+func (s *Suite) captureTracingOutput(action func()) string {
+ out := bytes.Buffer{}
+ Out = &out
+ Tracing = true
+
+ action()
+
+ Tracing = false
+ Out = nil
+ return out.String()
+}