github.com/mattn/go@v0.0.0-20171011075504-07f7db3ea99f/src/go/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 "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 {"-6e-1886451601", "0", "0"}, // issue #20228 249 250 // Complex 251 {"0i", "(0 + 0i)", "(0 + 0i)"}, 252 {"-0i", "(0 + 0i)", "(0 + 0i)"}, 253 {"10i", "(0 + 10i)", "(0 + 10i)"}, 254 {"-10i", "(0 + -10i)", "(0 + -10i)"}, 255 {"1e9999i", "(0 + 1e+9999i)", "(0 + 0x.f8d4a9da224650a8cb2959e10d985ad92adbd44c62917e608b1f24c0e1b76b6f61edffeb15c135a4b601637315f7662f325f82325422b244286a07663c9415d2p+33216i)"}, 256 } 257 258 func TestString(t *testing.T) { 259 for _, test := range stringTests { 260 x := val(test.input) 261 if got := x.String(); got != test.short { 262 t.Errorf("%s: got %q; want %q as short string", test.input, got, test.short) 263 } 264 if got := x.ExactString(); got != test.exact { 265 t.Errorf("%s: got %q; want %q as exact string", test.input, got, test.exact) 266 } 267 } 268 } 269 270 // ---------------------------------------------------------------------------- 271 // Support functions 272 273 func val(lit string) Value { 274 if len(lit) == 0 { 275 return MakeUnknown() 276 } 277 278 switch lit { 279 case "?": 280 return MakeUnknown() 281 case "true": 282 return MakeBool(true) 283 case "false": 284 return MakeBool(false) 285 } 286 287 if i := strings.IndexByte(lit, '/'); i >= 0 { 288 // assume fraction 289 a := MakeFromLiteral(lit[:i], token.INT, 0) 290 b := MakeFromLiteral(lit[i+1:], token.INT, 0) 291 return BinaryOp(a, token.QUO, b) 292 } 293 294 tok := token.INT 295 switch first, last := lit[0], lit[len(lit)-1]; { 296 case first == '"' || first == '`': 297 tok = token.STRING 298 lit = strings.Replace(lit, "_", " ", -1) 299 case first == '\'': 300 tok = token.CHAR 301 case last == 'i': 302 tok = token.IMAG 303 default: 304 if !strings.HasPrefix(lit, "0x") && strings.ContainsAny(lit, "./Ee") { 305 tok = token.FLOAT 306 } 307 } 308 309 return MakeFromLiteral(lit, tok, 0) 310 } 311 312 var optab = map[string]token.Token{ 313 "!": token.NOT, 314 315 "+": token.ADD, 316 "-": token.SUB, 317 "*": token.MUL, 318 "/": token.QUO, 319 "%": token.REM, 320 321 "<<": token.SHL, 322 ">>": token.SHR, 323 324 "&": token.AND, 325 "|": token.OR, 326 "^": token.XOR, 327 "&^": token.AND_NOT, 328 329 "==": token.EQL, 330 "!=": token.NEQ, 331 "<": token.LSS, 332 "<=": token.LEQ, 333 ">": token.GTR, 334 ">=": token.GEQ, 335 } 336 337 func panicHandler(v *Value) { 338 switch p := recover().(type) { 339 case nil: 340 // nothing to do 341 case string: 342 *v = MakeString(p) 343 case error: 344 *v = MakeString(p.Error()) 345 default: 346 panic(p) 347 } 348 } 349 350 func doOp(x Value, op token.Token, y Value) (z Value) { 351 defer panicHandler(&z) 352 353 if x == nil { 354 return UnaryOp(op, y, 0) 355 } 356 357 switch op { 358 case token.EQL, token.NEQ, token.LSS, token.LEQ, token.GTR, token.GEQ: 359 return MakeBool(Compare(x, op, y)) 360 case token.SHL, token.SHR: 361 s, _ := Int64Val(y) 362 return Shift(x, op, uint(s)) 363 default: 364 return BinaryOp(x, op, y) 365 } 366 } 367 368 // ---------------------------------------------------------------------------- 369 // Other tests 370 371 var fracTests = []string{ 372 "0", 373 "1", 374 "-1", 375 "1.2", 376 "-0.991", 377 "2.718281828", 378 "3.14159265358979323e-10", 379 "1e100", 380 "1e1000", 381 } 382 383 func TestFractions(t *testing.T) { 384 for _, test := range fracTests { 385 x := val(test) 386 // We don't check the actual numerator and denominator because they 387 // are unlikely to be 100% correct due to floatVal rounding errors. 388 // Instead, we compute the fraction again and compare the rounded 389 // result. 390 q := BinaryOp(Num(x), token.QUO, Denom(x)) 391 got := q.String() 392 want := x.String() 393 if got != want { 394 t.Errorf("%s: got quotient %s, want %s", x, got, want) 395 } 396 } 397 } 398 399 var bytesTests = []string{ 400 "0", 401 "1", 402 "123456789", 403 "123456789012345678901234567890123456789012345678901234567890", 404 } 405 406 func TestBytes(t *testing.T) { 407 for _, test := range bytesTests { 408 x := val(test) 409 bytes := Bytes(x) 410 411 // special case 0 412 if Sign(x) == 0 && len(bytes) != 0 { 413 t.Errorf("%s: got %v; want empty byte slice", test, bytes) 414 } 415 416 if n := len(bytes); n > 0 && bytes[n-1] == 0 { 417 t.Errorf("%s: got %v; want no leading 0 byte", test, bytes) 418 } 419 420 if got := MakeFromBytes(bytes); !eql(got, x) { 421 t.Errorf("%s: got %s; want %s (bytes = %v)", test, got, x, bytes) 422 } 423 } 424 } 425 426 func TestUnknown(t *testing.T) { 427 u := MakeUnknown() 428 var values = []Value{ 429 u, 430 MakeBool(false), // token.ADD ok below, operation is never considered 431 MakeString(""), 432 MakeInt64(1), 433 MakeFromLiteral("-1234567890123456789012345678901234567890", token.INT, 0), 434 MakeFloat64(1.2), 435 MakeImag(MakeFloat64(1.2)), 436 } 437 for _, val := range values { 438 x, y := val, u 439 for i := range [2]int{} { 440 if i == 1 { 441 x, y = y, x 442 } 443 if got := BinaryOp(x, token.ADD, y); got.Kind() != Unknown { 444 t.Errorf("%s + %s: got %s; want %s", x, y, got, u) 445 } 446 if got := Compare(x, token.EQL, y); got { 447 t.Errorf("%s == %s: got true; want false", x, y) 448 } 449 } 450 } 451 }