1package cmp 2 3import ( 4 "bytes" 5 "fmt" 6 "go/ast" 7 "text/template" 8 9 "gotest.tools/v3/internal/source" 10) 11 12// A Result of a Comparison. 13type Result interface { 14 Success() bool 15} 16 17// StringResult is an implementation of Result that reports the error message 18// string verbatim and does not provide any templating or formatting of the 19// message. 20type StringResult struct { 21 success bool 22 message string 23} 24 25// Success returns true if the comparison was successful. 26func (r StringResult) Success() bool { 27 return r.success 28} 29 30// FailureMessage returns the message used to provide additional information 31// about the failure. 32func (r StringResult) FailureMessage() string { 33 return r.message 34} 35 36// ResultSuccess is a constant which is returned by a ComparisonWithResult to 37// indicate success. 38var ResultSuccess = StringResult{success: true} 39 40// ResultFailure returns a failed Result with a failure message. 41func ResultFailure(message string) StringResult { 42 return StringResult{message: message} 43} 44 45// ResultFromError returns ResultSuccess if err is nil. Otherwise ResultFailure 46// is returned with the error message as the failure message. 47func ResultFromError(err error) Result { 48 if err == nil { 49 return ResultSuccess 50 } 51 return ResultFailure(err.Error()) 52} 53 54type templatedResult struct { 55 success bool 56 template string 57 data map[string]interface{} 58} 59 60func (r templatedResult) Success() bool { 61 return r.success 62} 63 64func (r templatedResult) FailureMessage(args []ast.Expr) string { 65 msg, err := renderMessage(r, args) 66 if err != nil { 67 return fmt.Sprintf("failed to render failure message: %s", err) 68 } 69 return msg 70} 71 72// ResultFailureTemplate returns a Result with a template string and data which 73// can be used to format a failure message. The template may access data from .Data, 74// the comparison args with the callArg function, and the formatNode function may 75// be used to format the call args. 76func ResultFailureTemplate(template string, data map[string]interface{}) Result { 77 return templatedResult{template: template, data: data} 78} 79 80func renderMessage(result templatedResult, args []ast.Expr) (string, error) { 81 tmpl := template.New("failure").Funcs(template.FuncMap{ 82 "formatNode": source.FormatNode, 83 "callArg": func(index int) ast.Expr { 84 if index >= len(args) { 85 return nil 86 } 87 return args[index] 88 }, 89 }) 90 var err error 91 tmpl, err = tmpl.Parse(result.template) 92 if err != nil { 93 return "", err 94 } 95 buf := new(bytes.Buffer) 96 err = tmpl.Execute(buf, map[string]interface{}{ 97 "Data": result.data, 98 }) 99 return buf.String(), err 100} 101