github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/clients/pkg/logentry/logql/parser_test.go (about)

     1  package logql
     2  
     3  import (
     4  	"strings"
     5  	"testing"
     6  	"text/scanner"
     7  
     8  	"github.com/prometheus/prometheus/model/labels"
     9  	"github.com/stretchr/testify/require"
    10  )
    11  
    12  func TestLex(t *testing.T) {
    13  	for _, tc := range []struct {
    14  		input    string
    15  		expected []int
    16  	}{
    17  		{`{foo="bar"}`, []int{OPEN_BRACE, IDENTIFIER, EQ, STRING, CLOSE_BRACE}},
    18  		{`{ foo = "bar" }`, []int{OPEN_BRACE, IDENTIFIER, EQ, STRING, CLOSE_BRACE}},
    19  		{`{ foo != "bar" }`, []int{OPEN_BRACE, IDENTIFIER, NEQ, STRING, CLOSE_BRACE}},
    20  		{`{ foo =~ "bar" }`, []int{OPEN_BRACE, IDENTIFIER, RE, STRING, CLOSE_BRACE}},
    21  		{`{ foo !~ "bar" }`, []int{OPEN_BRACE, IDENTIFIER, NRE, STRING, CLOSE_BRACE}},
    22  		{`{ foo = "bar", bar != "baz" }`, []int{OPEN_BRACE, IDENTIFIER, EQ, STRING,
    23  			COMMA, IDENTIFIER, NEQ, STRING, CLOSE_BRACE}},
    24  		{`{ foo = "ba\"r" }`, []int{OPEN_BRACE, IDENTIFIER, EQ, STRING, CLOSE_BRACE}},
    25  	} {
    26  		t.Run(tc.input, func(t *testing.T) {
    27  			actual := []int{}
    28  			l := lexer{
    29  				Scanner: scanner.Scanner{
    30  					Mode: scanner.SkipComments | scanner.ScanStrings,
    31  				},
    32  			}
    33  			l.Init(strings.NewReader(tc.input))
    34  			var lval exprSymType
    35  			for {
    36  				tok := l.Lex(&lval)
    37  				if tok == 0 {
    38  					break
    39  				}
    40  				actual = append(actual, tok)
    41  			}
    42  			require.Equal(t, tc.expected, actual)
    43  		})
    44  	}
    45  }
    46  
    47  func TestParse(t *testing.T) {
    48  	for _, tc := range []struct {
    49  		in  string
    50  		exp Expr
    51  		err error
    52  	}{
    53  		{
    54  			in:  `{foo="bar"}`,
    55  			exp: &matchersExpr{matchers: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}},
    56  		},
    57  		{
    58  			in:  `{ foo = "bar" }`,
    59  			exp: &matchersExpr{matchers: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}},
    60  		},
    61  		{
    62  			in:  `{ foo != "bar" }`,
    63  			exp: &matchersExpr{matchers: []*labels.Matcher{mustNewMatcher(labels.MatchNotEqual, "foo", "bar")}},
    64  		},
    65  		{
    66  			in:  `{ foo =~ "bar" }`,
    67  			exp: &matchersExpr{matchers: []*labels.Matcher{mustNewMatcher(labels.MatchRegexp, "foo", "bar")}},
    68  		},
    69  		{
    70  			in:  `{ foo !~ "bar" }`,
    71  			exp: &matchersExpr{matchers: []*labels.Matcher{mustNewMatcher(labels.MatchNotRegexp, "foo", "bar")}},
    72  		},
    73  		{
    74  			in: `{ foo = "bar", bar != "baz" }`,
    75  			exp: &matchersExpr{matchers: []*labels.Matcher{
    76  				mustNewMatcher(labels.MatchEqual, "foo", "bar"),
    77  				mustNewMatcher(labels.MatchNotEqual, "bar", "baz"),
    78  			}},
    79  		},
    80  		{
    81  			in: `{foo="bar"} |= "baz"`,
    82  			exp: &filterExpr{
    83  				left:  &matchersExpr{matchers: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}},
    84  				ty:    labels.MatchEqual,
    85  				match: "baz",
    86  			},
    87  		},
    88  		{
    89  			in: `{foo="bar"} |= "baz" |~ "blip" != "flip" !~ "flap"`,
    90  			exp: &filterExpr{
    91  				left: &filterExpr{
    92  					left: &filterExpr{
    93  						left: &filterExpr{
    94  							left:  &matchersExpr{matchers: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}},
    95  							ty:    labels.MatchEqual,
    96  							match: "baz",
    97  						},
    98  						ty:    labels.MatchRegexp,
    99  						match: "blip",
   100  					},
   101  					ty:    labels.MatchNotEqual,
   102  					match: "flip",
   103  				},
   104  				ty:    labels.MatchNotRegexp,
   105  				match: "flap",
   106  			},
   107  		},
   108  		{
   109  			in: `{foo="bar}`,
   110  			err: ParseError{
   111  				msg:  "literal not terminated",
   112  				line: 1,
   113  				col:  6,
   114  			},
   115  		},
   116  		{
   117  			in: `{foo="bar"`,
   118  			err: ParseError{
   119  				msg:  "syntax error: unexpected $end, expecting } or ,",
   120  				line: 1,
   121  				col:  11,
   122  			},
   123  		},
   124  
   125  		{
   126  			in: `{foo="bar"} |~`,
   127  			err: ParseError{
   128  				msg:  "syntax error: unexpected $end, expecting STRING",
   129  				line: 1,
   130  				col:  15,
   131  			},
   132  		},
   133  
   134  		{
   135  			in: `{foo="bar"} "foo"`,
   136  			err: ParseError{
   137  				msg:  "syntax error: unexpected STRING, expecting != or !~ or |~ or |=",
   138  				line: 1,
   139  				col:  13,
   140  			},
   141  		},
   142  		{
   143  			in: `{foo="bar"} foo`,
   144  			err: ParseError{
   145  				msg:  "syntax error: unexpected IDENTIFIER, expecting != or !~ or |~ or |=",
   146  				line: 1,
   147  				col:  13,
   148  			},
   149  		},
   150  	} {
   151  		t.Run(tc.in, func(t *testing.T) {
   152  			ast, err := ParseExpr(tc.in)
   153  			require.Equal(t, tc.err, err)
   154  			require.Equal(t, tc.exp, ast)
   155  		})
   156  	}
   157  }