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