github.com/google/grumpy@v0.0.0-20171122020858-3ec87959189c/runtime/object_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  	"regexp"
    21  	"testing"
    22  )
    23  
    24  func TestObjectCall(t *testing.T) {
    25  	arg0 := newObject(ObjectType)
    26  	arg1 := newObject(ObjectType)
    27  	args := wrapArgs(arg0, arg1)
    28  	kwargs := wrapKWArgs("kwarg", newObject(ObjectType))
    29  	kwargsDict := kwargs.makeDict()
    30  	fn := func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
    31  		kwargsOrNone := None
    32  		if len(kwargs) > 0 {
    33  			kwargsOrNone = kwargs.makeDict().ToObject()
    34  		}
    35  		return newTestTuple(NewTuple(args.makeCopy()...), kwargsOrNone).ToObject(), nil
    36  	}
    37  	foo := newBuiltinFunction("foo", fn).ToObject()
    38  	typ := newTestClass("Foo", []*Type{ObjectType}, newStringDict(map[string]*Object{
    39  		"__call__": newBuiltinFunction("__call__", fn).ToObject(),
    40  	}))
    41  	callable := newObject(typ)
    42  	raisesFunc := newBuiltinFunction("bar", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
    43  		return nil, f.RaiseType(RuntimeErrorType, "bar")
    44  	}).ToObject()
    45  	cases := []struct {
    46  		callable *Object
    47  		invokeTestCase
    48  	}{
    49  		{foo, invokeTestCase{args: args, kwargs: kwargs, want: newTestTuple(NewTuple(args...), kwargsDict).ToObject()}},
    50  		{foo, invokeTestCase{args: args, want: newTestTuple(NewTuple(args...).ToObject(), None).ToObject()}},
    51  		{foo, invokeTestCase{kwargs: kwargs, want: newTestTuple(NewTuple(), kwargsDict).ToObject()}},
    52  		{foo, invokeTestCase{want: newTestTuple(NewTuple(), None).ToObject()}},
    53  		{foo, invokeTestCase{args: wrapArgs(arg0), want: newTestTuple(NewTuple(arg0), None).ToObject()}},
    54  		{callable, invokeTestCase{args: args, kwargs: kwargs, want: newTestTuple(NewTuple(callable, arg0, arg1), kwargsDict).ToObject()}},
    55  		{newObject(ObjectType), invokeTestCase{wantExc: mustCreateException(TypeErrorType, "'object' object is not callable")}},
    56  		{raisesFunc, invokeTestCase{wantExc: mustCreateException(RuntimeErrorType, "bar")}},
    57  	}
    58  	for _, cas := range cases {
    59  		if err := runInvokeTestCase(cas.callable, &cas.invokeTestCase); err != "" {
    60  			t.Error(err)
    61  		}
    62  	}
    63  }
    64  
    65  func TestNewObject(t *testing.T) {
    66  	cases := []*Type{DictType, ObjectType, StrType, TypeType}
    67  	for _, c := range cases {
    68  		if o := newObject(c); o.Type() != c {
    69  			t.Errorf("new object has type %q, want %q", o.Type().Name(), c.Name())
    70  		}
    71  	}
    72  }
    73  
    74  func TestObjectString(t *testing.T) {
    75  	typ := newTestClass("Foo", []*Type{ObjectType}, newStringDict(map[string]*Object{
    76  		"__repr__": newBuiltinFunction("__repr__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
    77  			return nil, f.RaiseType(ExceptionType, "ruh roh")
    78  		}).ToObject(),
    79  	}))
    80  	cases := []struct {
    81  		o           *Object
    82  		wantPattern string
    83  	}{
    84  		{newObject(ObjectType), `^<object object at \w+>$`},
    85  		{NewTuple(NewStr("foo").ToObject(), NewStr("bar").ToObject()).ToObject(), `^\('foo', 'bar'\)$`},
    86  		{ExceptionType.ToObject(), "^<type 'Exception'>$"},
    87  		{NewStr("foo\nbar").ToObject(), `^'foo\\nbar'$`},
    88  		{newObject(typ), `^<Foo object \(repr raised Exception\)>$`},
    89  	}
    90  	for _, cas := range cases {
    91  		re := regexp.MustCompile(cas.wantPattern)
    92  		s := cas.o.String()
    93  		if matched := re.MatchString(s); !matched {
    94  			t.Errorf("%v.String() = %q, doesn't match pattern %q", cas.o, s, re)
    95  		}
    96  	}
    97  }
    98  
    99  func TestObjectDelAttr(t *testing.T) {
   100  	fun := wrapFuncForTest(func(f *Frame, o *Object, name *Str) (*Object, *BaseException) {
   101  		if raised := DelAttr(f, o, name); raised != nil {
   102  			return nil, raised
   103  		}
   104  		return GetAttr(f, o, name, None)
   105  	})
   106  	dellerType := newTestClass("Deller", []*Type{ObjectType}, newStringDict(map[string]*Object{
   107  		"__get__": newBuiltinFunction("__get__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
   108  			attr, raised := args[1].Dict().GetItemString(f, "attr")
   109  			if raised != nil {
   110  				return nil, raised
   111  			}
   112  			if attr == nil {
   113  				return nil, f.RaiseType(AttributeErrorType, "attr")
   114  			}
   115  			return attr, nil
   116  		}).ToObject(),
   117  		"__delete__": newBuiltinFunction("__delete__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
   118  			deleted, raised := args[1].Dict().DelItemString(f, "attr")
   119  			if raised != nil {
   120  				return nil, raised
   121  			}
   122  			if !deleted {
   123  				return nil, f.RaiseType(AttributeErrorType, "attr")
   124  			}
   125  			return None, nil
   126  		}).ToObject(),
   127  	}))
   128  	fooType := newTestClass("Foo", []*Type{ObjectType}, newStringDict(map[string]*Object{"deller": newObject(dellerType)}))
   129  	foo := newObject(fooType)
   130  	if raised := foo.Dict().SetItemString(NewRootFrame(), "attr", NewInt(123).ToObject()); raised != nil {
   131  		t.Fatal(raised)
   132  	}
   133  	cases := []invokeTestCase{
   134  		{args: wrapArgs(foo, "deller"), want: None},
   135  		{args: wrapArgs(newObject(fooType), "foo"), wantExc: mustCreateException(AttributeErrorType, "'Foo' object has no attribute 'foo'")},
   136  		{args: wrapArgs(newObject(fooType), "deller"), wantExc: mustCreateException(AttributeErrorType, "attr")},
   137  	}
   138  	for _, cas := range cases {
   139  		if err := runInvokeTestCase(fun, &cas); err != "" {
   140  			t.Error(err)
   141  		}
   142  	}
   143  }
   144  
   145  func TestObjectGetAttribute(t *testing.T) {
   146  	fun := wrapFuncForTest(func(f *Frame, o *Object, name *Str) (*Object, *BaseException) {
   147  		return GetAttr(f, o, name, nil)
   148  	})
   149  	// class Getter(object):
   150  	//   def __get__(self, *args):
   151  	//     return "got getter"
   152  	getterType := newTestClass("Getter", []*Type{ObjectType}, newStringDict(map[string]*Object{
   153  		"__get__": newBuiltinFunction("__get__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
   154  			return NewStr("got getter").ToObject(), nil
   155  		}).ToObject(),
   156  	}))
   157  	getter := newObject(getterType)
   158  	// class Setter(object):
   159  	//   def __get__(self, *args):
   160  	//     return "got setter"
   161  	//   def __set__(self, *args):
   162  	//     pass
   163  	setterType := newTestClass("Setter", []*Type{ObjectType}, newStringDict(map[string]*Object{
   164  		"__get__": newBuiltinFunction("__get__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
   165  			return NewStr("got setter").ToObject(), nil
   166  		}).ToObject(),
   167  		"__set__": newBuiltinFunction("__set__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
   168  			return None, nil
   169  		}).ToObject(),
   170  	}))
   171  	setter := newObject(setterType)
   172  	// class Foo(object):
   173  	//   pass
   174  	// foo = Foo()
   175  	fooType := newTestClass("Foo", []*Type{ObjectType}, newStringDict(map[string]*Object{
   176  		"bar":       NewInt(42).ToObject(),
   177  		"baz":       NewStr("Foo's baz").ToObject(),
   178  		"foogetter": getter,
   179  		"foo":       NewInt(101).ToObject(),
   180  		"barsetter": setter,
   181  	}))
   182  	foo := newObject(fooType)
   183  	if raised := foo.Dict().SetItemString(NewRootFrame(), "fooattr", True.ToObject()); raised != nil {
   184  		t.Fatal(raised)
   185  	}
   186  	if raised := foo.Dict().SetItemString(NewRootFrame(), "barattr", NewInt(-1).ToObject()); raised != nil {
   187  		t.Fatal(raised)
   188  	}
   189  	if raised := foo.Dict().SetItemString(NewRootFrame(), "barsetter", NewStr("NOT setter").ToObject()); raised != nil {
   190  		t.Fatal(raised)
   191  	}
   192  	cases := []invokeTestCase{
   193  		{args: wrapArgs(foo, "bar"), want: NewInt(42).ToObject()},
   194  		{args: wrapArgs(foo, "fooattr"), want: True.ToObject()},
   195  		{args: wrapArgs(foo, "foogetter"), want: NewStr("got getter").ToObject()},
   196  		{args: wrapArgs(foo, "bar"), want: NewInt(42).ToObject()},
   197  		{args: wrapArgs(foo, "foo"), want: NewInt(101).ToObject()},
   198  		{args: wrapArgs(foo, "barattr"), want: NewInt(-1).ToObject()},
   199  		{args: wrapArgs(foo, "barsetter"), want: NewStr("got setter").ToObject()},
   200  	}
   201  	for _, cas := range cases {
   202  		if err := runInvokeTestCase(fun, &cas); err != "" {
   203  			t.Error(err)
   204  		}
   205  	}
   206  }
   207  
   208  func TestObjectGetDict(t *testing.T) {
   209  	fooType := newTestClass("Foo", []*Type{ObjectType}, NewDict())
   210  	foo := newObject(fooType)
   211  	if raised := SetAttr(NewRootFrame(), foo, NewStr("bar"), NewInt(123).ToObject()); raised != nil {
   212  		panic(raised)
   213  	}
   214  	fun := wrapFuncForTest(func(f *Frame, o *Object) (*Object, *BaseException) {
   215  		return GetAttr(f, o, NewStr("__dict__"), nil)
   216  	})
   217  	cases := []invokeTestCase{
   218  		{args: wrapArgs(newObject(ObjectType)), wantExc: mustCreateException(AttributeErrorType, "'object' object has no attribute '__dict__'")},
   219  		{args: wrapArgs(newObject(fooType)), want: NewDict().ToObject()},
   220  		{args: wrapArgs(foo), want: newStringDict(map[string]*Object{"bar": NewInt(123).ToObject()}).ToObject()},
   221  	}
   222  	for _, cas := range cases {
   223  		if err := runInvokeTestCase(fun, &cas); err != "" {
   224  			t.Error(err)
   225  		}
   226  	}
   227  }
   228  
   229  func TestObjectSetDict(t *testing.T) {
   230  	fooType := newTestClass("Foo", []*Type{ObjectType}, NewDict())
   231  	testDict := newStringDict(map[string]*Object{"bar": NewInt(123).ToObject()})
   232  	fun := wrapFuncForTest(func(f *Frame, o, val *Object) (*Object, *BaseException) {
   233  		if raised := SetAttr(f, o, NewStr("__dict__"), val); raised != nil {
   234  			return nil, raised
   235  		}
   236  		d := o.Dict()
   237  		if d == nil {
   238  			return None, nil
   239  		}
   240  		return d.ToObject(), nil
   241  	})
   242  	cases := []invokeTestCase{
   243  		{args: wrapArgs(newObject(ObjectType), NewDict()), wantExc: mustCreateException(AttributeErrorType, "'object' object has no attribute '__dict__'")},
   244  		{args: wrapArgs(newObject(fooType), testDict), want: testDict.ToObject()},
   245  		{args: wrapArgs(newObject(fooType), 123), wantExc: mustCreateException(TypeErrorType, "'_set_dict' requires a 'dict' object but received a 'int'")},
   246  	}
   247  	for _, cas := range cases {
   248  		if err := runInvokeTestCase(fun, &cas); err != "" {
   249  			t.Error(err)
   250  		}
   251  	}
   252  }
   253  
   254  func TestObjectNew(t *testing.T) {
   255  	foo := makeTestType("Foo", ObjectType)
   256  	foo.flags &= ^typeFlagInstantiable
   257  	prepareType(foo)
   258  	cases := []invokeTestCase{
   259  		{args: wrapArgs(ExceptionType), want: newObject(ExceptionType)},
   260  		{args: wrapArgs(IntType), want: NewInt(0).ToObject()},
   261  		{wantExc: mustCreateException(TypeErrorType, "'__new__' requires 1 arguments")},
   262  		{args: wrapArgs(None), wantExc: mustCreateException(TypeErrorType, `'__new__' requires a 'type' object but received a "NoneType"`)},
   263  		{args: wrapArgs(foo), wantExc: mustCreateException(TypeErrorType, "object.__new__(Foo) is not safe, use Foo.__new__()")},
   264  	}
   265  	for _, cas := range cases {
   266  		if err := runInvokeMethodTestCase(ObjectType, "__new__", &cas); err != "" {
   267  			t.Error(err)
   268  		}
   269  	}
   270  }
   271  
   272  func TestObjectReduce(t *testing.T) {
   273  	fun := wrapFuncForTest(func(f *Frame, method *Str, o *Object, args Args) (*Object, *BaseException) {
   274  		// Call __reduce/reduce_ex__.
   275  		reduce, raised := GetAttr(f, o, method, nil)
   276  		if raised != nil {
   277  			return nil, raised
   278  		}
   279  		result, raised := reduce.Call(f, args, nil)
   280  		if raised != nil {
   281  			return nil, raised
   282  		}
   283  		msg := NewStr(fmt.Sprintf("reduce must return a tuple, got %s", result.Type().Name())).ToObject()
   284  		if raised := Assert(f, GetBool(result.isInstance(TupleType)).ToObject(), msg); raised != nil {
   285  			return nil, raised
   286  		}
   287  		elems := toTupleUnsafe(result).elems
   288  		numElems := len(elems)
   289  		msg = NewStr(fmt.Sprintf("reduce must return a tuple with 2 <= len <= 5, got %d", numElems)).ToObject()
   290  		if raised := Assert(f, GetBool(numElems >= 2 && numElems <= 5).ToObject(), msg); raised != nil {
   291  			return nil, raised
   292  		}
   293  		newArgs := elems[1]
   294  		msg = NewStr(fmt.Sprintf("reduce second return value must be tuple, got %s", newArgs.Type().Name())).ToObject()
   295  		if raised := Assert(f, GetBool(newArgs.isInstance(TupleType)).ToObject(), msg); raised != nil {
   296  			return nil, raised
   297  		}
   298  		// Call the reconstructor function with the args returned.
   299  		reduced, raised := elems[0].Call(f, toTupleUnsafe(newArgs).elems, nil)
   300  		if raised != nil {
   301  			return nil, raised
   302  		}
   303  		// Return the reconstructed object, object state, list items
   304  		// and dict items.
   305  		state, list, dict := None, None, None
   306  		if numElems > 2 && elems[2] != None {
   307  			state = elems[2]
   308  		}
   309  		if numElems > 3 && elems[3] != None {
   310  			if list, raised = ListType.Call(f, Args{elems[3]}, nil); raised != nil {
   311  				return nil, raised
   312  			}
   313  		}
   314  		if numElems > 4 && elems[4] != None {
   315  			if dict, raised = DictType.Call(f, Args{elems[4]}, nil); raised != nil {
   316  				return nil, raised
   317  			}
   318  		}
   319  		return NewTuple(reduced, state, list, dict).ToObject(), nil
   320  	})
   321  	fooType := newTestClass("Foo", []*Type{StrType}, NewDict())
   322  	fooNoDict := &Str{Object: Object{typ: fooType}, value: "fooNoDict"}
   323  	// Calling __reduce_ex__ on a type that overrides __reduce__ should
   324  	// forward to the call to __reduce__.
   325  	reduceOverrideType := newTestClass("ReduceOverride", []*Type{ObjectType}, newStringDict(map[string]*Object{
   326  		"__reduce__": newBuiltinFunction("__reduce__", func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
   327  			strNew, raised := GetAttr(f, StrType.ToObject(), NewStr("__new__"), nil)
   328  			if raised != nil {
   329  				return nil, raised
   330  			}
   331  			return newTestTuple(strNew, newTestTuple(StrType, "ReduceOverride")).ToObject(), nil
   332  		}).ToObject(),
   333  	}))
   334  	getNewArgsRaisesType := newTestClass("GetNewArgsRaises", []*Type{ObjectType}, newStringDict(map[string]*Object{
   335  		"__getnewargs__": newBuiltinFunction("__getnewargs__", func(f *Frame, _ Args, _ KWArgs) (*Object, *BaseException) {
   336  			return nil, f.RaiseType(RuntimeErrorType, "uh oh")
   337  		}).ToObject(),
   338  	}))
   339  	getNewArgsReturnsNonTupleType := newTestClass("GetNewArgsReturnsNonTuple", []*Type{ObjectType}, newStringDict(map[string]*Object{
   340  		"__getnewargs__": newBuiltinFunction("__getnewargs__", func(f *Frame, _ Args, _ KWArgs) (*Object, *BaseException) {
   341  			return NewInt(123).ToObject(), nil
   342  		}).ToObject(),
   343  	}))
   344  	// Attempting to reduce an int will fail with "can't pickle" but
   345  	// subclasses can be reduced.
   346  	intSubclass := newTestClass("IntSubclass", []*Type{IntType}, NewDict())
   347  	intSubclassInst := &Int{Object{typ: intSubclass}, 123}
   348  	cases := []invokeTestCase{
   349  		{args: wrapArgs("__reduce__", 42, Args{}), wantExc: mustCreateException(TypeErrorType, "can't pickle int objects")},
   350  		{args: wrapArgs("__reduce__", 42, wrapArgs(2)), want: newTestTuple(42, None, None, None).ToObject()},
   351  		{args: wrapArgs("__reduce_ex__", 42, Args{}), wantExc: mustCreateException(TypeErrorType, "can't pickle int objects")},
   352  		{args: wrapArgs("__reduce__", 3.14, wrapArgs("bad proto")), wantExc: mustCreateException(TypeErrorType, "'__reduce__' requires a 'int' object but received a 'str'")},
   353  		{args: wrapArgs("__reduce_ex__", 3.14, wrapArgs("bad proto")), wantExc: mustCreateException(TypeErrorType, "'__reduce_ex__' requires a 'int' object but received a 'str'")},
   354  		{args: wrapArgs("__reduce__", newObject(fooType), Args{}), want: newTestTuple("", NewDict(), None, None).ToObject()},
   355  		{args: wrapArgs("__reduce__", newObject(fooType), wrapArgs(2)), want: newTestTuple("", NewDict(), None, None).ToObject()},
   356  		{args: wrapArgs("__reduce_ex__", newObject(fooType), Args{}), want: newTestTuple("", NewDict(), None, None).ToObject()},
   357  		{args: wrapArgs("__reduce_ex__", newObject(reduceOverrideType), Args{}), want: newTestTuple("ReduceOverride", None, None, None).ToObject()},
   358  		{args: wrapArgs("__reduce__", fooNoDict, Args{}), want: newTestTuple("fooNoDict", None, None, None).ToObject()},
   359  		{args: wrapArgs("__reduce__", newTestList(1, 2, 3), wrapArgs(2)), want: newTestTuple(NewList(), None, newTestList(1, 2, 3), None).ToObject()},
   360  		{args: wrapArgs("__reduce__", newTestDict("a", 1, "b", 2), wrapArgs(2)), want: newTestTuple(NewDict(), None, None, newTestDict("a", 1, "b", 2)).ToObject()},
   361  		{args: wrapArgs("__reduce__", newObject(getNewArgsRaisesType), wrapArgs(2)), wantExc: mustCreateException(RuntimeErrorType, "uh oh")},
   362  		{args: wrapArgs("__reduce__", newObject(getNewArgsReturnsNonTupleType), wrapArgs(2)), wantExc: mustCreateException(TypeErrorType, "__getnewargs__ should return a tuple, not 'int'")},
   363  		{args: wrapArgs("__reduce__", newTestTuple("foo", "bar"), wrapArgs(2)), want: newTestTuple(newTestTuple("foo", "bar"), None, None, None).ToObject()},
   364  		{args: wrapArgs("__reduce__", 3.14, wrapArgs(2)), want: newTestTuple(3.14, None, None, None).ToObject()},
   365  		{args: wrapArgs("__reduce__", NewUnicode("abc"), wrapArgs(2)), want: newTestTuple(NewUnicode("abc"), None, None, None).ToObject()},
   366  		{args: wrapArgs("__reduce__", intSubclassInst, Args{}), want: newTestTuple(intSubclassInst, None, None, None).ToObject()},
   367  	}
   368  	for _, cas := range cases {
   369  		if err := runInvokeTestCase(fun, &cas); err != "" {
   370  			t.Error(err)
   371  		}
   372  	}
   373  }
   374  
   375  func TestObjectSetAttr(t *testing.T) {
   376  	fun := wrapFuncForTest(func(f *Frame, o *Object, name *Str, value *Object) (*Object, *BaseException) {
   377  		if raised := SetAttr(f, o, name, value); raised != nil {
   378  			return nil, raised
   379  		}
   380  		return GetAttr(f, o, name, None)
   381  	})
   382  	setterType := newTestClass("Setter", []*Type{ObjectType}, newStringDict(map[string]*Object{
   383  		"__get__": newBuiltinFunction("__get__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
   384  			item, raised := args[1].Dict().GetItemString(f, "attr")
   385  			if raised != nil {
   386  				return nil, raised
   387  			}
   388  			if item == nil {
   389  				return nil, raiseKeyError(f, NewStr("attr").ToObject())
   390  			}
   391  			return item, nil
   392  		}).ToObject(),
   393  		"__set__": newBuiltinFunction("__set__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
   394  			if raised := args[1].Dict().SetItemString(f, "attr", NewTuple(args.makeCopy()...).ToObject()); raised != nil {
   395  				return nil, raised
   396  			}
   397  			return None, nil
   398  		}).ToObject(),
   399  	}))
   400  	setter := newObject(setterType)
   401  	fooType := newTestClass("Foo", []*Type{ObjectType}, newStringDict(map[string]*Object{"setter": setter}))
   402  	foo := newObject(fooType)
   403  	cases := []invokeTestCase{
   404  		{args: wrapArgs(newObject(fooType), "foo", "abc"), want: NewStr("abc").ToObject()},
   405  		{args: wrapArgs(foo, "setter", "baz"), want: NewTuple(setter, foo, NewStr("baz").ToObject()).ToObject()},
   406  		{args: wrapArgs(newObject(ObjectType), "foo", 10), wantExc: mustCreateException(AttributeErrorType, "'object' has no attribute 'foo'")},
   407  	}
   408  	for _, cas := range cases {
   409  		if err := runInvokeTestCase(fun, &cas); err != "" {
   410  			t.Error(err)
   411  		}
   412  	}
   413  }
   414  
   415  func TestObjectStrRepr(t *testing.T) {
   416  	fun := wrapFuncForTest(func(f *Frame, o *Object, wantPattern string) *BaseException {
   417  		re := regexp.MustCompile(wantPattern)
   418  		s, raised := ToStr(f, o)
   419  		if raised != nil {
   420  			return raised
   421  		}
   422  		if !re.MatchString(s.Value()) {
   423  			t.Errorf("str(%v) = %v, want %q", o, s, re)
   424  		}
   425  		s, raised = Repr(f, o)
   426  		if raised != nil {
   427  			return raised
   428  		}
   429  		if !re.MatchString(s.Value()) {
   430  			t.Errorf("repr(%v) = %v, want %q", o, s, re)
   431  		}
   432  		return nil
   433  	})
   434  	type noReprMethodBasis struct{ Object }
   435  	noReprMethodType := newType(TypeType, "noReprMethod", reflect.TypeOf(noReprMethodBasis{}), []*Type{}, NewDict())
   436  	noReprMethodType.mro = []*Type{noReprMethodType}
   437  	fooType := newTestClass("Foo", []*Type{ObjectType}, newTestDict("__module__", "foo.bar"))
   438  	cases := []invokeTestCase{
   439  		{args: wrapArgs(newObject(ObjectType), `^<object object at \w+>$`), want: None},
   440  		{args: wrapArgs(newObject(noReprMethodType), `^<noReprMethod object at \w+>$`), want: None},
   441  		{args: wrapArgs(newObject(fooType), `<foo\.bar\.Foo object at \w+>`), want: None},
   442  	}
   443  	for _, cas := range cases {
   444  		if err := runInvokeTestCase(fun, &cas); err != "" {
   445  			t.Error(err)
   446  		}
   447  	}
   448  }