github.com/google/grumpy@v0.0.0-20171122020858-3ec87959189c/runtime/dict_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  	"reflect"
    19  	"regexp"
    20  	"runtime"
    21  	"sync"
    22  	"testing"
    23  	"time"
    24  )
    25  
    26  // hashFoo is the hash of the string 'foo'. We use this to validate some corner
    27  // cases around hash collision below.
    28  // NOTE: Inline func helps support 32bit systems.
    29  var hashFoo = NewInt(func(i int64) int { return int(i) }(-4177197833195190597)).ToObject()
    30  
    31  func TestNewStringDict(t *testing.T) {
    32  	cases := []struct {
    33  		m    map[string]*Object
    34  		want *Dict
    35  	}{
    36  		{nil, NewDict()},
    37  		{map[string]*Object{"baz": NewFloat(3.14).ToObject()}, newTestDict("baz", 3.14)},
    38  		{map[string]*Object{"foo": NewInt(2).ToObject(), "bar": NewInt(4).ToObject()}, newTestDict("bar", 4, "foo", 2)},
    39  	}
    40  	for _, cas := range cases {
    41  		fun := newBuiltinFunction("newStringDict", func(*Frame, Args, KWArgs) (*Object, *BaseException) {
    42  			return newStringDict(cas.m).ToObject(), nil
    43  		}).ToObject()
    44  		if err := runInvokeTestCase(fun, &invokeTestCase{want: cas.want.ToObject()}); err != "" {
    45  			t.Error(err)
    46  		}
    47  	}
    48  }
    49  
    50  func TestDictClear(t *testing.T) {
    51  	clear := mustNotRaise(GetAttr(NewRootFrame(), DictType.ToObject(), NewStr("clear"), nil))
    52  	fun := newBuiltinFunction("TestDictClear", func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
    53  		if _, raised := clear.Call(f, args, nil); raised != nil {
    54  			return nil, raised
    55  		}
    56  		return args[0], nil
    57  	}).ToObject()
    58  	cases := []invokeTestCase{
    59  		{args: wrapArgs(NewDict()), want: NewDict().ToObject()},
    60  		{args: wrapArgs(newStringDict(map[string]*Object{"foo": NewInt(1).ToObject()})), want: NewDict().ToObject()},
    61  		{args: wrapArgs(newTestDict(2, None, "baz", 3.14)), want: NewDict().ToObject()},
    62  		{args: wrapArgs(NewDict(), NewList()), wantExc: mustCreateException(TypeErrorType, "'clear' of 'dict' requires 1 arguments")},
    63  		{args: wrapArgs(NewDict(), None), wantExc: mustCreateException(TypeErrorType, "'clear' of 'dict' requires 1 arguments")},
    64  		{args: wrapArgs(None), wantExc: mustCreateException(TypeErrorType, "unbound method clear() must be called with dict instance as first argument (got NoneType instance instead)")},
    65  	}
    66  	for _, cas := range cases {
    67  		if err := runInvokeTestCase(fun, &cas); err != "" {
    68  			t.Error(err)
    69  		}
    70  	}
    71  }
    72  
    73  func TestDictContains(t *testing.T) {
    74  	cases := []invokeTestCase{
    75  		{args: wrapArgs(NewDict(), "foo"), want: False.ToObject()},
    76  		{args: wrapArgs(newTestDict("foo", 1, "bar", 2), "foo"), want: True.ToObject()},
    77  		{args: wrapArgs(newTestDict(3, "foo", "bar", 42), 42), want: False.ToObject()},
    78  	}
    79  	for _, cas := range cases {
    80  		if err := runInvokeMethodTestCase(DictType, "__contains__", &cas); err != "" {
    81  			t.Error(err)
    82  		}
    83  	}
    84  }
    85  
    86  func TestDictDelItem(t *testing.T) {
    87  	fun := newBuiltinFunction("TestDictDelItem", func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
    88  		if raised := checkMethodArgs(f, "TestDictDelItem", args, DictType, ObjectType); raised != nil {
    89  			return nil, raised
    90  		}
    91  		if raised := DelItem(f, args[0], args[1]); raised != nil {
    92  			return nil, raised
    93  		}
    94  		return args[0], nil
    95  	}).ToObject()
    96  	testDict := newTestDict("a", 1, "b", 2, "c", 3)
    97  	cases := []invokeTestCase{
    98  		{args: wrapArgs(newTestDict("foo", 1), "foo"), want: NewDict().ToObject()},
    99  		{args: wrapArgs(NewDict(), 10), wantExc: mustCreateException(KeyErrorType, "10")},
   100  		{args: wrapArgs(testDict, "a"), want: newTestDict("b", 2, "c", 3).ToObject()},
   101  		{args: wrapArgs(testDict, "c"), want: newTestDict("b", 2).ToObject()},
   102  		{args: wrapArgs(testDict, "a"), wantExc: mustCreateException(KeyErrorType, "a")},
   103  		{args: wrapArgs(NewDict(), NewList()), wantExc: mustCreateException(TypeErrorType, "unhashable type: 'list'")},
   104  	}
   105  	for _, cas := range cases {
   106  		if err := runInvokeTestCase(fun, &cas); err != "" {
   107  			t.Error(err)
   108  		}
   109  	}
   110  }
   111  
   112  func TestDictDelItemString(t *testing.T) {
   113  	fun := newBuiltinFunction("TestDictDelItemString", func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
   114  		if raised := checkMethodArgs(f, "TestDictDelItemString", args, DictType, StrType); raised != nil {
   115  			return nil, raised
   116  		}
   117  		deleted, raised := toDictUnsafe(args[0]).DelItemString(f, toStrUnsafe(args[1]).Value())
   118  		if raised != nil {
   119  			return nil, raised
   120  		}
   121  		return newTestTuple(deleted, args[0]).ToObject(), nil
   122  	}).ToObject()
   123  	cases := []invokeTestCase{
   124  		{args: wrapArgs(newTestDict("foo", 1), "foo"), want: newTestTuple(true, NewDict()).ToObject()},
   125  		{args: wrapArgs(NewDict(), "qux"), want: newTestTuple(false, NewDict()).ToObject()},
   126  	}
   127  	for _, cas := range cases {
   128  		if err := runInvokeTestCase(fun, &cas); err != "" {
   129  			t.Error(err)
   130  		}
   131  	}
   132  }
   133  
   134  func TestDictEqNE(t *testing.T) {
   135  	fun := wrapFuncForTest(func(f *Frame, v, w *Object) (*Object, *BaseException) {
   136  		eq, raised := Eq(f, v, w)
   137  		if raised != nil {
   138  			return nil, raised
   139  		}
   140  		ne, raised := NE(f, v, w)
   141  		if raised != nil {
   142  			return nil, raised
   143  		}
   144  		valid := GetBool(eq == True.ToObject() && ne == False.ToObject() || eq == False.ToObject() && ne == True.ToObject()).ToObject()
   145  		if raised := Assert(f, valid, NewStr("invalid values for __eq__ or __ne__").ToObject()); raised != nil {
   146  			return nil, raised
   147  		}
   148  		return eq, nil
   149  	})
   150  	f := NewRootFrame()
   151  	large1, large2 := NewDict(), NewDict()
   152  	largeSize := 100
   153  	for i := 0; i < largeSize; i++ {
   154  		s, raised := ToStr(f, NewInt(i).ToObject())
   155  		if raised != nil {
   156  			t.Fatal(raised)
   157  		}
   158  		large1.SetItem(f, NewInt(i).ToObject(), s.ToObject())
   159  		s, raised = ToStr(f, NewInt(largeSize-i-1).ToObject())
   160  		if raised != nil {
   161  			t.Fatal(raised)
   162  		}
   163  		large2.SetItem(f, NewInt(largeSize-i-1).ToObject(), s.ToObject())
   164  	}
   165  	o := newObject(ObjectType)
   166  	cases := []invokeTestCase{
   167  		{args: wrapArgs(NewDict(), NewDict()), want: True.ToObject()},
   168  		{args: wrapArgs(NewDict(), newTestDict("foo", true)), want: False.ToObject()},
   169  		{args: wrapArgs(newTestDict("foo", "foo"), newTestDict("foo", "foo")), want: True.ToObject()},
   170  		{args: wrapArgs(newTestDict("foo", true), newTestDict("bar", true)), want: False.ToObject()},
   171  		{args: wrapArgs(newTestDict("foo", true), newTestDict("foo", newObject(ObjectType))), want: False.ToObject()},
   172  		{args: wrapArgs(newTestDict("foo", true, "bar", false), newTestDict("bar", true)), want: False.ToObject()},
   173  		{args: wrapArgs(newTestDict("foo", o, "bar", o), newTestDict("foo", o, "bar", o)), want: True.ToObject()},
   174  		{args: wrapArgs(newTestDict(2, None, "foo", o), newTestDict("foo", o, 2, None)), want: True.ToObject()},
   175  		{args: wrapArgs(large1, large2), want: True.ToObject()},
   176  		{args: wrapArgs(NewDict(), 123), want: False.ToObject()},
   177  	}
   178  	for _, cas := range cases {
   179  		if err := runInvokeTestCase(fun, &cas); err != "" {
   180  			t.Error(err)
   181  		}
   182  	}
   183  }
   184  
   185  func TestDictGet(t *testing.T) {
   186  	cases := []invokeTestCase{
   187  		{args: wrapArgs(NewDict(), "foo"), want: None},
   188  		{args: wrapArgs(newTestDict("foo", 1, "bar", 2), "foo"), want: NewInt(1).ToObject()},
   189  		{args: wrapArgs(newTestDict(3, "foo", "bar", 42), 42, "nope"), want: NewStr("nope").ToObject()},
   190  	}
   191  	for _, cas := range cases {
   192  		if err := runInvokeMethodTestCase(DictType, "get", &cas); err != "" {
   193  			t.Error(err)
   194  		}
   195  	}
   196  }
   197  
   198  func TestDictGetItem(t *testing.T) {
   199  	getItem := newBuiltinFunction("TestDictGetItem", func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
   200  		if raised := checkFunctionArgs(f, "TestDictGetItem", args, DictType, ObjectType); raised != nil {
   201  			return nil, raised
   202  		}
   203  		result, raised := toDictUnsafe(args[0]).GetItem(f, args[1])
   204  		if raised == nil && result == nil {
   205  			result = None
   206  		}
   207  		return result, raised
   208  	}).ToObject()
   209  	f := NewRootFrame()
   210  	h, raised := Hash(f, NewStr("foo").ToObject())
   211  	if raised != nil {
   212  		t.Fatal(raised)
   213  	}
   214  	if b, raised := IsTrue(f, mustNotRaise(NE(f, h.ToObject(), hashFoo))); raised != nil {
   215  		t.Fatal(raised)
   216  	} else if b {
   217  		t.Fatalf("hash('foo') = %v, want %v", h, hashFoo)
   218  	}
   219  	deletedItemDict := newTestDict(hashFoo, true, "foo", true)
   220  	deletedItemDict.DelItem(f, hashFoo)
   221  	cases := []invokeTestCase{
   222  		{args: wrapArgs(NewDict(), "foo"), want: None},
   223  		{args: wrapArgs(newStringDict(map[string]*Object{"foo": True.ToObject()}), "foo"), want: True.ToObject()},
   224  		{args: wrapArgs(newTestDict(2, "bar", "baz", 3.14), 2), want: NewStr("bar").ToObject()},
   225  		{args: wrapArgs(newTestDict(2, "bar", "baz", 3.14), 3), want: None},
   226  		{args: wrapArgs(deletedItemDict, hashFoo), want: None},
   227  		{args: wrapArgs(NewDict(), NewList()), wantExc: mustCreateException(TypeErrorType, "unhashable type: 'list'")},
   228  	}
   229  	for _, cas := range cases {
   230  		if err := runInvokeTestCase(getItem, &cas); err != "" {
   231  			t.Error(err)
   232  		}
   233  	}
   234  }
   235  
   236  // BenchmarkDictGetItem is to keep an eye on the speed of contended dict access
   237  // in a fast read loop.
   238  func BenchmarkDictGetItem(b *testing.B) {
   239  	d := newTestDict(
   240  		"foo", 1,
   241  		"bar", 2,
   242  		None, 3,
   243  		4, 5)
   244  	k := NewInt(4).ToObject()
   245  
   246  	b.ResetTimer()
   247  	b.RunParallel(func(pb *testing.PB) {
   248  		f := NewRootFrame()
   249  		var ret *Object
   250  		var raised *BaseException
   251  		for pb.Next() {
   252  			ret, raised = d.GetItem(f, k)
   253  		}
   254  		runtime.KeepAlive(ret)
   255  		runtime.KeepAlive(raised)
   256  	})
   257  }
   258  
   259  func BenchmarkDictIterItems(b *testing.B) {
   260  	bench := func(d *Dict) func(*testing.B) {
   261  		return func(b *testing.B) {
   262  			f := NewRootFrame()
   263  			args := f.MakeArgs(1)
   264  			args[0] = d.ToObject()
   265  			b.ResetTimer()
   266  
   267  			var ret *Object
   268  			var raised *BaseException
   269  			for i := 0; i < b.N; i++ {
   270  				iter, _ := dictIterItems(f, args, nil)
   271  				for {
   272  					ret, raised = Next(f, iter)
   273  					if raised != nil {
   274  						if !raised.isInstance(StopIterationType) {
   275  							b.Fatalf("iteration failed with: %v", raised)
   276  						}
   277  						f.RestoreExc(nil, nil)
   278  						break
   279  					}
   280  				}
   281  			}
   282  			runtime.KeepAlive(ret)
   283  			runtime.KeepAlive(raised)
   284  		}
   285  	}
   286  
   287  	b.Run("0-elements", bench(newTestDict()))
   288  	b.Run("1-elements", bench(newTestDict(1, 2)))
   289  	b.Run("2-elements", bench(newTestDict(1, 2, 3, 4)))
   290  	b.Run("3-elements", bench(newTestDict(1, 2, 3, 4, 5, 6)))
   291  	b.Run("4-elements", bench(newTestDict(1, 2, 3, 4, 5, 6, 7, 8)))
   292  	b.Run("5-elements", bench(newTestDict(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)))
   293  	b.Run("6-elements", bench(newTestDict(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)))
   294  	b.Run("7-elements", bench(newTestDict(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)))
   295  	b.Run("8-elements", bench(newTestDict(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)))
   296  }
   297  
   298  func BenchmarkDictIterKeys(b *testing.B) {
   299  	bench := func(d *Dict) func(*testing.B) {
   300  		return func(b *testing.B) {
   301  			f := NewRootFrame()
   302  			args := f.MakeArgs(1)
   303  			args[0] = d.ToObject()
   304  			b.ResetTimer()
   305  
   306  			var ret *Object
   307  			var raised *BaseException
   308  			for i := 0; i < b.N; i++ {
   309  				iter, _ := dictIterKeys(f, args, nil)
   310  				for {
   311  					ret, raised = Next(f, iter)
   312  					if raised != nil {
   313  						if !raised.isInstance(StopIterationType) {
   314  							b.Fatalf("iteration failed with: %v", raised)
   315  						}
   316  						f.RestoreExc(nil, nil)
   317  						break
   318  					}
   319  				}
   320  			}
   321  			runtime.KeepAlive(ret)
   322  			runtime.KeepAlive(raised)
   323  		}
   324  	}
   325  
   326  	b.Run("0-elements", bench(newTestDict()))
   327  	b.Run("1-elements", bench(newTestDict(1, 2)))
   328  	b.Run("2-elements", bench(newTestDict(1, 2, 3, 4)))
   329  	b.Run("3-elements", bench(newTestDict(1, 2, 3, 4, 5, 6)))
   330  	b.Run("4-elements", bench(newTestDict(1, 2, 3, 4, 5, 6, 7, 8)))
   331  	b.Run("5-elements", bench(newTestDict(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)))
   332  	b.Run("6-elements", bench(newTestDict(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)))
   333  	b.Run("7-elements", bench(newTestDict(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)))
   334  	b.Run("8-elements", bench(newTestDict(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)))
   335  }
   336  
   337  func BenchmarkDictIterValues(b *testing.B) {
   338  	bench := func(d *Dict) func(*testing.B) {
   339  		return func(b *testing.B) {
   340  			f := NewRootFrame()
   341  			args := f.MakeArgs(1)
   342  			args[0] = d.ToObject()
   343  			b.ResetTimer()
   344  
   345  			var ret *Object
   346  			var raised *BaseException
   347  			for i := 0; i < b.N; i++ {
   348  				iter, _ := dictIterValues(f, args, nil)
   349  				for {
   350  					ret, raised = Next(f, iter)
   351  					if raised != nil {
   352  						if !raised.isInstance(StopIterationType) {
   353  							b.Fatalf("iteration failed with: %v", raised)
   354  						}
   355  						f.RestoreExc(nil, nil)
   356  						break
   357  					}
   358  				}
   359  			}
   360  			runtime.KeepAlive(ret)
   361  			runtime.KeepAlive(raised)
   362  		}
   363  	}
   364  
   365  	b.Run("0-elements", bench(newTestDict()))
   366  	b.Run("1-elements", bench(newTestDict(1, 2)))
   367  	b.Run("2-elements", bench(newTestDict(1, 2, 3, 4)))
   368  	b.Run("3-elements", bench(newTestDict(1, 2, 3, 4, 5, 6)))
   369  	b.Run("4-elements", bench(newTestDict(1, 2, 3, 4, 5, 6, 7, 8)))
   370  	b.Run("5-elements", bench(newTestDict(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)))
   371  	b.Run("6-elements", bench(newTestDict(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)))
   372  	b.Run("7-elements", bench(newTestDict(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)))
   373  	b.Run("8-elements", bench(newTestDict(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)))
   374  }
   375  
   376  func TestDictGetItemString(t *testing.T) {
   377  	getItemString := newBuiltinFunction("TestDictGetItemString", func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
   378  		if raised := checkFunctionArgs(f, "TestDictGetItem", args, DictType, StrType); raised != nil {
   379  			return nil, raised
   380  		}
   381  		result, raised := toDictUnsafe(args[0]).GetItemString(f, toStrUnsafe(args[1]).Value())
   382  		if raised == nil && result == nil {
   383  			result = None
   384  		}
   385  		return result, raised
   386  	}).ToObject()
   387  	cases := []invokeTestCase{
   388  		{args: wrapArgs(NewDict(), "foo"), want: None},
   389  		{args: wrapArgs(newTestDict("foo", true), "foo"), want: True.ToObject()},
   390  		{args: wrapArgs(newTestDict(2, "bar", "baz", 3.14), "baz"), want: NewFloat(3.14).ToObject()},
   391  		{args: wrapArgs(newTestDict(2, "bar", "baz", 3.14), "qux"), want: None},
   392  	}
   393  	for _, cas := range cases {
   394  		if err := runInvokeTestCase(getItemString, &cas); err != "" {
   395  			t.Error(err)
   396  		}
   397  	}
   398  }
   399  
   400  func TestDictHasKey(t *testing.T) {
   401  	cases := []invokeTestCase{
   402  		{args: wrapArgs(NewDict(), "foo"), want: False.ToObject()},
   403  		{args: wrapArgs(newTestDict("foo", 1, "bar", 2), "foo"), want: True.ToObject()},
   404  		{args: wrapArgs(newTestDict(3, "foo", "bar", 42), 42), want: False.ToObject()},
   405  	}
   406  	for _, cas := range cases {
   407  		if err := runInvokeMethodTestCase(DictType, "has_key", &cas); err != "" {
   408  			t.Error(err)
   409  		}
   410  	}
   411  }
   412  
   413  func TestDictItemIteratorIter(t *testing.T) {
   414  	iter := &newDictItemIterator(NewDict()).Object
   415  	cas := &invokeTestCase{args: wrapArgs(iter), want: iter}
   416  	if err := runInvokeMethodTestCase(dictItemIteratorType, "__iter__", cas); err != "" {
   417  		t.Error(err)
   418  	}
   419  }
   420  
   421  func TestDictItemIterModified(t *testing.T) {
   422  	f := NewRootFrame()
   423  	iterItems := mustNotRaise(GetAttr(f, DictType.ToObject(), NewStr("iteritems"), nil))
   424  	d := NewDict()
   425  	iter := mustNotRaise(iterItems.Call(f, wrapArgs(d), nil))
   426  	if raised := d.SetItemString(f, "foo", None); raised != nil {
   427  		t.Fatal(raised)
   428  	}
   429  	cas := invokeTestCase{
   430  		args:    wrapArgs(iter),
   431  		wantExc: mustCreateException(RuntimeErrorType, "dictionary changed during iteration"),
   432  	}
   433  	if err := runInvokeMethodTestCase(dictItemIteratorType, "next", &cas); err != "" {
   434  		t.Error(err)
   435  	}
   436  }
   437  
   438  func TestDictIter(t *testing.T) {
   439  	iter := newBuiltinFunction("TestDictIter", func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
   440  		if raised := checkFunctionArgs(f, "TestDictIter", args, DictType); raised != nil {
   441  			return nil, raised
   442  		}
   443  		iter, raised := Iter(f, args[0])
   444  		if raised != nil {
   445  			return nil, raised
   446  		}
   447  		return TupleType.Call(f, []*Object{iter}, nil)
   448  	}).ToObject()
   449  	f := NewRootFrame()
   450  	deletedItemDict := newTestDict(hashFoo, None, "foo", None)
   451  	deletedItemDict.DelItem(f, hashFoo)
   452  	cases := []invokeTestCase{
   453  		{args: wrapArgs(NewDict()), want: NewTuple().ToObject()},
   454  		{args: wrapArgs(newStringDict(map[string]*Object{"foo": NewInt(1).ToObject(), "bar": NewInt(2).ToObject()})), want: newTestTuple("foo", "bar").ToObject()},
   455  		{args: wrapArgs(newTestDict(123, True, "foo", False)), want: newTestTuple(123, "foo").ToObject()},
   456  		{args: wrapArgs(deletedItemDict), want: newTestTuple("foo").ToObject()},
   457  	}
   458  	for _, cas := range cases {
   459  		if err := runInvokeTestCase(iter, &cas); err != "" {
   460  			t.Error(err)
   461  		}
   462  	}
   463  }
   464  
   465  func TestDictIterKeys(t *testing.T) {
   466  	iterkeys := mustNotRaise(GetAttr(NewRootFrame(), DictType.ToObject(), NewStr("iterkeys"), nil))
   467  	fun := wrapFuncForTest(func(f *Frame, args ...*Object) (*Object, *BaseException) {
   468  		iter, raised := iterkeys.Call(f, args, nil)
   469  		if raised != nil {
   470  			return nil, raised
   471  		}
   472  		return TupleType.Call(f, Args{iter}, nil)
   473  	})
   474  	cases := []invokeTestCase{
   475  		{args: wrapArgs(NewDict()), want: NewTuple().ToObject()},
   476  		{args: wrapArgs(newTestDict("foo", 1, "bar", 2)), want: newTestTuple("foo", "bar").ToObject()},
   477  		{args: wrapArgs(NewDict(), "bad"), wantExc: mustCreateException(TypeErrorType, "'iterkeys' of 'dict' requires 1 arguments")},
   478  	}
   479  	for _, cas := range cases {
   480  		if err := runInvokeTestCase(fun, &cas); err != "" {
   481  			t.Error(err)
   482  		}
   483  	}
   484  }
   485  
   486  func TestDictIterValues(t *testing.T) {
   487  	itervalues := mustNotRaise(GetAttr(NewRootFrame(), DictType.ToObject(), NewStr("itervalues"), nil))
   488  	fun := wrapFuncForTest(func(f *Frame, args ...*Object) (*Object, *BaseException) {
   489  		iter, raised := itervalues.Call(f, args, nil)
   490  		if raised != nil {
   491  			return nil, raised
   492  		}
   493  		return TupleType.Call(f, Args{iter}, nil)
   494  	})
   495  	cases := []invokeTestCase{
   496  		{args: wrapArgs(NewDict()), want: NewTuple().ToObject()},
   497  		{args: wrapArgs(newTestDict("foo", 1, "bar", 2)), want: newTestTuple(1, 2).ToObject()},
   498  		{args: wrapArgs(NewDict(), "bad"), wantExc: mustCreateException(TypeErrorType, "'itervalues' of 'dict' requires 1 arguments")},
   499  	}
   500  	for _, cas := range cases {
   501  		if err := runInvokeTestCase(fun, &cas); err != "" {
   502  			t.Error(err)
   503  		}
   504  	}
   505  }
   506  
   507  // Tests dict.items and dict.iteritems.
   508  func TestDictItems(t *testing.T) {
   509  	f := NewRootFrame()
   510  	iterItems := mustNotRaise(GetAttr(f, DictType.ToObject(), NewStr("iteritems"), nil))
   511  	items := newBuiltinFunction("TestDictIterItems", func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
   512  		if raised := checkFunctionArgs(f, "TestDictIterItems", args, DictType); raised != nil {
   513  			return nil, raised
   514  		}
   515  		iter, raised := iterItems.Call(f, []*Object{args[0]}, nil)
   516  		if raised != nil {
   517  			return nil, raised
   518  		}
   519  		return ListType.Call(f, []*Object{iter}, nil)
   520  	}).ToObject()
   521  	deletedItemDict := newTestDict(hashFoo, None, "foo", None)
   522  	deletedItemDict.DelItem(f, hashFoo)
   523  	cases := []invokeTestCase{
   524  		{args: wrapArgs(NewDict()), want: NewList().ToObject()},
   525  		{args: wrapArgs(newStringDict(map[string]*Object{"foo": NewInt(1).ToObject(), "bar": NewInt(2).ToObject()})), want: newTestList(newTestTuple("foo", 1), newTestTuple("bar", 2)).ToObject()},
   526  		{args: wrapArgs(newTestDict(123, True, "foo", False)), want: newTestList(newTestTuple(123, true), newTestTuple("foo", false)).ToObject()},
   527  		{args: wrapArgs(deletedItemDict), want: newTestList(newTestTuple("foo", None)).ToObject()},
   528  	}
   529  	for _, cas := range cases {
   530  		if err := runInvokeTestCase(items, &cas); err != "" {
   531  			t.Error(err)
   532  		}
   533  		if err := runInvokeMethodTestCase(DictType, "items", &cas); err != "" {
   534  			t.Error(err)
   535  		}
   536  	}
   537  }
   538  
   539  func TestDictKeyIteratorIter(t *testing.T) {
   540  	iter := &newDictKeyIterator(NewDict()).Object
   541  	cas := &invokeTestCase{args: wrapArgs(iter), want: iter}
   542  	if err := runInvokeMethodTestCase(dictKeyIteratorType, "__iter__", cas); err != "" {
   543  		t.Error(err)
   544  	}
   545  }
   546  
   547  func TestDictKeyIterModified(t *testing.T) {
   548  	f := NewRootFrame()
   549  	d := NewDict()
   550  	iter := mustNotRaise(Iter(f, d.ToObject()))
   551  	if raised := d.SetItemString(f, "foo", None); raised != nil {
   552  		t.Fatal(raised)
   553  	}
   554  	cas := invokeTestCase{
   555  		args:    wrapArgs(iter),
   556  		wantExc: mustCreateException(RuntimeErrorType, "dictionary changed during iteration"),
   557  	}
   558  	if err := runInvokeMethodTestCase(dictKeyIteratorType, "next", &cas); err != "" {
   559  		t.Error(err)
   560  	}
   561  }
   562  
   563  func TestDictKeys(t *testing.T) {
   564  	cases := []invokeTestCase{
   565  		{args: wrapArgs(NewDict()), want: NewList().ToObject()},
   566  		{args: wrapArgs(newTestDict("foo", None, 42, None)), want: newTestList(42, "foo").ToObject()},
   567  	}
   568  	for _, cas := range cases {
   569  		if err := runInvokeMethodTestCase(DictType, "keys", &cas); err != "" {
   570  			t.Error(err)
   571  		}
   572  	}
   573  }
   574  
   575  func TestDictPop(t *testing.T) {
   576  	cases := []invokeTestCase{
   577  		{args: wrapArgs(newTestDict("foo", 42), "foo"), want: NewInt(42).ToObject()},
   578  		{args: wrapArgs(NewDict(), "foo", 42), want: NewInt(42).ToObject()},
   579  		{args: wrapArgs(NewDict(), "foo"), wantExc: mustCreateException(KeyErrorType, "foo")},
   580  	}
   581  	for _, cas := range cases {
   582  		if err := runInvokeMethodTestCase(DictType, "pop", &cas); err != "" {
   583  			t.Error(err)
   584  		}
   585  	}
   586  }
   587  
   588  func TestDictPopItem(t *testing.T) {
   589  	popItem := mustNotRaise(GetAttr(NewRootFrame(), DictType.ToObject(), NewStr("popitem"), nil))
   590  	fun := wrapFuncForTest(func(f *Frame, d *Dict) (*Object, *BaseException) {
   591  		result := NewDict()
   592  		item, raised := popItem.Call(f, wrapArgs(d), nil)
   593  		for ; raised == nil; item, raised = popItem.Call(f, wrapArgs(d), nil) {
   594  			t := toTupleUnsafe(item)
   595  			result.SetItem(f, t.GetItem(0), t.GetItem(1))
   596  		}
   597  		if raised != nil {
   598  			if !raised.isInstance(KeyErrorType) {
   599  				return nil, raised
   600  			}
   601  			f.RestoreExc(nil, nil)
   602  		}
   603  		if raised = Assert(f, GetBool(d.Len() == 0).ToObject(), nil); raised != nil {
   604  			return nil, raised
   605  		}
   606  		return result.ToObject(), nil
   607  	})
   608  	cases := []invokeTestCase{
   609  		{args: wrapArgs(newTestDict("foo", 42)), want: newTestDict("foo", 42).ToObject()},
   610  		{args: wrapArgs(newTestDict("foo", 42, 123, "bar")), want: newTestDict("foo", 42, 123, "bar").ToObject()},
   611  	}
   612  	for _, cas := range cases {
   613  		if err := runInvokeTestCase(fun, &cas); err != "" {
   614  			t.Error(err)
   615  		}
   616  	}
   617  }
   618  
   619  func TestDictNewInit(t *testing.T) {
   620  	cases := []invokeTestCase{
   621  		{args: wrapArgs(), want: NewDict().ToObject()},
   622  		{args: wrapArgs(newTestDict("foo", 42)), want: newTestDict("foo", 42).ToObject()},
   623  		{args: wrapArgs(), kwargs: wrapKWArgs("foo", 42), want: newTestDict("foo", 42).ToObject()},
   624  		{args: wrapArgs(newTestDict("foo", 42)), kwargs: wrapKWArgs("foo", "bar"), want: newTestDict("foo", "bar").ToObject()},
   625  		{args: wrapArgs(newTestList(newTestTuple("baz", 42))), kwargs: wrapKWArgs("foo", "bar"), want: newTestDict("baz", 42, "foo", "bar").ToObject()},
   626  		{args: wrapArgs(True), wantExc: mustCreateException(TypeErrorType, "'bool' object is not iterable")},
   627  		{args: wrapArgs(NewList(), "foo"), wantExc: mustCreateException(TypeErrorType, "'__init__' requires 1 arguments")},
   628  	}
   629  	for _, cas := range cases {
   630  		if err := runInvokeTestCase(DictType.ToObject(), &cas); err != "" {
   631  			t.Error(err)
   632  		}
   633  	}
   634  }
   635  
   636  func TestDictNewRaises(t *testing.T) {
   637  	cases := []invokeTestCase{
   638  		{args: wrapArgs(), wantExc: mustCreateException(TypeErrorType, "'__new__' requires 1 arguments")},
   639  		{args: wrapArgs(123), wantExc: mustCreateException(TypeErrorType, `'__new__' requires a 'type' object but received a "int"`)},
   640  		{args: wrapArgs(NoneType), wantExc: mustCreateException(TypeErrorType, "dict.__new__(NoneType): NoneType is not a subtype of dict")},
   641  	}
   642  	for _, cas := range cases {
   643  		if err := runInvokeMethodTestCase(DictType, "__new__", &cas); err != "" {
   644  			t.Error(err)
   645  		}
   646  	}
   647  }
   648  
   649  func TestDictSetDefault(t *testing.T) {
   650  	setDefaultMethod := mustNotRaise(GetAttr(NewRootFrame(), DictType.ToObject(), NewStr("setdefault"), nil))
   651  	setDefault := newBuiltinFunction("TestDictSetDefault", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
   652  		i, raised := setDefaultMethod.Call(f, args, kwargs)
   653  		if raised != nil {
   654  			return nil, raised
   655  		}
   656  		return NewTuple(i, args[0]).ToObject(), nil
   657  	}).ToObject()
   658  	cases := []invokeTestCase{
   659  		{args: wrapArgs(NewDict(), "foo"), want: newTestTuple(None, newTestDict("foo", None)).ToObject()},
   660  		{args: wrapArgs(NewDict(), "foo", 42), want: newTestTuple(42, newTestDict("foo", 42)).ToObject()},
   661  		{args: wrapArgs(newTestDict("foo", 42), "foo"), want: newTestTuple(42, newTestDict("foo", 42)).ToObject()},
   662  		{args: wrapArgs(newTestDict("foo", 42), "foo", 43), want: newTestTuple(42, newTestDict("foo", 42)).ToObject()},
   663  		{args: wrapArgs(NewDict()), wantExc: mustCreateException(TypeErrorType, "setdefault expected at least 1 arguments, got 0")},
   664  		{args: wrapArgs(NewDict(), "foo", "bar", "baz"), wantExc: mustCreateException(TypeErrorType, "setdefault expected at most 2 arguments, got 3")},
   665  	}
   666  	for _, cas := range cases {
   667  		if err := runInvokeTestCase(setDefault, &cas); err != "" {
   668  			t.Error(err)
   669  		}
   670  	}
   671  }
   672  
   673  func TestDictSetItem(t *testing.T) {
   674  	setItem := newBuiltinFunction("TestDictSetItem", func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
   675  		if raised := checkFunctionArgs(f, "TestDictSetItem", args, DictType, ObjectType, ObjectType); raised != nil {
   676  			return nil, raised
   677  		}
   678  		d := toDictUnsafe(args[0])
   679  		if raised := d.SetItem(f, args[1], args[2]); raised != nil {
   680  			return nil, raised
   681  		}
   682  		return d.ToObject(), nil
   683  	}).ToObject()
   684  	f := NewRootFrame()
   685  	o := newObject(ObjectType)
   686  	deletedItemDict := newStringDict(map[string]*Object{"foo": None})
   687  	if _, raised := deletedItemDict.DelItemString(f, "foo"); raised != nil {
   688  		t.Fatal(raised)
   689  	}
   690  	modifiedDict := newTestDict(0, None)
   691  	modifiedType := newTestClass("Foo", []*Type{IntType}, newStringDict(map[string]*Object{
   692  		"__eq__": newBuiltinFunction("__eq__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
   693  			for i := 1000; i < 1100; i++ {
   694  				if raised := modifiedDict.SetItem(f, NewInt(i).ToObject(), None); raised != nil {
   695  					return nil, raised
   696  				}
   697  			}
   698  			return False.ToObject(), nil
   699  		}).ToObject(),
   700  	}))
   701  	cases := []invokeTestCase{
   702  		{args: wrapArgs(NewDict(), "foo", o), want: newStringDict(map[string]*Object{"foo": o}).ToObject()},
   703  		{args: wrapArgs(newStringDict(map[string]*Object{"foo": NewInt(1).ToObject()}), "foo", 2), want: newStringDict(map[string]*Object{"foo": NewInt(2).ToObject()}).ToObject()},
   704  		{args: wrapArgs(newTestDict(2, None, "baz", 3.14), 2, o), want: newTestDict(2, o, "baz", 3.14).ToObject()},
   705  		{args: wrapArgs(deletedItemDict, "foo", o), want: newStringDict(map[string]*Object{"foo": o}).ToObject()},
   706  		{args: wrapArgs(NewDict(), NewList(), None), wantExc: mustCreateException(TypeErrorType, "unhashable type: 'list'")},
   707  		{args: wrapArgs(modifiedDict, newObject(modifiedType), None), wantExc: mustCreateException(RuntimeErrorType, "dictionary changed during write")},
   708  	}
   709  	for _, cas := range cases {
   710  		if err := runInvokeTestCase(setItem, &cas); err != "" {
   711  			t.Error(err)
   712  		}
   713  	}
   714  }
   715  
   716  func TestDictSetItemString(t *testing.T) {
   717  	setItemString := newBuiltinFunction("TestDictSetItemString", func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
   718  		if raised := checkFunctionArgs(f, "TestDictSetItemString", args, DictType, StrType, ObjectType); raised != nil {
   719  			return nil, raised
   720  		}
   721  		d := toDictUnsafe(args[0])
   722  		if raised := d.SetItemString(f, toStrUnsafe(args[1]).Value(), args[2]); raised != nil {
   723  			return nil, raised
   724  		}
   725  		return d.ToObject(), nil
   726  	}).ToObject()
   727  	o := newObject(ObjectType)
   728  	cases := []invokeTestCase{
   729  		{args: wrapArgs(NewDict(), "foo", o), want: newStringDict(map[string]*Object{"foo": o}).ToObject()},
   730  		{args: wrapArgs(newStringDict(map[string]*Object{"foo": NewInt(1).ToObject()}), "foo", 2), want: newStringDict(map[string]*Object{"foo": NewInt(2).ToObject()}).ToObject()},
   731  		{args: wrapArgs(newTestDict(2, None, "baz", 3.14), "baz", o), want: newTestDict(2, None, "baz", o).ToObject()},
   732  		{args: wrapArgs(newTestDict(hashFoo, o, "foo", None), "foo", 3.14), want: newTestDict(hashFoo, o, "foo", 3.14).ToObject()},
   733  	}
   734  	for _, cas := range cases {
   735  		if err := runInvokeTestCase(setItemString, &cas); err != "" {
   736  			t.Error(err)
   737  		}
   738  	}
   739  }
   740  
   741  func TestDictStrRepr(t *testing.T) {
   742  	recursiveDict := NewDict()
   743  	if raised := recursiveDict.SetItemString(NewRootFrame(), "key", recursiveDict.ToObject()); raised != nil {
   744  		t.Fatal(raised)
   745  	}
   746  	cases := []struct {
   747  		o            *Object
   748  		wantPatterns []string
   749  	}{
   750  		{NewDict().ToObject(), []string{"^{}$"}},
   751  		{newStringDict(map[string]*Object{"foo": NewStr("foo value").ToObject()}).ToObject(), []string{`^\{'foo': 'foo value'\}$`}},
   752  		{newStringDict(map[string]*Object{"foo": NewStr("foo value").ToObject(), "bar": NewStr("bar value").ToObject()}).ToObject(), []string{`^{.*, .*}$`, `'foo': 'foo value'`, `'bar': 'bar value'`}},
   753  		{recursiveDict.ToObject(), []string{`^{'key': {\.\.\.}}$`}},
   754  	}
   755  	for _, cas := range cases {
   756  		fun := wrapFuncForTest(func(f *Frame) *BaseException {
   757  			for _, pattern := range cas.wantPatterns {
   758  				re := regexp.MustCompile(pattern)
   759  				s, raised := ToStr(f, cas.o)
   760  				if raised != nil {
   761  					return raised
   762  				}
   763  				if !re.MatchString(s.Value()) {
   764  					t.Errorf("str(%v) = %v, want %q", cas.o, s, re)
   765  				}
   766  				s, raised = Repr(f, cas.o)
   767  				if raised != nil {
   768  					return raised
   769  				}
   770  				if !re.MatchString(s.Value()) {
   771  					t.Errorf("repr(%v) = %v, want %q", cas.o, s, re)
   772  				}
   773  			}
   774  			return nil
   775  		})
   776  		if err := runInvokeTestCase(fun, &invokeTestCase{want: None}); err != "" {
   777  			t.Error(err)
   778  		}
   779  	}
   780  }
   781  
   782  func TestDictUpdate(t *testing.T) {
   783  	updateMethod := mustNotRaise(GetAttr(NewRootFrame(), DictType.ToObject(), NewStr("update"), nil))
   784  	update := newBuiltinFunction("TestDictUpdate", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
   785  		if raised := checkFunctionVarArgs(f, "TestDictUpdate", args, DictType); raised != nil {
   786  			return nil, raised
   787  		}
   788  		if _, raised := updateMethod.Call(f, args, kwargs); raised != nil {
   789  			return nil, raised
   790  		}
   791  		return args[0], nil
   792  	}).ToObject()
   793  	cases := []invokeTestCase{
   794  		{args: wrapArgs(newTestDict(42, "foo")), want: newTestDict(42, "foo").ToObject()},
   795  		{args: wrapArgs(NewDict(), NewDict()), want: NewDict().ToObject()},
   796  		{args: wrapArgs(NewDict(), newTestDict("foo", 42, "bar", 43)), want: newTestDict("foo", 42, "bar", 43).ToObject()},
   797  		{args: wrapArgs(newTestDict(123, None), newTestDict(124, True)), want: newTestDict(123, None, 124, True).ToObject()},
   798  		{args: wrapArgs(newTestDict("foo", 3.14), newTestDict("foo", "bar")), want: newTestDict("foo", "bar").ToObject()},
   799  		{args: wrapArgs(NewDict(), NewTuple()), want: NewDict().ToObject()},
   800  		{args: wrapArgs(NewDict(), newTestList(newTestTuple("foo", 42), newTestTuple("bar", 43))), want: newTestDict("foo", 42, "bar", 43).ToObject()},
   801  		{args: wrapArgs(newTestDict(123, None), newTestTuple(newTestTuple(124, True))), want: newTestDict(123, None, 124, True).ToObject()},
   802  		{args: wrapArgs(newTestDict("foo", 3.14), newTestList(newTestList("foo", "bar"))), want: newTestDict("foo", "bar").ToObject()},
   803  		{args: wrapArgs(NewDict(), None), wantExc: mustCreateException(TypeErrorType, "'NoneType' object is not iterable")},
   804  		{args: wrapArgs(NewDict(), newTestTuple(newTestList(None, 42, "foo"))), wantExc: mustCreateException(ValueErrorType, "dictionary update sequence element has length 3; 2 is required")},
   805  		{args: wrapArgs(NewDict()), want: NewDict().ToObject()},
   806  		{args: wrapArgs(NewDict()), kwargs: wrapKWArgs("foo", "bar"), want: newTestDict("foo", "bar").ToObject()},
   807  		{args: wrapArgs(newTestDict("foo", 1, "bar", 3.14), newTestDict("foo", 2)), kwargs: wrapKWArgs("foo", 3), want: newTestDict("foo", 3, "bar", 3.14).ToObject()},
   808  	}
   809  	for _, cas := range cases {
   810  		if err := runInvokeTestCase(update, &cas); err != "" {
   811  			t.Error(err)
   812  		}
   813  	}
   814  }
   815  
   816  func TestDictValues(t *testing.T) {
   817  	cases := []invokeTestCase{
   818  		{args: wrapArgs(NewDict()), want: NewList().ToObject()},
   819  		{args: wrapArgs(newTestDict("foo", 1, "bar", 2)), want: newTestList(1, 2).ToObject()},
   820  		{args: wrapArgs(NewDict(), "bad"), wantExc: mustCreateException(TypeErrorType, "'values' of 'dict' requires 1 arguments")},
   821  	}
   822  	for _, cas := range cases {
   823  		if err := runInvokeMethodTestCase(DictType, "values", &cas); err != "" {
   824  			t.Error(err)
   825  		}
   826  	}
   827  }
   828  
   829  func TestParallelDictUpdates(t *testing.T) {
   830  	keys := []*Object{
   831  		NewStr("abc").ToObject(),
   832  		NewStr("def").ToObject(),
   833  		NewStr("ghi").ToObject(),
   834  		NewStr("jkl").ToObject(),
   835  		NewStr("mno").ToObject(),
   836  		NewStr("pqr").ToObject(),
   837  		NewStr("stu").ToObject(),
   838  		NewStr("vwx").ToObject(),
   839  		NewStr("yz0").ToObject(),
   840  		NewStr("123").ToObject(),
   841  		NewStr("456").ToObject(),
   842  		NewStr("789").ToObject(),
   843  		NewStr("ABC").ToObject(),
   844  		NewStr("DEF").ToObject(),
   845  		NewStr("GHI").ToObject(),
   846  		NewStr("JKL").ToObject(),
   847  		NewStr("MNO").ToObject(),
   848  		NewStr("PQR").ToObject(),
   849  		NewStr("STU").ToObject(),
   850  		NewStr("VWX").ToObject(),
   851  		NewStr("YZ)").ToObject(),
   852  		NewStr("!@#").ToObject(),
   853  		NewStr("$%^").ToObject(),
   854  		NewStr("&*(").ToObject(),
   855  	}
   856  
   857  	var started, finished sync.WaitGroup
   858  	stop := make(chan struct{})
   859  	runner := func(f func(*Frame, *Object, int)) {
   860  		for i := 0; i < 8; i++ {
   861  			started.Add(1)
   862  			finished.Add(1)
   863  			go func() {
   864  				defer finished.Done()
   865  				frame := NewRootFrame()
   866  				i := 0
   867  				for _, k := range keys {
   868  					f(frame, k, i)
   869  					frame.RestoreExc(nil, nil)
   870  					i++
   871  				}
   872  				started.Done()
   873  				for {
   874  					if _, ok := <-stop; !ok {
   875  						break
   876  					}
   877  					for _, k := range keys {
   878  						f(frame, k, i)
   879  						frame.RestoreExc(nil, nil)
   880  						i++
   881  					}
   882  				}
   883  			}()
   884  		}
   885  	}
   886  
   887  	d := NewDict().ToObject()
   888  	runner(func(f *Frame, k *Object, _ int) {
   889  		GetItem(f, d, k)
   890  	})
   891  
   892  	runner(func(f *Frame, k *Object, i int) {
   893  		mustNotRaise(nil, SetItem(f, d, k, NewInt(i).ToObject()))
   894  	})
   895  
   896  	runner(func(f *Frame, k *Object, _ int) {
   897  		DelItem(f, d, k)
   898  	})
   899  
   900  	started.Wait()
   901  	time.AfterFunc(time.Second, func() { close(stop) })
   902  	finished.Wait()
   903  }
   904  
   905  func newTestDict(elems ...interface{}) *Dict {
   906  	if len(elems)%2 != 0 {
   907  		panic("invalid test dict spec")
   908  	}
   909  	numItems := len(elems) / 2
   910  	d := NewDict()
   911  	f := NewRootFrame()
   912  	for i := 0; i < numItems; i++ {
   913  		k := mustNotRaise(WrapNative(f, reflect.ValueOf(elems[i*2])))
   914  		v := mustNotRaise(WrapNative(f, reflect.ValueOf(elems[i*2+1])))
   915  		d.SetItem(f, k, v)
   916  	}
   917  	return d
   918  }