Source file
src/go/constant/value_test.go
1
2
3
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
18 `0_123 = 0123`,
19 `0123_456 = 0123456`,
20
21
22 `1_234 = 1234`,
23 `1_234_567 = 1234567`,
24
25
26 `0X_0 = 0`,
27 `0X_1234 = 0x1234`,
28 `0X_CAFE_f00d = 0xcafef00d`,
29
30
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
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
62 var floatTests = []string{
63
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
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
176
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
185 `+ 0 = 0`,
186 `+ ? = ?`,
187 `- 1 = -1`,
188 `- ? = ?`,
189 `^ 0 = -1`,
190 `^ ? = ?`,
191
192 `! true = false`,
193 `! false = true`,
194 `! ? = ?`,
195
196
197
198
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"`,
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
261
262
263 `0 << 0 = 0`,
264 `1 << 10 = 1024`,
265 `0 >> 0 = 0`,
266 `1024 >> 10 == 1`,
267 `? << 0 == ?`,
268 `? >> 10 == ?`,
269
270
271
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
318 }
319
320 func TestOps(t *testing.T) {
321 for _, test := range opTests {
322 a := strings.Split(test, " ")
323 i := 0
324
325 var x, x0 Value
326 switch len(a) {
327 case 4:
328
329 case 5:
330
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
375
376 var xxx = strings.Repeat("x", 68)
377 var issue14262 = `"بموجب الشروط التالية نسب المصنف — يجب عليك أن تنسب العمل بالطريقة التي تحددها المؤلف أو المرخص (ولكن ليس بأي حال من الأحوال أن توحي وتقترح بتحول أو استخدامك للعمل). المشاركة على قدم المساواة — إذا كنت يعدل ، والتغيير ، أو الاستفادة من هذا العمل ، قد ينتج عن توزيع العمل إلا في ظل تشابه او تطابق فى واحد لهذا الترخيص."`
378
379 var stringTests = []struct {
380 input, short, exact string
381 }{
382
383 {"", "unknown", "unknown"},
384 {"0x", "unknown", "unknown"},
385 {"'", "unknown", "unknown"},
386 {"1f0", "unknown", "unknown"},
387 {"unknown", "unknown", "unknown"},
388
389
390 {"true", "true", "true"},
391 {"false", "false", "false"},
392
393
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
402 {"0", "0", "0"},
403 {"-1", "-1", "-1"},
404 {"12345", "12345", "12345"},
405 {"-12345678901234567890", "-12345678901234567890", "-12345678901234567890"},
406 {"12345678901234567890", "12345678901234567890", "12345678901234567890"},
407
408
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"},
418 {"-6e-1886451601", "0", "0"},
419
420
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
441
442
443 func val(lit string) Value {
444 if len(lit) == 0 {
445 return MakeUnknown()
446 }
447
448 switch lit {
449 case "?":
450 return MakeUnknown()
451 case "true":
452 return MakeBool(true)
453 case "false":
454 return MakeBool(false)
455 }
456
457 if as, bs, ok := strings.Cut(lit, "/"); ok {
458
459 a := MakeFromLiteral(as, token.INT, 0)
460 b := MakeFromLiteral(bs, token.INT, 0)
461 return BinaryOp(a, token.QUO, b)
462 }
463
464 tok := token.INT
465 switch first, last := lit[0], lit[len(lit)-1]; {
466 case first == '"' || first == '`':
467 tok = token.STRING
468 lit = strings.ReplaceAll(lit, "_", " ")
469 case first == '\'':
470 tok = token.CHAR
471 case last == 'i':
472 tok = token.IMAG
473 default:
474 if !strings.HasPrefix(lit, "0x") && strings.ContainsAny(lit, "./Ee") {
475 tok = token.FLOAT
476 }
477 }
478
479 return MakeFromLiteral(lit, tok, 0)
480 }
481
482 var optab = map[string]token.Token{
483 "!": token.NOT,
484
485 "+": token.ADD,
486 "-": token.SUB,
487 "*": token.MUL,
488 "/": token.QUO,
489 "%": token.REM,
490
491 "<<": token.SHL,
492 ">>": token.SHR,
493
494 "&": token.AND,
495 "|": token.OR,
496 "^": token.XOR,
497 "&^": token.AND_NOT,
498
499 "==": token.EQL,
500 "!=": token.NEQ,
501 "<": token.LSS,
502 "<=": token.LEQ,
503 ">": token.GTR,
504 ">=": token.GEQ,
505 }
506
507 func panicHandler(v *Value) {
508 switch p := recover().(type) {
509 case nil:
510
511 case string:
512 *v = MakeString(p)
513 case error:
514 *v = MakeString(p.Error())
515 default:
516 panic(p)
517 }
518 }
519
520 func doOp(x Value, op token.Token, y Value) (z Value) {
521 defer panicHandler(&z)
522
523 if x == nil {
524 return UnaryOp(op, y, 0)
525 }
526
527 switch op {
528 case token.EQL, token.NEQ, token.LSS, token.LEQ, token.GTR, token.GEQ:
529 return MakeBool(Compare(x, op, y))
530 case token.SHL, token.SHR:
531 s, _ := Int64Val(y)
532 return Shift(x, op, uint(s))
533 default:
534 return BinaryOp(x, op, y)
535 }
536 }
537
538
539
540
541 var fracTests = []string{
542 "0",
543 "1",
544 "-1",
545 "1.2",
546 "-0.991",
547 "2.718281828",
548 "3.14159265358979323e-10",
549 "1e100",
550 "1e1000",
551 }
552
553 func TestFractions(t *testing.T) {
554 for _, test := range fracTests {
555 x := val(test)
556
557
558
559
560 q := BinaryOp(Num(x), token.QUO, Denom(x))
561 got := q.String()
562 want := x.String()
563 if got != want {
564 t.Errorf("%s: got quotient %s, want %s", x, got, want)
565 }
566 }
567 }
568
569 var bytesTests = []string{
570 "0",
571 "1",
572 "123456789",
573 "123456789012345678901234567890123456789012345678901234567890",
574 }
575
576 func TestBytes(t *testing.T) {
577 for _, test := range bytesTests {
578 x := val(test)
579 bytes := Bytes(x)
580
581
582 if Sign(x) == 0 && len(bytes) != 0 {
583 t.Errorf("%s: got %v; want empty byte slice", test, bytes)
584 }
585
586 if n := len(bytes); n > 0 && bytes[n-1] == 0 {
587 t.Errorf("%s: got %v; want no leading 0 byte", test, bytes)
588 }
589
590 if got := MakeFromBytes(bytes); !eql(got, x) {
591 t.Errorf("%s: got %s; want %s (bytes = %v)", test, got, x, bytes)
592 }
593 }
594 }
595
596 func TestUnknown(t *testing.T) {
597 u := MakeUnknown()
598 var values = []Value{
599 u,
600 MakeBool(false),
601 MakeString(""),
602 MakeInt64(1),
603 MakeFromLiteral("''", token.CHAR, 0),
604 MakeFromLiteral("-1234567890123456789012345678901234567890", token.INT, 0),
605 MakeFloat64(1.2),
606 MakeImag(MakeFloat64(1.2)),
607 }
608 for _, val := range values {
609 x, y := val, u
610 for i := range [2]int{} {
611 if i == 1 {
612 x, y = y, x
613 }
614 if got := BinaryOp(x, token.ADD, y); got.Kind() != Unknown {
615 t.Errorf("%s + %s: got %s; want %s", x, y, got, u)
616 }
617 if got := Compare(x, token.EQL, y); got {
618 t.Errorf("%s == %s: got true; want false", x, y)
619 }
620 }
621 }
622 }
623
624 func TestMakeFloat64(t *testing.T) {
625 var zero float64
626 for _, arg := range []float64{
627 -math.MaxFloat32,
628 -10,
629 -0.5,
630 -zero,
631 zero,
632 1,
633 10,
634 123456789.87654321e-23,
635 1e10,
636 math.MaxFloat64,
637 } {
638 val := MakeFloat64(arg)
639 if val.Kind() != Float {
640 t.Errorf("%v: got kind = %d; want %d", arg, val.Kind(), Float)
641 }
642
643
644 got, exact := Float64Val(val)
645 if !exact || math.Float64bits(got) != math.Float64bits(arg+0) {
646 t.Errorf("%v: got %v (exact = %v)", arg, got, exact)
647 }
648 }
649
650
651 for sign := range []int{-1, 1} {
652 arg := math.Inf(sign)
653 val := MakeFloat64(arg)
654 if val.Kind() != Unknown {
655 t.Errorf("%v: got kind = %d; want %d", arg, val.Kind(), Unknown)
656 }
657 }
658 }
659
660 type makeTestCase struct {
661 kind Kind
662 arg, want any
663 }
664
665 func dup(k Kind, x any) makeTestCase { return makeTestCase{k, x, x} }
666
667 func TestMake(t *testing.T) {
668 for _, test := range []makeTestCase{
669 {Bool, false, false},
670 {String, "hello", "hello"},
671
672 {Int, int64(1), int64(1)},
673 {Int, big.NewInt(10), int64(10)},
674 {Int, new(big.Int).Lsh(big.NewInt(1), 62), int64(1 << 62)},
675 dup(Int, new(big.Int).Lsh(big.NewInt(1), 63)),
676
677 {Float, big.NewFloat(0), floatVal0.val},
678 dup(Float, big.NewFloat(2.0)),
679 dup(Float, big.NewRat(1, 3)),
680 } {
681 val := Make(test.arg)
682 got := Val(val)
683 if val.Kind() != test.kind || got != test.want {
684 t.Errorf("got %v (%T, kind = %d); want %v (%T, kind = %d)",
685 got, got, val.Kind(), test.want, test.want, test.kind)
686 }
687 }
688 }
689
690 func BenchmarkStringAdd(b *testing.B) {
691 for size := 1; size <= 65536; size *= 4 {
692 b.Run(fmt.Sprint(size), func(b *testing.B) {
693 b.ReportAllocs()
694 n := int64(0)
695 for i := 0; i < b.N; i++ {
696 x := MakeString(strings.Repeat("x", 100))
697 y := x
698 for j := 0; j < size-1; j++ {
699 y = BinaryOp(y, token.ADD, x)
700 }
701 n += int64(len(StringVal(y)))
702 }
703 if n != int64(b.N)*int64(size)*100 {
704 b.Fatalf("bad string %d != %d", n, int64(b.N)*int64(size)*100)
705 }
706 })
707 }
708 }
709
710 var bitLenTests = []struct {
711 val int64
712 want int
713 }{
714 {0, 0},
715 {1, 1},
716 {-16, 5},
717 {1 << 61, 62},
718 {1 << 62, 63},
719 {-1 << 62, 63},
720 {-1 << 63, 64},
721 }
722
723 func TestBitLen(t *testing.T) {
724 for _, test := range bitLenTests {
725 if got := BitLen(MakeInt64(test.val)); got != test.want {
726 t.Errorf("%v: got %v, want %v", test.val, got, test.want)
727 }
728 }
729 }
730
View as plain text