github.com/grumpyhome/grumpy@v0.3.1-0.20201208125205-7b775405bdf1/grumpy-runtime-src/runtime/long_test.go (about)

     1  package grumpy
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  	"math/big"
     7  	"reflect"
     8  	"testing"
     9  )
    10  
    11  var overflowLong = big.NewInt(0).Add(maxIntBig, big.NewInt(101))
    12  
    13  func TestLongBasis(t *testing.T) {
    14  	got := LongType.slots.Basis.Fn(NewLong(big.NewInt(42)).ToObject()).Type()
    15  	want := reflect.TypeOf(Long{})
    16  	if got != want {
    17  		t.Fatalf("LongType.slots.Basis.Fn(NewLong(big.NewInt(42).ToObject()).Type() = %v, want %v", got, want)
    18  	}
    19  }
    20  
    21  func TestNewLongFromBytes(t *testing.T) {
    22  	cases := []struct {
    23  		bytes []byte
    24  		want  string
    25  	}{
    26  		{bytes: []byte{0x01, 0x00}, want: "100"},
    27  		{bytes: []byte{0x01, 0x02, 0x03}, want: "10203"},
    28  		{bytes: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09},
    29  			want: "10203040506070809"},
    30  	}
    31  	for _, cas := range cases {
    32  		got := NewLongFromBytes(cas.bytes).value.Text(16)
    33  		if got != cas.want {
    34  			t.Errorf("NewLongFromBytes(%v).value.Text(16) = %v, want %v", cas.bytes, got, cas.want)
    35  		}
    36  	}
    37  }
    38  
    39  func TestLongReprStr(t *testing.T) {
    40  	cases := []string{
    41  		"0",
    42  		"123",
    43  		"-1",
    44  		"3000",
    45  		"42",
    46  		fmt.Sprint(MaxInt),
    47  		fmt.Sprint(MinInt),
    48  		"10000000000000000",
    49  	}
    50  	for _, cas := range cases {
    51  		i, _ := new(big.Int).SetString(cas, 0)
    52  		o := NewLong(i).ToObject()
    53  		repr, raised := o.typ.slots.Repr.Fn(nil, o)
    54  		if raised != nil || toStrUnsafe(repr).Value() != cas+"L" {
    55  			t.Errorf("(%sL).__repr__() = (%v, %v), want (%v, %v)", cas, toStrUnsafe(repr).Value(), raised, cas, nil)
    56  		}
    57  		str, raised := o.typ.slots.Str.Fn(nil, o)
    58  		if raised != nil || toStrUnsafe(str).Value() != cas {
    59  			t.Errorf("(%sL).__str__() = (%v, %v), want (%v, %v)", cas, toStrUnsafe(str).Value(), raised, cas, nil)
    60  		}
    61  	}
    62  }
    63  
    64  func TestLongNew(t *testing.T) {
    65  	fooType := newTestClass("Foo", []*Type{ObjectType}, newStringDict(map[string]*Object{
    66  		"__long__": newBuiltinFunction("__long__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
    67  			return args[0], nil
    68  		}).ToObject(),
    69  	}))
    70  	strictEqType := newTestClassStrictEq("StrictEq", LongType)
    71  	newStrictEq := func(i *big.Int) *Object {
    72  		l := Long{Object: Object{typ: strictEqType}}
    73  		l.value.Set(i)
    74  		return l.ToObject()
    75  	}
    76  	longSubType := newTestClass("LongSubType", []*Type{LongType}, newStringDict(map[string]*Object{}))
    77  	cases := []invokeTestCase{
    78  		{args: wrapArgs(LongType), want: NewLong(big.NewInt(0)).ToObject()},
    79  		{args: wrapArgs(LongType, "123"), want: NewLong(big.NewInt(123)).ToObject()},
    80  		{args: wrapArgs(LongType, "123L"), want: NewLong(big.NewInt(123)).ToObject()},
    81  		{args: wrapArgs(LongType, "123l"), want: NewLong(big.NewInt(123)).ToObject()},
    82  		{args: wrapArgs(LongType, " \t123L"), want: NewLong(big.NewInt(123)).ToObject()},
    83  		{args: wrapArgs(LongType, "123L \t"), want: NewLong(big.NewInt(123)).ToObject()},
    84  		{args: wrapArgs(LongType, "FF", 16), want: NewLong(big.NewInt(255)).ToObject()},
    85  		{args: wrapArgs(LongType, "0xFFL", 16), want: NewLong(big.NewInt(255)).ToObject()},
    86  		{args: wrapArgs(LongType, "0xE", 0), want: NewLong(big.NewInt(14)).ToObject()},
    87  		{args: wrapArgs(LongType, "0b101L", 0), want: NewLong(big.NewInt(5)).ToObject()},
    88  		{args: wrapArgs(LongType, "0o726", 0), want: NewLong(big.NewInt(470)).ToObject()},
    89  		{args: wrapArgs(LongType, "102", 0), want: NewLong(big.NewInt(102)).ToObject()},
    90  		{args: wrapArgs(LongType, 42), want: NewLong(big.NewInt(42)).ToObject()},
    91  		{args: wrapArgs(LongType, -3.14), want: NewLong(big.NewInt(-3)).ToObject()},
    92  		{args: wrapArgs(LongType, newObject(longSubType)), want: NewLong(big.NewInt(0)).ToObject()},
    93  		{args: wrapArgs(strictEqType, big.NewInt(42)), want: newStrictEq(big.NewInt(42))},
    94  		{args: wrapArgs(LongType, "0xff"), wantExc: mustCreateException(ValueErrorType, "invalid literal for long() with base 10: 0xff")},
    95  		{args: wrapArgs(LongType, ""), wantExc: mustCreateException(ValueErrorType, "invalid literal for long() with base 10: ")},
    96  		{args: wrapArgs(LongType, " "), wantExc: mustCreateException(ValueErrorType, "invalid literal for long() with base 10:  ")},
    97  		{args: wrapArgs(FloatType), wantExc: mustCreateException(TypeErrorType, "long.__new__(float): float is not a subtype of long")},
    98  		{args: wrapArgs(LongType, "asldkfj", 1), wantExc: mustCreateException(ValueErrorType, "long() base must be >= 2 and <= 36")},
    99  		{args: wrapArgs(LongType, "asldkfj", 37), wantExc: mustCreateException(ValueErrorType, "long() base must be >= 2 and <= 36")},
   100  		{args: wrapArgs(LongType, "@#%*(#", 36), wantExc: mustCreateException(ValueErrorType, "invalid literal for long() with base 36: @#%*(#")},
   101  		{args: wrapArgs(LongType, "32059823095809238509238590835"), want: NewLong(func() *big.Int { i, _ := new(big.Int).SetString("32059823095809238509238590835", 0); return i }()).ToObject()},
   102  		{args: wrapArgs(LongType, big.NewInt(3)), want: NewLong(big.NewInt(3)).ToObject()},
   103  		{args: wrapArgs(LongType, NewInt(3)), want: NewLong(big.NewInt(3)).ToObject()},
   104  		{args: wrapArgs(LongType, NewInt(3).ToObject()), want: NewLong(big.NewInt(3)).ToObject()},
   105  		{args: wrapArgs(LongType, NewLong(big.NewInt(3))), want: NewLong(big.NewInt(3)).ToObject()},
   106  		{args: wrapArgs(LongType, NewLong(big.NewInt(3)).ToObject()), want: NewLong(big.NewInt(3)).ToObject()},
   107  		{args: wrapArgs(LongType, newObject(ObjectType)), wantExc: mustCreateException(TypeErrorType, "'__new__' requires a 'str' object but received a 'object'")},
   108  		{args: wrapArgs(LongType, newObject(fooType)), wantExc: mustCreateException(TypeErrorType, "__long__ returned non-long (type Foo)")},
   109  	}
   110  	for _, cas := range cases {
   111  		if err := runInvokeMethodTestCase(LongType, "__new__", &cas); err != "" {
   112  			t.Error(err)
   113  		}
   114  	}
   115  }
   116  
   117  func TestLongBinaryOps(t *testing.T) {
   118  	cases := []struct {
   119  		fun     binaryOpFunc
   120  		v, w    interface{}
   121  		want    *Object
   122  		wantExc *BaseException
   123  	}{
   124  		{Add, -100, 50, NewLong(big.NewInt(-50)).ToObject(), nil},
   125  		{Add, newObject(ObjectType), -100, nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for +: 'object' and 'long'")},
   126  		{Add, MaxInt, 1, NewLong(new(big.Int).Add(maxIntBig, big.NewInt(1))).ToObject(), nil},
   127  		{And, -100, 50, NewLong(big.NewInt(16)).ToObject(), nil},
   128  		{And, MaxInt, MinInt, NewLong(big.NewInt(0)).ToObject(), nil},
   129  		{And, newObject(ObjectType), -100, nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for &: 'object' and 'long'")},
   130  		{Div, 7, 3, NewLong(big.NewInt(2)).ToObject(), nil},
   131  		{Div, MaxInt, MinInt, NewLong(big.NewInt(-1)).ToObject(), nil},
   132  		{Div, MinInt, MaxInt, NewLong(big.NewInt(-2)).ToObject(), nil},
   133  		{Div, NewList().ToObject(), NewLong(big.NewInt(21)).ToObject(), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for /: 'list' and 'long'")},
   134  		{Div, 1, 0, nil, mustCreateException(ZeroDivisionErrorType, "integer division or modulo by zero")},
   135  		{Div, MinInt, -1, NewLong(new(big.Int).Neg(minIntBig)).ToObject(), nil},
   136  		{DivMod, 7, 3, NewTuple2(NewLong(big.NewInt(2)).ToObject(), NewLong(big.NewInt(1)).ToObject()).ToObject(), nil},
   137  		{DivMod, 3, -7, NewTuple2(NewLong(big.NewInt(-1)).ToObject(), NewLong(big.NewInt(-4)).ToObject()).ToObject(), nil},
   138  		{DivMod, MaxInt, MinInt, NewTuple2(NewLong(big.NewInt(-1)).ToObject(), NewLong(big.NewInt(-1)).ToObject()).ToObject(), nil},
   139  		{DivMod, MinInt, MaxInt, NewTuple2(NewLong(big.NewInt(-2)).ToObject(), NewLong(big.NewInt(MaxInt-1)).ToObject()).ToObject(), nil},
   140  		{DivMod, MinInt, 1, NewTuple2(NewLong(big.NewInt(MinInt)).ToObject(), NewLong(big.NewInt(0)).ToObject()).ToObject(), nil},
   141  		{DivMod, MinInt, -1, NewTuple2(NewLong(new(big.Int).Neg(minIntBig)).ToObject(), NewLong(big.NewInt(0)).ToObject()).ToObject(), nil},
   142  		{DivMod, NewList().ToObject(), NewLong(big.NewInt(21)).ToObject(), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for divmod(): 'list' and 'long'")},
   143  		{DivMod, 1, 0, nil, mustCreateException(ZeroDivisionErrorType, "integer division or modulo by zero")},
   144  		{FloorDiv, 7, 3, NewLong(big.NewInt(2)).ToObject(), nil},
   145  		{FloorDiv, MaxInt, MinInt, NewLong(big.NewInt(-1)).ToObject(), nil},
   146  		{FloorDiv, MinInt, MaxInt, NewLong(big.NewInt(-2)).ToObject(), nil},
   147  		{FloorDiv, NewList().ToObject(), NewLong(big.NewInt(21)).ToObject(), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for //: 'list' and 'long'")},
   148  		{FloorDiv, 1, 0, nil, mustCreateException(ZeroDivisionErrorType, "integer division or modulo by zero")},
   149  		{FloorDiv, MinInt, -1, NewLong(new(big.Int).Neg(minIntBig)).ToObject(), nil},
   150  		{LShift, 2, 4, NewLong(big.NewInt(32)).ToObject(), nil},
   151  		{LShift, 12, 10, NewLong(big.NewInt(12288)).ToObject(), nil},
   152  		{LShift, 10, 100, NewLong(new(big.Int).Lsh(big.NewInt(10), 100)).ToObject(), nil},
   153  		{LShift, 2, -5, nil, mustCreateException(ValueErrorType, "negative shift count")},
   154  		{LShift, 4, NewFloat(3.14).ToObject(), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for <<: 'long' and 'float'")},
   155  		{LShift, newObject(ObjectType), 4, nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for <<: 'object' and 'long'")},
   156  		{RShift, 87, 3, NewLong(big.NewInt(10)).ToObject(), nil},
   157  		{RShift, -101, 5, NewLong(big.NewInt(-4)).ToObject(), nil},
   158  		{RShift, 12, NewInt(10).ToObject(), NewLong(big.NewInt(0)).ToObject(), nil},
   159  		{RShift, 12, -10, nil, mustCreateException(ValueErrorType, "negative shift count")},
   160  		{RShift, 4, NewFloat(3.14).ToObject(), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for >>: 'long' and 'float'")},
   161  		{RShift, newObject(ObjectType), 4, nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for >>: 'object' and 'long'")},
   162  		{RShift, 4, newObject(ObjectType), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for >>: 'long' and 'object'")},
   163  		{Mod, 3, -7, NewLong(big.NewInt(-4)).ToObject(), nil},
   164  		{Mod, MaxInt, MinInt, NewLong(big.NewInt(-1)).ToObject(), nil},
   165  		{Mod, MinInt, MaxInt, NewLong(big.NewInt(int64(MaxInt) - 1)).ToObject(), nil},
   166  		{Mod, None, 4, nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for %: 'NoneType' and 'long'")},
   167  		{Mod, 10, 0, nil, mustCreateException(ZeroDivisionErrorType, "integer division or modulo by zero")},
   168  		{Mod, MinInt, 1, NewLong(big.NewInt(0)).ToObject(), nil},
   169  		{Mul, 1, 3, NewLong(big.NewInt(3)).ToObject(), nil},
   170  		{Mul, newObject(ObjectType), 101, nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for *: 'object' and 'long'")},
   171  		{Mul, int64(4294967295), int64(2147483649), NewLong(new(big.Int).Mul(big.NewInt(4294967295), big.NewInt(2147483649))).ToObject(), nil},
   172  		{Or, -100, 50, NewLong(big.NewInt(-66)).ToObject(), nil},
   173  		{Or, MaxInt, MinInt, NewLong(big.NewInt(-1)).ToObject(), nil},
   174  		{Or, newObject(ObjectType), 100, nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for |: 'object' and 'long'")},
   175  		{Pow, 2, 128, NewLong(big.NewInt(0).Exp(big.NewInt(2), big.NewInt(128), nil)).ToObject(), nil},
   176  		{Pow, 2, -2, NewFloat(0.25).ToObject(), nil},
   177  		{Pow, 2, newObject(ObjectType), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for **: 'long' and 'object'")},
   178  		{Sub, 22, 18, NewLong(big.NewInt(4)).ToObject(), nil},
   179  		{Sub, IntType.ToObject(), 42, nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for -: 'type' and 'long'")},
   180  		{Sub, MinInt, 1, NewLong(new(big.Int).Sub(minIntBig, big.NewInt(1))).ToObject(), nil},
   181  		{Xor, -100, 50, NewLong(big.NewInt(-82)).ToObject(), nil},
   182  		{Xor, MaxInt, MinInt, NewLong(big.NewInt(-1)).ToObject(), nil},
   183  		{Xor, newObject(ObjectType), 100, nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for ^: 'object' and 'long'")},
   184  	}
   185  	for _, cas := range cases {
   186  		v := (*Object)(nil)
   187  		switch casv := cas.v.(type) {
   188  		case int:
   189  			v = NewLong(big.NewInt(int64(casv))).ToObject()
   190  		case int64:
   191  			v = NewLong(big.NewInt(casv)).ToObject()
   192  		case *big.Int:
   193  			v = NewLong(casv).ToObject()
   194  		case *Object:
   195  			v = casv
   196  		default:
   197  			t.Errorf("invalid test case: %T", casv)
   198  			continue
   199  		}
   200  		w := (*Object)(nil)
   201  		switch casw := cas.w.(type) {
   202  		case int:
   203  			w = NewLong(big.NewInt(int64(casw))).ToObject()
   204  		case int64:
   205  			w = NewLong(big.NewInt(casw)).ToObject()
   206  		case *big.Int:
   207  			w = NewLong(casw).ToObject()
   208  		case *Object:
   209  			w = casw
   210  		default:
   211  			t.Errorf("invalid test case: %T", casw)
   212  			continue
   213  		}
   214  		testCase := invokeTestCase{args: wrapArgs(v, w), want: cas.want, wantExc: cas.wantExc}
   215  		if err := runInvokeTestCase(wrapFuncForTest(cas.fun), &testCase); err != "" {
   216  			t.Error(err)
   217  		}
   218  	}
   219  }
   220  
   221  func TestLongCompare(t *testing.T) {
   222  	// Equivalence classes of sample numbers, sorted from least to greatest, nil-separated
   223  	googol, _ := big.NewFloat(1e100).Int(nil)
   224  	numbers := []interface{}{
   225  		math.Inf(-1), nil,
   226  		-1e100, new(big.Int).Neg(googol), nil,
   227  		new(big.Int).Lsh(big.NewInt(-1), 100), nil, // -2^100
   228  		MinInt, nil,
   229  		-306, -306.0, nil,
   230  		1, big.NewInt(1), nil,
   231  		309683958, big.NewInt(309683958), nil,
   232  		MaxInt, nil,
   233  		1e100, googol, nil,
   234  		math.Inf(1), nil,
   235  	}
   236  	for i, v := range numbers {
   237  		if v == nil {
   238  			continue
   239  		}
   240  		want := compareAllResultEq
   241  		for _, w := range numbers[i:] {
   242  			if w == nil {
   243  				// switching to a new equivalency class
   244  				want = compareAllResultLT
   245  				continue
   246  			}
   247  			cas := invokeTestCase{args: wrapArgs(v, w), want: want}
   248  			if err := runInvokeTestCase(compareAll, &cas); err != "" {
   249  				t.Error(err)
   250  			}
   251  		}
   252  	}
   253  }
   254  
   255  func TestLongInvert(t *testing.T) {
   256  	googol, _ := big.NewFloat(1e100).Int(nil)
   257  	cases := []invokeTestCase{
   258  		{args: wrapArgs(big.NewInt(2592)), want: NewLong(big.NewInt(-2593)).ToObject()},
   259  		{args: wrapArgs(big.NewInt(0)), want: NewLong(big.NewInt(-1)).ToObject()},
   260  		{args: wrapArgs(big.NewInt(-43)), want: NewLong(big.NewInt(42)).ToObject()},
   261  		{args: wrapArgs(maxIntBig), want: NewLong(minIntBig).ToObject()},
   262  		{args: wrapArgs(minIntBig), want: NewLong(maxIntBig).ToObject()},
   263  		{args: wrapArgs(googol),
   264  			want: NewLong(new(big.Int).Not(googol)).ToObject()},
   265  		{args: wrapArgs(new(big.Int).Lsh(big.NewInt(-1), 100)),
   266  			want: NewLong(new(big.Int).Not(new(big.Int).Lsh(big.NewInt(-1), 100))).ToObject()},
   267  	}
   268  	for _, cas := range cases {
   269  		if err := runInvokeMethodTestCase(LongType, "__invert__", &cas); err != "" {
   270  			t.Error(err)
   271  		}
   272  	}
   273  }
   274  
   275  func TestLongInt(t *testing.T) {
   276  	googol, _ := big.NewFloat(1e100).Int(nil)
   277  	cases := []invokeTestCase{
   278  		{args: wrapArgs(big.NewInt(2592)), want: NewInt(2592).ToObject()},
   279  		{args: wrapArgs(big.NewInt(0)), want: NewInt(0).ToObject()},
   280  		{args: wrapArgs(big.NewInt(-43)), want: NewInt(-43).ToObject()},
   281  		{args: wrapArgs(maxIntBig), want: NewInt(MaxInt).ToObject()},
   282  		{args: wrapArgs(minIntBig), want: NewInt(MinInt).ToObject()},
   283  		{args: wrapArgs(googol), want: NewLong(googol).ToObject()},
   284  		{args: wrapArgs(new(big.Int).Lsh(big.NewInt(-1), 100)),
   285  			want: NewLong(new(big.Int).Lsh(big.NewInt(-1), 100)).ToObject()},
   286  	}
   287  	for _, cas := range cases {
   288  		if err := runInvokeMethodTestCase(LongType, "__int__", &cas); err != "" {
   289  			t.Error(err)
   290  		}
   291  	}
   292  }
   293  
   294  func TestLongFloat(t *testing.T) {
   295  	googol, _ := big.NewFloat(1e100).Int(nil)
   296  	cases := []invokeTestCase{
   297  		{args: wrapArgs(big.NewInt(2592)), want: NewFloat(2592).ToObject()},
   298  		{args: wrapArgs(big.NewInt(0)), want: NewFloat(0).ToObject()},
   299  		{args: wrapArgs(big.NewInt(-43)), want: NewFloat(-43).ToObject()},
   300  		{args: wrapArgs(maxIntBig), want: NewFloat(float64(MaxInt)).ToObject()},
   301  		{args: wrapArgs(minIntBig), want: NewFloat(float64(MinInt)).ToObject()},
   302  		{args: wrapArgs(googol), want: NewFloat(1e100).ToObject()},
   303  		{args: wrapArgs(new(big.Int).Lsh(big.NewInt(-1), 100)),
   304  			want: NewFloat(-math.Pow(2, 100) + 1).ToObject()},
   305  		{args: wrapArgs(new(big.Int).Lsh(big.NewInt(1), 10000)),
   306  			wantExc: mustCreateException(OverflowErrorType, "long int too large to convert to float")},
   307  	}
   308  	for _, cas := range cases {
   309  		if err := runInvokeMethodTestCase(LongType, "__float__", &cas); err != "" {
   310  			t.Error(err)
   311  		}
   312  	}
   313  }
   314  
   315  // tests needed:
   316  // ✓ arithmetic (long, long) -> long
   317  // ✓   add
   318  // ✓   sub
   319  // ✓   mul
   320  // ✓   div
   321  // ✓   mod
   322  // ✓ boolean logic (long, long) -> long
   323  // ✓   and
   324  // ✓   or
   325  // ✓   xor
   326  // ✓ shifts (long, int) -> long
   327  // ✓   lsh
   328  // ✓   rsh
   329  // ✓ comparison (long, long) -> bool
   330  // unary ops
   331  //   hash    long -> int
   332  //   nonzero long -> bool
   333  // ✓   invert  long -> long
   334  //   negate  long -> long   (this slot doesn't exist yet)
   335  // ✓ int compatibility
   336  // ✓   conversion
   337  // ✓   comparison
   338  // ✓ float compatibility
   339  // ✓   conversion
   340  // ✓   comparison
   341  // ✓ parsing
   342  // ✓   new
   343  // ✓ formatting
   344  // ✓   repr
   345  // ✓   str
   346  // native
   347  //   istrue
   348  //   native