github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/sem/tree/constant_test.go (about)

     1  // Copyright 2016 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package tree_test
    12  
    13  import (
    14  	"context"
    15  	"go/constant"
    16  	"go/token"
    17  	"reflect"
    18  	"strconv"
    19  	"strings"
    20  	"testing"
    21  	"time"
    22  
    23  	"github.com/cockroachdb/apd"
    24  	"github.com/cockroachdb/cockroach/pkg/settings/cluster"
    25  	"github.com/cockroachdb/cockroach/pkg/sql/parser"
    26  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    27  	"github.com/cockroachdb/cockroach/pkg/sql/types"
    28  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    29  )
    30  
    31  // TestNumericConstantVerifyAndResolveAvailableTypes verifies that test NumVals will
    32  // all return expected available type sets, and that attempting to resolve the NumVals
    33  // as each of these types will all succeed with an expected tree.Datum result.
    34  func TestNumericConstantVerifyAndResolveAvailableTypes(t *testing.T) {
    35  	defer leaktest.AfterTest(t)()
    36  	wantInt := tree.NumValAvailInteger
    37  	wantDecButCanBeInt := tree.NumValAvailDecimalNoFraction
    38  	wantDec := tree.NumValAvailDecimalWithFraction
    39  
    40  	testCases := []struct {
    41  		str   string
    42  		avail []*types.T
    43  	}{
    44  		{"1", wantInt},
    45  		{"0", wantInt},
    46  		{"-1", wantInt},
    47  		{"9223372036854775807", wantInt},
    48  		{"1.0", wantDecButCanBeInt},
    49  		{"-1234.0000", wantDecButCanBeInt},
    50  		{"1e10", wantDecButCanBeInt},
    51  		{"1E10", wantDecButCanBeInt},
    52  		{"1.1", wantDec},
    53  		{"1e-10", wantDec},
    54  		{"1E-10", wantDec},
    55  		{"-1231.131", wantDec},
    56  		{"876543234567898765436787654321", wantDec},
    57  	}
    58  
    59  	for i, test := range testCases {
    60  		tok := token.INT
    61  		if strings.ContainsAny(test.str, ".eE") {
    62  			tok = token.FLOAT
    63  		}
    64  
    65  		str := test.str
    66  		neg := false
    67  		if str[0] == '-' {
    68  			neg = true
    69  			str = str[1:]
    70  		}
    71  
    72  		val := constant.MakeFromLiteral(str, tok, 0)
    73  		if val.Kind() == constant.Unknown {
    74  			t.Fatalf("%d: could not parse value string %q", i, test.str)
    75  		}
    76  
    77  		// Check available types.
    78  		c := tree.NewNumVal(val, str, neg)
    79  		avail := c.AvailableTypes()
    80  		if !reflect.DeepEqual(avail, test.avail) {
    81  			t.Errorf("%d: expected the available type set %v for %v, found %v",
    82  				i, test.avail, c.ExactString(), avail)
    83  		}
    84  
    85  		// Make sure it can be resolved as each of those types.
    86  		for _, availType := range avail {
    87  			semaCtx := tree.MakeSemaContext()
    88  			if res, err := c.ResolveAsType(&semaCtx, availType); err != nil {
    89  				t.Errorf("%d: expected resolving %v as available type %s would succeed, found %v",
    90  					i, c.ExactString(), availType, err)
    91  			} else {
    92  				resErr := func(parsed, resolved interface{}) {
    93  					t.Errorf("%d: expected resolving %v as available type %s would produce a tree.Datum"+
    94  						" with the value %v, found %v",
    95  						i, c, availType, parsed, resolved)
    96  				}
    97  				switch typ := res.(type) {
    98  				case *tree.DInt:
    99  					var i int64
   100  					var err error
   101  					if tok == token.INT {
   102  						if i, err = strconv.ParseInt(test.str, 10, 64); err != nil {
   103  							t.Fatal(err)
   104  						}
   105  					} else {
   106  						var f float64
   107  						if f, err = strconv.ParseFloat(test.str, 64); err != nil {
   108  							t.Fatal(err)
   109  						}
   110  						i = int64(f)
   111  					}
   112  					if resI := int64(*typ); i != resI {
   113  						resErr(i, resI)
   114  					}
   115  				case *tree.DFloat:
   116  					f, err := strconv.ParseFloat(test.str, 64)
   117  					if err != nil {
   118  						t.Fatal(err)
   119  					}
   120  					if resF := float64(*typ); f != resF {
   121  						resErr(f, resF)
   122  					}
   123  				case *tree.DDecimal:
   124  					d := new(apd.Decimal)
   125  					if !strings.ContainsAny(test.str, "eE") {
   126  						if _, _, err := d.SetString(test.str); err != nil {
   127  							t.Fatalf("could not set %q on decimal", test.str)
   128  						}
   129  					} else {
   130  						_, _, err = d.SetString(test.str)
   131  						if err != nil {
   132  							t.Fatal(err)
   133  						}
   134  					}
   135  					resD := &typ.Decimal
   136  					if d.Cmp(resD) != 0 {
   137  						resErr(d, resD)
   138  					}
   139  				}
   140  			}
   141  		}
   142  	}
   143  }
   144  
   145  // TestStringConstantVerifyAvailableTypes verifies that test StrVals will all
   146  // return expected available type sets, and that attempting to resolve the StrVals
   147  // as each of these types will either succeed or return a parse error.
   148  func TestStringConstantVerifyAvailableTypes(t *testing.T) {
   149  	defer leaktest.AfterTest(t)()
   150  	wantStringButCanBeAll := tree.StrValAvailAllParsable
   151  	wantBytes := tree.StrValAvailBytes
   152  
   153  	testCases := []struct {
   154  		c     *tree.StrVal
   155  		avail []*types.T
   156  	}{
   157  		{tree.NewStrVal("abc 世界"), wantStringButCanBeAll},
   158  		{tree.NewStrVal("t"), wantStringButCanBeAll},
   159  		{tree.NewStrVal("2010-09-28"), wantStringButCanBeAll},
   160  		{tree.NewStrVal("2010-09-28 12:00:00.1"), wantStringButCanBeAll},
   161  		{tree.NewStrVal("PT12H2M"), wantStringButCanBeAll},
   162  		{tree.NewBytesStrVal("abc 世界"), wantBytes},
   163  		{tree.NewBytesStrVal("t"), wantBytes},
   164  		{tree.NewBytesStrVal("2010-09-28"), wantBytes},
   165  		{tree.NewBytesStrVal("2010-09-28 12:00:00.1"), wantBytes},
   166  		{tree.NewBytesStrVal("PT12H2M"), wantBytes},
   167  		{tree.NewBytesStrVal(string([]byte{0xff, 0xfe, 0xfd})), wantBytes},
   168  	}
   169  
   170  	for i, test := range testCases {
   171  		// Check that the expected available types are returned.
   172  		avail := test.c.AvailableTypes()
   173  		if !reflect.DeepEqual(avail, test.avail) {
   174  			t.Errorf("%d: expected the available type set %v for %+v, found %v",
   175  				i, test.avail, test.c, avail)
   176  		}
   177  
   178  		// Make sure it can be resolved as each of those types or throws a parsing error.
   179  		for _, availType := range avail {
   180  
   181  			// The enum value in c.AvailableTypes() is AnyEnum, so we will not be able to
   182  			// resolve that exact type. In actual execution, the constant would be resolved
   183  			// as a hydrated enum type instead.
   184  			if availType.Family() == types.EnumFamily {
   185  				continue
   186  			}
   187  
   188  			semaCtx := tree.MakeSemaContext()
   189  			if _, err := test.c.ResolveAsType(&semaCtx, availType); err != nil {
   190  				if !strings.Contains(err.Error(), "could not parse") {
   191  					// Parsing errors are permitted for this test, as proper tree.StrVal parsing
   192  					// is tested in TestStringConstantTypeResolution. Any other error should
   193  					// throw a failure.
   194  					t.Errorf("%d: expected resolving %v as available type %s would either succeed"+
   195  						" or throw a parsing error, found %v",
   196  						i, test.c, availType, err)
   197  				}
   198  			}
   199  		}
   200  	}
   201  }
   202  
   203  func mustParseDBool(t *testing.T, s string) tree.Datum {
   204  	d, err := tree.ParseDBool(s)
   205  	if err != nil {
   206  		t.Fatal(err)
   207  	}
   208  	return d
   209  }
   210  func mustParseDDate(t *testing.T, s string) tree.Datum {
   211  	d, err := tree.ParseDDate(nil, s)
   212  	if err != nil {
   213  		t.Fatal(err)
   214  	}
   215  	return d
   216  }
   217  func mustParseDTime(t *testing.T, s string) tree.Datum {
   218  	d, err := tree.ParseDTime(nil, s, time.Microsecond)
   219  	if err != nil {
   220  		t.Fatal(err)
   221  	}
   222  	return d
   223  }
   224  func mustParseDTimeTZ(t *testing.T, s string) tree.Datum {
   225  	d, err := tree.ParseDTimeTZ(nil, s, time.Microsecond)
   226  	if err != nil {
   227  		t.Fatal(err)
   228  	}
   229  	return d
   230  }
   231  func mustParseDTimestamp(t *testing.T, s string) tree.Datum {
   232  	d, err := tree.ParseDTimestamp(nil, s, time.Millisecond)
   233  	if err != nil {
   234  		t.Fatal(err)
   235  	}
   236  	return d
   237  }
   238  func mustParseDTimestampTZ(t *testing.T, s string) tree.Datum {
   239  	d, err := tree.ParseDTimestampTZ(nil, s, time.Millisecond)
   240  	if err != nil {
   241  		t.Fatal(err)
   242  	}
   243  	return d
   244  }
   245  func mustParseDInterval(t *testing.T, s string) tree.Datum {
   246  	d, err := tree.ParseDInterval(s)
   247  	if err != nil {
   248  		t.Fatal(err)
   249  	}
   250  	return d
   251  }
   252  func mustParseDJSON(t *testing.T, s string) tree.Datum {
   253  	d, err := tree.ParseDJSON(s)
   254  	if err != nil {
   255  		t.Fatal(err)
   256  	}
   257  	return d
   258  }
   259  func mustParseDStringArray(t *testing.T, s string) tree.Datum {
   260  	evalContext := tree.MakeTestingEvalContext(cluster.MakeTestingClusterSettings())
   261  	d, err := tree.ParseDArrayFromString(&evalContext, s, types.String)
   262  	if err != nil {
   263  		t.Fatal(err)
   264  	}
   265  	return d
   266  }
   267  func mustParseDIntArray(t *testing.T, s string) tree.Datum {
   268  	evalContext := tree.MakeTestingEvalContext(cluster.MakeTestingClusterSettings())
   269  	d, err := tree.ParseDArrayFromString(&evalContext, s, types.Int)
   270  	if err != nil {
   271  		t.Fatal(err)
   272  	}
   273  	return d
   274  }
   275  func mustParseDDecimalArray(t *testing.T, s string) tree.Datum {
   276  	evalContext := tree.MakeTestingEvalContext(cluster.MakeTestingClusterSettings())
   277  	d, err := tree.ParseDArrayFromString(&evalContext, s, types.Decimal)
   278  	if err != nil {
   279  		t.Fatal(err)
   280  	}
   281  	return d
   282  }
   283  
   284  var parseFuncs = map[*types.T]func(*testing.T, string) tree.Datum{
   285  	types.String:       func(t *testing.T, s string) tree.Datum { return tree.NewDString(s) },
   286  	types.Bytes:        func(t *testing.T, s string) tree.Datum { return tree.NewDBytes(tree.DBytes(s)) },
   287  	types.Bool:         mustParseDBool,
   288  	types.Date:         mustParseDDate,
   289  	types.Time:         mustParseDTime,
   290  	types.TimeTZ:       mustParseDTimeTZ,
   291  	types.Timestamp:    mustParseDTimestamp,
   292  	types.TimestampTZ:  mustParseDTimestampTZ,
   293  	types.Interval:     mustParseDInterval,
   294  	types.Jsonb:        mustParseDJSON,
   295  	types.DecimalArray: mustParseDDecimalArray,
   296  	types.IntArray:     mustParseDIntArray,
   297  	types.StringArray:  mustParseDStringArray,
   298  }
   299  
   300  func typeSet(tys ...*types.T) map[*types.T]struct{} {
   301  	set := make(map[*types.T]struct{}, len(tys))
   302  	for _, t := range tys {
   303  		set[t] = struct{}{}
   304  	}
   305  	return set
   306  }
   307  
   308  // TestStringConstantResolveAvailableTypes verifies that test StrVals can all be
   309  // resolved successfully into an expected set of tree.Datum types. The test will make sure
   310  // the correct set of tree.Datum types are resolvable, and that the resolved tree.Datum match
   311  // the expected results which come from running the string literal through a
   312  // corresponding parseFunc (above).
   313  func TestStringConstantResolveAvailableTypes(t *testing.T) {
   314  	defer leaktest.AfterTest(t)()
   315  	testCases := []struct {
   316  		c            *tree.StrVal
   317  		parseOptions map[*types.T]struct{}
   318  	}{
   319  		{
   320  			c:            tree.NewStrVal("abc 世界"),
   321  			parseOptions: typeSet(types.String, types.Bytes),
   322  		},
   323  		{
   324  			c:            tree.NewStrVal("true"),
   325  			parseOptions: typeSet(types.String, types.Bytes, types.Bool, types.Jsonb),
   326  		},
   327  		{
   328  			c:            tree.NewStrVal("2010-09-28"),
   329  			parseOptions: typeSet(types.String, types.Bytes, types.Date, types.Timestamp, types.TimestampTZ),
   330  		},
   331  		{
   332  			c:            tree.NewStrVal("2010-09-28 12:00:00.1"),
   333  			parseOptions: typeSet(types.String, types.Bytes, types.Time, types.TimeTZ, types.Timestamp, types.TimestampTZ, types.Date),
   334  		},
   335  		{
   336  			c:            tree.NewStrVal("2006-07-08T00:00:00.000000123Z"),
   337  			parseOptions: typeSet(types.String, types.Bytes, types.Time, types.TimeTZ, types.Timestamp, types.TimestampTZ, types.Date),
   338  		},
   339  		{
   340  			c:            tree.NewStrVal("PT12H2M"),
   341  			parseOptions: typeSet(types.String, types.Bytes, types.Interval),
   342  		},
   343  		{
   344  			c:            tree.NewBytesStrVal("abc 世界"),
   345  			parseOptions: typeSet(types.String, types.Bytes),
   346  		},
   347  		{
   348  			c:            tree.NewBytesStrVal("true"),
   349  			parseOptions: typeSet(types.String, types.Bytes),
   350  		},
   351  		{
   352  			c:            tree.NewBytesStrVal("2010-09-28"),
   353  			parseOptions: typeSet(types.String, types.Bytes),
   354  		},
   355  		{
   356  			c:            tree.NewBytesStrVal("2010-09-28 12:00:00.1"),
   357  			parseOptions: typeSet(types.String, types.Bytes),
   358  		},
   359  		{
   360  			c:            tree.NewBytesStrVal("PT12H2M"),
   361  			parseOptions: typeSet(types.String, types.Bytes),
   362  		},
   363  		{
   364  			c:            tree.NewStrVal(`{"a": 1}`),
   365  			parseOptions: typeSet(types.String, types.Bytes, types.Jsonb),
   366  		},
   367  		{
   368  			c:            tree.NewStrVal(`{1,2}`),
   369  			parseOptions: typeSet(types.String, types.Bytes, types.StringArray, types.IntArray, types.DecimalArray),
   370  		},
   371  		{
   372  			c:            tree.NewStrVal(`{1.5,2.0}`),
   373  			parseOptions: typeSet(types.String, types.Bytes, types.StringArray, types.DecimalArray),
   374  		},
   375  		{
   376  			c:            tree.NewStrVal(`{a,b}`),
   377  			parseOptions: typeSet(types.String, types.Bytes, types.StringArray),
   378  		},
   379  		{
   380  			c:            tree.NewBytesStrVal(string([]byte{0xff, 0xfe, 0xfd})),
   381  			parseOptions: typeSet(types.String, types.Bytes),
   382  		},
   383  	}
   384  
   385  	for i, test := range testCases {
   386  		parseableCount := 0
   387  
   388  		// Make sure it can be resolved as each of those types or throws a parsing error.
   389  		for _, availType := range test.c.AvailableTypes() {
   390  
   391  			// The enum value in c.AvailableTypes() is AnyEnum, so we will not be able to
   392  			// resolve that exact type. In actual execution, the constant would be resolved
   393  			// as a hydrated enum type instead.
   394  			if availType.Family() == types.EnumFamily {
   395  				continue
   396  			}
   397  
   398  			semaCtx := tree.MakeSemaContext()
   399  			res, err := test.c.ResolveAsType(&semaCtx, availType)
   400  			if err != nil {
   401  				if !strings.Contains(err.Error(), "could not parse") && !strings.Contains(err.Error(), "parsing") {
   402  					// Parsing errors are permitted for this test, but the number of correctly
   403  					// parseable types will be verified. Any other error should throw a failure.
   404  					t.Errorf("%d: expected resolving %v as available type %s would either succeed"+
   405  						" or throw a parsing error, found %v",
   406  						i, test.c, availType, err)
   407  				}
   408  				continue
   409  			}
   410  			parseableCount++
   411  
   412  			if _, isExpected := test.parseOptions[availType]; !isExpected {
   413  				t.Errorf("%d: type %s not expected to be resolvable from the tree.StrVal %v, found %v",
   414  					i, availType, test.c, res)
   415  			} else {
   416  				expectedDatum := parseFuncs[availType](t, test.c.RawString())
   417  				evalCtx := tree.NewTestingEvalContext(cluster.MakeTestingClusterSettings())
   418  				defer evalCtx.Stop(context.Background())
   419  				if res.Compare(evalCtx, expectedDatum) != 0 {
   420  					t.Errorf("%d: type %s expected to be resolved from the tree.StrVal %v to tree.Datum %v"+
   421  						", found %v",
   422  						i, availType, test.c, expectedDatum, res)
   423  				}
   424  			}
   425  		}
   426  
   427  		// Make sure the expected number of types can be resolved from the tree.StrVal.
   428  		if expCount := len(test.parseOptions); parseableCount != expCount {
   429  			t.Errorf("%d: expected %d successfully resolvable types for the tree.StrVal %v, found %d",
   430  				i, expCount, test.c, parseableCount)
   431  		}
   432  	}
   433  }
   434  
   435  type constantLiteralFoldingTestCase struct {
   436  	expr     string
   437  	expected string
   438  }
   439  
   440  func testConstantLiteralFolding(t *testing.T, testData []constantLiteralFoldingTestCase) {
   441  	for _, d := range testData {
   442  		expr, err := parser.ParseExpr(d.expr)
   443  		if err != nil {
   444  			t.Fatalf("%s: %v", d.expr, err)
   445  		}
   446  		rOrig := expr.String()
   447  		r, err := tree.FoldConstantLiterals(expr)
   448  		if err != nil {
   449  			t.Fatalf("%s: %v", d.expr, err)
   450  		}
   451  		if s := r.String(); d.expected != s {
   452  			t.Errorf("%s: expected %s, but found %s", d.expr, d.expected, s)
   453  		}
   454  		// Folding again should be a no-op.
   455  		r2, err := tree.FoldConstantLiterals(r)
   456  		if err != nil {
   457  			t.Fatalf("%s: %v", d.expr, err)
   458  		}
   459  		if s := r2.String(); d.expected != s {
   460  			t.Errorf("%s: expected %s, but found %s", d.expr, d.expected, s)
   461  		}
   462  		// The original expression should be unchanged.
   463  		if rStr := expr.String(); rOrig != rStr {
   464  			t.Fatalf("Original expression `%s` changed to `%s`", rOrig, rStr)
   465  		}
   466  	}
   467  }
   468  
   469  func TestFoldNumericConstants(t *testing.T) {
   470  	defer leaktest.AfterTest(t)()
   471  	testConstantLiteralFolding(t, []constantLiteralFoldingTestCase{
   472  		// Unary ops.
   473  		{`+1`, `1`},
   474  		{`+1.2`, `1.2`},
   475  		{`-1`, `-1`},
   476  		{`-1.2`, `-1.2`},
   477  		// Unary ops (int only).
   478  		{`~1`, `-2`},
   479  		{`~1.2`, `~1.2`},
   480  		// Binary ops.
   481  		{`1 + 1`, `2`},
   482  		{`1.2 + 2.3`, `3.5`},
   483  		{`1 + 2.3`, `3.3`},
   484  		{`2 - 1`, `1`},
   485  		{`1.2 - 2.3`, `-1.1`},
   486  		{`1 - 2.3`, `-1.3`},
   487  		{`2 * 1`, `2`},
   488  		{`1.2 * 2.3`, `2.76`},
   489  		{`1 * 2.3`, `2.3`},
   490  		{`123456789.987654321 * 987654321`, `1.21933e+17`},
   491  		{`9 / 4`, `2.25`},
   492  		{`9.7 / 4`, `2.425`},
   493  		{`4.72 / 2.36`, `2`},
   494  		{`0 / 0`, `0 / 0`}, // Will be caught during evaluation.
   495  		{`1 / 0`, `1 / 0`}, // Will be caught during evaluation.
   496  		// Binary ops (int only).
   497  		{`9 // 2`, `4`},
   498  		{`-5 // 3`, `-1`},
   499  		{`100 // 17`, `5`},
   500  		{`100.43 // 17.82`, `100.43 // 17.82`}, // Constant folding won't fold numeric modulo.
   501  		{`0 // 0`, `0 // 0`},                   // Will be caught during evaluation.
   502  		{`1 // 0`, `1 // 0`},                   // Will be caught during evaluation.
   503  		{`9 % 2`, `1`},
   504  		{`100 % 17`, `15`},
   505  		{`100.43 % 17.82`, `100.43 % 17.82`}, // Constant folding won't fold numeric modulo.
   506  		{`1 & 3`, `1`},
   507  		{`1.3 & 3.2`, `1.3 & 3.2`}, // Will be caught during type checking.
   508  		{`1 | 2`, `3`},
   509  		{`1.3 | 2.8`, `1.3 | 2.8`}, // Will be caught during type checking.
   510  		{`1 # 3`, `2`},
   511  		{`1.3 # 3.9`, `1.3 # 3.9`}, // Will be caught during type checking.
   512  		{`2 ^ 3`, `2 ^ 3`},         // Constant folding won't fold power.
   513  		{`1.3 ^ 3.9`, `1.3 ^ 3.9`},
   514  		// Shift ops (int only).
   515  		{`1 << 2`, `1 << 2`},
   516  		{`1 << -2`, `1 << -2`}, // Should be caught during evaluation.
   517  		{`1 << 9999999999999999999999999999`, `1 << 9999999999999999999999999999`}, // Will be caught during type checking.
   518  		{`1.2 << 2.4`, `1.2 << 2.4`}, // Will be caught during type checking.
   519  		{`4 >> 2`, `4 >> 2`},
   520  		{`4.1 >> 2.9`, `4.1 >> 2.9`}, // Will be caught during type checking.
   521  		// Comparison ops.
   522  		{`4 = 2`, `false`},
   523  		{`4 = 4.0`, `true`},
   524  		{`4.0 = 4`, `true`},
   525  		{`4.9 = 4`, `false`},
   526  		{`4.9 = 4.9`, `true`},
   527  		{`4 != 2`, `true`},
   528  		{`4 != 4.0`, `false`},
   529  		{`4.0 != 4`, `false`},
   530  		{`4.9 != 4`, `true`},
   531  		{`4.9 != 4.9`, `false`},
   532  		{`4 < 2`, `false`},
   533  		{`4 < 4.0`, `false`},
   534  		{`4.0 < 4`, `false`},
   535  		{`4.9 < 4`, `false`},
   536  		{`4.9 < 4.9`, `false`},
   537  		{`4 <= 2`, `false`},
   538  		{`4 <= 4.0`, `true`},
   539  		{`4.0 <= 4`, `true`},
   540  		{`4.9 <= 4`, `false`},
   541  		{`4.9 <= 4.9`, `true`},
   542  		{`4 > 2`, `true`},
   543  		{`4 > 4.0`, `false`},
   544  		{`4.0 > 4`, `false`},
   545  		{`4.9 > 4`, `true`},
   546  		{`4.9 > 4.9`, `false`},
   547  		{`4 >= 2`, `true`},
   548  		{`4 >= 4.0`, `true`},
   549  		{`4.0 >= 4`, `true`},
   550  		{`4.9 >= 4`, `true`},
   551  		{`4.9 >= 4.9`, `true`},
   552  		// With parentheses.
   553  		{`(4)`, `4`},
   554  		{`(((4)))`, `4`},
   555  		{`(((9 / 3) * (1 / 3)))`, `1`},
   556  		{`(((9 / 3) % (1 / 3)))`, `((3 % 0.333333))`},
   557  		{`(1.0) << ((2) + 3 / (1/9))`, `1.0 << 29`},
   558  		// With non-constants.
   559  		{`a + 5 * b`, `a + (5 * b)`},
   560  		{`a + 5 + b + 7`, `((a + 5) + b) + 7`},
   561  		{`a + 5 * 2`, `a + 10`},
   562  		{`a * b + 5 / 2`, `(a * b) + 2.5`},
   563  		{`a - b * 5 - 3`, `(a - (b * 5)) - 3`},
   564  		{`a - b + 5 * 3`, `(a - b) + 15`},
   565  	})
   566  }
   567  
   568  func TestFoldStringConstants(t *testing.T) {
   569  	defer leaktest.AfterTest(t)()
   570  	testConstantLiteralFolding(t, []constantLiteralFoldingTestCase{
   571  		// Binary ops.
   572  		{`'string' || 'string'`, `'stringstring'`},
   573  		{`'string' || b'bytes'`, `b'stringbytes'`},
   574  		{`b'bytes' || b'bytes'`, `b'bytesbytes'`},
   575  		{`'a' || 'b' || 'c'`, `'abc'`},
   576  		{`'\' || (b'0a' || b'\x0a')`, `b'\\0a\n'`},
   577  		// Comparison ops.
   578  		{`'string' = 'string'`, `true`},
   579  		{`'string' = b'bytes'`, `false`},
   580  		{`'value' = b'value'`, `true`},
   581  		{`b'bytes' = b'bytes'`, `true`},
   582  		{`'string' != 'string'`, `false`},
   583  		{`'string' != b'bytes'`, `true`},
   584  		{`'value' != b'value'`, `false`},
   585  		{`b'bytes' != b'bytes'`, `false`},
   586  		{`'string' < 'string'`, `false`},
   587  		{`'string' < b'bytes'`, `false`},
   588  		{`'value' < b'value'`, `false`},
   589  		{`b'bytes' < b'bytes'`, `false`},
   590  		{`'string' <= 'string'`, `true`},
   591  		{`'string' <= b'bytes'`, `false`},
   592  		{`'value' <= b'value'`, `true`},
   593  		{`b'bytes' <= b'bytes'`, `true`},
   594  		{`'string' > 'string'`, `false`},
   595  		{`'string' > b'bytes'`, `true`},
   596  		{`'value' > b'value'`, `false`},
   597  		{`b'bytes' > b'bytes'`, `false`},
   598  		{`'string' >= 'string'`, `true`},
   599  		{`'string' >= b'bytes'`, `true`},
   600  		{`'value' >= b'value'`, `true`},
   601  		{`b'bytes' >= b'bytes'`, `true`},
   602  		// With parentheses.
   603  		{`('string') || (b'bytes')`, `b'stringbytes'`},
   604  		{`('a') || (('b') || ('c'))`, `'abc'`},
   605  		// With non-constants.
   606  		{`a > 'str' || b`, `a > ('str' || b)`},
   607  		{`a > 'str' || 'ing'`, `a > 'string'`},
   608  	})
   609  }