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