github.com/pygolin/runtime@v0.0.0-20201208210830-a62e3cd39798/type_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 "reflect" 20 "strings" 21 "testing" 22 ) 23 24 func TestNewClass(t *testing.T) { 25 type strBasisStruct struct{ Str } 26 strBasisStructFunc := func(o *Object) *strBasisStruct { return (*strBasisStruct)(o.toPointer()) } 27 fooType := newBasisType("Foo", reflect.TypeOf(strBasisStruct{}), strBasisStructFunc, StrType) 28 defer delete(basisTypes, fooType.basis) 29 fooType.setDict(NewDict()) 30 prepareType(fooType) 31 cases := []struct { 32 wantBasis reflect.Type 33 invokeTestCase 34 }{ 35 {objectBasis, invokeTestCase{args: wrapArgs([]*Type{ObjectType}), want: None}}, 36 {fooType.basis, invokeTestCase{args: wrapArgs([]*Type{fooType, StrType}), want: None}}, 37 {fooType.basis, invokeTestCase{args: wrapArgs([]*Type{fooType, StrType, ObjectType}), want: None}}, 38 {nil, invokeTestCase{args: wrapArgs([]*Type{}), wantExc: mustCreateException(TypeErrorType, "class must have base classes")}}, 39 {nil, invokeTestCase{args: wrapArgs([]*Type{BoolType, ObjectType}), wantExc: mustCreateException(TypeErrorType, "type 'bool' is not an acceptable base type")}}, 40 {nil, invokeTestCase{args: wrapArgs([]*Type{IntType, StrType}), wantExc: mustCreateException(TypeErrorType, "class layout error")}}, 41 {nil, invokeTestCase{args: wrapArgs([]*Type{StrType, fooType}), wantExc: mustCreateException(TypeErrorType, "mro error for: Foo")}}, 42 } 43 for _, cas := range cases { 44 fun := wrapFuncForTest(func(f *Frame, bases []*Type) *BaseException { 45 cls, raised := newClass(f, TypeType, "Foo", bases, NewDict()) 46 if raised != nil { 47 return raised 48 } 49 if cls.basis != cas.wantBasis { 50 t.Errorf("type('Foo', %v, {}) had basis %v, want %v", bases, cls.basis, cas.wantBasis) 51 } 52 return nil 53 }) 54 if err := runInvokeTestCase(fun, &cas.invokeTestCase); err != "" { 55 t.Error(err) 56 } 57 } 58 } 59 60 func TestNewBasisType(t *testing.T) { 61 type basisStruct struct{ Object } 62 basisStructFunc := func(o *Object) *basisStruct { return (*basisStruct)(o.toPointer()) } 63 basis := reflect.TypeOf(basisStruct{}) 64 typ := newBasisType("Foo", basis, basisStructFunc, ObjectType) 65 defer delete(basisTypes, basis) 66 if typ.Type() != TypeType { 67 t.Errorf("got %q, want a type", typ.Type().Name()) 68 } 69 if typ.Dict() != nil { 70 t.Error("type's dict was expected to be nil") 71 } 72 wantBases := []*Type{ObjectType} 73 if !reflect.DeepEqual(wantBases, typ.bases) { 74 t.Errorf("typ.bases = %v, want %v, ", typ.bases, wantBases) 75 } 76 if typ.mro != nil { 77 t.Errorf("type's mro expected to be nil, got %v", typ.mro) 78 } 79 if name := typ.Name(); name != "Foo" { 80 t.Errorf(`Foo.Name() = %q, want "Foo"`, name) 81 } 82 foo := (*basisStruct)(newObject(typ).toPointer()) 83 if typ.slots.Basis == nil { 84 t.Error("type's Basis slot is nil") 85 } else if got := typ.slots.Basis.Fn(&foo.Object); got.Type() != basis || got.Addr().Interface().(*basisStruct) != foo { 86 t.Errorf("Foo.__basis__(%v) = %v, want %v", &foo.Object, got, foo) 87 } 88 } 89 90 func TestNewSimpleType(t *testing.T) { 91 got := newSimpleType("Foo", ObjectType) 92 if got.Object.typ != TypeType { 93 t.Errorf(`newSimpleType got %q, want "type"`, got.Type().Name()) 94 } 95 if got.basis != objectBasis { 96 t.Errorf("newSimpleType result got basis %v, want %v", got.basis, objectBasis) 97 } 98 wantBases := []*Type{ObjectType} 99 if !reflect.DeepEqual(got.bases, wantBases) { 100 t.Errorf("newSimpleType got bases %v, want %v", got.bases, wantBases) 101 } 102 if name := got.Name(); name != "Foo" { 103 t.Errorf(`Foo.Name() = %q, want "Foo"`, name) 104 } 105 } 106 107 func TestInvalidBasisType(t *testing.T) { 108 type intFieldStruct struct{ int } 109 type emptyStruct struct{} 110 type objectBasisStruct struct{ Object } 111 oldLogFatal := logFatal 112 defer func() { logFatal = oldLogFatal }() 113 logFatal = func(msg string) { panic(msg) } 114 cases := []struct { 115 basis reflect.Type 116 basisFunc interface{} 117 wantMsg string 118 }{ 119 {objectBasis, objectBasisFunc, "basis already exists"}, 120 {reflect.TypeOf(int(0)), objectBasisFunc, "basis must be a struct"}, 121 {reflect.TypeOf(emptyStruct{}), objectBasisFunc, "1st field of basis must be base type's basis"}, 122 {reflect.TypeOf(intFieldStruct{}), objectBasisFunc, "1st field of basis must be base type's basis not: int"}, 123 {reflect.TypeOf(objectBasisStruct{}), objectBasisFunc, "expected basis func of type func(*Object) *objectBasisStruct"}, 124 } 125 for _, cas := range cases { 126 func() { 127 defer func() { 128 if msg, ok := recover().(string); !ok || !strings.Contains(msg, cas.wantMsg) { 129 t.Errorf("logFatal() called with %q, want error like %q", msg, cas.wantMsg) 130 } 131 }() 132 newBasisType("Foo", cas.basis, cas.basisFunc, ObjectType) 133 }() 134 } 135 } 136 137 func TestPrepareType(t *testing.T) { 138 type objectBasisStruct struct{ Object } 139 objectBasisStructFunc := func(o *Object) *objectBasisStruct { return (*objectBasisStruct)(o.toPointer()) } 140 type strBasisStruct struct{ Str } 141 strBasisStructFunc := func(o *Object) *strBasisStruct { return (*strBasisStruct)(o.toPointer()) } 142 cases := []struct { 143 basis reflect.Type 144 basisFunc interface{} 145 base *Type 146 wantMro []*Type 147 }{ 148 {reflect.TypeOf(objectBasisStruct{}), objectBasisStructFunc, ObjectType, []*Type{nil, ObjectType}}, 149 {reflect.TypeOf(strBasisStruct{}), strBasisStructFunc, StrType, []*Type{nil, StrType, BaseStringType, ObjectType}}, 150 } 151 for _, cas := range cases { 152 typ := newBasisType("Foo", cas.basis, cas.basisFunc, cas.base) 153 defer delete(basisTypes, cas.basis) 154 typ.setDict(NewDict()) 155 prepareType(typ) 156 cas.wantMro[0] = typ 157 if !reflect.DeepEqual(typ.mro, cas.wantMro) { 158 t.Errorf("typ.mro = %v, want %v", typ.mro, cas.wantMro) 159 } 160 } 161 } 162 163 func makeTestType(name string, bases ...*Type) *Type { 164 return newType(TypeType, name, nil, bases, NewDict()) 165 } 166 167 func TestMroCalc(t *testing.T) { 168 fooType := makeTestType("Foo", ObjectType) 169 barType := makeTestType("Bar", StrType, fooType) 170 bazType := makeTestType("Baz", fooType, StrType) 171 // Boo has an inconsistent hierarchy since it's not possible to order 172 // mro such that StrType is before fooType and fooType is also before 173 // StrType. 174 booType := makeTestType("Boo", barType, bazType) 175 cases := []struct { 176 typ *Type 177 wantMro []*Type 178 }{ 179 {fooType, []*Type{fooType, ObjectType}}, 180 {barType, []*Type{barType, StrType, BaseStringType, fooType, ObjectType}}, 181 {bazType, []*Type{bazType, fooType, StrType, BaseStringType, ObjectType}}, 182 {booType, nil}, 183 } 184 for _, cas := range cases { 185 cas.typ.mro = mroCalc(cas.typ) 186 if !reflect.DeepEqual(cas.wantMro, cas.typ.mro) { 187 t.Errorf("%s.mro = %v, want %v", cas.typ.Name(), cas.typ.mro, cas.wantMro) 188 } 189 } 190 } 191 192 func TestTypeIsSubclass(t *testing.T) { 193 fooType := makeTestType("Foo", ObjectType) 194 prepareType(fooType) 195 barType := makeTestType("Bar", StrType, fooType) 196 prepareType(barType) 197 cases := []struct { 198 typ *Type 199 super *Type 200 want bool 201 }{ 202 {fooType, ObjectType, true}, 203 {fooType, StrType, false}, 204 {barType, ObjectType, true}, 205 {barType, fooType, true}, 206 {barType, StrType, true}, 207 {barType, TypeType, false}, 208 } 209 for _, cas := range cases { 210 got := cas.typ.isSubclass(cas.super) 211 if got != cas.want { 212 t.Errorf("%s.isSubclass(%s) = %v, want %v", cas.typ.Name(), cas.super.Name(), got, cas.want) 213 } 214 } 215 } 216 217 func TestTypeCall(t *testing.T) { 218 fooType := makeTestType("Foo") 219 prepareType(fooType) 220 emptyExc := toBaseExceptionUnsafe(newObject(ExceptionType)) 221 emptyExc.args = NewTuple() 222 cases := []invokeTestCase{ 223 {wantExc: mustCreateException(TypeErrorType, "unbound method __call__() must be called with type instance as first argument (got nothing instead)")}, 224 {args: wrapArgs(42), wantExc: mustCreateException(TypeErrorType, "unbound method __call__() must be called with type instance as first argument (got int instance instead)")}, 225 {args: wrapArgs(fooType), wantExc: mustCreateException(TypeErrorType, "type Foo has no __new__")}, 226 {args: wrapArgs(IntType), want: NewInt(0).ToObject()}, 227 {args: wrapArgs(ExceptionType, "blah"), want: mustCreateException(ExceptionType, "blah").ToObject()}, 228 } 229 for _, cas := range cases { 230 if err := runInvokeMethodTestCase(TypeType, "__call__", &cas); err != "" { 231 t.Error(err) 232 } 233 } 234 } 235 236 func TestNewWithSubclass(t *testing.T) { 237 cases := []invokeTestCase{ 238 {args: wrapArgs(StrType, "abc"), want: None}, 239 {args: wrapArgs(IntType, 3), want: None}, 240 {args: wrapArgs(UnicodeType, "abc"), want: None}, 241 } 242 simpleRepr := newBuiltinFunction("__repr__", func(_ *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 243 return NewStr(fmt.Sprintf("%s object", args[0].typ.Name())).ToObject(), nil 244 }).ToObject() 245 constantFunc := func(name string, value *Object) *Object { 246 return newBuiltinFunction(name, func(_ *Frame, _ Args, _ KWArgs) (*Object, *BaseException) { 247 return value, nil 248 }).ToObject() 249 } 250 for _, cas := range cases { 251 fun := wrapFuncForTest(func(f *Frame, basisType *Type, o *Object) *BaseException { 252 subclassTypeName := "SubclassOf" + basisType.Name() 253 // Create a subclass of the basis type. 254 subclassType := newTestClass(subclassTypeName, []*Type{basisType}, newStringDict(map[string]*Object{ 255 "__repr__": simpleRepr, 256 })) 257 subclassObject, raised := subclassType.Call(f, Args{o}, nil) 258 if raised != nil { 259 return raised 260 } 261 slotName := "__" + basisType.Name() + "__" 262 fooType := newTestClass("FooFor"+basisType.Name(), []*Type{ObjectType}, newStringDict(map[string]*Object{ 263 slotName: constantFunc(slotName, subclassObject), 264 "__repr__": simpleRepr, 265 })) 266 foo := newObject(fooType) 267 // Test that <basistype>(subclassObject) returns an object of the basis type, not the subclass. 268 got, raised := basisType.Call(f, Args{subclassObject}, nil) 269 if raised != nil { 270 return raised 271 } 272 if got.typ != basisType { 273 t.Errorf("type(%s(%s)) = %s, want %s", basisType.Name(), subclassObject, got.typ.Name(), basisType.Name()) 274 } 275 // Test that subclass objects returned from __<typename>__ slots are left intact. 276 got, raised = basisType.Call(f, Args{foo}, nil) 277 if raised != nil { 278 return raised 279 } 280 if got.typ != subclassType { 281 t.Errorf("type(%s(%s)) = %s, want %s", basisType.Name(), foo, got.typ.Name(), basisType.Name()) 282 } 283 return nil 284 }) 285 if err := runInvokeTestCase(fun, &cas); err != "" { 286 t.Error(err) 287 } 288 } 289 } 290 291 func TestTypeGetAttribute(t *testing.T) { 292 fun := wrapFuncForTest(func(f *Frame, o *Object, name *Str) (*Object, *BaseException) { 293 return GetAttr(f, o, name, nil) 294 }) 295 // class Getter(object): 296 // def __get__(self, *args): 297 // return "got getter" 298 getterType := newTestClass("Getter", []*Type{ObjectType}, newStringDict(map[string]*Object{ 299 "__get__": newBuiltinFunction("__get__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 300 return NewStr("got getter").ToObject(), nil 301 }).ToObject(), 302 })) 303 getter := newObject(getterType) 304 // class Setter(object): 305 // def __get__(self, *args): 306 // return "got setter" 307 // def __set__(self, *args): 308 // pass 309 setterType := newTestClass("Setter", []*Type{ObjectType}, newStringDict(map[string]*Object{ 310 "__get__": newBuiltinFunction("__get__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 311 return NewStr("got setter").ToObject(), nil 312 }).ToObject(), 313 "__set__": newBuiltinFunction("__set__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 314 return None, nil 315 }).ToObject(), 316 })) 317 setter := newObject(setterType) 318 // class Foo(object): 319 // pass 320 fooType := newTestClass("Foo", []*Type{ObjectType}, newStringDict(map[string]*Object{ 321 "bar": NewInt(42).ToObject(), 322 "baz": NewStr("Foo's baz").ToObject(), 323 "foogetter": getter, 324 })) 325 // class BarMeta(type): 326 // pass 327 barMetaType := newTestClass("BarMeta", []*Type{TypeType}, newStringDict(map[string]*Object{ 328 "bar": NewStr("BarMeta's bar").ToObject(), 329 "boo": NewInt(123).ToObject(), 330 "barmetagetter": getter, 331 "barmetasetter": setter, 332 })) 333 // class Bar(Foo): 334 // __metaclass__ = BarMeta 335 // bar = Bar() 336 barType := &Type{Object: Object{typ: barMetaType}, name: "Bar", basis: fooType.basis, bases: []*Type{fooType}} 337 barType.setDict(newTestDict("bar", "Bar's bar", "foo", 101, "barsetter", setter, "barmetasetter", "NOT setter")) 338 bar := newObject(barType) 339 prepareType(barType) 340 cases := []invokeTestCase{ 341 {args: wrapArgs(fooType, "bar"), want: NewInt(42).ToObject()}, 342 {args: wrapArgs(fooType, "baz"), want: NewStr("Foo's baz").ToObject()}, 343 {args: wrapArgs(barMetaType, "barmetagetter"), want: NewStr("got getter").ToObject()}, 344 {args: wrapArgs(barType, "bar"), want: NewStr("Bar's bar").ToObject()}, 345 {args: wrapArgs(barType, "baz"), want: NewStr("Foo's baz").ToObject()}, 346 {args: wrapArgs(barType, "foo"), want: NewInt(101).ToObject()}, 347 {args: wrapArgs(barType, "barmetagetter"), want: NewStr("got getter").ToObject()}, 348 {args: wrapArgs(barType, "barmetasetter"), want: NewStr("got setter").ToObject()}, 349 {args: wrapArgs(barType, "boo"), want: NewInt(123).ToObject()}, 350 {args: wrapArgs(bar, "boo"), wantExc: mustCreateException(AttributeErrorType, "'Bar' object has no attribute 'boo'")}, 351 } 352 for _, cas := range cases { 353 if err := runInvokeTestCase(fun, &cas); err != "" { 354 t.Error(err) 355 } 356 } 357 } 358 359 func TestTypeName(t *testing.T) { 360 fooType := newTestClass("Foo", []*Type{ObjectType}, NewDict()) 361 fun := wrapFuncForTest(func(f *Frame, t *Type) (*Object, *BaseException) { 362 return GetAttr(f, t.ToObject(), internedName, nil) 363 }) 364 cas := invokeTestCase{args: wrapArgs(fooType), want: NewStr("Foo").ToObject()} 365 if err := runInvokeTestCase(fun, &cas); err != "" { 366 t.Error(err) 367 } 368 } 369 370 func TestTypeNew(t *testing.T) { 371 fooMetaType := newTestClass("FooMeta", []*Type{TypeType}, NewDict()) 372 fooType, raised := newClass(NewRootFrame(), fooMetaType, "Foo", []*Type{ObjectType}, NewDict()) 373 if raised != nil { 374 panic(raised) 375 } 376 barMetaType := newTestClass("BarMeta", []*Type{TypeType}, NewDict()) 377 barType, raised := newClass(NewRootFrame(), barMetaType, "Bar", []*Type{ObjectType}, NewDict()) 378 if raised != nil { 379 panic(raised) 380 } 381 var bazMetaType *Type 382 bazMetaType = newTestClass("BazMeta", []*Type{barMetaType}, newStringDict(map[string]*Object{ 383 // Returns true if type(lhs) == rhs. 384 "__eq__": newBuiltinFunction("__eq__", func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 385 if raised := checkMethodArgs(f, "__eq__", args, TypeType, TypeType); raised != nil { 386 return nil, raised 387 } 388 return GetBool(args[0].typ == toTypeUnsafe(args[1])).ToObject(), nil 389 }).ToObject(), 390 })) 391 bazType, raised := newClass(NewRootFrame(), bazMetaType, "Baz", []*Type{ObjectType}, NewDict()) 392 if raised != nil { 393 panic(raised) 394 } 395 cases := []invokeTestCase{ 396 {wantExc: mustCreateException(TypeErrorType, "'__new__' requires 1 arguments")}, 397 {args: wrapArgs(TypeType), wantExc: mustCreateException(TypeErrorType, "type() takes 1 or 3 arguments")}, 398 {args: wrapArgs(TypeType, "foo", newTestTuple(false), NewDict()), wantExc: mustCreateException(TypeErrorType, "not a valid base class: False")}, 399 {args: wrapArgs(TypeType, None), want: NoneType.ToObject()}, 400 {args: wrapArgs(fooMetaType, "Qux", newTestTuple(fooType, barType), NewDict()), wantExc: mustCreateException(TypeErrorType, "metaclass conflict: the metaclass of a derived class must a be a (non-strict) subclass of the metaclasses of all its bases")}, 401 // Test that the metaclass of the result is the most derived 402 // metaclass of the bases. In this case that should be 403 // bazMetaType so pass bazMetaType to be compared by the __eq__ 404 // operator defined above. 405 {args: wrapArgs(barMetaType, "Qux", newTestTuple(barType, bazType), NewDict()), want: bazMetaType.ToObject()}, 406 } 407 for _, cas := range cases { 408 if err := runInvokeMethodTestCase(TypeType, "__new__", &cas); err != "" { 409 t.Error(err) 410 } 411 } 412 } 413 414 func TestTypeNewResult(t *testing.T) { 415 fooType := makeTestType("Foo", ObjectType) 416 prepareType(fooType) 417 fun := wrapFuncForTest(func(f *Frame) *BaseException { 418 newFunc, raised := GetAttr(f, TypeType.ToObject(), NewStr("__new__"), nil) 419 if raised != nil { 420 return raised 421 } 422 ret, raised := newFunc.Call(f, wrapArgs(TypeType, "Bar", newTestTuple(fooType, StrType), NewDict()), nil) 423 if raised != nil { 424 return raised 425 } 426 if !ret.isInstance(TypeType) { 427 t.Errorf("type('Bar', (Foo, str), {}) = %v, want type instance", ret) 428 } else if typ := toTypeUnsafe(ret); typ.basis != StrType.basis { 429 t.Errorf("type('Bar', (Foo, str), {}) basis is %v, want %v", typ.basis, StrType.basis) 430 } else if wantMro := []*Type{typ, fooType, StrType, BaseStringType, ObjectType}; !reflect.DeepEqual(typ.mro, wantMro) { 431 t.Errorf("type('Bar', (Foo, str), {}).__mro__ = %v, want %v", typ.mro, wantMro) 432 } 433 return nil 434 }) 435 if err := runInvokeTestCase(fun, &invokeTestCase{want: None}); err != "" { 436 t.Error(err) 437 } 438 } 439 440 func TestTypeStrRepr(t *testing.T) { 441 fun := wrapFuncForTest(func(f *Frame, o *Object) (*Tuple, *BaseException) { 442 str, raised := ToStr(f, o) 443 if raised != nil { 444 return nil, raised 445 } 446 repr, raised := Repr(f, o) 447 if raised != nil { 448 return nil, raised 449 } 450 return newTestTuple(str, repr), nil 451 }) 452 fooType := newTestClass("Foo", []*Type{ObjectType}, newTestDict("__module__", "foo.bar")) 453 cases := []invokeTestCase{ 454 {args: wrapArgs(TypeErrorType), want: newTestTuple("<type 'TypeError'>", "<type 'TypeError'>").ToObject()}, 455 {args: wrapArgs(TupleType), want: newTestTuple("<type 'tuple'>", "<type 'tuple'>").ToObject()}, 456 {args: wrapArgs(TypeType), want: newTestTuple("<type 'type'>", "<type 'type'>").ToObject()}, 457 {args: wrapArgs(fooType), want: newTestTuple("<type 'foo.bar.Foo'>", "<type 'foo.bar.Foo'>").ToObject()}, 458 {args: wrapArgs(mustNotRaise(WrapNative(NewRootFrame(), reflect.ValueOf(t))).Type()), want: newTestTuple("<type '*T'>", "<type '*T'>").ToObject()}, 459 } 460 for _, cas := range cases { 461 if err := runInvokeTestCase(fun, &cas); err != "" { 462 t.Error(err) 463 } 464 } 465 } 466 467 func TestTypeModule(t *testing.T) { 468 fn := newBuiltinFunction("__module__", func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 469 if raised := checkFunctionArgs(f, "__module__", args, TypeType); raised != nil { 470 return nil, raised 471 } 472 mod, raised := toTypeUnsafe(args[0]).Dict().GetItemString(f, "__module__") 473 if raised != nil || mod != nil { 474 return mod, raised 475 } 476 return None, nil 477 }).ToObject() 478 fooType := newTestClass("Foo", []*Type{ObjectType}, newTestDict("__module__", "foo.bar")) 479 barType := newTestClass("Bar", []*Type{ObjectType}, NewDict()) 480 cases := []invokeTestCase{ 481 {args: wrapArgs(IntType), want: NewStr("__builtin__").ToObject()}, 482 {args: wrapArgs(mustNotRaise(WrapNative(NewRootFrame(), reflect.ValueOf(t))).Type()), want: NewStr("__builtin__").ToObject()}, 483 {args: wrapArgs(fooType), want: NewStr("foo.bar").ToObject()}, 484 {args: wrapArgs(barType), want: NewStr("__builtin__").ToObject()}, 485 } 486 for _, cas := range cases { 487 if err := runInvokeTestCase(fn, &cas); err != "" { 488 t.Error(err) 489 } 490 } 491 } 492 493 func newTestClass(name string, bases []*Type, dict *Dict) *Type { 494 t, raised := newClass(NewRootFrame(), TypeType, name, bases, dict) 495 if raised != nil { 496 panic(raised) 497 } 498 return t 499 } 500 501 // newTestClassStrictEq returns a new class that defines eq and ne operators 502 // that check whether the lhs and rhs have the same type and that the value 503 // fields are also equal. This is useful for testing that the builtin types 504 // return objects of the correct type for their __new__ method. 505 func newTestClassStrictEq(name string, base *Type) *Type { 506 var t *Type 507 t = newTestClass(name, []*Type{base}, newStringDict(map[string]*Object{ 508 "__repr__": newBuiltinFunction("__repr__", func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 509 if raised := checkMethodArgs(f, "__repr__", args, t); raised != nil { 510 return nil, raised 511 } 512 repr, raised := GetAttr(f, base.ToObject(), NewStr("__repr__"), nil) 513 if raised != nil { 514 return nil, raised 515 } 516 s, raised := repr.Call(f, Args{args[0]}, nil) 517 if raised != nil { 518 return nil, raised 519 } 520 if !s.isInstance(StrType) { 521 return nil, f.RaiseType(TypeErrorType, "__repr__ returned non-str") 522 } 523 return NewStr(fmt.Sprintf("%s(%s)", t.Name(), toStrUnsafe(s).Value())).ToObject(), nil 524 }).ToObject(), 525 "__eq__": newBuiltinFunction("__eq__", func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 526 if raised := checkMethodArgs(f, "__eq__", args, t, ObjectType); raised != nil { 527 return nil, raised 528 } 529 if args[1].typ != t { 530 return False.ToObject(), nil 531 } 532 return base.slots.Eq.Fn(f, args[0], args[1]) 533 }).ToObject(), 534 "__ne__": newBuiltinFunction("__ne__", func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 535 if raised := checkMethodArgs(f, "__ne__", args, t, ObjectType); raised != nil { 536 return nil, raised 537 } 538 o, raised := Eq(f, args[0], args[1]) 539 if raised != nil { 540 return nil, raised 541 } 542 eq, raised := IsTrue(f, o) 543 if raised != nil { 544 return nil, raised 545 } 546 return GetBool(eq).ToObject(), nil 547 }).ToObject(), 548 })) 549 return t 550 }