github.com/remobjects/goldbaselibrary@v0.0.0-20230924164425-d458680a936b/Source/Gold/constant/value_test.go (about)

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