github.com/google/grumpy@v0.0.0-20171122020858-3ec87959189c/runtime/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 grumpy 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 TestNeg(t *testing.T) { 630 cases := []invokeTestCase{ 631 {args: wrapArgs(42), want: NewInt(-42).ToObject()}, 632 {args: wrapArgs(1.2), want: NewFloat(-1.2).ToObject()}, 633 {args: wrapArgs(NewLong(big.NewInt(123))), want: NewLong(big.NewInt(-123)).ToObject()}, 634 {args: wrapArgs("foo"), wantExc: mustCreateException(TypeErrorType, "bad operand type for unary -: 'str'")}, 635 } 636 for _, cas := range cases { 637 if err := runInvokeTestCase(wrapFuncForTest(Neg), &cas); err != "" { 638 t.Error(err) 639 } 640 } 641 } 642 643 func TestNext(t *testing.T) { 644 fun := newBuiltinFunction("TestNext", func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 645 if argc := len(args); argc != 1 { 646 return nil, f.RaiseType(SystemErrorType, fmt.Sprintf("Next expected 1 arg, got %d", argc)) 647 } 648 iter := args[0] 649 var elems []*Object 650 elem, raised := Next(f, iter) 651 for ; raised == nil; elem, raised = Next(f, iter) { 652 elems = append(elems, elem) 653 } 654 if !raised.isInstance(StopIterationType) { 655 return nil, raised 656 } 657 f.RestoreExc(nil, nil) 658 return NewTuple(elems...).ToObject(), nil 659 }).ToObject() 660 testElems := []*Object{NewInt(42).ToObject(), NewStr("foo").ToObject(), newObject(ObjectType)} 661 cases := []invokeTestCase{ 662 {args: wrapArgs(mustNotRaise(Iter(NewRootFrame(), NewTuple().ToObject()))), want: NewTuple().ToObject()}, 663 {args: wrapArgs(mustNotRaise(Iter(NewRootFrame(), NewTuple(testElems...).ToObject()))), want: NewTuple(testElems...).ToObject()}, 664 {args: wrapArgs(mustNotRaise(Iter(NewRootFrame(), NewList(testElems...).ToObject()))), want: NewTuple(testElems...).ToObject()}, 665 {args: wrapArgs(123), wantExc: mustCreateException(TypeErrorType, "int object is not an iterator")}, 666 } 667 for _, cas := range cases { 668 if err := runInvokeTestCase(fun, &cas); err != "" { 669 t.Error(err) 670 } 671 } 672 } 673 674 func TestLen(t *testing.T) { 675 badLenType := newTestClass("BadLen", []*Type{ObjectType}, newStringDict(map[string]*Object{ 676 "__len__": newBuiltinFunction("__len__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 677 return None, nil 678 }).ToObject(), 679 })) 680 cases := []invokeTestCase{ 681 {args: wrapArgs(NewDict()), want: NewInt(0).ToObject()}, 682 {args: wrapArgs(newStringDict(map[string]*Object{"foo": NewStr("foo value").ToObject(), "bar": NewStr("bar value").ToObject()})), want: NewInt(2).ToObject()}, 683 {args: wrapArgs(NewTuple()), want: NewInt(0).ToObject()}, 684 {args: wrapArgs(NewTuple(None, None, None)), want: NewInt(3).ToObject()}, 685 {args: wrapArgs(10), wantExc: mustCreateException(TypeErrorType, "object of type 'int' has no len()")}, 686 {args: wrapArgs(newObject(badLenType)), wantExc: mustCreateException(TypeErrorType, "an integer is required")}, 687 } 688 for _, cas := range cases { 689 if err := runInvokeTestCase(wrapFuncForTest(Len), &cas); err != "" { 690 t.Error(err) 691 } 692 } 693 } 694 695 func TestLenRaise(t *testing.T) { 696 testTypes := []*Type{ 697 DictType, 698 TupleType, 699 } 700 for _, typ := range testTypes { 701 cases := []invokeTestCase{ 702 {args: wrapArgs(), wantExc: mustCreateException(TypeErrorType, fmt.Sprintf("unbound method __len__() must be called with %s instance as first argument (got nothing instead)", typ.Name()))}, 703 {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()))}, 704 {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()))}, 705 } 706 for _, cas := range cases { 707 if err := runInvokeMethodTestCase(typ, "__len__", &cas); err != "" { 708 t.Error(err) 709 } 710 } 711 } 712 } 713 714 func TestInvokePositionalArgs(t *testing.T) { 715 fun := newBuiltinFunction("TestInvokePositionalArgs", func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 716 return NewTuple(args.makeCopy()...).ToObject(), nil 717 }).ToObject() 718 cases := []struct { 719 varargs *Object 720 args Args 721 want *Object 722 }{ 723 {nil, nil, NewTuple().ToObject()}, 724 {NewTuple(NewInt(2).ToObject()).ToObject(), nil, NewTuple(NewInt(2).ToObject()).ToObject()}, 725 {nil, []*Object{NewStr("foo").ToObject()}, NewTuple(NewStr("foo").ToObject()).ToObject()}, 726 {NewTuple(NewFloat(3.14).ToObject()).ToObject(), []*Object{NewStr("foo").ToObject()}, NewTuple(NewStr("foo").ToObject(), NewFloat(3.14).ToObject()).ToObject()}, 727 {NewList(NewFloat(3.14).ToObject()).ToObject(), []*Object{NewStr("foo").ToObject()}, NewTuple(NewStr("foo").ToObject(), NewFloat(3.14).ToObject()).ToObject()}, 728 } 729 for _, cas := range cases { 730 got, raised := Invoke(NewRootFrame(), fun, cas.args, cas.varargs, nil, nil) 731 switch checkResult(got, cas.want, raised, nil) { 732 case checkInvokeResultExceptionMismatch: 733 t.Errorf("PackArgs(%v, %v) raised %v, want nil", cas.args, cas.varargs, raised) 734 case checkInvokeResultReturnValueMismatch: 735 t.Errorf("PackArgs(%v, %v) = %v, want %v", cas.args, cas.varargs, got, cas.want) 736 } 737 } 738 } 739 740 func TestInvokeKeywordArgs(t *testing.T) { 741 fun := newBuiltinFunction("TestInvokeKeywordArgs", func(f *Frame, _ Args, kwargs KWArgs) (*Object, *BaseException) { 742 got := map[string]*Object{} 743 for _, kw := range kwargs { 744 got[kw.Name] = kw.Value 745 } 746 return newStringDict(got).ToObject(), nil 747 }).ToObject() 748 d := NewDict() 749 d.SetItem(NewRootFrame(), NewInt(123).ToObject(), None) 750 cases := []struct { 751 keywords KWArgs 752 kwargs *Object 753 want *Object 754 wantExc *BaseException 755 }{ 756 {nil, nil, NewDict().ToObject(), nil}, 757 {wrapKWArgs("foo", 42), nil, newTestDict("foo", 42).ToObject(), nil}, 758 {nil, newTestDict("foo", None).ToObject(), newTestDict("foo", None).ToObject(), nil}, 759 {wrapKWArgs("foo", 42), newTestDict("bar", None).ToObject(), newTestDict("foo", 42, "bar", None).ToObject(), nil}, 760 {nil, NewList().ToObject(), nil, mustCreateException(TypeErrorType, "argument after ** must be a dict, not list")}, 761 {nil, d.ToObject(), nil, mustCreateException(TypeErrorType, "keywords must be strings")}, 762 } 763 for _, cas := range cases { 764 got, raised := Invoke(NewRootFrame(), fun, nil, nil, cas.keywords, cas.kwargs) 765 switch checkResult(got, cas.want, raised, cas.wantExc) { 766 case checkInvokeResultExceptionMismatch: 767 t.Errorf("PackKwargs(%v, %v) raised %v, want %v", cas.keywords, cas.kwargs, raised, cas.wantExc) 768 case checkInvokeResultReturnValueMismatch: 769 t.Errorf("PackKwargs(%v, %v) = %v, want %v", cas.keywords, cas.kwargs, got, cas.want) 770 } 771 } 772 } 773 774 func TestOct(t *testing.T) { 775 badOct := newTestClass("badOct", []*Type{ObjectType}, newStringDict(map[string]*Object{ 776 "__oct__": newBuiltinFunction("__oct__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 777 return NewInt(123).ToObject(), nil 778 }).ToObject(), 779 })) 780 goodOct := newTestClass("goodOct", []*Type{ObjectType}, newStringDict(map[string]*Object{ 781 "__oct__": newBuiltinFunction("__oct__", func(f *Frame, _ Args, _ KWArgs) (*Object, *BaseException) { 782 return NewStr("0123").ToObject(), nil 783 }).ToObject(), 784 })) 785 cases := []invokeTestCase{ 786 {args: wrapArgs(-123), want: NewStr("-0173").ToObject()}, 787 {args: wrapArgs(123), want: NewStr("0173").ToObject()}, 788 {args: wrapArgs(newObject(goodOct)), want: NewStr("0123").ToObject()}, 789 {args: wrapArgs(NewList()), wantExc: mustCreateException(TypeErrorType, "oct() argument can't be converted to oct")}, 790 {args: wrapArgs(NewDict()), wantExc: mustCreateException(TypeErrorType, "oct() argument can't be converted to oct")}, 791 {args: wrapArgs(newObject(badOct)), wantExc: mustCreateException(TypeErrorType, "__oct__ returned non-string (type int)")}, 792 } 793 for _, cas := range cases { 794 if err := runInvokeTestCase(wrapFuncForTest(Oct), &cas); err != "" { 795 t.Error(err) 796 } 797 } 798 } 799 800 func TestPos(t *testing.T) { 801 pos := newTestClass("pos", []*Type{ObjectType}, newStringDict(map[string]*Object{ 802 "__pos__": newBuiltinFunction("__pos__", func(f *Frame, _ Args, _ KWArgs) (*Object, *BaseException) { 803 return NewInt(-42).ToObject(), nil 804 }).ToObject(), 805 })) 806 cases := []invokeTestCase{ 807 {args: wrapArgs(42), want: NewInt(42).ToObject()}, 808 {args: wrapArgs(1.2), want: NewFloat(1.2).ToObject()}, 809 {args: wrapArgs(NewLong(big.NewInt(123))), want: NewLong(big.NewInt(123)).ToObject()}, 810 {args: wrapArgs(newObject(pos)), want: NewInt(-42).ToObject()}, 811 {args: wrapArgs("foo"), wantExc: mustCreateException(TypeErrorType, "bad operand type for unary +: 'str'")}, 812 } 813 for _, cas := range cases { 814 if err := runInvokeTestCase(wrapFuncForTest(Pos), &cas); err != "" { 815 t.Error(err) 816 } 817 } 818 } 819 820 func TestPyPrint(t *testing.T) { 821 fun := wrapFuncForTest(func(f *Frame, args *Tuple, sep, end string) (string, *BaseException) { 822 return captureStdout(f, func() *BaseException { 823 return pyPrint(NewRootFrame(), args.elems, sep, end, Stdout) 824 }) 825 }) 826 cases := []invokeTestCase{ 827 {args: wrapArgs(NewTuple(), "", "\n"), want: NewStr("\n").ToObject()}, 828 {args: wrapArgs(NewTuple(), "", ""), want: NewStr("").ToObject()}, 829 {args: wrapArgs(newTestTuple("abc", 123), " ", "\n"), want: NewStr("abc 123\n").ToObject()}, 830 {args: wrapArgs(newTestTuple("foo"), "", " "), want: NewStr("foo ").ToObject()}, 831 } 832 for _, cas := range cases { 833 if err := runInvokeTestCase(fun, &cas); err != "" { 834 t.Error(err) 835 } 836 } 837 } 838 839 // TODO(corona10): Re-enable once #282 is addressed. 840 /*func TestPrint(t *testing.T) { 841 fun := wrapFuncForTest(func(f *Frame, args *Tuple, nl bool) (string, *BaseException) { 842 return captureStdout(f, func() *BaseException { 843 return Print(NewRootFrame(), args.elems, nl) 844 }) 845 }) 846 cases := []invokeTestCase{ 847 {args: wrapArgs(NewTuple(), true), want: NewStr("\n").ToObject()}, 848 {args: wrapArgs(NewTuple(), false), want: NewStr("").ToObject()}, 849 {args: wrapArgs(newTestTuple("abc", 123), true), want: NewStr("abc 123\n").ToObject()}, 850 {args: wrapArgs(newTestTuple("foo"), false), want: NewStr("foo ").ToObject()}, 851 } 852 for _, cas := range cases { 853 if err := runInvokeTestCase(fun, &cas); err != "" { 854 t.Error(err) 855 } 856 } 857 }*/ 858 859 func TestReprRaise(t *testing.T) { 860 testTypes := []*Type{ 861 BaseExceptionType, 862 BoolType, 863 DictType, 864 IntType, 865 FunctionType, 866 StrType, 867 TupleType, 868 TypeType, 869 } 870 for _, typ := range testTypes { 871 cases := []invokeTestCase{ 872 {args: wrapArgs(), wantExc: mustCreateException(TypeErrorType, fmt.Sprintf("unbound method __repr__() must be called with %s instance as first argument (got nothing instead)", typ.Name()))}, 873 {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()))}, 874 } 875 for _, cas := range cases { 876 if err := runInvokeMethodTestCase(typ, "__repr__", &cas); err != "" { 877 t.Error(err) 878 } 879 } 880 } 881 } 882 883 func TestReprMethodReturnsNonStr(t *testing.T) { 884 // Don't use runInvokeTestCase since it takes repr(args) and in this 885 // case repr will raise. 886 typ := newTestClass("Foo", []*Type{ObjectType}, newStringDict(map[string]*Object{ 887 "__repr__": newBuiltinFunction("__repr__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 888 return None, nil 889 }).ToObject(), 890 })) 891 _, raised := Repr(NewRootFrame(), newObject(typ)) 892 wantExc := mustCreateException(TypeErrorType, "__repr__ returned non-string (type NoneType)") 893 if !exceptionsAreEquivalent(raised, wantExc) { 894 t.Errorf(`Repr() raised %v, want %v`, raised, wantExc) 895 } 896 } 897 898 func TestResolveClass(t *testing.T) { 899 f := NewRootFrame() 900 cases := []struct { 901 class *Dict 902 local *Object 903 globals *Dict 904 name string 905 want *Object 906 wantExc *BaseException 907 }{ 908 {newStringDict(map[string]*Object{"foo": NewStr("bar").ToObject()}), NewStr("baz").ToObject(), NewDict(), "foo", NewStr("bar").ToObject(), nil}, 909 {newStringDict(map[string]*Object{"str": NewInt(42).ToObject()}), nil, NewDict(), "str", NewInt(42).ToObject(), nil}, 910 {NewDict(), nil, newStringDict(map[string]*Object{"foo": NewStr("bar").ToObject()}), "foo", NewStr("bar").ToObject(), nil}, 911 {NewDict(), nil, NewDict(), "str", StrType.ToObject(), nil}, 912 {NewDict(), nil, NewDict(), "foo", nil, mustCreateException(NameErrorType, "name 'foo' is not defined")}, 913 } 914 for _, cas := range cases { 915 f.globals = cas.globals 916 got, raised := ResolveClass(f, cas.class, cas.local, NewStr(cas.name)) 917 switch checkResult(got, cas.want, raised, cas.wantExc) { 918 case checkInvokeResultExceptionMismatch: 919 t.Errorf("ResolveClass(%v, %q) raised %v, want %v", cas.globals, cas.name, raised, cas.wantExc) 920 case checkInvokeResultReturnValueMismatch: 921 t.Errorf("ResolveClass(%v, %q) = %v, want %v", cas.globals, cas.name, got, cas.want) 922 } 923 } 924 } 925 926 func TestResolveGlobal(t *testing.T) { 927 fun := wrapFuncForTest(func(f *Frame, globals *Dict, name *Str) (*Object, *BaseException) { 928 f.globals = globals 929 return ResolveGlobal(f, name) 930 }) 931 cases := []invokeTestCase{ 932 {args: wrapArgs(newStringDict(map[string]*Object{"foo": NewStr("bar").ToObject()}), "foo"), want: NewStr("bar").ToObject()}, 933 {args: wrapArgs(NewDict(), "str"), want: StrType.ToObject()}, 934 {args: wrapArgs(NewDict(), "foo"), wantExc: mustCreateException(NameErrorType, "name 'foo' is not defined")}, 935 } 936 for _, cas := range cases { 937 if err := runInvokeTestCase(fun, &cas); err != "" { 938 t.Error(err) 939 } 940 } 941 } 942 943 func TestRichCompare(t *testing.T) { 944 badCmpType := newTestClass("BadCmp", []*Type{ObjectType}, newStringDict(map[string]*Object{ 945 "__cmp__": newBuiltinFunction("__cmp__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 946 return nil, f.RaiseType(TypeErrorType, "uh oh") 947 }).ToObject(), 948 })) 949 cmpEqType := newTestClass("BadCmp", []*Type{ObjectType}, newStringDict(map[string]*Object{ 950 "__cmp__": newBuiltinFunction("__cmp__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 951 return NewInt(0).ToObject(), nil 952 }).ToObject(), 953 })) 954 cmpByEqType := newTestClass("Eq", []*Type{IntType}, newStringDict(map[string]*Object{ 955 "__eq__": newBuiltinFunction("__eq__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 956 return True.ToObject(), nil 957 }).ToObject(), 958 "__cmp__": newBuiltinFunction("__cmp__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 959 return NotImplemented, nil 960 }).ToObject(), 961 })) 962 badCmpEqType := newTestClass("Eq", []*Type{IntType}, newStringDict(map[string]*Object{ 963 "__eq__": newBuiltinFunction("__eq__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 964 return nil, f.RaiseType(TypeErrorType, "uh oh") 965 }).ToObject(), 966 })) 967 cases := []invokeTestCase{ 968 // Test `__eq__` fallback to `__cmp__`. 969 {args: wrapArgs(newObject(cmpEqType), newObject(cmpEqType)), want: compareAllResultEq}, 970 // Test `__cmp__` fallback to `__eq__`. 971 {args: wrapArgs(newObject(cmpByEqType), newObject(cmpByEqType)), want: compareAllResultEq}, 972 // Test rich compare fallback to bad `__cmp__`. 973 {args: wrapArgs(newObject(badCmpType), newObject(badCmpType)), wantExc: mustCreateException(TypeErrorType, "uh oh")}, 974 // Test bad `__eq__` where the second object being compared is a subclass of the first. 975 {args: wrapArgs(NewInt(13).ToObject(), newObject(badCmpEqType)), wantExc: mustCreateException(TypeErrorType, "uh oh")}, 976 } 977 for _, cas := range cases { 978 if err := runInvokeTestCase(compareAll, &cas); err != "" { 979 t.Error(err) 980 } 981 } 982 } 983 984 func TestCheckLocal(t *testing.T) { 985 o := newObject(ObjectType) 986 cases := []invokeTestCase{ 987 {args: wrapArgs(o, "foo"), want: None}, 988 {args: wrapArgs(UnboundLocal, "bar"), wantExc: mustCreateException(UnboundLocalErrorType, "local variable 'bar' referenced before assignment")}, 989 } 990 for _, cas := range cases { 991 if err := runInvokeTestCase(wrapFuncForTest(CheckLocal), &cas); err != "" { 992 t.Error(err) 993 } 994 } 995 } 996 997 func TestSetItem(t *testing.T) { 998 setItem := newBuiltinFunction("TestSetItem", func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 999 if raised := checkFunctionArgs(f, "TestSetItem", args, ObjectType, ObjectType, ObjectType); raised != nil { 1000 return nil, raised 1001 } 1002 o := args[0] 1003 if raised := SetItem(f, o, args[1], args[2]); raised != nil { 1004 return nil, raised 1005 } 1006 return o, nil 1007 }).ToObject() 1008 cases := []invokeTestCase{ 1009 {args: wrapArgs(NewDict(), "bar", None), want: newTestDict("bar", None).ToObject()}, 1010 {args: wrapArgs(123, "bar", None), wantExc: mustCreateException(TypeErrorType, "'int' object has no attribute '__setitem__'")}, 1011 } 1012 for _, cas := range cases { 1013 if err := runInvokeTestCase(setItem, &cas); err != "" { 1014 t.Error(err) 1015 } 1016 } 1017 } 1018 1019 func TestStartThread(t *testing.T) { 1020 c := make(chan bool) 1021 callable := newBuiltinFunction("TestStartThread", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 1022 close(c) 1023 return None, nil 1024 }).ToObject() 1025 StartThread(callable) 1026 // Deadlock indicates the thread didn't start. 1027 <-c 1028 } 1029 1030 func TestStartThreadRaises(t *testing.T) { 1031 // Since there's no way to notify that the goroutine has returned we 1032 // can't actually test the exception output but we can at least make 1033 // sure the callable ran and didn't blow up the rest of the program. 1034 c := make(chan bool) 1035 callable := newBuiltinFunction("TestStartThreadRaises", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 1036 defer close(c) 1037 return nil, f.RaiseType(ExceptionType, "foo") 1038 }).ToObject() 1039 StartThread(callable) 1040 <-c 1041 } 1042 1043 func TestTie(t *testing.T) { 1044 targets := make([]*Object, 3) 1045 cases := []struct { 1046 t TieTarget 1047 o *Object 1048 want *Object 1049 wantExc *BaseException 1050 }{ 1051 {TieTarget{Target: &targets[0]}, NewInt(42).ToObject(), NewTuple(NewInt(42).ToObject()).ToObject(), nil}, 1052 {TieTarget{Target: &targets[0]}, NewTuple().ToObject(), NewTuple(NewTuple().ToObject()).ToObject(), nil}, 1053 { 1054 TieTarget{ 1055 Children: []TieTarget{{Target: &targets[0]}, {Target: &targets[1]}}, 1056 }, 1057 NewList(NewStr("foo").ToObject(), NewStr("bar").ToObject()).ToObject(), 1058 NewTuple(NewStr("foo").ToObject(), NewStr("bar").ToObject()).ToObject(), 1059 nil, 1060 }, 1061 { 1062 TieTarget{ 1063 Children: []TieTarget{ 1064 {Target: &targets[0]}, 1065 {Children: []TieTarget{{Target: &targets[1]}, {Target: &targets[2]}}}, 1066 }, 1067 }, 1068 NewTuple(NewStr("foo").ToObject(), NewTuple(NewStr("bar").ToObject(), NewStr("baz").ToObject()).ToObject()).ToObject(), 1069 NewTuple(NewStr("foo").ToObject(), NewStr("bar").ToObject(), NewStr("baz").ToObject()).ToObject(), 1070 nil, 1071 }, 1072 { 1073 TieTarget{ 1074 Children: []TieTarget{ 1075 {Target: &targets[0]}, 1076 {Target: &targets[1]}, 1077 }, 1078 }, 1079 NewList(NewStr("foo").ToObject()).ToObject(), 1080 nil, 1081 mustCreateException(ValueErrorType, "need more than 1 values to unpack"), 1082 }, 1083 { 1084 TieTarget{Children: []TieTarget{{Target: &targets[0]}}}, 1085 NewTuple(NewInt(1).ToObject(), NewInt(2).ToObject()).ToObject(), 1086 nil, 1087 mustCreateException(ValueErrorType, "too many values to unpack"), 1088 }, 1089 } 1090 for _, cas := range cases { 1091 for i := range targets { 1092 targets[i] = nil 1093 } 1094 var got *Object 1095 raised := Tie(NewRootFrame(), cas.t, cas.o) 1096 if raised == nil { 1097 var elems []*Object 1098 for _, t := range targets { 1099 if t == nil { 1100 break 1101 } 1102 elems = append(elems, t) 1103 } 1104 got = NewTuple(elems...).ToObject() 1105 } 1106 switch checkResult(got, cas.want, raised, cas.wantExc) { 1107 case checkInvokeResultExceptionMismatch: 1108 t.Errorf("Tie(%+v, %v) raised %v, want %v", cas.t, cas.o, raised, cas.wantExc) 1109 case checkInvokeResultReturnValueMismatch: 1110 t.Errorf("Tie(%+v, %v) = %v, want %v", cas.t, cas.o, got, cas.want) 1111 } 1112 } 1113 } 1114 1115 func TestToInt(t *testing.T) { 1116 fun := wrapFuncForTest(func(f *Frame, o *Object) (*Tuple, *BaseException) { 1117 i, raised := ToInt(f, o) 1118 if raised != nil { 1119 return nil, raised 1120 } 1121 return newTestTuple(i, i.Type()), nil 1122 }) 1123 cases := []invokeTestCase{ 1124 {args: wrapArgs(42), want: newTestTuple(42, IntType).ToObject()}, 1125 {args: wrapArgs(big.NewInt(123)), want: newTestTuple(123, LongType).ToObject()}, 1126 } 1127 for _, cas := range cases { 1128 if err := runInvokeTestCase(fun, &cas); err != "" { 1129 t.Error(err) 1130 } 1131 } 1132 } 1133 1134 func TestToIntValue(t *testing.T) { 1135 cases := []invokeTestCase{ 1136 {args: wrapArgs(42), want: NewInt(42).ToObject()}, 1137 {args: wrapArgs(big.NewInt(123)), want: NewInt(123).ToObject()}, 1138 {args: wrapArgs(overflowLong), wantExc: mustCreateException(OverflowErrorType, "Python int too large to convert to a Go int")}, 1139 } 1140 for _, cas := range cases { 1141 if err := runInvokeTestCase(wrapFuncForTest(ToIntValue), &cas); err != "" { 1142 t.Error(err) 1143 } 1144 } 1145 } 1146 1147 func TestToNative(t *testing.T) { 1148 foo := newObject(ObjectType) 1149 cases := []struct { 1150 o *Object 1151 want interface{} 1152 wantExc *BaseException 1153 }{ 1154 {True.ToObject(), true, nil}, 1155 {NewInt(42).ToObject(), 42, nil}, 1156 {NewStr("bar").ToObject(), "bar", nil}, 1157 {foo, foo, nil}, 1158 } 1159 for _, cas := range cases { 1160 got, raised := ToNative(NewRootFrame(), cas.o) 1161 if !exceptionsAreEquivalent(raised, cas.wantExc) { 1162 t.Errorf("ToNative(%v) raised %v, want %v", cas.o, raised, cas.wantExc) 1163 } else if raised == nil && (!got.IsValid() || !reflect.DeepEqual(got.Interface(), cas.want)) { 1164 t.Errorf("ToNative(%v) = %v, want %v", cas.o, got, cas.want) 1165 } 1166 } 1167 } 1168 1169 func BenchmarkGetAttr(b *testing.B) { 1170 f := NewRootFrame() 1171 attr := NewStr("bar") 1172 fooType := newTestClass("Foo", []*Type{ObjectType}, NewDict()) 1173 foo := newObject(fooType) 1174 if raised := SetAttr(f, foo, attr, NewInt(123).ToObject()); raised != nil { 1175 panic(raised) 1176 } 1177 b.ResetTimer() 1178 for i := 0; i < b.N; i++ { 1179 mustNotRaise(GetAttr(f, foo, attr, nil)) 1180 } 1181 } 1182 1183 // SetAttr is tested in TestObjectSetAttr. 1184 1185 func exceptionsAreEquivalent(e1 *BaseException, e2 *BaseException) bool { 1186 if e1 == nil && e2 == nil { 1187 return true 1188 } 1189 if e1 == nil || e2 == nil { 1190 return false 1191 } 1192 if e1.typ != e2.typ { 1193 return false 1194 } 1195 if e1.args == nil && e2.args == nil { 1196 return true 1197 } 1198 if e1.args == nil || e2.args == nil { 1199 return false 1200 } 1201 f := NewRootFrame() 1202 b, raised := IsTrue(f, mustNotRaise(Eq(f, e1.args.ToObject(), e2.args.ToObject()))) 1203 if raised != nil { 1204 panic(raised) 1205 } 1206 return b 1207 } 1208 1209 func getFuncName(f interface{}) string { 1210 s := runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name() 1211 return regexp.MustCompile(`\w+$`).FindString(s) 1212 } 1213 1214 // wrapFuncForTest creates a callable object that invokes fun, passing the 1215 // current frame as its first argument followed by caller provided args. 1216 func wrapFuncForTest(fun interface{}) *Object { 1217 return newBuiltinFunction(getFuncName(fun), func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 1218 callable, raised := WrapNative(f, reflect.ValueOf(fun)) 1219 if raised != nil { 1220 return nil, raised 1221 } 1222 argc := len(args) 1223 nativeArgs := make(Args, argc+1, argc+1) 1224 nativeArgs[0] = f.ToObject() 1225 copy(nativeArgs[1:], args) 1226 return callable.Call(f, nativeArgs, nil) 1227 }).ToObject() 1228 } 1229 1230 func mustCreateException(t *Type, msg string) *BaseException { 1231 if !t.isSubclass(BaseExceptionType) { 1232 panic(fmt.Sprintf("type does not inherit from BaseException: %s", t.Name())) 1233 } 1234 e := toBaseExceptionUnsafe(newObject(t)) 1235 if msg == "" { 1236 e.args = NewTuple() 1237 } else { 1238 e.args = NewTuple(NewStr(msg).ToObject()) 1239 } 1240 return e 1241 } 1242 1243 func mustNotRaise(o *Object, raised *BaseException) *Object { 1244 if raised != nil { 1245 panic(raised) 1246 } 1247 return o 1248 } 1249 1250 var ( 1251 compareAll = wrapFuncForTest(func(f *Frame, v, w *Object) (*Object, *BaseException) { 1252 lt, raised := LT(f, v, w) 1253 if raised != nil { 1254 return nil, raised 1255 } 1256 le, raised := LE(f, v, w) 1257 if raised != nil { 1258 return nil, raised 1259 } 1260 eq, raised := Eq(f, v, w) 1261 if raised != nil { 1262 return nil, raised 1263 } 1264 ne, raised := NE(f, v, w) 1265 if raised != nil { 1266 return nil, raised 1267 } 1268 ge, raised := GE(f, v, w) 1269 if raised != nil { 1270 return nil, raised 1271 } 1272 gt, raised := GT(f, v, w) 1273 if raised != nil { 1274 return nil, raised 1275 } 1276 return NewTuple(lt, le, eq, ne, ge, gt).ToObject(), nil 1277 }) 1278 compareAllResultLT = newTestTuple(true, true, false, true, false, false).ToObject() 1279 compareAllResultEq = newTestTuple(false, true, true, false, true, false).ToObject() 1280 compareAllResultGT = newTestTuple(false, false, false, true, true, true).ToObject() 1281 )