Enhance lexer testing output

This commit is contained in:
Fabian Reinartz 2015-05-12 10:39:10 +02:00
parent 969c231191
commit d122749b39
2 changed files with 88 additions and 19 deletions

View file

@ -104,6 +104,8 @@ const (
itemString itemString
itemNumber itemNumber
itemDuration itemDuration
itemBlank
itemTimes
operatorsStart operatorsStart
// Operators. // Operators.
@ -193,6 +195,8 @@ var itemTypeStr = map[itemType]string{
itemComma: ",", itemComma: ",",
itemAssign: "=", itemAssign: "=",
itemSemicolon: ";", itemSemicolon: ";",
itemBlank: "_",
itemTimes: "x",
itemSUB: "-", itemSUB: "-",
itemADD: "+", itemADD: "+",
@ -214,6 +218,9 @@ func init() {
for s, ty := range key { for s, ty := range key {
itemTypeStr[ty] = s itemTypeStr[ty] = s
} }
// Special numbers.
key["inf"] = itemNumber
key["nan"] = itemNumber
} }
func (t itemType) String() string { func (t itemType) String() string {
@ -450,21 +457,6 @@ func lexStatements(l *lexer) stateFn {
case r == '"' || r == '\'': case r == '"' || r == '\'':
l.stringOpen = r l.stringOpen = r
return lexString return lexString
case r == 'N' || r == 'n' || r == 'I' || r == 'i':
n2 := strings.ToLower(l.input[l.pos:])
if len(n2) < 3 || !isAlphaNumeric(rune(n2[2])) {
if (r == 'N' || r == 'n') && strings.HasPrefix(n2, "an") {
l.pos += 2
l.emit(itemNumber)
break
}
if (r == 'I' || r == 'i') && strings.HasPrefix(n2, "nf") {
l.pos += 2
l.emit(itemNumber)
break
}
}
fallthrough
case isAlpha(r) || r == ':': case isAlpha(r) || r == ':':
l.backup() l.backup()
return lexKeywordOrIdentifier return lexKeywordOrIdentifier
@ -551,6 +543,34 @@ func lexInsideBraces(l *lexer) stateFn {
return lexInsideBraces return lexInsideBraces
} }
// lexValueSequence scans a value sequence of a series description.
func lexValueSequence(l *lexer) stateFn {
switch r := l.next(); {
case r == eof:
return lexStatements
case isSpace(r):
lexSpace(l)
case r == '+':
l.emit(itemADD)
case r == '-':
l.emit(itemSUB)
case r == 'x':
l.emit(itemTimes)
case r == '_':
l.emit(itemBlank)
case unicode.IsDigit(r) || (r == '.' && unicode.IsDigit(l.peek())):
l.backup()
lexNumber(l)
case isAlpha(r):
l.backup()
// We might lex invalid items here but this will be caught by the parser.
return lexKeywordOrIdentifier
default:
return l.errorf("unexpected character in series sequence: %q", r)
}
return lexValueSequence
}
// lexString scans a quoted string. The initial quote has already been seen. // lexString scans a quoted string. The initial quote has already been seen.
func lexString(l *lexer) stateFn { func lexString(l *lexer) stateFn {
Loop: Loop:

View file

@ -14,6 +14,7 @@
package promql package promql
import ( import (
"fmt"
"reflect" "reflect"
"testing" "testing"
) )
@ -354,6 +355,42 @@ var tests = []struct {
}, { }, {
input: `]`, fail: true, input: `]`, fail: true,
}, },
// Test series description.
{
input: `{} _ 1 x .3`,
expected: []item{
{itemLeftBrace, 0, `{`},
{itemRightBrace, 1, `}`},
{itemBlank, 3, `_`},
{itemNumber, 5, `1`},
{itemTimes, 7, `x`},
{itemNumber, 9, `.3`},
},
seriesDesc: true,
},
{
input: `metric +Inf Inf NaN`,
expected: []item{
{itemIdentifier, 0, `metric`},
{itemADD, 7, `+`},
{itemNumber, 8, `Inf`},
{itemNumber, 12, `Inf`},
{itemNumber, 16, `NaN`},
},
seriesDesc: true,
},
{
input: `metric 1+1x4`,
expected: []item{
{itemIdentifier, 0, `metric`},
{itemNumber, 7, `1`},
{itemADD, 8, `+`},
{itemNumber, 9, `1`},
{itemTimes, 10, `x`},
{itemNumber, 11, `4`},
},
seriesDesc: true,
},
} }
// TestLexer tests basic functionality of the lexer. More elaborate tests are implemented // TestLexer tests basic functionality of the lexer. More elaborate tests are implemented
@ -370,20 +407,32 @@ func TestLexer(t *testing.T) {
lastItem := out[len(out)-1] lastItem := out[len(out)-1]
if test.fail { if test.fail {
if lastItem.typ != itemError { if lastItem.typ != itemError {
t.Fatalf("%d: expected lexing error but did not fail", i) t.Logf("%d: input %q", i, test.input)
t.Fatalf("expected lexing error but did not fail")
} }
continue continue
} }
if lastItem.typ == itemError { if lastItem.typ == itemError {
t.Fatalf("%d: unexpected lexing error: %s", i, lastItem) t.Logf("%d: input %q", i, test.input)
t.Fatalf("unexpected lexing error at position %d: %s", lastItem.pos, lastItem)
} }
if !reflect.DeepEqual(lastItem, item{itemEOF, Pos(len(test.input)), ""}) { if !reflect.DeepEqual(lastItem, item{itemEOF, Pos(len(test.input)), ""}) {
t.Fatalf("%d: lexing error: expected output to end with EOF item", i) t.Logf("%d: input %q", i, test.input)
t.Fatalf("lexing error: expected output to end with EOF item.\ngot:\n%s", expectedList(out))
} }
out = out[:len(out)-1] out = out[:len(out)-1]
if !reflect.DeepEqual(out, test.expected) { if !reflect.DeepEqual(out, test.expected) {
t.Errorf("%d: lexing mismatch:\nexpected: %#v\n-----\ngot: %#v", i, test.expected, out) t.Logf("%d: input %q", i, test.input)
t.Fatalf("lexing mismatch:\nexpected:\n%s\ngot:\n%s", expectedList(test.expected), expectedList(out))
} }
} }
} }
func expectedList(exp []item) string {
s := ""
for _, it := range exp {
s += fmt.Sprintf("\t%#v\n", it)
}
return s
}