Home | History | Annotate | Download | only in constant
      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 	"go/token"
      9 	"strings"
     10 	"testing"
     11 )
     12 
     13 // TODO(gri) expand this test framework
     14 
     15 var opTests = []string{
     16 	// unary operations
     17 	`+ 0 = 0`,
     18 	`+ ? = ?`,
     19 	`- 1 = -1`,
     20 	`- ? = ?`,
     21 	`^ 0 = -1`,
     22 	`^ ? = ?`,
     23 
     24 	`! true = false`,
     25 	`! false = true`,
     26 	`! ? = ?`,
     27 
     28 	// etc.
     29 
     30 	// binary operations
     31 	`"" + "" = ""`,
     32 	`"foo" + "" = "foo"`,
     33 	`"" + "bar" = "bar"`,
     34 	`"foo" + "bar" = "foobar"`,
     35 
     36 	`0 + 0 = 0`,
     37 	`0 + 0.1 = 0.1`,
     38 	`0 + 0.1i = 0.1i`,
     39 	`0.1 + 0.9 = 1`,
     40 	`1e100 + 1e100 = 2e100`,
     41 	`? + 0 = ?`,
     42 	`0 + ? = ?`,
     43 
     44 	`0 - 0 = 0`,
     45 	`0 - 0.1 = -0.1`,
     46 	`0 - 0.1i = -0.1i`,
     47 	`1e100 - 1e100 = 0`,
     48 	`? - 0 = ?`,
     49 	`0 - ? = ?`,
     50 
     51 	`0 * 0 = 0`,
     52 	`1 * 0.1 = 0.1`,
     53 	`1 * 0.1i = 0.1i`,
     54 	`1i * 1i = -1`,
     55 	`? * 0 = ?`,
     56 	`0 * ? = ?`,
     57 
     58 	`0 / 0 = "division_by_zero"`,
     59 	`10 / 2 = 5`,
     60 	`5 / 3 = 5/3`,
     61 	`5i / 3i = 5/3`,
     62 	`? / 0 = ?`,
     63 	`0 / ? = ?`,
     64 
     65 	`0 % 0 = "runtime_error:_integer_divide_by_zero"`, // TODO(gri) should be the same as for /
     66 	`10 % 3 = 1`,
     67 	`? % 0 = ?`,
     68 	`0 % ? = ?`,
     69 
     70 	`0 & 0 = 0`,
     71 	`12345 & 0 = 0`,
     72 	`0xff & 0xf = 0xf`,
     73 	`? & 0 = ?`,
     74 	`0 & ? = ?`,
     75 
     76 	`0 | 0 = 0`,
     77 	`12345 | 0 = 12345`,
     78 	`0xb | 0xa0 = 0xab`,
     79 	`? | 0 = ?`,
     80 	`0 | ? = ?`,
     81 
     82 	`0 ^ 0 = 0`,
     83 	`1 ^ -1 = -2`,
     84 	`? ^ 0 = ?`,
     85 	`0 ^ ? = ?`,
     86 
     87 	`0 &^ 0 = 0`,
     88 	`0xf &^ 1 = 0xe`,
     89 	`1 &^ 0xf = 0`,
     90 	// etc.
     91 
     92 	// shifts
     93 	`0 << 0 = 0`,
     94 	`1 << 10 = 1024`,
     95 	`0 >> 0 = 0`,
     96 	`1024 >> 10 == 1`,
     97 	`? << 0 == ?`,
     98 	`? >> 10 == ?`,
     99 	// etc.
    100 
    101 	// comparisons
    102 	`false == false = true`,
    103 	`false == true = false`,
    104 	`true == false = false`,
    105 	`true == true = true`,
    106 
    107 	`false != false = false`,
    108 	`false != true = true`,
    109 	`true != false = true`,
    110 	`true != true = false`,
    111 
    112 	`"foo" == "bar" = false`,
    113 	`"foo" != "bar" = true`,
    114 	`"foo" < "bar" = false`,
    115 	`"foo" <= "bar" = false`,
    116 	`"foo" > "bar" = true`,
    117 	`"foo" >= "bar" = true`,
    118 
    119 	`0 == 0 = true`,
    120 	`0 != 0 = false`,
    121 	`0 < 10 = true`,
    122 	`10 <= 10 = true`,
    123 	`0 > 10 = false`,
    124 	`10 >= 10 = true`,
    125 
    126 	`1/123456789 == 1/123456789 == true`,
    127 	`1/123456789 != 1/123456789 == false`,
    128 	`1/123456789 < 1/123456788 == true`,
    129 	`1/123456788 <= 1/123456789 == false`,
    130 	`0.11 > 0.11 = false`,
    131 	`0.11 >= 0.11 = true`,
    132 
    133 	`? == 0 = false`,
    134 	`? != 0 = false`,
    135 	`? < 10 = false`,
    136 	`? <= 10 = false`,
    137 	`? > 10 = false`,
    138 	`? >= 10 = false`,
    139 
    140 	`0 == ? = false`,
    141 	`0 != ? = false`,
    142 	`0 < ? = false`,
    143 	`10 <= ? = false`,
    144 	`0 > ? = false`,
    145 	`10 >= ? = false`,
    146 
    147 	// etc.
    148 }
    149 
    150 func TestOps(t *testing.T) {
    151 	for _, test := range opTests {
    152 		a := strings.Split(test, " ")
    153 		i := 0 // operator index
    154 
    155 		var x, x0 Value
    156 		switch len(a) {
    157 		case 4:
    158 			// unary operation
    159 		case 5:
    160 			// binary operation
    161 			x, x0 = val(a[0]), val(a[0])
    162 			i = 1
    163 		default:
    164 			t.Errorf("invalid test case: %s", test)
    165 			continue
    166 		}
    167 
    168 		op, ok := optab[a[i]]
    169 		if !ok {
    170 			panic("missing optab entry for " + a[i])
    171 		}
    172 
    173 		y, y0 := val(a[i+1]), val(a[i+1])
    174 
    175 		got := doOp(x, op, y)
    176 		want := val(a[i+3])
    177 		if !eql(got, want) {
    178 			t.Errorf("%s: got %s; want %s", test, got, want)
    179 			continue
    180 		}
    181 
    182 		if x0 != nil && !eql(x, x0) {
    183 			t.Errorf("%s: x changed to %s", test, x)
    184 			continue
    185 		}
    186 
    187 		if !eql(y, y0) {
    188 			t.Errorf("%s: y changed to %s", test, y)
    189 			continue
    190 		}
    191 	}
    192 }
    193 
    194 func eql(x, y Value) bool {
    195 	_, ux := x.(unknownVal)
    196 	_, uy := y.(unknownVal)
    197 	if ux || uy {
    198 		return ux == uy
    199 	}
    200 	return Compare(x, token.EQL, y)
    201 }
    202 
    203 // ----------------------------------------------------------------------------
    204 // String tests
    205 
    206 var xxx = strings.Repeat("x", 68)
    207 var issue14262 = `"                 (            ).                                 ."`
    208 
    209 var stringTests = []struct {
    210 	input, short, exact string
    211 }{
    212 	// Unknown
    213 	{"", "unknown", "unknown"},
    214 	{"0x", "unknown", "unknown"},
    215 	{"'", "unknown", "unknown"},
    216 	{"1f0", "unknown", "unknown"},
    217 	{"unknown", "unknown", "unknown"},
    218 
    219 	// Bool
    220 	{"true", "true", "true"},
    221 	{"false", "false", "false"},
    222 
    223 	// String
    224 	{`""`, `""`, `""`},
    225 	{`"foo"`, `"foo"`, `"foo"`},
    226 	{`"` + xxx + `xx"`, `"` + xxx + `xx"`, `"` + xxx + `xx"`},
    227 	{`"` + xxx + `xxx"`, `"` + xxx + `...`, `"` + xxx + `xxx"`},
    228 	{`"` + xxx + xxx + `xxx"`, `"` + xxx + `...`, `"` + xxx + xxx + `xxx"`},
    229 	{issue14262, `"            ...`, issue14262},
    230 
    231 	// Int
    232 	{"0", "0", "0"},
    233 	{"-1", "-1", "-1"},
    234 	{"12345", "12345", "12345"},
    235 	{"-12345678901234567890", "-12345678901234567890", "-12345678901234567890"},
    236 	{"12345678901234567890", "12345678901234567890", "12345678901234567890"},
    237 
    238 	// Float
    239 	{"0.", "0", "0"},
    240 	{"-0.0", "0", "0"},
    241 	{"10.0", "10", "10"},
    242 	{"2.1", "2.1", "21/10"},
    243 	{"-2.1", "-2.1", "-21/10"},
    244 	{"1e9999", "1e+9999", "0x.f8d4a9da224650a8cb2959e10d985ad92adbd44c62917e608b1f24c0e1b76b6f61edffeb15c135a4b601637315f7662f325f82325422b244286a07663c9415d2p+33216"},
    245 	{"1e-9999", "1e-9999", "0x.83b01ba6d8c0425eec1b21e96f7742d63c2653ed0a024cf8a2f9686df578d7b07d7a83d84df6a2ec70a921d1f6cd5574893a7eda4d28ee719e13a5dce2700759p-33215"},
    246 	{"2.71828182845904523536028747135266249775724709369995957496696763", "2.71828", "271828182845904523536028747135266249775724709369995957496696763/100000000000000000000000000000000000000000000000000000000000000"},
    247 	{"0e9999999999", "0", "0"}, // issue #16176
    248 
    249 	// Complex
    250 	{"0i", "(0 + 0i)", "(0 + 0i)"},
    251 	{"-0i", "(0 + 0i)", "(0 + 0i)"},
    252 	{"10i", "(0 + 10i)", "(0 + 10i)"},
    253 	{"-10i", "(0 + -10i)", "(0 + -10i)"},
    254 	{"1e9999i", "(0 + 1e+9999i)", "(0 + 0x.f8d4a9da224650a8cb2959e10d985ad92adbd44c62917e608b1f24c0e1b76b6f61edffeb15c135a4b601637315f7662f325f82325422b244286a07663c9415d2p+33216i)"},
    255 }
    256 
    257 func TestString(t *testing.T) {
    258 	for _, test := range stringTests {
    259 		x := val(test.input)
    260 		if got := x.String(); got != test.short {
    261 			t.Errorf("%s: got %q; want %q as short string", test.input, got, test.short)
    262 		}
    263 		if got := x.ExactString(); got != test.exact {
    264 			t.Errorf("%s: got %q; want %q as exact string", test.input, got, test.exact)
    265 		}
    266 	}
    267 }
    268 
    269 // ----------------------------------------------------------------------------
    270 // Support functions
    271 
    272 func val(lit string) Value {
    273 	if len(lit) == 0 {
    274 		return MakeUnknown()
    275 	}
    276 
    277 	switch lit {
    278 	case "?":
    279 		return MakeUnknown()
    280 	case "true":
    281 		return MakeBool(true)
    282 	case "false":
    283 		return MakeBool(false)
    284 	}
    285 
    286 	if i := strings.IndexByte(lit, '/'); i >= 0 {
    287 		// assume fraction
    288 		a := MakeFromLiteral(lit[:i], token.INT, 0)
    289 		b := MakeFromLiteral(lit[i+1:], token.INT, 0)
    290 		return BinaryOp(a, token.QUO, b)
    291 	}
    292 
    293 	tok := token.INT
    294 	switch first, last := lit[0], lit[len(lit)-1]; {
    295 	case first == '"' || first == '`':
    296 		tok = token.STRING
    297 		lit = strings.Replace(lit, "_", " ", -1)
    298 	case first == '\'':
    299 		tok = token.CHAR
    300 	case last == 'i':
    301 		tok = token.IMAG
    302 	default:
    303 		if !strings.HasPrefix(lit, "0x") && strings.ContainsAny(lit, "./Ee") {
    304 			tok = token.FLOAT
    305 		}
    306 	}
    307 
    308 	return MakeFromLiteral(lit, tok, 0)
    309 }
    310 
    311 var optab = map[string]token.Token{
    312 	"!": token.NOT,
    313 
    314 	"+": token.ADD,
    315 	"-": token.SUB,
    316 	"*": token.MUL,
    317 	"/": token.QUO,
    318 	"%": token.REM,
    319 
    320 	"<<": token.SHL,
    321 	">>": token.SHR,
    322 
    323 	"&":  token.AND,
    324 	"|":  token.OR,
    325 	"^":  token.XOR,
    326 	"&^": token.AND_NOT,
    327 
    328 	"==": token.EQL,
    329 	"!=": token.NEQ,
    330 	"<":  token.LSS,
    331 	"<=": token.LEQ,
    332 	">":  token.GTR,
    333 	">=": token.GEQ,
    334 }
    335 
    336 func panicHandler(v *Value) {
    337 	switch p := recover().(type) {
    338 	case nil:
    339 		// nothing to do
    340 	case string:
    341 		*v = MakeString(p)
    342 	case error:
    343 		*v = MakeString(p.Error())
    344 	default:
    345 		panic(p)
    346 	}
    347 }
    348 
    349 func doOp(x Value, op token.Token, y Value) (z Value) {
    350 	defer panicHandler(&z)
    351 
    352 	if x == nil {
    353 		return UnaryOp(op, y, 0)
    354 	}
    355 
    356 	switch op {
    357 	case token.EQL, token.NEQ, token.LSS, token.LEQ, token.GTR, token.GEQ:
    358 		return MakeBool(Compare(x, op, y))
    359 	case token.SHL, token.SHR:
    360 		s, _ := Int64Val(y)
    361 		return Shift(x, op, uint(s))
    362 	default:
    363 		return BinaryOp(x, op, y)
    364 	}
    365 }
    366 
    367 // ----------------------------------------------------------------------------
    368 // Other tests
    369 
    370 var fracTests = []string{
    371 	"0",
    372 	"1",
    373 	"-1",
    374 	"1.2",
    375 	"-0.991",
    376 	"2.718281828",
    377 	"3.14159265358979323e-10",
    378 	"1e100",
    379 	"1e1000",
    380 }
    381 
    382 func TestFractions(t *testing.T) {
    383 	for _, test := range fracTests {
    384 		x := val(test)
    385 		// We don't check the actual numerator and denominator because they
    386 		// are unlikely to be 100% correct due to floatVal rounding errors.
    387 		// Instead, we compute the fraction again and compare the rounded
    388 		// result.
    389 		q := BinaryOp(Num(x), token.QUO, Denom(x))
    390 		got := q.String()
    391 		want := x.String()
    392 		if got != want {
    393 			t.Errorf("%s: got quotient %s, want %s", x, got, want)
    394 		}
    395 	}
    396 }
    397 
    398 var bytesTests = []string{
    399 	"0",
    400 	"1",
    401 	"123456789",
    402 	"123456789012345678901234567890123456789012345678901234567890",
    403 }
    404 
    405 func TestBytes(t *testing.T) {
    406 	for _, test := range bytesTests {
    407 		x := val(test)
    408 		bytes := Bytes(x)
    409 
    410 		// special case 0
    411 		if Sign(x) == 0 && len(bytes) != 0 {
    412 			t.Errorf("%s: got %v; want empty byte slice", test, bytes)
    413 		}
    414 
    415 		if n := len(bytes); n > 0 && bytes[n-1] == 0 {
    416 			t.Errorf("%s: got %v; want no leading 0 byte", test, bytes)
    417 		}
    418 
    419 		if got := MakeFromBytes(bytes); !eql(got, x) {
    420 			t.Errorf("%s: got %s; want %s (bytes = %v)", test, got, x, bytes)
    421 		}
    422 	}
    423 }
    424 
    425 func TestUnknown(t *testing.T) {
    426 	u := MakeUnknown()
    427 	var values = []Value{
    428 		u,
    429 		MakeBool(false), // token.ADD ok below, operation is never considered
    430 		MakeString(""),
    431 		MakeInt64(1),
    432 		MakeFromLiteral("-1234567890123456789012345678901234567890", token.INT, 0),
    433 		MakeFloat64(1.2),
    434 		MakeImag(MakeFloat64(1.2)),
    435 	}
    436 	for _, val := range values {
    437 		x, y := val, u
    438 		for i := range [2]int{} {
    439 			if i == 1 {
    440 				x, y = y, x
    441 			}
    442 			if got := BinaryOp(x, token.ADD, y); got.Kind() != Unknown {
    443 				t.Errorf("%s + %s: got %s; want %s", x, y, got, u)
    444 			}
    445 			if got := Compare(x, token.EQL, y); got {
    446 				t.Errorf("%s == %s: got true; want false", x, y)
    447 			}
    448 		}
    449 	}
    450 }
    451