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/big"
11	"strings"
12	"testing"
13)
14
15var 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.
61var 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
109var 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
122func 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.
155func TestNumbers(t *testing.T) {
156	testNumbers(t, token.INT, intTests)
157	testNumbers(t, token.FLOAT, floatTests)
158	testNumbers(t, token.IMAG, imagTests)
159}
160
161var 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
296func 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
340func 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
352var xxx = strings.Repeat("x", 68)
353var issue14262 = `"بموجب الشروط التالية نسب المصنف — يجب عليك أن تنسب العمل بالطريقة التي تحددها المؤلف أو المرخص (ولكن ليس بأي حال من الأحوال أن توحي وتقترح بتحول أو استخدامك للعمل).  المشاركة على قدم المساواة — إذا كنت يعدل ، والتغيير ، أو الاستفادة من هذا العمل ، قد ينتج عن توزيع العمل إلا في ظل تشابه او تطابق فى واحد لهذا الترخيص."`
354
355var 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
404func 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
419func 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
458var 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
483func 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
496func 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
517var 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
529func 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
545var bytesTests = []string{
546	"0",
547	"1",
548	"123456789",
549	"123456789012345678901234567890123456789012345678901234567890",
550}
551
552func 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
572func 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
600func 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
616func 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}
635