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
5package constant
6
7import (
8	"fmt"
9	"go/token"
10	"math"
11	"math/big"
12	"strings"
13	"testing"
14)
15
16var 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.
62var 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
115var 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
133func 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.
177func TestNumbers(t *testing.T) {
178	testNumbers(t, token.INT, intTests)
179	testNumbers(t, token.FLOAT, floatTests)
180	testNumbers(t, token.IMAG, imagTests)
181}
182
183var 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
320func 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
364func 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
376var xxx = strings.Repeat("x", 68)
377var issue14262 = `"بموجب الشروط التالية نسب المصنف — يجب عليك أن تنسب العمل بالطريقة التي تحددها المؤلف أو المرخص (ولكن ليس بأي حال من الأحوال أن توحي وتقترح بتحول أو استخدامك للعمل).  المشاركة على قدم المساواة — إذا كنت يعدل ، والتغيير ، أو الاستفادة من هذا العمل ، قد ينتج عن توزيع العمل إلا في ظل تشابه او تطابق فى واحد لهذا الترخيص."`
378
379var 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
428func 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// Support functions
442
443func 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		// assume fraction
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
482var 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
507func panicHandler(v *Value) {
508	switch p := recover().(type) {
509	case nil:
510		// nothing to do
511	case string:
512		*v = MakeString(p)
513	case error:
514		*v = MakeString(p.Error())
515	default:
516		panic(p)
517	}
518}
519
520func 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// Other tests
540
541var 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
553func TestFractions(t *testing.T) {
554	for _, test := range fracTests {
555		x := val(test)
556		// We don't check the actual numerator and denominator because they
557		// are unlikely to be 100% correct due to floatVal rounding errors.
558		// Instead, we compute the fraction again and compare the rounded
559		// result.
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
569var bytesTests = []string{
570	"0",
571	"1",
572	"123456789",
573	"123456789012345678901234567890123456789012345678901234567890",
574}
575
576func TestBytes(t *testing.T) {
577	for _, test := range bytesTests {
578		x := val(test)
579		bytes := Bytes(x)
580
581		// special case 0
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
596func TestUnknown(t *testing.T) {
597	u := MakeUnknown()
598	var values = []Value{
599		u,
600		MakeBool(false), // token.ADD ok below, operation is never considered
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
624func 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		// -0.0 is mapped to 0.0
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	// infinity
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
660type makeTestCase struct {
661	kind      Kind
662	arg, want any
663}
664
665func dup(k Kind, x any) makeTestCase { return makeTestCase{k, x, x} }
666
667func 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
690func 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
710var 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
723func 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