mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-01 00:33:05 +08:00
pkg/diag: Include line:col of start position in Error and Show methods.
The Error methods used to show the start and end indices, while the Show methods used to show line ranges. Showing line:col of the start position seems to be pretty standard; both Go and Rust do that. I tried including the line:col of the end position too, but can't find a good enough format.
This commit is contained in:
parent
1acc45cfc2
commit
78862465a4
|
@ -51,8 +51,7 @@ func (err cognateErrors) Error() string {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
sb.WriteString("; ")
|
sb.WriteString("; ")
|
||||||
}
|
}
|
||||||
// TODO: Include line and column numbers instead of byte indices.
|
fmt.Fprintf(&sb, "%s: %s", e.Context.culprit.describeStart(), e.Message)
|
||||||
fmt.Fprintf(&sb, "%d-%d: %s", e.Context.From, e.Context.To, e.Message)
|
|
||||||
}
|
}
|
||||||
return sb.String()
|
return sb.String()
|
||||||
}
|
}
|
||||||
|
@ -62,12 +61,12 @@ func (err cognateErrors) Show(indent string) string {
|
||||||
fmt.Fprintf(&sb, "Multiple %ss in %s:", err[0].Type, err[0].Context.Name)
|
fmt.Fprintf(&sb, "Multiple %ss in %s:", err[0].Type, err[0].Context.Name)
|
||||||
for _, e := range err {
|
for _, e := range err {
|
||||||
sb.WriteString("\n" + indent + " ")
|
sb.WriteString("\n" + indent + " ")
|
||||||
fmt.Fprintf(&sb, "\033[31;1m%s\033[m", e.Message)
|
sb.WriteString(messageStart + e.Message + messageEnd)
|
||||||
sb.WriteString("\n" + indent + " ")
|
sb.WriteString("\n" + indent + " ")
|
||||||
// This duplicates part of [Context.ShowCompact].
|
// This duplicates part of [Context.ShowCompact].
|
||||||
desc := e.Context.lineRange() + " "
|
desc := e.Context.culprit.describeStart() + ": "
|
||||||
descIndent := strings.Repeat(" ", wcwidth.Of(desc))
|
descIndent := strings.Repeat(" ", wcwidth.Of(desc))
|
||||||
sb.WriteString(desc + e.Context.relevantSource(indent+" "+descIndent))
|
sb.WriteString(desc + e.Context.culprit.Show(indent+" "+descIndent))
|
||||||
}
|
}
|
||||||
return sb.String()
|
return sb.String()
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,51 +22,33 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
var cognateErrorsTests = []struct {
|
var cognateErrorsTests = []struct {
|
||||||
name string
|
name string
|
||||||
errs []*Error
|
errs []*Error
|
||||||
wantError string
|
wantErr error
|
||||||
wantShow string
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "no error",
|
name: "no error",
|
||||||
errs: nil,
|
errs: nil,
|
||||||
wantError: "",
|
wantErr: nil,
|
||||||
wantShow: "",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "one error",
|
name: "one error",
|
||||||
errs: []*Error{err1},
|
errs: []*Error{err1},
|
||||||
wantError: err1.Error(),
|
wantErr: err1,
|
||||||
wantShow: err1.Show(""),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "multiple errors",
|
name: "multiple errors",
|
||||||
errs: []*Error{err1, err2},
|
errs: []*Error{err1, err2},
|
||||||
wantError: "multiple foo errors in [test]: 5-8: bad 1; 5-8: bad 2",
|
wantErr: cognateErrors{err1, err2},
|
||||||
wantShow: lines(
|
|
||||||
"Multiple foo errors in [test]:",
|
|
||||||
" \x1b[31;1mbad 1\x1b[m",
|
|
||||||
" line 1: echo \x1b[1;4m(1)\x1b[m",
|
|
||||||
" \x1b[31;1mbad 2\x1b[m",
|
|
||||||
" line 1: echo \x1b[1;4m(2)\x1b[m"),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCognateErrors(t *testing.T) {
|
func TestPackAndUnpackCognateErrors(t *testing.T) {
|
||||||
for _, tc := range cognateErrorsTests {
|
for _, tc := range cognateErrorsTests {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
err := PackCognateErrors(tc.errs)
|
err := PackCognateErrors(tc.errs)
|
||||||
if err == nil {
|
if !reflect.DeepEqual(err, tc.wantErr) {
|
||||||
if tc.wantError != "" || tc.wantShow != "" {
|
t.Errorf("got packed error %#v, want %#v", err, tc.wantErr)
|
||||||
t.Errorf("Want non-nil error, got nil")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if got := err.Error(); got != tc.wantError {
|
|
||||||
t.Errorf("Error() (-want +got):\n%s", cmp.Diff(tc.wantError, got))
|
|
||||||
}
|
|
||||||
if got := err.(Shower).Show(""); got != tc.wantShow {
|
|
||||||
t.Errorf("Show() (-want +got):\n%s", cmp.Diff(tc.wantShow, got))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
unpacked := UnpackCognateErrors(err)
|
unpacked := UnpackCognateErrors(err)
|
||||||
if !reflect.DeepEqual(unpacked, tc.errs) {
|
if !reflect.DeepEqual(unpacked, tc.errs) {
|
||||||
|
@ -82,3 +64,24 @@ func TestUnpackCognateErrors_CalledWithOtherErrorType(t *testing.T) {
|
||||||
t.Errorf("want nil, got %v", unpacked)
|
t.Errorf("want nil, got %v", unpacked)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCognateErrors(t *testing.T) {
|
||||||
|
setCulpritMarkers(t, "<", ">")
|
||||||
|
setMessageMarkers(t, "{", "}")
|
||||||
|
err := PackCognateErrors([]*Error{err1, err2})
|
||||||
|
wantError := "multiple foo errors in [test]: 1:6: bad 1; 1:6: bad 2"
|
||||||
|
if s := err.Error(); s != wantError {
|
||||||
|
t.Errorf(".Error() returns unexpected result (-want +got):\n%s",
|
||||||
|
cmp.Diff(wantError, s))
|
||||||
|
}
|
||||||
|
wantShow := dedent(`
|
||||||
|
Multiple foo errors in [test]:
|
||||||
|
{bad 1}
|
||||||
|
1:6: echo <(1)>
|
||||||
|
{bad 2}
|
||||||
|
1:6: echo <(2)>`)
|
||||||
|
if show := err.(Shower).Show(""); show != wantShow {
|
||||||
|
t.Errorf(".Show(\"\") returns unexpected result (-want +got):\n%s",
|
||||||
|
cmp.Diff(wantShow, show))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package diag
|
package diag
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -11,132 +10,102 @@ import (
|
||||||
// Context is a range of text in a source code. It is typically used for
|
// Context is a range of text in a source code. It is typically used for
|
||||||
// errors that can be associated with a part of the source code, like parse
|
// errors that can be associated with a part of the source code, like parse
|
||||||
// errors and a traceback entry.
|
// errors and a traceback entry.
|
||||||
|
//
|
||||||
|
// Context values should only be constructed using [NewContext].
|
||||||
type Context struct {
|
type Context struct {
|
||||||
Name string
|
Name string
|
||||||
Source string
|
Source string
|
||||||
Ranging
|
Ranging
|
||||||
|
|
||||||
savedShowInfo *rangeShowInfo
|
culprit culprit
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewContext creates a new Context.
|
// NewContext creates a new Context.
|
||||||
func NewContext(name, source string, r Ranger) *Context {
|
func NewContext(name, source string, r Ranger) *Context {
|
||||||
return &Context{name, source, r.Range(), nil}
|
rg := r.Range()
|
||||||
|
return &Context{name, source, rg, makeCulprit(source, rg)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Information about the source range that are needed for showing.
|
// Show shows a SourceContext.
|
||||||
type rangeShowInfo struct {
|
func (c *Context) Show(indent string) string {
|
||||||
// Head is the piece of text immediately before Culprit, extending to, but
|
return fmt.Sprintf("%s:%s:\n%s%s",
|
||||||
// not including the closest line boundary. If Culprit already starts after
|
c.Name, c.culprit.describeStart(), indent+" ", c.culprit.Show(indent+" "))
|
||||||
// a line boundary, Head is an empty string.
|
}
|
||||||
|
|
||||||
|
// ShowCompact shows a Context, with no line break between the culprit range
|
||||||
|
// description and relevant source excerpt.
|
||||||
|
func (c *Context) ShowCompact(indent string) string {
|
||||||
|
desc := fmt.Sprintf("%s:%s: ", c.Name, c.culprit.describeStart())
|
||||||
|
// Extra indent so that following lines line up with the first line.
|
||||||
|
descIndent := strings.Repeat(" ", wcwidth.Of(desc))
|
||||||
|
return desc + c.culprit.Show(indent+descIndent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Information about the lines that contain the culprit.
|
||||||
|
type culprit struct {
|
||||||
|
// The actual culprit text.
|
||||||
|
Body string
|
||||||
|
// Text before Body on its first line.
|
||||||
Head string
|
Head string
|
||||||
// Culprit is Source[Begin:End], with any trailing newlines stripped.
|
// Text after Body on its last line.
|
||||||
Culprit string
|
|
||||||
// Tail is the piece of text immediately after Culprit, extending to, but
|
|
||||||
// not including the closet line boundary. If Culprit already ends before a
|
|
||||||
// line boundary, Tail is an empty string.
|
|
||||||
Tail string
|
Tail string
|
||||||
// BeginLine is the (1-based) line number that the first character of Culprit is on.
|
// 1-based line and column numbers of the start position.
|
||||||
BeginLine int
|
StartLine, StartCol int
|
||||||
// EndLine is the (1-based) line number that the last character of Culprit is on.
|
|
||||||
EndLine int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Variables controlling the style of the culprit.
|
func makeCulprit(source string, r Ranging) culprit {
|
||||||
var (
|
before := source[:r.From]
|
||||||
culpritLineBegin = "\033[1;4m"
|
body := source[r.From:r.To]
|
||||||
culpritLineEnd = "\033[m"
|
after := source[r.To:]
|
||||||
culpritPlaceHolder = "^"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *Context) showInfo() *rangeShowInfo {
|
|
||||||
if c.savedShowInfo != nil {
|
|
||||||
return c.savedShowInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
before := c.Source[:c.From]
|
|
||||||
culprit := c.Source[c.From:c.To]
|
|
||||||
after := c.Source[c.To:]
|
|
||||||
|
|
||||||
head := lastLine(before)
|
head := lastLine(before)
|
||||||
beginLine := strings.Count(before, "\n") + 1
|
fromLine := strings.Count(before, "\n") + 1
|
||||||
|
fromCol := 1 + wcwidth.Of(head)
|
||||||
|
|
||||||
// If the culprit ends with a newline, stripe it. Otherwise, tail is nonempty.
|
// If the culprit ends with a newline, stripe it, and tail is empty.
|
||||||
|
// Otherwise, tail is nonempty.
|
||||||
var tail string
|
var tail string
|
||||||
if strings.HasSuffix(culprit, "\n") {
|
if strings.HasSuffix(body, "\n") {
|
||||||
culprit = culprit[:len(culprit)-1]
|
body = body[:len(body)-1]
|
||||||
} else {
|
} else {
|
||||||
tail = firstLine(after)
|
tail = firstLine(after)
|
||||||
}
|
}
|
||||||
|
|
||||||
endLine := beginLine + strings.Count(culprit, "\n")
|
return culprit{body, head, tail, fromLine, fromCol}
|
||||||
|
|
||||||
c.savedShowInfo = &rangeShowInfo{head, culprit, tail, beginLine, endLine}
|
|
||||||
return c.savedShowInfo
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show shows a SourceContext.
|
// Variables controlling the style of the culprit.
|
||||||
func (c *Context) Show(sourceIndent string) string {
|
var (
|
||||||
if err := c.checkPosition(); err != nil {
|
culpritStart = "\033[1;4m"
|
||||||
return err.Error()
|
culpritEnd = "\033[m"
|
||||||
}
|
culpritPlaceHolder = "^"
|
||||||
return (c.Name + ", " + c.lineRange() +
|
)
|
||||||
"\n" + sourceIndent + c.relevantSource(sourceIndent))
|
|
||||||
|
func (cl *culprit) describeStart() string {
|
||||||
|
return fmt.Sprintf("%d:%d", cl.StartLine, cl.StartCol)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShowCompact shows a SourceContext, with no line break between the
|
func (cl *culprit) Show(indent string) string {
|
||||||
// source position range description and relevant source excerpt.
|
var sb strings.Builder
|
||||||
func (c *Context) ShowCompact(sourceIndent string) string {
|
sb.WriteString(cl.Head)
|
||||||
if err := c.checkPosition(); err != nil {
|
|
||||||
return err.Error()
|
|
||||||
}
|
|
||||||
desc := c.Name + ", " + c.lineRange() + " "
|
|
||||||
// Extra indent so that following lines line up with the first line.
|
|
||||||
descIndent := strings.Repeat(" ", wcwidth.Of(desc))
|
|
||||||
return desc + c.relevantSource(sourceIndent+descIndent)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Context) checkPosition() error {
|
body := cl.Body
|
||||||
if c.From == -1 {
|
if body == "" {
|
||||||
return fmt.Errorf("%s, unknown position", c.Name)
|
body = culpritPlaceHolder
|
||||||
} else if c.From < 0 || c.To > len(c.Source) || c.From > c.To {
|
|
||||||
return fmt.Errorf("%s, invalid position %d-%d", c.Name, c.From, c.To)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Context) lineRange() string {
|
|
||||||
info := c.showInfo()
|
|
||||||
|
|
||||||
if info.BeginLine == info.EndLine {
|
|
||||||
return fmt.Sprintf("line %d:", info.BeginLine)
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("line %d-%d:", info.BeginLine, info.EndLine)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Context) relevantSource(sourceIndent string) string {
|
|
||||||
info := c.showInfo()
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
buf.WriteString(info.Head)
|
|
||||||
|
|
||||||
culprit := info.Culprit
|
|
||||||
if culprit == "" {
|
|
||||||
culprit = culpritPlaceHolder
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, line := range strings.Split(culprit, "\n") {
|
for i, line := range strings.Split(body, "\n") {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
buf.WriteByte('\n')
|
sb.WriteByte('\n')
|
||||||
buf.WriteString(sourceIndent)
|
sb.WriteString(indent)
|
||||||
}
|
}
|
||||||
buf.WriteString(culpritLineBegin)
|
sb.WriteString(culpritStart)
|
||||||
buf.WriteString(line)
|
sb.WriteString(line)
|
||||||
buf.WriteString(culpritLineEnd)
|
sb.WriteString(culpritEnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.WriteString(info.Tail)
|
sb.WriteString(cl.Tail)
|
||||||
return buf.String()
|
return sb.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func firstLine(s string) string {
|
func firstLine(s string) string {
|
||||||
|
|
|
@ -18,69 +18,47 @@ var sourceRangeTests = []struct {
|
||||||
Context: contextInParen("[test]", "echo (bad)"),
|
Context: contextInParen("[test]", "echo (bad)"),
|
||||||
Indent: "_",
|
Indent: "_",
|
||||||
|
|
||||||
WantShow: lines(
|
WantShow: dedent(`
|
||||||
"[test], line 1:",
|
[test]:1:6:
|
||||||
"_echo <(bad)>",
|
_ echo <(bad)>`),
|
||||||
),
|
WantShowCompact: "[test]:1:6: echo <(bad)>",
|
||||||
WantShowCompact: "[test], line 1: echo <(bad)>",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "multi-line culprit",
|
Name: "multi-line culprit",
|
||||||
Context: contextInParen("[test]", "echo (bad\nbad)\nmore"),
|
Context: contextInParen("[test]", "echo (bad\nbad)\nmore"),
|
||||||
Indent: "_",
|
Indent: "_",
|
||||||
|
|
||||||
WantShow: lines(
|
WantShow: dedent(`
|
||||||
"[test], line 1-2:",
|
[test]:1:6:
|
||||||
"_echo <(bad>",
|
_ echo <(bad>
|
||||||
"_<bad)>",
|
_ <bad)>`),
|
||||||
),
|
WantShowCompact: dedent(`
|
||||||
WantShowCompact: lines(
|
[test]:1:6: echo <(bad>
|
||||||
"[test], line 1-2: echo <(bad>",
|
_ <bad)>`),
|
||||||
"_ <bad)>",
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "trailing newline in culprit is removed",
|
Name: "trailing newline in culprit is removed",
|
||||||
// 012345678 9
|
|
||||||
Context: NewContext("[test]", "echo bad\n", Ranging{5, 9}),
|
Context: NewContext("[test]", "echo bad\n", Ranging{5, 9}),
|
||||||
Indent: "_",
|
Indent: "_",
|
||||||
|
|
||||||
WantShow: lines(
|
WantShow: dedent(`
|
||||||
"[test], line 1:",
|
[test]:1:6:
|
||||||
"_echo <bad>",
|
_ echo <bad>`),
|
||||||
),
|
WantShowCompact: "[test]:1:6: echo <bad>",
|
||||||
WantShowCompact: lines(
|
|
||||||
"[test], line 1: echo <bad>",
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "empty culprit",
|
Name: "empty culprit",
|
||||||
// 012345
|
|
||||||
Context: NewContext("[test]", "echo x", Ranging{5, 5}),
|
Context: NewContext("[test]", "echo x", Ranging{5, 5}),
|
||||||
|
|
||||||
WantShow: lines(
|
WantShow: dedent(`
|
||||||
"[test], line 1:",
|
[test]:1:6:
|
||||||
"echo <^>x",
|
echo <^>x`),
|
||||||
),
|
WantShowCompact: "[test]:1:6: echo <^>x",
|
||||||
WantShowCompact: "[test], line 1: echo <^>x",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "unknown culprit range",
|
|
||||||
Context: NewContext("[test]", "echo", Ranging{-1, -1}),
|
|
||||||
WantShow: "[test], unknown position",
|
|
||||||
WantShowCompact: "[test], unknown position",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "invalid culprit range",
|
|
||||||
Context: NewContext("[test]", "echo", Ranging{2, 1}),
|
|
||||||
WantShow: "[test], invalid position 2-1",
|
|
||||||
WantShowCompact: "[test], invalid position 2-1",
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContext(t *testing.T) {
|
func TestContext(t *testing.T) {
|
||||||
culpritLineBegin = "<"
|
setCulpritMarkers(t, "<", ">")
|
||||||
culpritLineEnd = ">"
|
|
||||||
for _, test := range sourceRangeTests {
|
for _, test := range sourceRangeTests {
|
||||||
t.Run(test.Name, func(t *testing.T) {
|
t.Run(test.Name, func(t *testing.T) {
|
||||||
gotShow := test.Context.Show(test.Indent)
|
gotShow := test.Context.Show(test.Indent)
|
||||||
|
|
|
@ -15,9 +15,8 @@ type Error struct {
|
||||||
|
|
||||||
// Error returns a plain text representation of the error.
|
// Error returns a plain text representation of the error.
|
||||||
func (e *Error) Error() string {
|
func (e *Error) Error() string {
|
||||||
// TODO: Include line and column numbers instead of byte indices.
|
return fmt.Sprintf("%s: %s:%s: %s",
|
||||||
return fmt.Sprintf("%s: %d-%d in %s: %s",
|
e.Type, e.Context.Name, e.Context.culprit.describeStart(), e.Message)
|
||||||
e.Type, e.Context.From, e.Context.To, e.Context.Name, e.Message)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Range returns the range of the error.
|
// Range returns the range of the error.
|
||||||
|
@ -25,8 +24,14 @@ func (e *Error) Range() Ranging {
|
||||||
return e.Context.Range()
|
return e.Context.Range()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
messageStart = "\033[31;1m"
|
||||||
|
messageEnd = "\033[m"
|
||||||
|
)
|
||||||
|
|
||||||
// Show shows the error.
|
// Show shows the error.
|
||||||
func (e *Error) Show(indent string) string {
|
func (e *Error) Show(indent string) string {
|
||||||
header := fmt.Sprintf("%s: \033[31;1m%s\033[m\n", strutil.Title(e.Type), e.Message)
|
return fmt.Sprintf("%s: %s%s%s\n%s%s",
|
||||||
return header + e.Context.ShowCompact(indent+" ")
|
strutil.Title(e.Type), messageStart, e.Message, messageEnd,
|
||||||
|
indent+" ", e.Context.ShowCompact(indent+" "))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
package diag
|
package diag
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"src.elv.sh/pkg/testutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestError(t *testing.T) {
|
func TestError(t *testing.T) {
|
||||||
testutil.Set(t, &culpritLineBegin, "<")
|
setCulpritMarkers(t, "<", ">")
|
||||||
testutil.Set(t, &culpritLineEnd, ">")
|
setMessageMarkers(t, "{", "}")
|
||||||
|
|
||||||
err := &Error{
|
err := &Error{
|
||||||
Type: "some error",
|
Type: "some error",
|
||||||
|
@ -17,7 +14,7 @@ func TestError(t *testing.T) {
|
||||||
Context: *contextInParen("[test]", "echo (x)"),
|
Context: *contextInParen("[test]", "echo (x)"),
|
||||||
}
|
}
|
||||||
|
|
||||||
wantErrorString := "some error: 5-8 in [test]: bad list"
|
wantErrorString := "some error: [test]:1:6: bad list"
|
||||||
if gotErrorString := err.Error(); gotErrorString != wantErrorString {
|
if gotErrorString := err.Error(); gotErrorString != wantErrorString {
|
||||||
t.Errorf("Error() -> %q, want %q", gotErrorString, wantErrorString)
|
t.Errorf("Error() -> %q, want %q", gotErrorString, wantErrorString)
|
||||||
}
|
}
|
||||||
|
@ -27,16 +24,11 @@ func TestError(t *testing.T) {
|
||||||
t.Errorf("Range() -> %v, want %v", gotRanging, wantRanging)
|
t.Errorf("Range() -> %v, want %v", gotRanging, wantRanging)
|
||||||
}
|
}
|
||||||
|
|
||||||
wantShow := lines(
|
// Type is capitalized in return value of Show
|
||||||
// Type is capitalized in return value of Show
|
wantShow := dedent(`
|
||||||
"Some error: \033[31;1mbad list\033[m",
|
Some error: {bad list}
|
||||||
"[test], line 1: echo <(x)>",
|
[test]:1:6: echo <(x)>`)
|
||||||
)
|
|
||||||
if gotShow := err.Show(""); gotShow != wantShow {
|
if gotShow := err.Show(""); gotShow != wantShow {
|
||||||
t.Errorf("Show() -> %q, want %q", gotShow, wantShow)
|
t.Errorf("Show() -> %q, want %q", gotShow, wantShow)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func lines(lines ...string) string {
|
|
||||||
return strings.Join(lines, "\n")
|
|
||||||
}
|
|
||||||
|
|
19
pkg/diag/testutil_test.go
Normal file
19
pkg/diag/testutil_test.go
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
package diag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"src.elv.sh/pkg/testutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
var dedent = testutil.Dedent
|
||||||
|
|
||||||
|
func setCulpritMarkers(t *testing.T, start, end string) {
|
||||||
|
testutil.Set(t, &culpritStart, start)
|
||||||
|
testutil.Set(t, &culpritEnd, end)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setMessageMarkers(t *testing.T, start, end string) {
|
||||||
|
testutil.Set(t, &messageStart, start)
|
||||||
|
testutil.Set(t, &messageEnd, end)
|
||||||
|
}
|
|
@ -58,7 +58,7 @@ func TestCompile(t *testing.T) {
|
||||||
Filter("[re '[']").
|
Filter("[re '[']").
|
||||||
DoesNotCompile("error parsing regexp: missing closing ]: `[`"),
|
DoesNotCompile("error parsing regexp: missing closing ]: `[`"),
|
||||||
That("invalid syntax results in parse error").
|
That("invalid syntax results in parse error").
|
||||||
Filter("[and").DoesNotParse("parse error: 4-4 in [filter]: should be ']'"),
|
Filter("[and").DoesNotParse("parse error: [filter]:1:5: should be ']'"),
|
||||||
|
|
||||||
// Unsupported for now, but may be in future
|
// Unsupported for now, but may be in future
|
||||||
That("options are not supported yet").
|
That("options are not supported yet").
|
||||||
|
|
|
@ -30,7 +30,7 @@ func TestHighlighter(t *testing.T) {
|
||||||
f.TestTTY(t,
|
f.TestTTY(t,
|
||||||
"~> put $truex", Styles,
|
"~> put $truex", Styles,
|
||||||
" vvv ??????", term.DotHere, "\n",
|
" vvv ??????", term.DotHere, "\n",
|
||||||
"compilation error: 4-10 in [interactive]: variable $truex not found",
|
"compilation error: [interactive]:1:5: variable $truex not found",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -137,8 +137,7 @@ func (cp *compiler) deprecate(r diag.Ranger, msg string, minLevel int) {
|
||||||
if prog.DeprecationLevel >= minLevel && cp.deprecations.register(dep) {
|
if prog.DeprecationLevel >= minLevel && cp.deprecations.register(dep) {
|
||||||
err := diag.Error{
|
err := diag.Error{
|
||||||
Type: "deprecation", Message: msg,
|
Type: "deprecation", Message: msg,
|
||||||
Context: diag.Context{
|
Context: *diag.NewContext(cp.srcMeta.Name, cp.srcMeta.Code, r.Range())}
|
||||||
Name: cp.srcMeta.Name, Source: cp.srcMeta.Code, Ranging: r.Range()}}
|
|
||||||
fmt.Fprintln(cp.warn, err.Show(""))
|
fmt.Fprintln(cp.warn, err.Show(""))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,7 @@ func (exc *exception) Show(indent string) string {
|
||||||
buf.WriteString(indent + "Traceback:")
|
buf.WriteString(indent + "Traceback:")
|
||||||
for tb := exc.stackTrace; tb != nil; tb = tb.Next {
|
for tb := exc.stackTrace; tb != nil; tb = tb.Next {
|
||||||
buf.WriteString("\n" + indent + " ")
|
buf.WriteString("\n" + indent + " ")
|
||||||
buf.WriteString(tb.Head.Show(indent + " "))
|
buf.WriteString(tb.Head.Show(indent + " "))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user