| 184 | } |
| 185 | |
| 186 | func TestErrorFormat(t *testing.T) { |
| 187 | // Capture the first line of output as the error message and all following |
| 188 | // lines as the stack trace. |
| 189 | re := regexp.MustCompile(`(.+)?((?s) |
| 190 | .+/redact.TestErrorFormat |
| 191 | .+/redact/redact_test.go:\d+ |
| 192 | .* |
| 193 | runtime.goexit |
| 194 | .+:\d+.*)?`) |
| 195 | |
| 196 | cases := []struct { |
| 197 | format string |
| 198 | err error |
| 199 | wantMsg string |
| 200 | wantStack bool |
| 201 | }{ |
| 202 | {"%v", Errorf("error %%v"), "error %v", false}, |
| 203 | {"%+v", Errorf("error %%+v"), "error %+v", true}, |
| 204 | {"%s", Errorf("error %%s"), "error %s", false}, |
| 205 | {"%+s", Errorf("error %%+s"), "error %+s", true}, |
| 206 | {"%q", Errorf("error %%q"), `"error %q"`, false}, |
| 207 | } |
| 208 | for _, test := range cases { |
| 209 | t.Run(test.format, func(t *testing.T) { |
| 210 | got := fmt.Sprintf(test.format, test.err) |
| 211 | groups := re.FindStringSubmatch(got) |
| 212 | if groups == nil { |
| 213 | t.Fatal("formatted error doesn't match regexp") |
| 214 | } |
| 215 | t.Logf("got formatted stack trace:\n%q", got) |
| 216 | if got := groups[1]; got != test.wantMsg { |
| 217 | t.Errorf("got error message %q, want %q", got, test.wantMsg) |
| 218 | } |
| 219 | if test.wantStack && (len(groups) < 3 || groups[2] == "") { |
| 220 | t.Error("got formatted error without stack trace, wanted with stack trace") |
| 221 | } else if !test.wantStack && len(groups) > 2 && groups[2] != "" { |
| 222 | t.Error("got formatted error with stack trace, wanted without stack trace") |
| 223 | } |
| 224 | }) |
| 225 | } |
| 226 | } |
| 227 | |
| 228 | func TestStackTrace(t *testing.T) { |
| 229 | err := Errorf("error") |