github.com/pygolin/runtime@v0.0.0-20201208210830-a62e3cd39798/core_test.go (about) 1 // Copyright 2016 Google Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package runtime 16 17 import ( 18 "fmt" 19 "math/big" 20 "reflect" 21 "regexp" 22 "runtime" 23 "testing" 24 ) 25 26 func TestAssert(t *testing.T) { 27 assert := newBuiltinFunction("TestAssert", func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 28 switch argc := len(args); argc { 29 case 1: 30 if raised := Assert(f, args[0], nil); raised != nil { 31 return nil, raised 32 } 33 case 2: 34 if raised := Assert(f, args[0], args[1]); raised != nil { 35 return nil, raised 36 } 37 default: 38 return nil, f.RaiseType(SystemErrorType, fmt.Sprintf("Assert expected 1 or 2 args, got %d", argc)) 39 } 40 return None, nil 41 }).ToObject() 42 emptyAssert := toBaseExceptionUnsafe(mustNotRaise(AssertionErrorType.Call(NewRootFrame(), nil, nil))) 43 cases := []invokeTestCase{ 44 {args: wrapArgs(true), want: None}, 45 {args: wrapArgs(NewTuple(None)), want: None}, 46 {args: wrapArgs(None), wantExc: emptyAssert}, 47 {args: wrapArgs(NewDict()), wantExc: emptyAssert}, 48 {args: wrapArgs(false, "foo"), wantExc: mustCreateException(AssertionErrorType, "foo")}, 49 } 50 for _, cas := range cases { 51 if err := runInvokeTestCase(assert, &cas); err != "" { 52 t.Error(err) 53 } 54 } 55 } 56 57 func TestBinaryOps(t *testing.T) { 58 fooType := newTestClass("Foo", []*Type{ObjectType}, newStringDict(map[string]*Object{ 59 "__add__": newBuiltinFunction("__add__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 60 return NewStr("foo add").ToObject(), nil 61 }).ToObject(), 62 "__radd__": newBuiltinFunction("__add__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 63 return NewStr("foo radd").ToObject(), nil 64 }).ToObject(), 65 })) 66 barType := newTestClass("Bar", []*Type{fooType}, NewDict()) 67 bazType := newTestClass("Baz", []*Type{IntType}, newStringDict(map[string]*Object{ 68 "__rdiv__": newBuiltinFunction("__rdiv__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 69 s, raised := ToStr(f, args[1]) 70 if raised != nil { 71 return nil, raised 72 } 73 return s.ToObject(), nil 74 }).ToObject(), 75 })) 76 inplaceType := newTestClass("Inplace", []*Type{ObjectType}, newStringDict(map[string]*Object{ 77 "__iadd__": newBuiltinFunction("__iadd__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 78 return args[1], nil 79 }).ToObject(), 80 "__iand__": newBuiltinFunction("__iand__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 81 return args[1], nil 82 }).ToObject(), 83 "__idiv__": newBuiltinFunction("__idiv__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 84 return args[1], nil 85 }).ToObject(), 86 "__ilshift__": newBuiltinFunction("__ilshift__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 87 return args[1], nil 88 }).ToObject(), 89 "__imod__": newBuiltinFunction("__imod__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 90 return args[1], nil 91 }).ToObject(), 92 "__imul__": newBuiltinFunction("__imul__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 93 return args[1], nil 94 }).ToObject(), 95 "__ior__": newBuiltinFunction("__ior__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 96 return args[1], nil 97 }).ToObject(), 98 "__irshift__": newBuiltinFunction("__irshift__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 99 return args[1], nil 100 }).ToObject(), 101 "__isub__": newBuiltinFunction("__isub__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 102 return args[1], nil 103 }).ToObject(), 104 "__ixor__": newBuiltinFunction("__ixor__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 105 return args[1], nil 106 }).ToObject(), 107 })) 108 cases := []struct { 109 fun func(f *Frame, v, w *Object) (*Object, *BaseException) 110 v, w *Object 111 want *Object 112 wantExc *BaseException 113 }{ 114 {Add, NewStr("foo").ToObject(), NewStr("bar").ToObject(), NewStr("foobar").ToObject(), nil}, 115 {Add, NewStr("foo").ToObject(), NewStr("bar").ToObject(), NewStr("foobar").ToObject(), nil}, 116 {Add, newObject(fooType), newObject(ObjectType), NewStr("foo add").ToObject(), nil}, 117 {And, NewInt(-42).ToObject(), NewInt(244).ToObject(), NewInt(212).ToObject(), nil}, 118 {And, NewInt(42).ToObject(), NewStr("foo").ToObject(), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for &: 'int' and 'str'")}, 119 {Add, newObject(fooType), newObject(barType), NewStr("foo add").ToObject(), nil}, 120 {Div, NewInt(123).ToObject(), newObject(bazType), NewStr("123").ToObject(), nil}, 121 {IAdd, NewStr("foo").ToObject(), NewStr("bar").ToObject(), NewStr("foobar").ToObject(), nil}, 122 {IAdd, NewStr("foo").ToObject(), NewStr("bar").ToObject(), NewStr("foobar").ToObject(), nil}, 123 {IAdd, newObject(fooType), newObject(ObjectType), NewStr("foo add").ToObject(), nil}, 124 {IAdd, newObject(inplaceType), NewStr("foo").ToObject(), NewStr("foo").ToObject(), nil}, 125 {IAnd, NewInt(9).ToObject(), NewInt(12).ToObject(), NewInt(8).ToObject(), nil}, 126 {IAnd, newObject(inplaceType), NewStr("foo").ToObject(), NewStr("foo").ToObject(), nil}, 127 {IAnd, newObject(ObjectType), newObject(fooType), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for &: 'object' and 'Foo'")}, 128 {IDiv, NewInt(123).ToObject(), newObject(bazType), NewStr("123").ToObject(), nil}, 129 {IDiv, newObject(inplaceType), NewInt(42).ToObject(), NewInt(42).ToObject(), nil}, 130 {ILShift, newObject(inplaceType), NewInt(123).ToObject(), NewInt(123).ToObject(), nil}, 131 {IMod, NewInt(24).ToObject(), NewInt(6).ToObject(), NewInt(0).ToObject(), nil}, 132 {IMod, newObject(inplaceType), NewFloat(3.14).ToObject(), NewFloat(3.14).ToObject(), nil}, 133 {IMul, NewStr("foo").ToObject(), NewInt(3).ToObject(), NewStr("foofoofoo").ToObject(), nil}, 134 {IMul, newObject(inplaceType), True.ToObject(), True.ToObject(), nil}, 135 {IMul, newObject(ObjectType), newObject(fooType), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for *: 'object' and 'Foo'")}, 136 {IOr, newObject(inplaceType), NewInt(42).ToObject(), NewInt(42).ToObject(), nil}, 137 {IOr, NewInt(9).ToObject(), NewInt(12).ToObject(), NewInt(13).ToObject(), nil}, 138 {IOr, newObject(ObjectType), newObject(fooType), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for |: 'object' and 'Foo'")}, 139 {IRShift, newObject(inplaceType), NewInt(123).ToObject(), NewInt(123).ToObject(), nil}, 140 {ISub, NewInt(3).ToObject(), NewInt(-3).ToObject(), NewInt(6).ToObject(), nil}, 141 {ISub, newObject(inplaceType), None, None, nil}, 142 {IXor, newObject(inplaceType), None, None, nil}, 143 {IXor, NewInt(9).ToObject(), NewInt(12).ToObject(), NewInt(5).ToObject(), nil}, 144 {IXor, newObject(ObjectType), newObject(fooType), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for ^: 'object' and 'Foo'")}, 145 {Mod, NewInt(24).ToObject(), NewInt(6).ToObject(), NewInt(0).ToObject(), nil}, 146 {Mul, NewStr("foo").ToObject(), NewInt(3).ToObject(), NewStr("foofoofoo").ToObject(), nil}, 147 {Mul, newObject(ObjectType), newObject(fooType), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for *: 'object' and 'Foo'")}, 148 {Or, NewInt(-42).ToObject(), NewInt(244).ToObject(), NewInt(-10).ToObject(), nil}, 149 {Or, NewInt(42).ToObject(), NewStr("foo").ToObject(), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for |: 'int' and 'str'")}, 150 {Pow, NewInt(2).ToObject(), NewInt(-2).ToObject(), NewFloat(0.25).ToObject(), nil}, 151 {Pow, NewInt(2).ToObject(), newObject(fooType), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for **: 'int' and 'Foo'")}, 152 {Sub, NewInt(3).ToObject(), NewInt(-3).ToObject(), NewInt(6).ToObject(), nil}, 153 {Xor, NewInt(-42).ToObject(), NewInt(244).ToObject(), NewInt(-222).ToObject(), nil}, 154 {Xor, NewInt(42).ToObject(), NewStr("foo").ToObject(), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for ^: 'int' and 'str'")}, 155 } 156 for _, cas := range cases { 157 testCase := invokeTestCase{wrapArgs(cas.v, cas.w), nil, cas.want, cas.wantExc} 158 if err := runInvokeTestCase(wrapFuncForTest(cas.fun), &testCase); err != "" { 159 t.Error(err) 160 } 161 } 162 } 163 164 func TestCompare(t *testing.T) { 165 badCmpType := newTestClass("BadCmp", []*Type{ObjectType}, newStringDict(map[string]*Object{ 166 "__cmp__": newBuiltinFunction("__cmp__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 167 return nil, f.RaiseType(TypeErrorType, "uh oh") 168 }).ToObject(), 169 })) 170 cmpLtType := newTestClass("Lt", []*Type{ObjectType}, newStringDict(map[string]*Object{ 171 "__cmp__": newBuiltinFunction("__cmp__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 172 return NewInt(-1).ToObject(), nil 173 }).ToObject(), 174 })) 175 cmpEqType := newTestClass("Eq", []*Type{ObjectType}, newStringDict(map[string]*Object{ 176 "__cmp__": newBuiltinFunction("__cmp__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 177 return NewInt(0).ToObject(), nil 178 }).ToObject(), 179 })) 180 cmpGtType := newTestClass("Gt", []*Type{ObjectType}, newStringDict(map[string]*Object{ 181 "__cmp__": newBuiltinFunction("__cmp__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 182 return NewInt(1).ToObject(), nil 183 }).ToObject(), 184 })) 185 cmpByEqType := newTestClass("EqCmp", []*Type{IntType}, newStringDict(map[string]*Object{ 186 "__eq__": newBuiltinFunction("__eq__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 187 return True.ToObject(), nil 188 }).ToObject(), 189 })) 190 badCmpByEqType := newTestClass("BadEqCmp", []*Type{IntType}, newStringDict(map[string]*Object{ 191 "__eq__": newBuiltinFunction("__eq__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 192 return nil, f.RaiseType(TypeErrorType, "uh oh") 193 }).ToObject(), 194 })) 195 badNonZeroType := newTestClass("BadNonZeroType", []*Type{ObjectType}, newStringDict(map[string]*Object{ 196 "__nonzero__": newBuiltinFunction("__nonzero__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 197 return nil, f.RaiseType(TypeErrorType, "uh oh") 198 }).ToObject(), 199 })) 200 worseCmpByEqType := newTestClass("WorseEqCmp", []*Type{IntType}, newStringDict(map[string]*Object{ 201 "__eq__": newBuiltinFunction("__eq__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 202 return newObject(badNonZeroType), nil 203 }).ToObject(), 204 })) 205 cmpNonIntResultType := newTestClass("CmpNonIntResult", []*Type{ObjectType}, newStringDict(map[string]*Object{ 206 "__cmp__": newBuiltinFunction("__cmp__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 207 return NewStr("foo").ToObject(), nil 208 }).ToObject(), 209 })) 210 cases := []invokeTestCase{ 211 // Test `__cmp__` less than. 212 {args: wrapArgs(newObject(cmpLtType), None), want: NewInt(-1).ToObject()}, 213 {args: wrapArgs(None, newObject(cmpGtType)), want: NewInt(-1).ToObject()}, 214 // Test `__cmp__` equals. 215 {args: wrapArgs(newObject(cmpEqType), None), want: NewInt(0).ToObject()}, 216 {args: wrapArgs(None, newObject(cmpEqType)), want: NewInt(0).ToObject()}, 217 // Test `__cmp__` greater than. 218 {args: wrapArgs(newObject(cmpGtType), None), want: NewInt(1).ToObject()}, 219 {args: wrapArgs(None, newObject(cmpLtType)), want: NewInt(1).ToObject()}, 220 // Test `__cmp__` fallback to rich comparison. 221 {args: wrapArgs(newObject(cmpByEqType), None), want: NewInt(0).ToObject()}, 222 {args: wrapArgs(None, newObject(cmpByEqType)), want: NewInt(0).ToObject()}, 223 // Test bad `__cmp__` fallback to rich comparison. 224 {args: wrapArgs(newObject(badCmpByEqType), None), wantExc: mustCreateException(TypeErrorType, "uh oh")}, 225 {args: wrapArgs(None, newObject(badCmpByEqType)), wantExc: mustCreateException(TypeErrorType, "uh oh")}, 226 // Test bad `__cmp__` fallback to rich comparison where a bad object is returned from `__eq__`. 227 {args: wrapArgs(newObject(worseCmpByEqType), None), wantExc: mustCreateException(TypeErrorType, "uh oh")}, 228 {args: wrapArgs(None, newObject(worseCmpByEqType)), wantExc: mustCreateException(TypeErrorType, "uh oh")}, 229 // Test bad `__cmp__`. 230 {args: wrapArgs(newObject(badCmpType), None), wantExc: mustCreateException(TypeErrorType, "uh oh")}, 231 {args: wrapArgs(None, newObject(badCmpType)), wantExc: mustCreateException(TypeErrorType, "uh oh")}, 232 // Test bad `__cmp__` with non-int result. 233 {args: wrapArgs(newObject(cmpNonIntResultType), None), wantExc: mustCreateException(TypeErrorType, "an integer is required")}, 234 {args: wrapArgs(None, newObject(cmpNonIntResultType)), wantExc: mustCreateException(TypeErrorType, "an integer is required")}, 235 } 236 for _, cas := range cases { 237 if err := runInvokeTestCase(wrapFuncForTest(Compare), &cas); err != "" { 238 t.Error(err) 239 } 240 } 241 } 242 243 func TestCompareDefault(t *testing.T) { 244 o1, o2 := newObject(ObjectType), newObject(ObjectType) 245 // Make sure uintptr(o1) < uintptr(o2). 246 if uintptr(o1.toPointer()) > uintptr(o2.toPointer()) { 247 o1, o2 = o2, o1 248 } 249 // When type names are equal, comparison should fall back to comparing 250 // the pointer values of the types of the objects. 251 fakeObjectType := newTestClass("object", []*Type{ObjectType}, NewDict()) 252 o3, o4 := newObject(fakeObjectType), newObject(ObjectType) 253 if uintptr(o3.typ.toPointer()) > uintptr(o4.typ.toPointer()) { 254 o3, o4 = o4, o3 255 } 256 // An int subtype that equals anything, but doesn't override other 257 // comparison methods. 258 eqType := newTestClass("Eq", []*Type{IntType}, newStringDict(map[string]*Object{ 259 "__eq__": newBuiltinFunction("__eq__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 260 return True.ToObject(), nil 261 }).ToObject(), 262 "__repr__": newBuiltinFunction("__repr__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 263 return NewStr("<Foo>").ToObject(), nil 264 }).ToObject(), 265 })) 266 cases := []invokeTestCase{ 267 {args: wrapArgs(true, o1), want: compareAllResultLT}, 268 {args: wrapArgs(o1, -306), want: compareAllResultGT}, 269 {args: wrapArgs(-306, o1), want: compareAllResultLT}, 270 {args: wrapArgs(NewList(), None), want: compareAllResultGT}, 271 {args: wrapArgs(None, "foo"), want: compareAllResultLT}, 272 {args: wrapArgs(o1, o1), want: compareAllResultEq}, 273 {args: wrapArgs(o1, o2), want: compareAllResultLT}, 274 {args: wrapArgs(o2, o1), want: compareAllResultGT}, 275 {args: wrapArgs(o3, o4), want: compareAllResultLT}, 276 {args: wrapArgs(o4, o3), want: compareAllResultGT}, 277 // The equality test should dispatch to the eqType instance and 278 // return true. 279 {args: wrapArgs(42, newObject(eqType)), want: newTestTuple(false, false, true, true, true, true).ToObject()}, 280 } 281 for _, cas := range cases { 282 if err := runInvokeTestCase(compareAll, &cas); err != "" { 283 t.Error(err) 284 } 285 } 286 } 287 288 func TestContains(t *testing.T) { 289 cases := []invokeTestCase{ 290 {args: wrapArgs(NewTuple(), 42), want: False.ToObject()}, 291 {args: wrapArgs(newTestList("foo", "bar"), "bar"), want: True.ToObject()}, 292 {args: wrapArgs(newTestDict(1, "foo", 2, "bar", 3, "baz"), 2), want: True.ToObject()}, 293 {args: wrapArgs("foobar", "ooba"), want: True.ToObject()}, 294 {args: wrapArgs("qux", "ooba"), want: False.ToObject()}, 295 {args: wrapArgs(3.14, None), wantExc: mustCreateException(TypeErrorType, "'float' object is not iterable")}, 296 } 297 for _, cas := range cases { 298 if err := runInvokeTestCase(wrapFuncForTest(Contains), &cas); err != "" { 299 t.Error(err) 300 } 301 } 302 } 303 304 // DelAttr is tested in TestObjectDelAttr. 305 306 func TestDelItem(t *testing.T) { 307 delItem := newBuiltinFunction("TestDelItem", func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 308 if raised := checkFunctionArgs(f, "TestDelItem", args, ObjectType, ObjectType); raised != nil { 309 return nil, raised 310 } 311 o := args[0] 312 if raised := DelItem(f, o, args[1]); raised != nil { 313 return nil, raised 314 } 315 return args[0], nil 316 }).ToObject() 317 cases := []invokeTestCase{ 318 {args: wrapArgs(newTestDict("foo", None), "foo"), want: NewDict().ToObject()}, 319 {args: wrapArgs(NewDict(), "foo"), wantExc: mustCreateException(KeyErrorType, "foo")}, 320 {args: wrapArgs(123, "bar"), wantExc: mustCreateException(TypeErrorType, "'int' object does not support item deletion")}, 321 } 322 for _, cas := range cases { 323 if err := runInvokeTestCase(delItem, &cas); err != "" { 324 t.Error(err) 325 } 326 } 327 } 328 329 func TestFormatException(t *testing.T) { 330 fun := wrapFuncForTest(func(f *Frame, t *Type, args ...*Object) (string, *BaseException) { 331 e, raised := t.Call(f, args, nil) 332 if raised != nil { 333 return "", raised 334 } 335 f.Raise(e, nil, nil) 336 s := FormatExc(f) 337 f.RestoreExc(nil, nil) 338 return s, nil 339 }) 340 cases := []invokeTestCase{ 341 {args: wrapArgs(ExceptionType), want: NewStr("Exception\n").ToObject()}, 342 {args: wrapArgs(AttributeErrorType, ""), want: NewStr("AttributeError\n").ToObject()}, 343 {args: wrapArgs(TypeErrorType, 123), want: NewStr("TypeError: 123\n").ToObject()}, 344 {args: wrapArgs(AttributeErrorType, "hello", "there"), want: NewStr("AttributeError: ('hello', 'there')\n").ToObject()}, 345 } 346 for _, cas := range cases { 347 if err := runInvokeTestCase(fun, &cas); err != "" { 348 t.Error(err) 349 } 350 } 351 } 352 353 func TestGetAttr(t *testing.T) { 354 getAttr := newBuiltinFunction("TestGetAttr", func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 355 expectedTypes := []*Type{ObjectType, StrType, ObjectType} 356 argc := len(args) 357 if argc == 2 { 358 expectedTypes = expectedTypes[:2] 359 } 360 if raised := checkFunctionArgs(f, "TestGetAttr", args, expectedTypes...); raised != nil { 361 return nil, raised 362 } 363 var def *Object 364 if argc > 2 { 365 def = args[2] 366 } 367 s, raised := ToStr(f, args[1]) 368 if raised != nil { 369 return nil, raised 370 } 371 return GetAttr(f, args[0], s, def) 372 }).ToObject() 373 fooResult := newObject(ObjectType) 374 fooType := newTestClass("Foo", []*Type{ObjectType}, newStringDict(map[string]*Object{ 375 "__getattribute__": newBuiltinFunction("__getattribute__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 376 return fooResult, nil 377 }).ToObject(), 378 })) 379 barType := newTestClass("Bar", []*Type{ObjectType}, newStringDict(map[string]*Object{ 380 "__getattribute__": newBuiltinFunction("__getattribute__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 381 return nil, f.RaiseType(TypeErrorType, "uh oh") 382 }).ToObject(), 383 })) 384 cases := []invokeTestCase{ 385 {args: wrapArgs(newObject(fooType), "bar"), want: fooResult}, 386 {args: wrapArgs(newObject(fooType), "baz", None), want: fooResult}, 387 {args: wrapArgs(newObject(ObjectType), "qux", None), want: None}, 388 {args: wrapArgs(NewTuple(), "noexist"), wantExc: mustCreateException(AttributeErrorType, "'tuple' object has no attribute 'noexist'")}, 389 {args: wrapArgs(DictType, "noexist"), wantExc: mustCreateException(AttributeErrorType, "type object 'dict' has no attribute 'noexist'")}, 390 {args: wrapArgs(newObject(barType), "noexist"), wantExc: mustCreateException(TypeErrorType, "uh oh")}, 391 } 392 for _, cas := range cases { 393 if err := runInvokeTestCase(getAttr, &cas); err != "" { 394 t.Error(err) 395 } 396 } 397 } 398 399 func TestGetItem(t *testing.T) { 400 cases := []invokeTestCase{ 401 {args: wrapArgs(newStringDict(map[string]*Object{"foo": None}), "foo"), want: None}, 402 {args: wrapArgs(NewDict(), "bar"), wantExc: mustCreateException(KeyErrorType, "bar")}, 403 {args: wrapArgs(true, "baz"), wantExc: mustCreateException(TypeErrorType, "'bool' object has no attribute '__getitem__'")}, 404 } 405 for _, cas := range cases { 406 if err := runInvokeTestCase(wrapFuncForTest(GetItem), &cas); err != "" { 407 t.Error(err) 408 } 409 } 410 } 411 412 func TestHash(t *testing.T) { 413 badHash := newTestClass("badHash", []*Type{ObjectType}, newStringDict(map[string]*Object{ 414 "__hash__": newBuiltinFunction("__hash__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 415 return args[0], nil 416 }).ToObject(), 417 })) 418 o := newObject(ObjectType) 419 cases := []invokeTestCase{ 420 {args: wrapArgs("foo"), want: hashFoo}, 421 {args: wrapArgs(123), want: NewInt(123).ToObject()}, 422 {args: wrapArgs(o), want: NewInt(int(uintptr(o.toPointer()))).ToObject()}, 423 {args: wrapArgs(NewList()), wantExc: mustCreateException(TypeErrorType, "unhashable type: 'list'")}, 424 {args: wrapArgs(NewDict()), wantExc: mustCreateException(TypeErrorType, "unhashable type: 'dict'")}, 425 {args: wrapArgs(newObject(badHash)), wantExc: mustCreateException(TypeErrorType, "an integer is required")}, 426 } 427 for _, cas := range cases { 428 if err := runInvokeTestCase(wrapFuncForTest(Hash), &cas); err != "" { 429 t.Error(err) 430 } 431 } 432 } 433 434 func TestHex(t *testing.T) { 435 badHex := newTestClass("badHex", []*Type{ObjectType}, newStringDict(map[string]*Object{ 436 "__hex__": newBuiltinFunction("__hex__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 437 return NewInt(123).ToObject(), nil 438 }).ToObject(), 439 })) 440 goodHex := newTestClass("goodHex", []*Type{ObjectType}, newStringDict(map[string]*Object{ 441 "__hex__": newBuiltinFunction("__hex__", func(f *Frame, _ Args, _ KWArgs) (*Object, *BaseException) { 442 return NewStr("0x123").ToObject(), nil 443 }).ToObject(), 444 })) 445 cases := []invokeTestCase{ 446 {args: wrapArgs(-123), want: NewStr("-0x7b").ToObject()}, 447 {args: wrapArgs(123), want: NewStr("0x7b").ToObject()}, 448 {args: wrapArgs(newObject(goodHex)), want: NewStr("0x123").ToObject()}, 449 {args: wrapArgs(NewList()), wantExc: mustCreateException(TypeErrorType, "hex() argument can't be converted to hex")}, 450 {args: wrapArgs(NewDict()), wantExc: mustCreateException(TypeErrorType, "hex() argument can't be converted to hex")}, 451 {args: wrapArgs(newObject(badHex)), wantExc: mustCreateException(TypeErrorType, "__hex__ returned non-string (type int)")}, 452 } 453 for _, cas := range cases { 454 if err := runInvokeTestCase(wrapFuncForTest(Hex), &cas); err != "" { 455 t.Error(err) 456 } 457 } 458 } 459 460 func TestIndex(t *testing.T) { 461 goodType := newTestClass("GoodIndex", []*Type{ObjectType}, newStringDict(map[string]*Object{ 462 "__index__": newBuiltinFunction("__index__", func(f *Frame, _ Args, _ KWArgs) (*Object, *BaseException) { 463 return NewInt(123).ToObject(), nil 464 }).ToObject(), 465 })) 466 longType := newTestClass("LongIndex", []*Type{ObjectType}, newStringDict(map[string]*Object{ 467 "__index__": newBuiltinFunction("__index__", func(f *Frame, _ Args, _ KWArgs) (*Object, *BaseException) { 468 return NewLong(big.NewInt(123)).ToObject(), nil 469 }).ToObject(), 470 })) 471 raiseType := newTestClass("RaiseIndex", []*Type{ObjectType}, newStringDict(map[string]*Object{ 472 "__index__": newBuiltinFunction("__index__", func(f *Frame, _ Args, _ KWArgs) (*Object, *BaseException) { 473 return nil, f.RaiseType(RuntimeErrorType, "uh oh") 474 }).ToObject(), 475 })) 476 badType := newTestClass("BadIndex", []*Type{ObjectType}, newStringDict(map[string]*Object{ 477 "__index__": newBuiltinFunction("__index__", func(f *Frame, _ Args, _ KWArgs) (*Object, *BaseException) { 478 return NewFloat(3.14).ToObject(), nil 479 }).ToObject(), 480 })) 481 cases := []invokeTestCase{ 482 {args: wrapArgs(42), want: NewInt(42).ToObject()}, 483 {args: wrapArgs(newObject(goodType)), want: NewInt(123).ToObject()}, 484 {args: wrapArgs(newObject(longType)), want: NewLong(big.NewInt(123)).ToObject()}, 485 {args: wrapArgs(newObject(raiseType)), wantExc: mustCreateException(RuntimeErrorType, "uh oh")}, 486 {args: wrapArgs(newObject(badType)), wantExc: mustCreateException(TypeErrorType, "__index__ returned non-(int,long) (type float)")}, 487 {args: wrapArgs("abc"), want: None}, 488 } 489 for _, cas := range cases { 490 if err := runInvokeTestCase(wrapFuncForTest(Index), &cas); err != "" { 491 t.Error(err) 492 } 493 } 494 cases = []invokeTestCase{ 495 {args: wrapArgs(42), want: NewInt(42).ToObject()}, 496 {args: wrapArgs(newObject(goodType)), want: NewInt(123).ToObject()}, 497 {args: wrapArgs(newObject(raiseType)), wantExc: mustCreateException(RuntimeErrorType, "uh oh")}, 498 } 499 for _, cas := range cases { 500 if err := runInvokeMethodTestCase(cas.args[0].typ, "__index__", &cas); err != "" { 501 t.Error(err) 502 } 503 } 504 } 505 506 func TestInvert(t *testing.T) { 507 cases := []invokeTestCase{ 508 {args: wrapArgs(42), want: NewInt(-43).ToObject()}, 509 {args: wrapArgs(0), want: NewInt(-1).ToObject()}, 510 {args: wrapArgs(-35935), want: NewInt(35934).ToObject()}, 511 {args: wrapArgs("foo"), wantExc: mustCreateException(TypeErrorType, "bad operand type for unary ~: 'str'")}, 512 } 513 for _, cas := range cases { 514 if err := runInvokeTestCase(wrapFuncForTest(Invert), &cas); err != "" { 515 t.Error(err) 516 } 517 } 518 } 519 520 func TestIsInstanceIsSubclass(t *testing.T) { 521 fooType := newTestClass("Foo", []*Type{ObjectType}, NewDict()) 522 barType := newTestClass("Bar", []*Type{fooType, IntType}, NewDict()) 523 cases := []struct { 524 o *Object 525 classinfo *Object 526 want *Object 527 wantExc *BaseException 528 }{ 529 {newObject(ObjectType), ObjectType.ToObject(), True.ToObject(), nil}, 530 {NewInt(42).ToObject(), StrType.ToObject(), False.ToObject(), nil}, 531 {None, NewTuple(NoneType.ToObject(), IntType.ToObject()).ToObject(), True.ToObject(), nil}, 532 {NewStr("foo").ToObject(), NewTuple(NoneType.ToObject(), IntType.ToObject()).ToObject(), False.ToObject(), nil}, 533 {NewStr("foo").ToObject(), NewTuple(IntType.ToObject(), NoneType.ToObject()).ToObject(), False.ToObject(), nil}, 534 {None, NewTuple().ToObject(), False.ToObject(), nil}, 535 {newObject(barType), fooType.ToObject(), True.ToObject(), nil}, 536 {newObject(barType), IntType.ToObject(), True.ToObject(), nil}, 537 {newObject(fooType), IntType.ToObject(), False.ToObject(), nil}, 538 {newObject(ObjectType), None, nil, mustCreateException(TypeErrorType, "classinfo must be a type or tuple of types")}, 539 {newObject(ObjectType), NewTuple(None).ToObject(), nil, mustCreateException(TypeErrorType, "classinfo must be a type or tuple of types")}, 540 } 541 for _, cas := range cases { 542 // IsInstance 543 testCase := invokeTestCase{args: wrapArgs(cas.o, cas.classinfo), want: cas.want, wantExc: cas.wantExc} 544 if err := runInvokeTestCase(wrapFuncForTest(IsInstance), &testCase); err != "" { 545 t.Error(err) 546 } 547 // IsSubclass 548 testCase.args = wrapArgs(cas.o.Type(), cas.classinfo) 549 if err := runInvokeTestCase(wrapFuncForTest(IsSubclass), &testCase); err != "" { 550 t.Error(err) 551 } 552 } 553 // Test that IsSubclass raises when first arg is not a type. 554 testCase := invokeTestCase{args: wrapArgs(None, NoneType), wantExc: mustCreateException(TypeErrorType, "issubclass() arg 1 must be a class")} 555 if err := runInvokeTestCase(wrapFuncForTest(IsSubclass), &testCase); err != "" { 556 t.Error(err) 557 } 558 } 559 560 func TestIsTrue(t *testing.T) { 561 badNonZeroType := newTestClass("BadNonZeroType", []*Type{ObjectType}, newStringDict(map[string]*Object{ 562 "__nonzero__": newBuiltinFunction("__nonzero__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 563 return None, nil 564 }).ToObject(), 565 })) 566 badLenType := newTestClass("BadLen", []*Type{ObjectType}, newStringDict(map[string]*Object{ 567 "__len__": newBuiltinFunction("__len__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 568 return None, nil 569 }).ToObject(), 570 })) 571 cases := []invokeTestCase{ 572 // Bool 573 {args: wrapArgs(true), want: True.ToObject()}, 574 {args: wrapArgs(false), want: False.ToObject()}, 575 // Dict 576 {args: wrapArgs(NewDict()), want: False.ToObject()}, 577 {args: wrapArgs(newStringDict(map[string]*Object{"foo": True.ToObject()})), want: True.ToObject()}, 578 // Int 579 {args: wrapArgs(0), want: False.ToObject()}, 580 {args: wrapArgs(-1020), want: True.ToObject()}, 581 {args: wrapArgs(1698391283), want: True.ToObject()}, 582 // None 583 {args: wrapArgs(None), want: False.ToObject()}, 584 // Object 585 {args: wrapArgs(newObject(ObjectType)), want: True.ToObject()}, 586 // Str 587 {args: wrapArgs(""), want: False.ToObject()}, 588 {args: wrapArgs("\x00"), want: True.ToObject()}, 589 {args: wrapArgs("foo"), want: True.ToObject()}, 590 // Tuple 591 {args: wrapArgs(NewTuple()), want: False.ToObject()}, 592 {args: wrapArgs(newTestTuple("foo", None)), want: True.ToObject()}, 593 // Funky types 594 {args: wrapArgs(newObject(badNonZeroType)), wantExc: mustCreateException(TypeErrorType, "__nonzero__ should return bool, returned NoneType")}, 595 {args: wrapArgs(newObject(badLenType)), wantExc: mustCreateException(TypeErrorType, "an integer is required")}, 596 } 597 for _, cas := range cases { 598 if err := runInvokeTestCase(wrapFuncForTest(IsTrue), &cas); err != "" { 599 t.Error(err) 600 } 601 } 602 } 603 604 func TestIter(t *testing.T) { 605 fun := newBuiltinFunction("TestIter", func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 606 if argc := len(args); argc != 1 { 607 return nil, f.RaiseType(SystemErrorType, fmt.Sprintf("Iter expected 1 arg, got %d", argc)) 608 } 609 i, raised := Iter(f, args[0]) 610 if raised != nil { 611 return nil, raised 612 } 613 return Next(f, i) 614 }).ToObject() 615 cases := []invokeTestCase{ 616 {args: wrapArgs(NewTuple()), wantExc: mustCreateException(StopIterationType, "")}, 617 {args: wrapArgs(newTestTuple(42, "foo")), want: NewInt(42).ToObject()}, 618 {args: wrapArgs(newTestList("foo")), want: NewStr("foo").ToObject()}, 619 {args: wrapArgs("foo"), want: NewStr("f").ToObject()}, 620 {args: wrapArgs(123), wantExc: mustCreateException(TypeErrorType, "'int' object is not iterable")}, 621 } 622 for _, cas := range cases { 623 if err := runInvokeTestCase(fun, &cas); err != "" { 624 t.Error(err) 625 } 626 } 627 } 628 629 func TestIterCallable(t *testing.T) { 630 fun := newBuiltinFunction("TestIterCallable", func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 631 if argc := len(args); argc != 2 { 632 return nil, f.RaiseType(SystemErrorType, fmt.Sprintf("IterCallable expected 2 arg, got %d", argc)) 633 } 634 i, raised := IterCallable(f, args[0], args[1]) 635 if raised != nil { 636 return nil, raised 637 } 638 return Next(f, i) 639 }).ToObject() 640 foo := newBuiltinFunction("foo", func(f *Frame, _ Args, _ KWArgs) (*Object, *BaseException) { 641 return NewInt(23).ToObject(), nil 642 }).ToObject() 643 cases := []invokeTestCase{ 644 {args: wrapArgs(foo, 23), wantExc: mustCreateException(StopIterationType, "")}, 645 {args: wrapArgs(foo, 1), want: NewInt(23).ToObject()}, 646 {args: wrapArgs(123, 1), wantExc: mustCreateException(TypeErrorType, "iter(v, w): v must be callable")}, 647 } 648 for _, cas := range cases { 649 if err := runInvokeTestCase(fun, &cas); err != "" { 650 t.Error(err) 651 } 652 } 653 } 654 655 func TestNeg(t *testing.T) { 656 cases := []invokeTestCase{ 657 {args: wrapArgs(42), want: NewInt(-42).ToObject()}, 658 {args: wrapArgs(1.2), want: NewFloat(-1.2).ToObject()}, 659 {args: wrapArgs(NewLong(big.NewInt(123))), want: NewLong(big.NewInt(-123)).ToObject()}, 660 {args: wrapArgs("foo"), wantExc: mustCreateException(TypeErrorType, "bad operand type for unary -: 'str'")}, 661 } 662 for _, cas := range cases { 663 if err := runInvokeTestCase(wrapFuncForTest(Neg), &cas); err != "" { 664 t.Error(err) 665 } 666 } 667 } 668 669 func TestNext(t *testing.T) { 670 fun := newBuiltinFunction("TestNext", func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 671 if argc := len(args); argc != 1 { 672 return nil, f.RaiseType(SystemErrorType, fmt.Sprintf("Next expected 1 arg, got %d", argc)) 673 } 674 iter := args[0] 675 var elems []*Object 676 elem, raised := Next(f, iter) 677 for ; raised == nil; elem, raised = Next(f, iter) { 678 elems = append(elems, elem) 679 } 680 if !raised.isInstance(StopIterationType) { 681 return nil, raised 682 } 683 f.RestoreExc(nil, nil) 684 return NewTuple(elems...).ToObject(), nil 685 }).ToObject() 686 testElems := []*Object{NewInt(42).ToObject(), NewStr("foo").ToObject(), newObject(ObjectType)} 687 cases := []invokeTestCase{ 688 {args: wrapArgs(mustNotRaise(Iter(NewRootFrame(), NewTuple().ToObject()))), want: NewTuple().ToObject()}, 689 {args: wrapArgs(mustNotRaise(Iter(NewRootFrame(), NewTuple(testElems...).ToObject()))), want: NewTuple(testElems...).ToObject()}, 690 {args: wrapArgs(mustNotRaise(Iter(NewRootFrame(), NewList(testElems...).ToObject()))), want: NewTuple(testElems...).ToObject()}, 691 {args: wrapArgs(123), wantExc: mustCreateException(TypeErrorType, "int object is not an iterator")}, 692 } 693 for _, cas := range cases { 694 if err := runInvokeTestCase(fun, &cas); err != "" { 695 t.Error(err) 696 } 697 } 698 } 699 700 func TestLen(t *testing.T) { 701 badLenType := newTestClass("BadLen", []*Type{ObjectType}, newStringDict(map[string]*Object{ 702 "__len__": newBuiltinFunction("__len__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 703 return None, nil 704 }).ToObject(), 705 })) 706 cases := []invokeTestCase{ 707 {args: wrapArgs(NewDict()), want: NewInt(0).ToObject()}, 708 {args: wrapArgs(newStringDict(map[string]*Object{"foo": NewStr("foo value").ToObject(), "bar": NewStr("bar value").ToObject()})), want: NewInt(2).ToObject()}, 709 {args: wrapArgs(NewTuple()), want: NewInt(0).ToObject()}, 710 {args: wrapArgs(NewTuple(None, None, None)), want: NewInt(3).ToObject()}, 711 {args: wrapArgs(10), wantExc: mustCreateException(TypeErrorType, "object of type 'int' has no len()")}, 712 {args: wrapArgs(newObject(badLenType)), wantExc: mustCreateException(TypeErrorType, "an integer is required")}, 713 } 714 for _, cas := range cases { 715 if err := runInvokeTestCase(wrapFuncForTest(Len), &cas); err != "" { 716 t.Error(err) 717 } 718 } 719 } 720 721 func TestLenRaise(t *testing.T) { 722 testTypes := []*Type{ 723 DictType, 724 TupleType, 725 } 726 for _, typ := range testTypes { 727 cases := []invokeTestCase{ 728 {args: wrapArgs(), wantExc: mustCreateException(TypeErrorType, fmt.Sprintf("unbound method __len__() must be called with %s instance as first argument (got nothing instead)", typ.Name()))}, 729 {args: wrapArgs(newObject(ObjectType)), wantExc: mustCreateException(TypeErrorType, fmt.Sprintf("unbound method __len__() must be called with %s instance as first argument (got object instance instead)", typ.Name()))}, 730 {args: wrapArgs(newObject(ObjectType), newObject(ObjectType)), wantExc: mustCreateException(TypeErrorType, fmt.Sprintf("unbound method __len__() must be called with %s instance as first argument (got object instance instead)", typ.Name()))}, 731 } 732 for _, cas := range cases { 733 if err := runInvokeMethodTestCase(typ, "__len__", &cas); err != "" { 734 t.Error(err) 735 } 736 } 737 } 738 } 739 740 func TestInvokePositionalArgs(t *testing.T) { 741 fun := newBuiltinFunction("TestInvokePositionalArgs", func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 742 return NewTuple(args.makeCopy()...).ToObject(), nil 743 }).ToObject() 744 cases := []struct { 745 varargs *Object 746 args Args 747 want *Object 748 }{ 749 {nil, nil, NewTuple().ToObject()}, 750 {NewTuple(NewInt(2).ToObject()).ToObject(), nil, NewTuple(NewInt(2).ToObject()).ToObject()}, 751 {nil, []*Object{NewStr("foo").ToObject()}, NewTuple(NewStr("foo").ToObject()).ToObject()}, 752 {NewTuple(NewFloat(3.14).ToObject()).ToObject(), []*Object{NewStr("foo").ToObject()}, NewTuple(NewStr("foo").ToObject(), NewFloat(3.14).ToObject()).ToObject()}, 753 {NewList(NewFloat(3.14).ToObject()).ToObject(), []*Object{NewStr("foo").ToObject()}, NewTuple(NewStr("foo").ToObject(), NewFloat(3.14).ToObject()).ToObject()}, 754 } 755 for _, cas := range cases { 756 got, raised := Invoke(NewRootFrame(), fun, cas.args, cas.varargs, nil, nil) 757 switch checkResult(got, cas.want, raised, nil) { 758 case checkInvokeResultExceptionMismatch: 759 t.Errorf("PackArgs(%v, %v) raised %v, want nil", cas.args, cas.varargs, raised) 760 case checkInvokeResultReturnValueMismatch: 761 t.Errorf("PackArgs(%v, %v) = %v, want %v", cas.args, cas.varargs, got, cas.want) 762 } 763 } 764 } 765 766 func TestInvokeKeywordArgs(t *testing.T) { 767 fun := newBuiltinFunction("TestInvokeKeywordArgs", func(f *Frame, _ Args, kwargs KWArgs) (*Object, *BaseException) { 768 got := map[string]*Object{} 769 for _, kw := range kwargs { 770 got[kw.Name] = kw.Value 771 } 772 return newStringDict(got).ToObject(), nil 773 }).ToObject() 774 d := NewDict() 775 d.SetItem(NewRootFrame(), NewInt(123).ToObject(), None) 776 cases := []struct { 777 keywords KWArgs 778 kwargs *Object 779 want *Object 780 wantExc *BaseException 781 }{ 782 {nil, nil, NewDict().ToObject(), nil}, 783 {wrapKWArgs("foo", 42), nil, newTestDict("foo", 42).ToObject(), nil}, 784 {nil, newTestDict("foo", None).ToObject(), newTestDict("foo", None).ToObject(), nil}, 785 {wrapKWArgs("foo", 42), newTestDict("bar", None).ToObject(), newTestDict("foo", 42, "bar", None).ToObject(), nil}, 786 {nil, NewList().ToObject(), nil, mustCreateException(TypeErrorType, "argument after ** must be a dict, not list")}, 787 {nil, d.ToObject(), nil, mustCreateException(TypeErrorType, "keywords must be strings")}, 788 } 789 for _, cas := range cases { 790 got, raised := Invoke(NewRootFrame(), fun, nil, nil, cas.keywords, cas.kwargs) 791 switch checkResult(got, cas.want, raised, cas.wantExc) { 792 case checkInvokeResultExceptionMismatch: 793 t.Errorf("PackKwargs(%v, %v) raised %v, want %v", cas.keywords, cas.kwargs, raised, cas.wantExc) 794 case checkInvokeResultReturnValueMismatch: 795 t.Errorf("PackKwargs(%v, %v) = %v, want %v", cas.keywords, cas.kwargs, got, cas.want) 796 } 797 } 798 } 799 800 func TestOct(t *testing.T) { 801 badOct := newTestClass("badOct", []*Type{ObjectType}, newStringDict(map[string]*Object{ 802 "__oct__": newBuiltinFunction("__oct__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 803 return NewInt(123).ToObject(), nil 804 }).ToObject(), 805 })) 806 goodOct := newTestClass("goodOct", []*Type{ObjectType}, newStringDict(map[string]*Object{ 807 "__oct__": newBuiltinFunction("__oct__", func(f *Frame, _ Args, _ KWArgs) (*Object, *BaseException) { 808 return NewStr("0123").ToObject(), nil 809 }).ToObject(), 810 })) 811 cases := []invokeTestCase{ 812 {args: wrapArgs(-123), want: NewStr("-0173").ToObject()}, 813 {args: wrapArgs(123), want: NewStr("0173").ToObject()}, 814 {args: wrapArgs(newObject(goodOct)), want: NewStr("0123").ToObject()}, 815 {args: wrapArgs(NewList()), wantExc: mustCreateException(TypeErrorType, "oct() argument can't be converted to oct")}, 816 {args: wrapArgs(NewDict()), wantExc: mustCreateException(TypeErrorType, "oct() argument can't be converted to oct")}, 817 {args: wrapArgs(newObject(badOct)), wantExc: mustCreateException(TypeErrorType, "__oct__ returned non-string (type int)")}, 818 } 819 for _, cas := range cases { 820 if err := runInvokeTestCase(wrapFuncForTest(Oct), &cas); err != "" { 821 t.Error(err) 822 } 823 } 824 } 825 826 func TestPos(t *testing.T) { 827 pos := newTestClass("pos", []*Type{ObjectType}, newStringDict(map[string]*Object{ 828 "__pos__": newBuiltinFunction("__pos__", func(f *Frame, _ Args, _ KWArgs) (*Object, *BaseException) { 829 return NewInt(-42).ToObject(), nil 830 }).ToObject(), 831 })) 832 cases := []invokeTestCase{ 833 {args: wrapArgs(42), want: NewInt(42).ToObject()}, 834 {args: wrapArgs(1.2), want: NewFloat(1.2).ToObject()}, 835 {args: wrapArgs(NewLong(big.NewInt(123))), want: NewLong(big.NewInt(123)).ToObject()}, 836 {args: wrapArgs(newObject(pos)), want: NewInt(-42).ToObject()}, 837 {args: wrapArgs("foo"), wantExc: mustCreateException(TypeErrorType, "bad operand type for unary +: 'str'")}, 838 } 839 for _, cas := range cases { 840 if err := runInvokeTestCase(wrapFuncForTest(Pos), &cas); err != "" { 841 t.Error(err) 842 } 843 } 844 } 845 846 func TestPyPrint(t *testing.T) { 847 fun := wrapFuncForTest(func(f *Frame, args *Tuple, sep, end string) (string, *BaseException) { 848 return captureStdout(f, func() *BaseException { 849 return pyPrint(NewRootFrame(), args.elems, sep, end, Stdout) 850 }) 851 }) 852 cases := []invokeTestCase{ 853 {args: wrapArgs(NewTuple(), "", "\n"), want: NewStr("\n").ToObject()}, 854 {args: wrapArgs(NewTuple(), "", ""), want: NewStr("").ToObject()}, 855 {args: wrapArgs(newTestTuple("abc", 123), " ", "\n"), want: NewStr("abc 123\n").ToObject()}, 856 {args: wrapArgs(newTestTuple("foo"), "", " "), want: NewStr("foo ").ToObject()}, 857 } 858 for _, cas := range cases { 859 if err := runInvokeTestCase(fun, &cas); err != "" { 860 t.Error(err) 861 } 862 } 863 } 864 865 // TODO(corona10): Re-enable once #282 is addressed. 866 /*func TestPrint(t *testing.T) { 867 fun := wrapFuncForTest(func(f *Frame, args *Tuple, nl bool) (string, *BaseException) { 868 return captureStdout(f, func() *BaseException { 869 return Print(NewRootFrame(), args.elems, nl) 870 }) 871 }) 872 cases := []invokeTestCase{ 873 {args: wrapArgs(NewTuple(), true), want: NewStr("\n").ToObject()}, 874 {args: wrapArgs(NewTuple(), false), want: NewStr("").ToObject()}, 875 {args: wrapArgs(newTestTuple("abc", 123), true), want: NewStr("abc 123\n").ToObject()}, 876 {args: wrapArgs(newTestTuple("foo"), false), want: NewStr("foo ").ToObject()}, 877 } 878 for _, cas := range cases { 879 if err := runInvokeTestCase(fun, &cas); err != "" { 880 t.Error(err) 881 } 882 } 883 }*/ 884 885 func TestReprRaise(t *testing.T) { 886 testTypes := []*Type{ 887 BaseExceptionType, 888 BoolType, 889 DictType, 890 IntType, 891 FunctionType, 892 StrType, 893 TupleType, 894 TypeType, 895 } 896 for _, typ := range testTypes { 897 cases := []invokeTestCase{ 898 {args: wrapArgs(), wantExc: mustCreateException(TypeErrorType, fmt.Sprintf("unbound method __repr__() must be called with %s instance as first argument (got nothing instead)", typ.Name()))}, 899 {args: wrapArgs(newObject(ObjectType)), wantExc: mustCreateException(TypeErrorType, fmt.Sprintf("unbound method __repr__() must be called with %s instance as first argument (got object instance instead)", typ.Name()))}, 900 } 901 for _, cas := range cases { 902 if err := runInvokeMethodTestCase(typ, "__repr__", &cas); err != "" { 903 t.Error(err) 904 } 905 } 906 } 907 } 908 909 func TestReprMethodReturnsNonStr(t *testing.T) { 910 // Don't use runInvokeTestCase since it takes repr(args) and in this 911 // case repr will raise. 912 typ := newTestClass("Foo", []*Type{ObjectType}, newStringDict(map[string]*Object{ 913 "__repr__": newBuiltinFunction("__repr__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 914 return None, nil 915 }).ToObject(), 916 })) 917 _, raised := Repr(NewRootFrame(), newObject(typ)) 918 wantExc := mustCreateException(TypeErrorType, "__repr__ returned non-string (type NoneType)") 919 if !exceptionsAreEquivalent(raised, wantExc) { 920 t.Errorf(`Repr() raised %v, want %v`, raised, wantExc) 921 } 922 } 923 924 func TestResolveClass(t *testing.T) { 925 f := NewRootFrame() 926 cases := []struct { 927 class *Dict 928 local *Object 929 globals *Dict 930 name string 931 want *Object 932 wantExc *BaseException 933 }{ 934 {newStringDict(map[string]*Object{"foo": NewStr("bar").ToObject()}), NewStr("baz").ToObject(), NewDict(), "foo", NewStr("bar").ToObject(), nil}, 935 {newStringDict(map[string]*Object{"str": NewInt(42).ToObject()}), nil, NewDict(), "str", NewInt(42).ToObject(), nil}, 936 {NewDict(), nil, newStringDict(map[string]*Object{"foo": NewStr("bar").ToObject()}), "foo", NewStr("bar").ToObject(), nil}, 937 {NewDict(), nil, NewDict(), "str", StrType.ToObject(), nil}, 938 {NewDict(), nil, NewDict(), "foo", nil, mustCreateException(NameErrorType, "name 'foo' is not defined")}, 939 } 940 for _, cas := range cases { 941 f.globals = cas.globals 942 got, raised := ResolveClass(f, cas.class, cas.local, NewStr(cas.name)) 943 switch checkResult(got, cas.want, raised, cas.wantExc) { 944 case checkInvokeResultExceptionMismatch: 945 t.Errorf("ResolveClass(%v, %q) raised %v, want %v", cas.globals, cas.name, raised, cas.wantExc) 946 case checkInvokeResultReturnValueMismatch: 947 t.Errorf("ResolveClass(%v, %q) = %v, want %v", cas.globals, cas.name, got, cas.want) 948 } 949 } 950 } 951 952 func TestResolveGlobal(t *testing.T) { 953 fun := wrapFuncForTest(func(f *Frame, globals *Dict, name *Str) (*Object, *BaseException) { 954 f.globals = globals 955 return ResolveGlobal(f, name) 956 }) 957 cases := []invokeTestCase{ 958 {args: wrapArgs(newStringDict(map[string]*Object{"foo": NewStr("bar").ToObject()}), "foo"), want: NewStr("bar").ToObject()}, 959 {args: wrapArgs(NewDict(), "str"), want: StrType.ToObject()}, 960 {args: wrapArgs(NewDict(), "foo"), wantExc: mustCreateException(NameErrorType, "name 'foo' is not defined")}, 961 } 962 for _, cas := range cases { 963 if err := runInvokeTestCase(fun, &cas); err != "" { 964 t.Error(err) 965 } 966 } 967 } 968 969 func TestRichCompare(t *testing.T) { 970 badCmpType := newTestClass("BadCmp", []*Type{ObjectType}, newStringDict(map[string]*Object{ 971 "__cmp__": newBuiltinFunction("__cmp__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 972 return nil, f.RaiseType(TypeErrorType, "uh oh") 973 }).ToObject(), 974 })) 975 cmpEqType := newTestClass("BadCmp", []*Type{ObjectType}, newStringDict(map[string]*Object{ 976 "__cmp__": newBuiltinFunction("__cmp__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 977 return NewInt(0).ToObject(), nil 978 }).ToObject(), 979 })) 980 cmpByEqType := newTestClass("Eq", []*Type{IntType}, newStringDict(map[string]*Object{ 981 "__eq__": newBuiltinFunction("__eq__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 982 return True.ToObject(), nil 983 }).ToObject(), 984 "__cmp__": newBuiltinFunction("__cmp__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 985 return NotImplemented, nil 986 }).ToObject(), 987 })) 988 badCmpEqType := newTestClass("Eq", []*Type{IntType}, newStringDict(map[string]*Object{ 989 "__eq__": newBuiltinFunction("__eq__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 990 return nil, f.RaiseType(TypeErrorType, "uh oh") 991 }).ToObject(), 992 })) 993 cases := []invokeTestCase{ 994 // Test `__eq__` fallback to `__cmp__`. 995 {args: wrapArgs(newObject(cmpEqType), newObject(cmpEqType)), want: compareAllResultEq}, 996 // Test `__cmp__` fallback to `__eq__`. 997 {args: wrapArgs(newObject(cmpByEqType), newObject(cmpByEqType)), want: compareAllResultEq}, 998 // Test rich compare fallback to bad `__cmp__`. 999 {args: wrapArgs(newObject(badCmpType), newObject(badCmpType)), wantExc: mustCreateException(TypeErrorType, "uh oh")}, 1000 // Test bad `__eq__` where the second object being compared is a subclass of the first. 1001 {args: wrapArgs(NewInt(13).ToObject(), newObject(badCmpEqType)), wantExc: mustCreateException(TypeErrorType, "uh oh")}, 1002 } 1003 for _, cas := range cases { 1004 if err := runInvokeTestCase(compareAll, &cas); err != "" { 1005 t.Error(err) 1006 } 1007 } 1008 } 1009 1010 func TestCheckLocal(t *testing.T) { 1011 o := newObject(ObjectType) 1012 cases := []invokeTestCase{ 1013 {args: wrapArgs(o, "foo"), want: None}, 1014 {args: wrapArgs(UnboundLocal, "bar"), wantExc: mustCreateException(UnboundLocalErrorType, "local variable 'bar' referenced before assignment")}, 1015 } 1016 for _, cas := range cases { 1017 if err := runInvokeTestCase(wrapFuncForTest(CheckLocal), &cas); err != "" { 1018 t.Error(err) 1019 } 1020 } 1021 } 1022 1023 func TestSetItem(t *testing.T) { 1024 setItem := newBuiltinFunction("TestSetItem", func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 1025 if raised := checkFunctionArgs(f, "TestSetItem", args, ObjectType, ObjectType, ObjectType); raised != nil { 1026 return nil, raised 1027 } 1028 o := args[0] 1029 if raised := SetItem(f, o, args[1], args[2]); raised != nil { 1030 return nil, raised 1031 } 1032 return o, nil 1033 }).ToObject() 1034 cases := []invokeTestCase{ 1035 {args: wrapArgs(NewDict(), "bar", None), want: newTestDict("bar", None).ToObject()}, 1036 {args: wrapArgs(123, "bar", None), wantExc: mustCreateException(TypeErrorType, "'int' object has no attribute '__setitem__'")}, 1037 } 1038 for _, cas := range cases { 1039 if err := runInvokeTestCase(setItem, &cas); err != "" { 1040 t.Error(err) 1041 } 1042 } 1043 } 1044 1045 func TestStartThread(t *testing.T) { 1046 c := make(chan bool) 1047 callable := newBuiltinFunction("TestStartThread", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 1048 close(c) 1049 return None, nil 1050 }).ToObject() 1051 StartThread(callable) 1052 // Deadlock indicates the thread didn't start. 1053 <-c 1054 } 1055 1056 func TestStartThreadRaises(t *testing.T) { 1057 // Since there's no way to notify that the goroutine has returned we 1058 // can't actually test the exception output but we can at least make 1059 // sure the callable ran and didn't blow up the rest of the program. 1060 c := make(chan bool) 1061 callable := newBuiltinFunction("TestStartThreadRaises", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 1062 defer close(c) 1063 return nil, f.RaiseType(ExceptionType, "foo") 1064 }).ToObject() 1065 StartThread(callable) 1066 <-c 1067 } 1068 1069 func TestTie(t *testing.T) { 1070 targets := make([]*Object, 3) 1071 cases := []struct { 1072 t TieTarget 1073 o *Object 1074 want *Object 1075 wantExc *BaseException 1076 }{ 1077 {TieTarget{Target: &targets[0]}, NewInt(42).ToObject(), NewTuple(NewInt(42).ToObject()).ToObject(), nil}, 1078 {TieTarget{Target: &targets[0]}, NewTuple().ToObject(), NewTuple(NewTuple().ToObject()).ToObject(), nil}, 1079 { 1080 TieTarget{ 1081 Children: []TieTarget{{Target: &targets[0]}, {Target: &targets[1]}}, 1082 }, 1083 NewList(NewStr("foo").ToObject(), NewStr("bar").ToObject()).ToObject(), 1084 NewTuple(NewStr("foo").ToObject(), NewStr("bar").ToObject()).ToObject(), 1085 nil, 1086 }, 1087 { 1088 TieTarget{ 1089 Children: []TieTarget{ 1090 {Target: &targets[0]}, 1091 {Children: []TieTarget{{Target: &targets[1]}, {Target: &targets[2]}}}, 1092 }, 1093 }, 1094 NewTuple(NewStr("foo").ToObject(), NewTuple(NewStr("bar").ToObject(), NewStr("baz").ToObject()).ToObject()).ToObject(), 1095 NewTuple(NewStr("foo").ToObject(), NewStr("bar").ToObject(), NewStr("baz").ToObject()).ToObject(), 1096 nil, 1097 }, 1098 { 1099 TieTarget{ 1100 Children: []TieTarget{ 1101 {Target: &targets[0]}, 1102 {Target: &targets[1]}, 1103 }, 1104 }, 1105 NewList(NewStr("foo").ToObject()).ToObject(), 1106 nil, 1107 mustCreateException(ValueErrorType, "need more than 1 values to unpack"), 1108 }, 1109 { 1110 TieTarget{Children: []TieTarget{{Target: &targets[0]}}}, 1111 NewTuple(NewInt(1).ToObject(), NewInt(2).ToObject()).ToObject(), 1112 nil, 1113 mustCreateException(ValueErrorType, "too many values to unpack"), 1114 }, 1115 } 1116 for _, cas := range cases { 1117 for i := range targets { 1118 targets[i] = nil 1119 } 1120 var got *Object 1121 raised := Tie(NewRootFrame(), cas.t, cas.o) 1122 if raised == nil { 1123 var elems []*Object 1124 for _, t := range targets { 1125 if t == nil { 1126 break 1127 } 1128 elems = append(elems, t) 1129 } 1130 got = NewTuple(elems...).ToObject() 1131 } 1132 switch checkResult(got, cas.want, raised, cas.wantExc) { 1133 case checkInvokeResultExceptionMismatch: 1134 t.Errorf("Tie(%+v, %v) raised %v, want %v", cas.t, cas.o, raised, cas.wantExc) 1135 case checkInvokeResultReturnValueMismatch: 1136 t.Errorf("Tie(%+v, %v) = %v, want %v", cas.t, cas.o, got, cas.want) 1137 } 1138 } 1139 } 1140 1141 func TestToInt(t *testing.T) { 1142 fun := wrapFuncForTest(func(f *Frame, o *Object) (*Tuple, *BaseException) { 1143 i, raised := ToInt(f, o) 1144 if raised != nil { 1145 return nil, raised 1146 } 1147 return newTestTuple(i, i.Type()), nil 1148 }) 1149 cases := []invokeTestCase{ 1150 {args: wrapArgs(42), want: newTestTuple(42, IntType).ToObject()}, 1151 {args: wrapArgs(big.NewInt(123)), want: newTestTuple(123, LongType).ToObject()}, 1152 } 1153 for _, cas := range cases { 1154 if err := runInvokeTestCase(fun, &cas); err != "" { 1155 t.Error(err) 1156 } 1157 } 1158 } 1159 1160 func TestToIntValue(t *testing.T) { 1161 cases := []invokeTestCase{ 1162 {args: wrapArgs(42), want: NewInt(42).ToObject()}, 1163 {args: wrapArgs(big.NewInt(123)), want: NewInt(123).ToObject()}, 1164 {args: wrapArgs(overflowLong), wantExc: mustCreateException(OverflowErrorType, "Python int too large to convert to a Go int")}, 1165 } 1166 for _, cas := range cases { 1167 if err := runInvokeTestCase(wrapFuncForTest(ToIntValue), &cas); err != "" { 1168 t.Error(err) 1169 } 1170 } 1171 } 1172 1173 func TestToNative(t *testing.T) { 1174 foo := newObject(ObjectType) 1175 cases := []struct { 1176 o *Object 1177 want interface{} 1178 wantExc *BaseException 1179 }{ 1180 {True.ToObject(), true, nil}, 1181 {NewInt(42).ToObject(), 42, nil}, 1182 {NewStr("bar").ToObject(), "bar", nil}, 1183 {foo, foo, nil}, 1184 } 1185 for _, cas := range cases { 1186 got, raised := ToNative(NewRootFrame(), cas.o) 1187 if !exceptionsAreEquivalent(raised, cas.wantExc) { 1188 t.Errorf("ToNative(%v) raised %v, want %v", cas.o, raised, cas.wantExc) 1189 } else if raised == nil && (!got.IsValid() || !reflect.DeepEqual(got.Interface(), cas.want)) { 1190 t.Errorf("ToNative(%v) = %v, want %v", cas.o, got, cas.want) 1191 } 1192 } 1193 } 1194 1195 func BenchmarkGetAttr(b *testing.B) { 1196 f := NewRootFrame() 1197 attr := NewStr("bar") 1198 fooType := newTestClass("Foo", []*Type{ObjectType}, NewDict()) 1199 foo := newObject(fooType) 1200 if raised := SetAttr(f, foo, attr, NewInt(123).ToObject()); raised != nil { 1201 panic(raised) 1202 } 1203 b.ResetTimer() 1204 for i := 0; i < b.N; i++ { 1205 mustNotRaise(GetAttr(f, foo, attr, nil)) 1206 } 1207 } 1208 1209 // SetAttr is tested in TestObjectSetAttr. 1210 1211 func exceptionsAreEquivalent(e1 *BaseException, e2 *BaseException) bool { 1212 if e1 == nil && e2 == nil { 1213 return true 1214 } 1215 if e1 == nil || e2 == nil { 1216 return false 1217 } 1218 if e1.typ != e2.typ { 1219 return false 1220 } 1221 if e1.args == nil && e2.args == nil { 1222 return true 1223 } 1224 if e1.args == nil || e2.args == nil { 1225 return false 1226 } 1227 f := NewRootFrame() 1228 b, raised := IsTrue(f, mustNotRaise(Eq(f, e1.args.ToObject(), e2.args.ToObject()))) 1229 if raised != nil { 1230 panic(raised) 1231 } 1232 return b 1233 } 1234 1235 func getFuncName(f interface{}) string { 1236 s := runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name() 1237 return regexp.MustCompile(`\w+$`).FindString(s) 1238 } 1239 1240 // wrapFuncForTest creates a callable object that invokes fun, passing the 1241 // current frame as its first argument followed by caller provided args. 1242 func wrapFuncForTest(fun interface{}) *Object { 1243 return newBuiltinFunction(getFuncName(fun), func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 1244 callable, raised := WrapNative(f, reflect.ValueOf(fun)) 1245 if raised != nil { 1246 return nil, raised 1247 } 1248 argc := len(args) 1249 nativeArgs := make(Args, argc+1, argc+1) 1250 nativeArgs[0] = f.ToObject() 1251 copy(nativeArgs[1:], args) 1252 return callable.Call(f, nativeArgs, nil) 1253 }).ToObject() 1254 } 1255 1256 func mustCreateException(t *Type, msg string) *BaseException { 1257 if !t.isSubclass(BaseExceptionType) { 1258 panic(fmt.Sprintf("type does not inherit from BaseException: %s", t.Name())) 1259 } 1260 e := toBaseExceptionUnsafe(newObject(t)) 1261 if msg == "" { 1262 e.args = NewTuple() 1263 } else { 1264 e.args = NewTuple(NewStr(msg).ToObject()) 1265 } 1266 return e 1267 } 1268 1269 func mustNotRaise(o *Object, raised *BaseException) *Object { 1270 if raised != nil { 1271 panic(raised) 1272 } 1273 return o 1274 } 1275 1276 var ( 1277 compareAll = wrapFuncForTest(func(f *Frame, v, w *Object) (*Object, *BaseException) { 1278 lt, raised := LT(f, v, w) 1279 if raised != nil { 1280 return nil, raised 1281 } 1282 le, raised := LE(f, v, w) 1283 if raised != nil { 1284 return nil, raised 1285 } 1286 eq, raised := Eq(f, v, w) 1287 if raised != nil { 1288 return nil, raised 1289 } 1290 ne, raised := NE(f, v, w) 1291 if raised != nil { 1292 return nil, raised 1293 } 1294 ge, raised := GE(f, v, w) 1295 if raised != nil { 1296 return nil, raised 1297 } 1298 gt, raised := GT(f, v, w) 1299 if raised != nil { 1300 return nil, raised 1301 } 1302 return NewTuple(lt, le, eq, ne, ge, gt).ToObject(), nil 1303 }) 1304 compareAllResultLT = newTestTuple(true, true, false, true, false, false).ToObject() 1305 compareAllResultEq = newTestTuple(false, true, true, false, true, false).ToObject() 1306 compareAllResultGT = newTestTuple(false, false, false, true, true, true).ToObject() 1307 )