github.com/google/grumpy@v0.0.0-20171122020858-3ec87959189c/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