text/template: add ExecError type and return it from Execute on error
Useful to discriminate evaluation errors from write errors.
Fixes #11898.
Change-Id: I907d339a3820e887872d78e0e2d8fd011451fd19
Reviewed-on: https://go-review.googlesource.com/13957
Reviewed-by: Andrew Gerrand <adg@golang.org>
diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go
index ba0e434..07ebb55 100644
--- a/src/text/template/exec_test.go
+++ b/src/text/template/exec_test.go
@@ -9,6 +9,7 @@
"errors"
"flag"
"fmt"
+ "io/ioutil"
"reflect"
"strings"
"testing"
@@ -1141,3 +1142,45 @@
t.Fatalf("unexpected error: %s", str)
}
}
+
+const alwaysErrorText = "always be failing"
+
+var alwaysError = errors.New(alwaysErrorText)
+
+type ErrorWriter int
+
+func (e ErrorWriter) Write(p []byte) (int, error) {
+ return 0, alwaysError
+}
+
+func TestExecuteGivesExecError(t *testing.T) {
+ // First, a non-execution error shouldn't be an ExecError.
+ tmpl, err := New("X").Parse("hello")
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = tmpl.Execute(ErrorWriter(0), 0)
+ if err == nil {
+ t.Fatal("expected error; got none")
+ }
+ if err.Error() != alwaysErrorText {
+ t.Errorf("expected %q error; got %q", alwaysErrorText, err)
+ }
+ // This one should be an ExecError.
+ tmpl, err = New("X").Parse("hello, {{.X.Y}}")
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = tmpl.Execute(ioutil.Discard, 0)
+ if err == nil {
+ t.Fatal("expected error; got none")
+ }
+ eerr, ok := err.(ExecError)
+ if !ok {
+ t.Fatalf("did not expect ExecError %s", eerr)
+ }
+ expect := "field X in type int"
+ if !strings.Contains(err.Error(), expect) {
+ t.Errorf("expected %q; got %q", expect, err)
+ }
+}