1package jmespath 2 3import ( 4 "fmt" 5 "testing" 6 7 "github.com/jmespath/go-jmespath/internal/testify/assert" 8) 9 10var lexingTests = []struct { 11 expression string 12 expected []token 13}{ 14 {"*", []token{{tStar, "*", 0, 1}}}, 15 {".", []token{{tDot, ".", 0, 1}}}, 16 {"[?", []token{{tFilter, "[?", 0, 2}}}, 17 {"[]", []token{{tFlatten, "[]", 0, 2}}}, 18 {"(", []token{{tLparen, "(", 0, 1}}}, 19 {")", []token{{tRparen, ")", 0, 1}}}, 20 {"[", []token{{tLbracket, "[", 0, 1}}}, 21 {"]", []token{{tRbracket, "]", 0, 1}}}, 22 {"{", []token{{tLbrace, "{", 0, 1}}}, 23 {"}", []token{{tRbrace, "}", 0, 1}}}, 24 {"||", []token{{tOr, "||", 0, 2}}}, 25 {"|", []token{{tPipe, "|", 0, 1}}}, 26 {"29", []token{{tNumber, "29", 0, 2}}}, 27 {"2", []token{{tNumber, "2", 0, 1}}}, 28 {"0", []token{{tNumber, "0", 0, 1}}}, 29 {"-20", []token{{tNumber, "-20", 0, 3}}}, 30 {"foo", []token{{tUnquotedIdentifier, "foo", 0, 3}}}, 31 {`"bar"`, []token{{tQuotedIdentifier, "bar", 0, 3}}}, 32 // Escaping the delimiter 33 {`"bar\"baz"`, []token{{tQuotedIdentifier, `bar"baz`, 0, 7}}}, 34 {",", []token{{tComma, ",", 0, 1}}}, 35 {":", []token{{tColon, ":", 0, 1}}}, 36 {"<", []token{{tLT, "<", 0, 1}}}, 37 {"<=", []token{{tLTE, "<=", 0, 2}}}, 38 {">", []token{{tGT, ">", 0, 1}}}, 39 {">=", []token{{tGTE, ">=", 0, 2}}}, 40 {"==", []token{{tEQ, "==", 0, 2}}}, 41 {"!=", []token{{tNE, "!=", 0, 2}}}, 42 {"`[0, 1, 2]`", []token{{tJSONLiteral, "[0, 1, 2]", 1, 9}}}, 43 {"'foo'", []token{{tStringLiteral, "foo", 1, 3}}}, 44 {"'a'", []token{{tStringLiteral, "a", 1, 1}}}, 45 {`'foo\'bar'`, []token{{tStringLiteral, "foo'bar", 1, 7}}}, 46 {"@", []token{{tCurrent, "@", 0, 1}}}, 47 {"&", []token{{tExpref, "&", 0, 1}}}, 48 // Quoted identifier unicode escape sequences 49 {`"\u2713"`, []token{{tQuotedIdentifier, "✓", 0, 3}}}, 50 {`"\\"`, []token{{tQuotedIdentifier, `\`, 0, 1}}}, 51 {"`\"foo\"`", []token{{tJSONLiteral, "\"foo\"", 1, 5}}}, 52 // Combinations of tokens. 53 {"foo.bar", []token{ 54 {tUnquotedIdentifier, "foo", 0, 3}, 55 {tDot, ".", 3, 1}, 56 {tUnquotedIdentifier, "bar", 4, 3}, 57 }}, 58 {"foo[0]", []token{ 59 {tUnquotedIdentifier, "foo", 0, 3}, 60 {tLbracket, "[", 3, 1}, 61 {tNumber, "0", 4, 1}, 62 {tRbracket, "]", 5, 1}, 63 }}, 64 {"foo[?a<b]", []token{ 65 {tUnquotedIdentifier, "foo", 0, 3}, 66 {tFilter, "[?", 3, 2}, 67 {tUnquotedIdentifier, "a", 5, 1}, 68 {tLT, "<", 6, 1}, 69 {tUnquotedIdentifier, "b", 7, 1}, 70 {tRbracket, "]", 8, 1}, 71 }}, 72} 73 74func TestCanLexTokens(t *testing.T) { 75 assert := assert.New(t) 76 lexer := NewLexer() 77 for _, tt := range lexingTests { 78 tokens, err := lexer.tokenize(tt.expression) 79 if assert.Nil(err) { 80 errMsg := fmt.Sprintf("Mismatch expected number of tokens: (expected: %s, actual: %s)", 81 tt.expected, tokens) 82 tt.expected = append(tt.expected, token{tEOF, "", len(tt.expression), 0}) 83 if assert.Equal(len(tt.expected), len(tokens), errMsg) { 84 for i, token := range tokens { 85 expected := tt.expected[i] 86 assert.Equal(expected, token, "Token not equal") 87 } 88 } 89 } 90 } 91} 92 93var lexingErrorTests = []struct { 94 expression string 95 msg string 96}{ 97 {"'foo", "Missing closing single quote"}, 98 {"[?foo==bar?]", "Unknown char '?'"}, 99} 100 101func TestLexingErrors(t *testing.T) { 102 assert := assert.New(t) 103 lexer := NewLexer() 104 for _, tt := range lexingErrorTests { 105 _, err := lexer.tokenize(tt.expression) 106 assert.NotNil(err, fmt.Sprintf("Expected lexing error: %s", tt.msg)) 107 } 108} 109 110var exprIdentifier = "abcdefghijklmnopqrstuvwxyz" 111var exprSubexpr = "abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz" 112var deeplyNested50 = "j49.j48.j47.j46.j45.j44.j43.j42.j41.j40.j39.j38.j37.j36.j35.j34.j33.j32.j31.j30.j29.j28.j27.j26.j25.j24.j23.j22.j21.j20.j19.j18.j17.j16.j15.j14.j13.j12.j11.j10.j9.j8.j7.j6.j5.j4.j3.j2.j1.j0" 113var deeplyNested50Pipe = "j49|j48|j47|j46|j45|j44|j43|j42|j41|j40|j39|j38|j37|j36|j35|j34|j33|j32|j31|j30|j29|j28|j27|j26|j25|j24|j23|j22|j21|j20|j19|j18|j17|j16|j15|j14|j13|j12|j11|j10|j9|j8|j7|j6|j5|j4|j3|j2|j1|j0" 114var deeplyNested50Index = "[49][48][47][46][45][44][43][42][41][40][39][38][37][36][35][34][33][32][31][30][29][28][27][26][25][24][23][22][21][20][19][18][17][16][15][14][13][12][11][10][9][8][7][6][5][4][3][2][1][0]" 115var deepProjection104 = "a[*].b[*].c[*].d[*].e[*].f[*].g[*].h[*].i[*].j[*].k[*].l[*].m[*].n[*].o[*].p[*].q[*].r[*].s[*].t[*].u[*].v[*].w[*].x[*].y[*].z[*].a[*].b[*].c[*].d[*].e[*].f[*].g[*].h[*].i[*].j[*].k[*].l[*].m[*].n[*].o[*].p[*].q[*].r[*].s[*].t[*].u[*].v[*].w[*].x[*].y[*].z[*].a[*].b[*].c[*].d[*].e[*].f[*].g[*].h[*].i[*].j[*].k[*].l[*].m[*].n[*].o[*].p[*].q[*].r[*].s[*].t[*].u[*].v[*].w[*].x[*].y[*].z[*].a[*].b[*].c[*].d[*].e[*].f[*].g[*].h[*].i[*].j[*].k[*].l[*].m[*].n[*].o[*].p[*].q[*].r[*].s[*].t[*].u[*].v[*].w[*].x[*].y[*].z[*]" 116var exprQuotedIdentifier = `"abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz"` 117var quotedIdentifierEscapes = `"\n\r\b\t\n\r\b\t\n\r\b\t\n\r\b\t\n\r\b\t\n\r\b\t\n\r\b\t"` 118var rawStringLiteral = `'abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz'` 119 120func BenchmarkLexIdentifier(b *testing.B) { 121 runLexBenchmark(b, exprIdentifier) 122} 123 124func BenchmarkLexSubexpression(b *testing.B) { 125 runLexBenchmark(b, exprSubexpr) 126} 127 128func BenchmarkLexDeeplyNested50(b *testing.B) { 129 runLexBenchmark(b, deeplyNested50) 130} 131 132func BenchmarkLexDeepNested50Pipe(b *testing.B) { 133 runLexBenchmark(b, deeplyNested50Pipe) 134} 135 136func BenchmarkLexDeepNested50Index(b *testing.B) { 137 runLexBenchmark(b, deeplyNested50Index) 138} 139 140func BenchmarkLexQuotedIdentifier(b *testing.B) { 141 runLexBenchmark(b, exprQuotedIdentifier) 142} 143 144func BenchmarkLexQuotedIdentifierEscapes(b *testing.B) { 145 runLexBenchmark(b, quotedIdentifierEscapes) 146} 147 148func BenchmarkLexRawStringLiteral(b *testing.B) { 149 runLexBenchmark(b, rawStringLiteral) 150} 151 152func BenchmarkLexDeepProjection104(b *testing.B) { 153 runLexBenchmark(b, deepProjection104) 154} 155 156func runLexBenchmark(b *testing.B, expression string) { 157 lexer := NewLexer() 158 for i := 0; i < b.N; i++ { 159 lexer.tokenize(expression) 160 } 161} 162