github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/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  		}
   180  		if x0 != nil && !eql(x, x0) {
   181  			t.Errorf("%s: x changed to %s", test, x)
   182  		}
   183  		if !eql(y, y0) {
   184  			t.Errorf("%s: y changed to %s", test, y)
   185  		}
   186  	}
   187  }
   188  
   189  func eql(x, y Value) bool {
   190  	_, ux := x.(unknownVal)
   191  	_, uy := y.(unknownVal)
   192  	if ux || uy {
   193  		return ux == uy
   194  	}
   195  	return Compare(x, token.EQL, y)
   196  }
   197  
   198  // ----------------------------------------------------------------------------
   199  // Support functions
   200  
   201  func val(lit string) Value {
   202  	if len(lit) == 0 {
   203  		return MakeUnknown()
   204  	}
   205  
   206  	switch lit {
   207  	case "?":
   208  		return MakeUnknown()
   209  	case "true":
   210  		return MakeBool(true)
   211  	case "false":
   212  		return MakeBool(false)
   213  	}
   214  
   215  	tok := token.INT
   216  	switch first, last := lit[0], lit[len(lit)-1]; {
   217  	case first == '"' || first == '`':
   218  		tok = token.STRING
   219  		lit = strings.Replace(lit, "_", " ", -1)
   220  	case first == '\'':
   221  		tok = token.CHAR
   222  	case last == 'i':
   223  		tok = token.IMAG
   224  	default:
   225  		if !strings.HasPrefix(lit, "0x") && strings.ContainsAny(lit, "./Ee") {
   226  			tok = token.FLOAT
   227  		}
   228  	}
   229  
   230  	return MakeFromLiteral(lit, tok, 0)
   231  }
   232  
   233  var optab = map[string]token.Token{
   234  	"!": token.NOT,
   235  
   236  	"+": token.ADD,
   237  	"-": token.SUB,
   238  	"*": token.MUL,
   239  	"/": token.QUO,
   240  	"%": token.REM,
   241  
   242  	"<<": token.SHL,
   243  	">>": token.SHR,
   244  
   245  	"&":  token.AND,
   246  	"|":  token.OR,
   247  	"^":  token.XOR,
   248  	"&^": token.AND_NOT,
   249  
   250  	"==": token.EQL,
   251  	"!=": token.NEQ,
   252  	"<":  token.LSS,
   253  	"<=": token.LEQ,
   254  	">":  token.GTR,
   255  	">=": token.GEQ,
   256  }
   257  
   258  func panicHandler(v *Value) {
   259  	switch p := recover().(type) {
   260  	case nil:
   261  		// nothing to do
   262  	case string:
   263  		*v = MakeString(p)
   264  	case error:
   265  		*v = MakeString(p.Error())
   266  	default:
   267  		panic(p)
   268  	}
   269  }
   270  
   271  func doOp(x Value, op token.Token, y Value) (z Value) {
   272  	defer panicHandler(&z)
   273  
   274  	if x == nil {
   275  		return UnaryOp(op, y, 0)
   276  	}
   277  
   278  	switch op {
   279  	case token.EQL, token.NEQ, token.LSS, token.LEQ, token.GTR, token.GEQ:
   280  		return MakeBool(Compare(x, op, y))
   281  	case token.SHL, token.SHR:
   282  		s, _ := Int64Val(y)
   283  		return Shift(x, op, uint(s))
   284  	default:
   285  		return BinaryOp(x, op, y)
   286  	}
   287  }
   288  
   289  // ----------------------------------------------------------------------------
   290  // Other tests
   291  
   292  var fracTests = []string{
   293  	"0 0 1",
   294  	"1 1 1",
   295  	"-1 -1 1",
   296  	"1.2 6 5",
   297  	"-0.991 -991 1000",
   298  	"1e100 1e100 1",
   299  }
   300  
   301  func TestFractions(t *testing.T) {
   302  	for _, test := range fracTests {
   303  		a := strings.Split(test, " ")
   304  		if len(a) != 3 {
   305  			t.Errorf("invalid test case: %s", test)
   306  			continue
   307  		}
   308  
   309  		x := val(a[0])
   310  		n := val(a[1])
   311  		d := val(a[2])
   312  
   313  		if got := Num(x); !eql(got, n) {
   314  			t.Errorf("%s: got num = %s; want %s", test, got, n)
   315  		}
   316  
   317  		if got := Denom(x); !eql(got, d) {
   318  			t.Errorf("%s: got denom = %s; want %s", test, got, d)
   319  		}
   320  	}
   321  }
   322  
   323  var bytesTests = []string{
   324  	"0",
   325  	"1",
   326  	"123456789",
   327  	"123456789012345678901234567890123456789012345678901234567890",
   328  }
   329  
   330  func TestBytes(t *testing.T) {
   331  	for _, test := range bytesTests {
   332  		x := val(test)
   333  		bytes := Bytes(x)
   334  
   335  		// special case 0
   336  		if Sign(x) == 0 && len(bytes) != 0 {
   337  			t.Errorf("%s: got %v; want empty byte slice", test, bytes)
   338  		}
   339  
   340  		if n := len(bytes); n > 0 && bytes[n-1] == 0 {
   341  			t.Errorf("%s: got %v; want no leading 0 byte", test, bytes)
   342  		}
   343  
   344  		if got := MakeFromBytes(bytes); !eql(got, x) {
   345  			t.Errorf("%s: got %s; want %s (bytes = %v)", test, got, x, bytes)
   346  		}
   347  	}
   348  }
   349  
   350  func TestUnknown(t *testing.T) {
   351  	u := MakeUnknown()
   352  	var values = []Value{
   353  		u,
   354  		MakeBool(false), // token.ADD ok below, operation is never considered
   355  		MakeString(""),
   356  		MakeInt64(1),
   357  		MakeFromLiteral("-1234567890123456789012345678901234567890", token.INT, 0),
   358  		MakeFloat64(1.2),
   359  		MakeImag(MakeFloat64(1.2)),
   360  	}
   361  	for _, val := range values {
   362  		x, y := val, u
   363  		for i := range [2]int{} {
   364  			if i == 1 {
   365  				x, y = y, x
   366  			}
   367  			if got := BinaryOp(x, token.ADD, y); got.Kind() != Unknown {
   368  				t.Errorf("%s + %s: got %s; want %s", x, y, got, u)
   369  			}
   370  			if got := Compare(x, token.EQL, y); got {
   371  				t.Errorf("%s == %s: got true; want false", x, y)
   372  			}
   373  		}
   374  	}
   375  }