2018-02-28 10:11:02 -05:00
|
|
|
package cmp
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"go/ast"
|
|
|
|
"text/template"
|
|
|
|
|
2018-06-08 12:23:38 -04:00
|
|
|
"gotest.tools/internal/source"
|
2018-02-28 10:11:02 -05:00
|
|
|
)
|
|
|
|
|
2019-04-12 19:47:37 -04:00
|
|
|
// A Result of a Comparison.
|
2018-02-28 10:11:02 -05:00
|
|
|
type Result interface {
|
|
|
|
Success() bool
|
|
|
|
}
|
|
|
|
|
2019-04-12 19:47:37 -04:00
|
|
|
// StringResult is an implementation of Result that reports the error message
|
|
|
|
// string verbatim and does not provide any templating or formatting of the
|
|
|
|
// message.
|
|
|
|
type StringResult struct {
|
2018-02-28 10:11:02 -05:00
|
|
|
success bool
|
|
|
|
message string
|
|
|
|
}
|
|
|
|
|
2019-04-12 19:47:37 -04:00
|
|
|
// Success returns true if the comparison was successful.
|
|
|
|
func (r StringResult) Success() bool {
|
2018-02-28 10:11:02 -05:00
|
|
|
return r.success
|
|
|
|
}
|
|
|
|
|
2019-04-12 19:47:37 -04:00
|
|
|
// FailureMessage returns the message used to provide additional information
|
|
|
|
// about the failure.
|
|
|
|
func (r StringResult) FailureMessage() string {
|
2018-02-28 10:11:02 -05:00
|
|
|
return r.message
|
|
|
|
}
|
|
|
|
|
|
|
|
// ResultSuccess is a constant which is returned by a ComparisonWithResult to
|
|
|
|
// indicate success.
|
2019-04-12 19:47:37 -04:00
|
|
|
var ResultSuccess = StringResult{success: true}
|
2018-02-28 10:11:02 -05:00
|
|
|
|
|
|
|
// ResultFailure returns a failed Result with a failure message.
|
2019-04-12 19:47:37 -04:00
|
|
|
func ResultFailure(message string) StringResult {
|
|
|
|
return StringResult{message: message}
|
2018-02-28 10:11:02 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// ResultFromError returns ResultSuccess if err is nil. Otherwise ResultFailure
|
|
|
|
// is returned with the error message as the failure message.
|
|
|
|
func ResultFromError(err error) Result {
|
|
|
|
if err == nil {
|
|
|
|
return ResultSuccess
|
|
|
|
}
|
|
|
|
return ResultFailure(err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
type templatedResult struct {
|
|
|
|
success bool
|
|
|
|
template string
|
|
|
|
data map[string]interface{}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r templatedResult) Success() bool {
|
|
|
|
return r.success
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r templatedResult) FailureMessage(args []ast.Expr) string {
|
|
|
|
msg, err := renderMessage(r, args)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Sprintf("failed to render failure message: %s", err)
|
|
|
|
}
|
|
|
|
return msg
|
|
|
|
}
|
|
|
|
|
|
|
|
// ResultFailureTemplate returns a Result with a template string and data which
|
|
|
|
// can be used to format a failure message. The template may access data from .Data,
|
|
|
|
// the comparison args with the callArg function, and the formatNode function may
|
|
|
|
// be used to format the call args.
|
|
|
|
func ResultFailureTemplate(template string, data map[string]interface{}) Result {
|
|
|
|
return templatedResult{template: template, data: data}
|
|
|
|
}
|
|
|
|
|
|
|
|
func renderMessage(result templatedResult, args []ast.Expr) (string, error) {
|
|
|
|
tmpl := template.New("failure").Funcs(template.FuncMap{
|
|
|
|
"formatNode": source.FormatNode,
|
|
|
|
"callArg": func(index int) ast.Expr {
|
|
|
|
if index >= len(args) {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return args[index]
|
|
|
|
},
|
|
|
|
})
|
|
|
|
var err error
|
|
|
|
tmpl, err = tmpl.Parse(result.template)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
err = tmpl.Execute(buf, map[string]interface{}{
|
|
|
|
"Data": result.data,
|
|
|
|
})
|
|
|
|
return buf.String(), err
|
|
|
|
}
|