Source file src/go/constant/value_test.go

     1  // Copyright 2013 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package constant
     6  
     7  import (
     8  	"fmt"
     9  	"go/token"
    10  	"math"
    11  	"math/big"
    12  	"strings"
    13  	"testing"
    14  )
    15  
    16  var intTests = []string{
    17  	// 0-octals
    18  	`0_123 = 0123`,
    19  	`0123_456 = 0123456`,
    20  
    21  	// decimals
    22  	`1_234 = 1234`,
    23  	`1_234_567 = 1234567`,
    24  
    25  	// hexadecimals
    26  	`0X_0 = 0`,
    27  	`0X_1234 = 0x1234`,
    28  	`0X_CAFE_f00d = 0xcafef00d`,
    29  
    30  	// octals
    31  	`0o0 = 0`,
    32  	`0o1234 = 01234`,
    33  	`0o01234567 = 01234567`,
    34  
    35  	`0O0 = 0`,
    36  	`0O1234 = 01234`,
    37  	`0O01234567 = 01234567`,
    38  
    39  	`0o_0 = 0`,
    40  	`0o_1234 = 01234`,
    41  	`0o0123_4567 = 01234567`,
    42  
    43  	`0O_0 = 0`,
    44  	`0O_1234 = 01234`,
    45  	`0O0123_4567 = 01234567`,
    46  
    47  	// binaries
    48  	`0b0 = 0`,
    49  	`0b1011 = 0xb`,
    50  	`0b00101101 = 0x2d`,
    51  
    52  	`0B0 = 0`,
    53  	`0B1011 = 0xb`,
    54  	`0B00101101 = 0x2d`,
    55  
    56  	`0b_0 = 0`,
    57  	`0b10_11 = 0xb`,
    58  	`0b_0010_1101 = 0x2d`,
    59  }
    60  
    61  // The RHS operand may be a floating-point quotient n/d of two integer values n and d.
    62  var floatTests = []string{
    63  	// decimal floats
    64  	`1_2_3. = 123.`,
    65  	`0_123. = 123.`,
    66  
    67  	`0_0e0 = 0.`,
    68  	`1_2_3e0 = 123.`,
    69  	`0_123e0 = 123.`,
    70  
    71  	`0e-0_0 = 0.`,
    72  	`1_2_3E+0 = 123.`,
    73  	`0123E1_2_3 = 123e123`,
    74  
    75  	`0.e+1 = 0.`,
    76  	`123.E-1_0 = 123e-10`,
    77  	`01_23.e123 = 123e123`,
    78  
    79  	`.0e-1 = .0`,
    80  	`.123E+10 = .123e10`,
    81  	`.0123E123 = .0123e123`,
    82  
    83  	`1_2_3.123 = 123.123`,
    84  	`0123.01_23 = 123.0123`,
    85  
    86  	`1e-1000000000 = 0`,
    87  	`1e+1000000000 = ?`,
    88  	`6e5518446744 = ?`,
    89  	`-6e5518446744 = ?`,
    90  
    91  	// hexadecimal floats
    92  	`0x0.p+0 = 0.`,
    93  	`0Xdeadcafe.p-10 = 0xdeadcafe/1024`,
    94  	`0x1234.P84 = 0x1234000000000000000000000`,
    95  
    96  	`0x.1p-0 = 1/16`,
    97  	`0X.deadcafep4 = 0xdeadcafe/0x10000000`,
    98  	`0x.1234P+12 = 0x1234/0x10`,
    99  
   100  	`0x0p0 = 0.`,
   101  	`0Xdeadcafep+1 = 0x1bd5b95fc`,
   102  	`0x1234P-10 = 0x1234/1024`,
   103  
   104  	`0x0.0p0 = 0.`,
   105  	`0Xdead.cafep+1 = 0x1bd5b95fc/0x10000`,
   106  	`0x12.34P-10 = 0x1234/0x40000`,
   107  
   108  	`0Xdead_cafep+1 = 0xdeadcafep+1`,
   109  	`0x_1234P-10 = 0x1234p-10`,
   110  
   111  	`0X_dead_cafe.p-10 = 0xdeadcafe.p-10`,
   112  	`0x12_34.P1_2_3 = 0x1234.p123`,
   113  }
   114  
   115  var imagTests = []string{
   116  	`1_234i = 1234i`,
   117  	`1_234_567i = 1234567i`,
   118  
   119  	`0.i = 0i`,
   120  	`123.i = 123i`,
   121  	`0123.i = 123i`,
   122  
   123  	`0.e+1i = 0i`,
   124  	`123.E-1_0i = 123e-10i`,
   125  	`01_23.e123i = 123e123i`,
   126  
   127  	`1e-1000000000i = 0i`,
   128  	`1e+1000000000i = ?`,
   129  	`6e5518446744i = ?`,
   130  	`-6e5518446744i = ?`,
   131  }
   132  
   133  func testNumbers(t *testing.T, kind token.Token, tests []string) {
   134  	for _, test := range tests {
   135  		a := strings.Split(test, " = ")
   136  		if len(a) != 2 {
   137  			t.Errorf("invalid test case: %s", test)
   138  			continue
   139  		}
   140  
   141  		x := MakeFromLiteral(a[0], kind, 0)
   142  		var y Value
   143  		if a[1] == "?" {
   144  			y = MakeUnknown()
   145  		} else {
   146  			if ns, ds, ok := strings.Cut(a[1], "/"); ok && kind == token.FLOAT {
   147  				n := MakeFromLiteral(ns, token.INT, 0)
   148  				d := MakeFromLiteral(ds, token.INT, 0)
   149  				y = BinaryOp(n, token.QUO, d)
   150  			} else {
   151  				y = MakeFromLiteral(a[1], kind, 0)
   152  			}
   153  			if y.Kind() == Unknown {
   154  				panic(fmt.Sprintf("invalid test case: %s %d", test, y.Kind()))
   155  			}
   156  		}
   157  
   158  		xk := x.Kind()
   159  		yk := y.Kind()
   160  		if xk != yk {
   161  			t.Errorf("%s: got kind %d != %d", test, xk, yk)
   162  			continue
   163  		}
   164  
   165  		if yk == Unknown {
   166  			continue
   167  		}
   168  
   169  		if !Compare(x, token.EQL, y) {
   170  			t.Errorf("%s: %s != %s", test, x, y)
   171  		}
   172  	}
   173  }
   174  
   175  // TestNumbers verifies that differently written literals
   176  // representing the same number do have the same value.
   177  func TestNumbers(t *testing.T) {
   178  	testNumbers(t, token.INT, intTests)
   179  	testNumbers(t, token.FLOAT, floatTests)
   180  	testNumbers(t, token.IMAG, imagTests)
   181  }
   182  
   183  var opTests = []string{
   184  	// unary operations
   185  	`+ 0 = 0`,
   186  	`+ ? = ?`,
   187  	`- 1 = -1`,
   188  	`- ? = ?`,
   189  	`^ 0 = -1`,
   190  	`^ ? = ?`,
   191  
   192  	`! true = false`,
   193  	`! false = true`,
   194  	`! ? = ?`,
   195  
   196  	// etc.
   197  
   198  	// binary operations
   199  	`"" + "" = ""`,
   200  	`"foo" + "" = "foo"`,
   201  	`"" + "bar" = "bar"`,
   202  	`"foo" + "bar" = "foobar"`,
   203  
   204  	`0 + 0 = 0`,
   205  	`0 + 0.1 = 0.1`,
   206  	`0 + 0.1i = 0.1i`,
   207  	`0.1 + 0.9 = 1`,
   208  	`1e100 + 1e100 = 2e100`,
   209  	`? + 0 = ?`,
   210  	`0 + ? = ?`,
   211  
   212  	`0 - 0 = 0`,
   213  	`0 - 0.1 = -0.1`,
   214  	`0 - 0.1i = -0.1i`,
   215  	`1e100 - 1e100 = 0`,
   216  	`? - 0 = ?`,
   217  	`0 - ? = ?`,
   218  
   219  	`0 * 0 = 0`,
   220  	`1 * 0.1 = 0.1`,
   221  	`1 * 0.1i = 0.1i`,
   222  	`1i * 1i = -1`,
   223  	`? * 0 = ?`,
   224  	`0 * ? = ?`,
   225  	`0 * 1e+1000000000 = ?`,
   226  
   227  	`0 / 0 = "division_by_zero"`,
   228  	`10 / 2 = 5`,
   229  	`5 / 3 = 5/3`,
   230  	`5i / 3i = 5/3`,
   231  	`? / 0 = ?`,
   232  	`0 / ? = ?`,
   233  	`0 * 1e+1000000000i = ?`,
   234  
   235  	`0 % 0 = "runtime_error:_integer_divide_by_zero"`, // TODO(gri) should be the same as for /
   236  	`10 % 3 = 1`,
   237  	`? % 0 = ?`,
   238  	`0 % ? = ?`,
   239  
   240  	`0 & 0 = 0`,
   241  	`12345 & 0 = 0`,
   242  	`0xff & 0xf = 0xf`,
   243  	`? & 0 = ?`,
   244  	`0 & ? = ?`,
   245  
   246  	`0 | 0 = 0`,
   247  	`12345 | 0 = 12345`,
   248  	`0xb | 0xa0 = 0xab`,
   249  	`? | 0 = ?`,
   250  	`0 | ? = ?`,
   251  
   252  	`0 ^ 0 = 0`,
   253  	`1 ^ -1 = -2`,
   254  	`? ^ 0 = ?`,
   255  	`0 ^ ? = ?`,
   256  
   257  	`0 &^ 0 = 0`,
   258  	`0xf &^ 1 = 0xe`,
   259  	`1 &^ 0xf = 0`,
   260  	// etc.
   261  
   262  	// shifts
   263  	`0 << 0 = 0`,
   264  	`1 << 10 = 1024`,
   265  	`0 >> 0 = 0`,
   266  	`1024 >> 10 == 1`,
   267  	`? << 0 == ?`,
   268  	`? >> 10 == ?`,
   269  	// etc.
   270  
   271  	// comparisons
   272  	`false == false = true`,
   273  	`false == true = false`,
   274  	`true == false = false`,
   275  	`true == true = true`,
   276  
   277  	`false != false = false`,
   278  	`false != true = true`,
   279  	`true != false = true`,
   280  	`true != true = false`,
   281  
   282  	`"foo" == "bar" = false`,
   283  	`"foo" != "bar" = true`,
   284  	`"foo" < "bar" = false`,
   285  	`"foo" <= "bar" = false`,
   286  	`"foo" > "bar" = true`,
   287  	`"foo" >= "bar" = true`,
   288  
   289  	`0 == 0 = true`,
   290  	`0 != 0 = false`,
   291  	`0 < 10 = true`,
   292  	`10 <= 10 = true`,
   293  	`0 > 10 = false`,
   294  	`10 >= 10 = true`,
   295  
   296  	`1/123456789 == 1/123456789 == true`,
   297  	`1/123456789 != 1/123456789 == false`,
   298  	`1/123456789 < 1/123456788 == true`,
   299  	`1/123456788 <= 1/123456789 == false`,
   300  	`0.11 > 0.11 = false`,
   301  	`0.11 >= 0.11 = true`,
   302  
   303  	`? == 0 = false`,
   304  	`? != 0 = false`,
   305  	`? < 10 = false`,
   306  	`? <= 10 = false`,
   307  	`? > 10 = false`,
   308  	`? >= 10 = false`,
   309  
   310  	`0 == ? = false`,
   311  	`0 != ? = false`,
   312  	`0 < ? = false`,
   313  	`10 <= ? = false`,
   314  	`0 > ? = false`,
   315  	`10 >= ? = false`,
   316  
   317  	// etc.
   318  }
   319  
   320  func TestOps(t *testing.T) {
   321  	for _, test := range opTests {
   322  		a := strings.Split(test, " ")
   323  		i := 0 // operator index
   324  
   325  		var x, x0 Value
   326  		switch len(a) {
   327  		case 4:
   328  			// unary operation
   329  		case 5:
   330  			// binary operation
   331  			x, x0 = val(a[0]), val(a[0])
   332  			i = 1
   333  		default:
   334  			t.Errorf("invalid test case: %s", test)
   335  			continue
   336  		}
   337  
   338  		op, ok := optab[a[i]]
   339  		if !ok {
   340  			panic("missing optab entry for " + a[i])
   341  		}
   342  
   343  		y, y0 := val(a[i+1]), val(a[i+1])
   344  
   345  		got := doOp(x, op, y)
   346  		want := val(a[i+3])
   347  		if !eql(got, want) {
   348  			t.Errorf("%s: got %s; want %s", test, got, want)
   349  			continue
   350  		}
   351  
   352  		if x0 != nil && !eql(x, x0) {
   353  			t.Errorf("%s: x changed to %s", test, x)
   354  			continue
   355  		}
   356  
   357  		if !eql(y, y0) {
   358  			t.Errorf("%s: y changed to %s", test, y)
   359  			continue
   360  		}
   361  	}
   362  }
   363  
   364  func eql(x, y Value) bool {
   365  	_, ux := x.(unknownVal)
   366  	_, uy := y.(unknownVal)
   367  	if ux || uy {
   368  		return ux == uy
   369  	}
   370  	return Compare(x, token.EQL, y)
   371  }
   372  
   373  // ----------------------------------------------------------------------------
   374  // String tests
   375  
   376  var xxx = strings.Repeat("x", 68)
   377  var issue14262 = `"بموجب الشروط التالية نسب المصنف — يجب عليك أن تنسب العمل بالطريقة التي تحددها المؤلف أو المرخص (ولكن ليس بأي حال من الأحوال أن توحي وتقترح بتحول أو استخدامك للعمل).  المشاركة على قدم المساواة — إذا كنت يعدل ، والتغيير ، أو الاستفادة من هذا العمل ، قد ينتج عن توزيع العمل إلا في ظل تشابه او تطابق فى واحد لهذا الترخيص."`
   378  
   379  var stringTests = []struct {
   380  	input, short, exact string
   381  }{
   382  	// Unknown
   383  	{"", "unknown", "unknown"},
   384  	{"0x", "unknown", "unknown"},
   385  	{"'", "unknown", "unknown"},
   386  	{"1f0", "unknown", "unknown"},
   387  	{"unknown", "unknown", "unknown"},
   388  
   389  	// Bool
   390  	{"true", "true", "true"},
   391  	{"false", "false", "false"},
   392  
   393  	// String
   394  	{`""`, `""`, `""`},
   395  	{`"foo"`, `"foo"`, `"foo"`},
   396  	{`"` + xxx + `xx"`, `"` + xxx + `xx"`, `"` + xxx + `xx"`},
   397  	{`"` + xxx + `xxx"`, `"` + xxx + `...`, `"` + xxx + `xxx"`},
   398  	{`"` + xxx + xxx + `xxx"`, `"` + xxx + `...`, `"` + xxx + xxx + `xxx"`},
   399  	{issue14262, `"بموجب الشروط التالية نسب المصنف — يجب عليك أن تنسب العمل بالطريقة ال...`, issue14262},
   400  
   401  	// Int
   402  	{"0", "0", "0"},
   403  	{"-1", "-1", "-1"},
   404  	{"12345", "12345", "12345"},
   405  	{"-12345678901234567890", "-12345678901234567890", "-12345678901234567890"},
   406  	{"12345678901234567890", "12345678901234567890", "12345678901234567890"},
   407  
   408  	// Float
   409  	{"0.", "0", "0"},
   410  	{"-0.0", "0", "0"},
   411  	{"10.0", "10", "10"},
   412  	{"2.1", "2.1", "21/10"},
   413  	{"-2.1", "-2.1", "-21/10"},
   414  	{"1e9999", "1e+9999", "0x.f8d4a9da224650a8cb2959e10d985ad92adbd44c62917e608b1f24c0e1b76b6f61edffeb15c135a4b601637315f7662f325f82325422b244286a07663c9415d2p+33216"},
   415  	{"1e-9999", "1e-9999", "0x.83b01ba6d8c0425eec1b21e96f7742d63c2653ed0a024cf8a2f9686df578d7b07d7a83d84df6a2ec70a921d1f6cd5574893a7eda4d28ee719e13a5dce2700759p-33215"},
   416  	{"2.71828182845904523536028747135266249775724709369995957496696763", "2.71828", "271828182845904523536028747135266249775724709369995957496696763/100000000000000000000000000000000000000000000000000000000000000"},
   417  	{"0e9999999999", "0", "0"},   // issue #16176
   418  	{"-6e-1886451601", "0", "0"}, // issue #20228
   419  
   420  	// Complex
   421  	{"0i", "(0 + 0i)", "(0 + 0i)"},
   422  	{"-0i", "(0 + 0i)", "(0 + 0i)"},
   423  	{"10i", "(0 + 10i)", "(0 + 10i)"},
   424  	{"-10i", "(0 + -10i)", "(0 + -10i)"},
   425  	{"1e9999i", "(0 + 1e+9999i)", "(0 + 0x.f8d4a9da224650a8cb2959e10d985ad92adbd44c62917e608b1f24c0e1b76b6f61edffeb15c135a4b601637315f7662f325f82325422b244286a07663c9415d2p+33216i)"},
   426  }
   427  
   428  func TestString(t *testing.T) {
   429  	for _, test := range stringTests {
   430  		x := val(test.input)
   431  		if got := x.String(); got != test.short {
   432  			t.Errorf("%s: got %q; want %q as short string", test.input, got, test.short)
   433  		}
   434  		if got := x.ExactString(); got != test.exact {
   435  			t.Errorf("%s: got %q; want %q as exact string", test.input, got, test.exact)
   436  		}
   437  	}
   438  }
   439  
   440  func TestStringLen(t *testing.T) {
   441  	tests := []struct {
   442  		x    Value
   443  		want int64
   444  	}{
   445  		{MakeUnknown(), 0},
   446  		{val(`""`), 0},
   447  		{val(`"foo"`), 3},
   448  		{val(`"世界"`), 6},
   449  		{BinaryOp(val(`"foo"`), token.ADD, val(`"bar"`)), 6},
   450  		{BinaryOp(val(`"世界"`), token.ADD, val(`"!"`)), 7},
   451  		{BinaryOp(val(`"a"`), token.ADD, BinaryOp(val(`"b"`), token.ADD, val(`"c"`))), 3},
   452  	}
   453  
   454  	for _, test := range tests {
   455  		if got := StringLen(test.x); got != test.want {
   456  			t.Errorf("StringLen(%v): got %d; want %d", test.x, got, test.want)
   457  		}
   458  	}
   459  }
   460  
   461  // ----------------------------------------------------------------------------
   462  // Support functions
   463  
   464  func val(lit string) Value {
   465  	if len(lit) == 0 {
   466  		return MakeUnknown()
   467  	}
   468  
   469  	switch lit {
   470  	case "?":
   471  		return MakeUnknown()
   472  	case "true":
   473  		return MakeBool(true)
   474  	case "false":
   475  		return MakeBool(false)
   476  	}
   477  
   478  	if as, bs, ok := strings.Cut(lit, "/"); ok {
   479  		// assume fraction
   480  		a := MakeFromLiteral(as, token.INT, 0)
   481  		b := MakeFromLiteral(bs, token.INT, 0)
   482  		return BinaryOp(a, token.QUO, b)
   483  	}
   484  
   485  	tok := token.INT
   486  	switch first, last := lit[0], lit[len(lit)-1]; {
   487  	case first == '"' || first == '`':
   488  		tok = token.STRING
   489  		lit = strings.ReplaceAll(lit, "_", " ")
   490  	case first == '\'':
   491  		tok = token.CHAR
   492  	case last == 'i':
   493  		tok = token.IMAG
   494  	default:
   495  		if !strings.HasPrefix(lit, "0x") && strings.ContainsAny(lit, "./Ee") {
   496  			tok = token.FLOAT
   497  		}
   498  	}
   499  
   500  	return MakeFromLiteral(lit, tok, 0)
   501  }
   502  
   503  var optab = map[string]token.Token{
   504  	"!": token.NOT,
   505  
   506  	"+": token.ADD,
   507  	"-": token.SUB,
   508  	"*": token.MUL,
   509  	"/": token.QUO,
   510  	"%": token.REM,
   511  
   512  	"<<": token.SHL,
   513  	">>": token.SHR,
   514  
   515  	"&":  token.AND,
   516  	"|":  token.OR,
   517  	"^":  token.XOR,
   518  	"&^": token.AND_NOT,
   519  
   520  	"==": token.EQL,
   521  	"!=": token.NEQ,
   522  	"<":  token.LSS,
   523  	"<=": token.LEQ,
   524  	">":  token.GTR,
   525  	">=": token.GEQ,
   526  }
   527  
   528  func panicHandler(v *Value) {
   529  	switch p := recover().(type) {
   530  	case nil:
   531  		// nothing to do
   532  	case string:
   533  		*v = MakeString(p)
   534  	case error:
   535  		*v = MakeString(p.Error())
   536  	default:
   537  		panic(p)
   538  	}
   539  }
   540  
   541  func doOp(x Value, op token.Token, y Value) (z Value) {
   542  	defer panicHandler(&z)
   543  
   544  	if x == nil {
   545  		return UnaryOp(op, y, 0)
   546  	}
   547  
   548  	switch op {
   549  	case token.EQL, token.NEQ, token.LSS, token.LEQ, token.GTR, token.GEQ:
   550  		return MakeBool(Compare(x, op, y))
   551  	case token.SHL, token.SHR:
   552  		s, _ := Int64Val(y)
   553  		return Shift(x, op, uint(s))
   554  	default:
   555  		return BinaryOp(x, op, y)
   556  	}
   557  }
   558  
   559  // ----------------------------------------------------------------------------
   560  // Other tests
   561  
   562  var fracTests = []string{
   563  	"0",
   564  	"1",
   565  	"-1",
   566  	"1.2",
   567  	"-0.991",
   568  	"2.718281828",
   569  	"3.14159265358979323e-10",
   570  	"1e100",
   571  	"1e1000",
   572  }
   573  
   574  func TestFractions(t *testing.T) {
   575  	for _, test := range fracTests {
   576  		x := val(test)
   577  		// We don't check the actual numerator and denominator because they
   578  		// are unlikely to be 100% correct due to floatVal rounding errors.
   579  		// Instead, we compute the fraction again and compare the rounded
   580  		// result.
   581  		q := BinaryOp(Num(x), token.QUO, Denom(x))
   582  		got := q.String()
   583  		want := x.String()
   584  		if got != want {
   585  			t.Errorf("%s: got quotient %s, want %s", x, got, want)
   586  		}
   587  	}
   588  }
   589  
   590  var bytesTests = []string{
   591  	"0",
   592  	"1",
   593  	"123456789",
   594  	"123456789012345678901234567890123456789012345678901234567890",
   595  }
   596  
   597  func TestBytes(t *testing.T) {
   598  	for _, test := range bytesTests {
   599  		x := val(test)
   600  		bytes := Bytes(x)
   601  
   602  		// special case 0
   603  		if Sign(x) == 0 && len(bytes) != 0 {
   604  			t.Errorf("%s: got %v; want empty byte slice", test, bytes)
   605  		}
   606  
   607  		if n := len(bytes); n > 0 && bytes[n-1] == 0 {
   608  			t.Errorf("%s: got %v; want no leading 0 byte", test, bytes)
   609  		}
   610  
   611  		if got := MakeFromBytes(bytes); !eql(got, x) {
   612  			t.Errorf("%s: got %s; want %s (bytes = %v)", test, got, x, bytes)
   613  		}
   614  	}
   615  }
   616  
   617  func TestUnknown(t *testing.T) {
   618  	u := MakeUnknown()
   619  	var values = []Value{
   620  		u,
   621  		MakeBool(false), // token.ADD ok below, operation is never considered
   622  		MakeString(""),
   623  		MakeInt64(1),
   624  		MakeFromLiteral("''", token.CHAR, 0),
   625  		MakeFromLiteral("-1234567890123456789012345678901234567890", token.INT, 0),
   626  		MakeFloat64(1.2),
   627  		MakeImag(MakeFloat64(1.2)),
   628  	}
   629  	for _, val := range values {
   630  		x, y := val, u
   631  		for i := range [2]int{} {
   632  			if i == 1 {
   633  				x, y = y, x
   634  			}
   635  			if got := BinaryOp(x, token.ADD, y); got.Kind() != Unknown {
   636  				t.Errorf("%s + %s: got %s; want %s", x, y, got, u)
   637  			}
   638  			if got := Compare(x, token.EQL, y); got {
   639  				t.Errorf("%s == %s: got true; want false", x, y)
   640  			}
   641  			if got := Compare(x, token.NEQ, y); got {
   642  				t.Errorf("%s != %s: got true; want false", x, y)
   643  			}
   644  		}
   645  	}
   646  }
   647  
   648  func TestMakeFloat64(t *testing.T) {
   649  	var zero float64
   650  	for _, arg := range []float64{
   651  		-math.MaxFloat32,
   652  		-10,
   653  		-0.5,
   654  		-zero,
   655  		zero,
   656  		1,
   657  		10,
   658  		123456789.87654321e-23,
   659  		1e10,
   660  		math.MaxFloat64,
   661  	} {
   662  		val := MakeFloat64(arg)
   663  		if val.Kind() != Float {
   664  			t.Errorf("%v: got kind = %d; want %d", arg, val.Kind(), Float)
   665  		}
   666  
   667  		// -0.0 is mapped to 0.0
   668  		got, exact := Float64Val(val)
   669  		if !exact || math.Float64bits(got) != math.Float64bits(arg+0) {
   670  			t.Errorf("%v: got %v (exact = %v)", arg, got, exact)
   671  		}
   672  	}
   673  
   674  	// infinity
   675  	for sign := range []int{-1, 1} {
   676  		arg := math.Inf(sign)
   677  		val := MakeFloat64(arg)
   678  		if val.Kind() != Unknown {
   679  			t.Errorf("%v: got kind = %d; want %d", arg, val.Kind(), Unknown)
   680  		}
   681  	}
   682  }
   683  
   684  type makeTestCase struct {
   685  	kind      Kind
   686  	arg, want any
   687  }
   688  
   689  func dup(k Kind, x any) makeTestCase { return makeTestCase{k, x, x} }
   690  
   691  func TestMake(t *testing.T) {
   692  	for _, test := range []makeTestCase{
   693  		{Bool, false, false},
   694  		{String, "hello", "hello"},
   695  
   696  		{Int, int64(1), int64(1)},
   697  		{Int, big.NewInt(10), int64(10)},
   698  		{Int, new(big.Int).Lsh(big.NewInt(1), 62), int64(1 << 62)},
   699  		dup(Int, new(big.Int).Lsh(big.NewInt(1), 63)),
   700  
   701  		{Float, big.NewFloat(0), floatVal0.val},
   702  		dup(Float, big.NewFloat(2.0)),
   703  		dup(Float, big.NewRat(1, 3)),
   704  	} {
   705  		val := Make(test.arg)
   706  		got := Val(val)
   707  		if val.Kind() != test.kind || got != test.want {
   708  			t.Errorf("got %v (%T, kind = %d); want %v (%T, kind = %d)",
   709  				got, got, val.Kind(), test.want, test.want, test.kind)
   710  		}
   711  	}
   712  }
   713  
   714  func BenchmarkStringAdd(b *testing.B) {
   715  	for size := 1; size <= 65536; size *= 4 {
   716  		b.Run(fmt.Sprint(size), func(b *testing.B) {
   717  			b.ReportAllocs()
   718  			n := int64(0)
   719  			for i := 0; i < b.N; i++ {
   720  				x := MakeString(strings.Repeat("x", 100))
   721  				y := x
   722  				for j := 0; j < size-1; j++ {
   723  					y = BinaryOp(y, token.ADD, x)
   724  				}
   725  				n += int64(len(StringVal(y)))
   726  			}
   727  			if n != int64(b.N)*int64(size)*100 {
   728  				b.Fatalf("bad string %d != %d", n, int64(b.N)*int64(size)*100)
   729  			}
   730  		})
   731  	}
   732  }
   733  
   734  var bitLenTests = []struct {
   735  	val  int64
   736  	want int
   737  }{
   738  	{0, 0},
   739  	{1, 1},
   740  	{-16, 5},
   741  	{1 << 61, 62},
   742  	{1 << 62, 63},
   743  	{-1 << 62, 63},
   744  	{-1 << 63, 64},
   745  }
   746  
   747  func TestBitLen(t *testing.T) {
   748  	for _, test := range bitLenTests {
   749  		if got := BitLen(MakeInt64(test.val)); got != test.want {
   750  			t.Errorf("%v: got %v, want %v", test.val, got, test.want)
   751  		}
   752  	}
   753  }
   754  

View as plain text