github.com/attic-labs/noms@v0.0.0-20210827224422-e5fa29d95e8b/samples/go/nomdex/parser_test.go (about)

     1  // Copyright 2016 Attic Labs, Inc. All rights reserved.
     2  // Licensed under the Apache License, version 2.0:
     3  // http://www.apache.org/licenses/LICENSE-2.0
     4  
     5  package main
     6  
     7  import (
     8  	"testing"
     9  	"text/scanner"
    10  
    11  	"github.com/attic-labs/noms/go/chunks"
    12  	"github.com/attic-labs/noms/go/datas"
    13  	"github.com/attic-labs/noms/go/types"
    14  	"github.com/stretchr/testify/assert"
    15  )
    16  
    17  type scannerResult struct {
    18  	tok  int
    19  	text string
    20  }
    21  
    22  type parseResult struct {
    23  	query string
    24  	ex    expr
    25  }
    26  
    27  func TestQueryScanner(t *testing.T) {
    28  	assert := assert.New(t)
    29  
    30  	s := NewQueryScanner(`9 (99.9) -9 0x7F "99.9" and or http://localhost:8000/cli-tour::yo <= >= < > = _ !=`)
    31  
    32  	scannerResults := []scannerResult{
    33  		{tok: scanner.Int, text: "9"},
    34  		{tok: int('('), text: "("},
    35  		{tok: scanner.Float, text: "99.9"},
    36  		{tok: int(')'), text: ")"},
    37  		{tok: '-', text: "-"},
    38  		{tok: scanner.Int, text: "9"},
    39  		{tok: scanner.Int, text: "0x7F"},
    40  		{tok: scanner.String, text: `"99.9"`},
    41  		{tok: scanner.Ident, text: "and"},
    42  		{tok: scanner.Ident, text: "or"},
    43  		{tok: scanner.Ident, text: "http://localhost:8000/cli-tour::yo"},
    44  		{tok: scanner.Ident, text: "<="},
    45  		{tok: scanner.Ident, text: ">="},
    46  		{tok: scanner.Ident, text: "<"},
    47  		{tok: scanner.Ident, text: ">"},
    48  		{tok: int('='), text: "="},
    49  		{tok: int('_'), text: "_"},
    50  		{tok: scanner.Ident, text: "!="},
    51  	}
    52  
    53  	for _, sr := range scannerResults {
    54  		tok := s.Scan()
    55  		assert.Equal(sr.tok, int(tok), "expected text: %s, found: %s, pos: %s", sr.text, s.TokenText(), s.Pos())
    56  		assert.Equal(sr.text, s.TokenText())
    57  	}
    58  	tok := s.Scan()
    59  	assert.Equal(scanner.EOF, int(tok))
    60  }
    61  
    62  func TestPeek(t *testing.T) {
    63  	assert := assert.New(t)
    64  
    65  	s := NewQueryScanner(`_ < "one"`)
    66  	scannerResults := []scannerResult{
    67  		{tok: int('_'), text: "_"},
    68  		{tok: scanner.Ident, text: "<"},
    69  		{tok: scanner.String, text: `"one"`},
    70  		{tok: scanner.EOF, text: ""},
    71  	}
    72  
    73  	for _, sr := range scannerResults {
    74  		assert.Equal(sr.tok, int(s.Peek()))
    75  		assert.Equal(sr.text, s.TokenText())
    76  		assert.Equal(sr.tok, int(s.Scan()))
    77  		assert.Equal(sr.text, s.TokenText())
    78  	}
    79  }
    80  
    81  func TestParsing(t *testing.T) {
    82  	assert := assert.New(t)
    83  
    84  	re1 := compExpr{"index1", equals, types.Number(2015)}
    85  	re2 := compExpr{"index1", gte, types.Number(2020)}
    86  	re3 := compExpr{"index1", lte, types.Number(2022)}
    87  	re4 := compExpr{"index1", lt, types.Number(-2030)}
    88  	re5 := compExpr{"index1", ne, types.Number(3.5)}
    89  	re6 := compExpr{"index1", ne, types.Number(-3500.4536632)}
    90  	re7 := compExpr{"index1", ne, types.String("whassup")}
    91  
    92  	queries := []parseResult{
    93  		{`index1 = 2015`, re1},
    94  		{`(index1 = 2015 )`, re1},
    95  		{`(((index1 = 2015 ) ))`, re1},
    96  		{`index1 = 2015 or index1 >= 2020`, logExpr{or, re1, re2, "index1"}},
    97  		{`(index1 = 2015) or index1 >= 2020`, logExpr{or, re1, re2, "index1"}},
    98  		{`index1 = 2015 or (index1 >= 2020)`, logExpr{or, re1, re2, "index1"}},
    99  		{`(index1 = 2015 or index1 >= 2020)`, logExpr{or, re1, re2, "index1"}},
   100  		{`(index1 = 2015 or index1 >= 2020) and index1 <= 2022`, logExpr{and, logExpr{or, re1, re2, "index1"}, re3, "index1"}},
   101  		{`index1 = 2015 or index1 >= 2020 and index1 <= 2022`, logExpr{or, re1, logExpr{and, re2, re3, "index1"}, "index1"}},
   102  		{`index1 = 2015 or index1 >= 2020 and index1 <= 2022 or index1 < -2030`, logExpr{or, re1, logExpr{and, re2, logExpr{or, re3, re4, "index1"}, "index1"}, "index1"}},
   103  		{`(index1 = 2015 or index1 >= 2020) and (index1 <= 2022 or index1 < -2030)`, logExpr{and, logExpr{or, re1, re2, "index1"}, logExpr{or, re3, re4, "index1"}, "index1"}},
   104  		{`index1 != 3.5`, re5},
   105  		{`index1 != -3500.4536632`, re6},
   106  		{`index1 != "whassup"`, re7},
   107  	}
   108  
   109  	storage := &chunks.MemoryStorage{}
   110  	db := datas.NewDatabase(storage.NewView())
   111  	_, err := db.CommitValue(db.GetDataset("index1"), types.NewMap(db, types.String("one"), types.NewSet(db, types.String("two"))))
   112  	assert.NoError(err)
   113  
   114  	im := &indexManager{db: db, indexes: map[string]types.Map{}}
   115  	for _, pr := range queries {
   116  		expr, err := parseQuery(pr.query, im)
   117  		assert.NoError(err)
   118  		assert.Equal(pr.ex, expr, "bad query: %s", pr.query)
   119  	}
   120  
   121  	badQueries := []string{
   122  		`sdfsd = 2015`,
   123  		`index1 = "unfinished string`,
   124  		`index1 and 2015`,
   125  		`index1 < `,
   126  		`index1 < 2015 and ()`,
   127  		`index1 < 2015 an index1 > 2016`,
   128  		`(index1 < 2015) what`,
   129  		`(index1< 2015`,
   130  		`(badIndexName < 2015)`,
   131  	}
   132  
   133  	im1 := &indexManager{db: db, indexes: map[string]types.Map{}}
   134  	for _, q := range badQueries {
   135  		expr, err := parseQuery(q, im1)
   136  		assert.Error(err)
   137  		assert.Nil(expr)
   138  	}
   139  }