github.com/pygolin/runtime@v0.0.0-20201208210830-a62e3cd39798/native_test.go (about) 1 // Copyright 2016 Google Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package runtime 16 17 import ( 18 "errors" 19 "fmt" 20 "math/big" 21 "reflect" 22 "regexp" 23 "testing" 24 ) 25 26 func TestNativeMetaclassNew(t *testing.T) { 27 var i int16 28 intType := newNativeType(reflect.TypeOf(i), IntType) 29 fun := wrapFuncForTest(func(f *Frame, args ...*Object) *BaseException { 30 newFunc, raised := GetAttr(f, intType.ToObject(), NewStr("new"), nil) 31 if raised != nil { 32 return raised 33 } 34 ret, raised := newFunc.Call(f, args, nil) 35 if raised != nil { 36 return raised 37 } 38 got, raised := ToNative(f, ret) 39 if raised != nil { 40 return raised 41 } 42 if got.Type() != reflect.TypeOf(&i) { 43 t.Errorf("%v.new() returned a %s, want a *int16", intType, nativeTypeName(got.Type())) 44 } else if p, ok := got.Interface().(*int16); !ok || p == nil || *p != 0 { 45 t.Errorf("%v.new() returned %v, want &int16(0)", intType, got) 46 } 47 return nil 48 }) 49 cases := []invokeTestCase{ 50 {want: None}, 51 {args: wrapArgs("abc"), wantExc: mustCreateException(TypeErrorType, "'new' of 'nativetype' requires 1 arguments")}, 52 } 53 for _, cas := range cases { 54 if err := runInvokeTestCase(fun, &cas); err != "" { 55 t.Error(err) 56 } 57 } 58 } 59 60 func TestNativeFuncCall(t *testing.T) { 61 cases := []struct { 62 fun interface{} 63 invokeTestCase 64 }{ 65 {func() {}, invokeTestCase{want: None}}, 66 {func() float32 { return 2.0 }, invokeTestCase{want: NewFloat(2.0).ToObject()}}, 67 {func(s string) string { return s }, invokeTestCase{args: wrapArgs("foo"), want: NewStr("foo").ToObject()}}, 68 {func() (int, string) { return 42, "bar" }, invokeTestCase{want: newTestTuple(42, "bar").ToObject()}}, 69 {func(s ...string) int { return len(s) }, invokeTestCase{args: wrapArgs("foo", "bar"), want: NewInt(2).ToObject()}}, 70 {func() {}, invokeTestCase{args: wrapArgs(3.14), wantExc: mustCreateException(TypeErrorType, "native function takes 0 arguments, (1 given)")}}, 71 {func(int, ...string) {}, invokeTestCase{wantExc: mustCreateException(TypeErrorType, "native function takes at least 1 arguments, (0 given)")}}, 72 } 73 for _, cas := range cases { 74 n := &native{Object{typ: nativeFuncType}, reflect.ValueOf(cas.fun)} 75 if err := runInvokeTestCase(n.ToObject(), &cas.invokeTestCase); err != "" { 76 t.Error(err) 77 } 78 } 79 } 80 81 func TestNativeFuncName(t *testing.T) { 82 re := regexp.MustCompile(`(\w+\.)*\w+$`) 83 fun := wrapFuncForTest(func(f *Frame, o *Object) (string, *BaseException) { 84 desc, raised := GetItem(f, nativeFuncType.Dict().ToObject(), internedName.ToObject()) 85 if raised != nil { 86 return "", raised 87 } 88 get, raised := GetAttr(f, desc, NewStr("__get__"), nil) 89 if raised != nil { 90 return "", raised 91 } 92 name, raised := get.Call(f, wrapArgs(o, nativeFuncType), nil) 93 if raised != nil { 94 return "", raised 95 } 96 if raised := Assert(f, GetBool(name.isInstance(StrType)).ToObject(), nil); raised != nil { 97 return "", raised 98 } 99 return re.FindString(toStrUnsafe(name).Value()), nil 100 }) 101 cases := []invokeTestCase{ 102 {args: wrapArgs(TestNativeFuncName), want: NewStr("grumpy.TestNativeFuncName").ToObject()}, 103 {args: wrapArgs(None), wantExc: mustCreateException(TypeErrorType, "'_get_name' requires a 'func' object but received a 'NoneType'")}, 104 } 105 for _, cas := range cases { 106 if err := runInvokeTestCase(fun, &cas); err != "" { 107 t.Error(err) 108 } 109 } 110 } 111 112 func TestNativeFuncStrRepr(t *testing.T) { 113 cases := []struct { 114 args Args 115 wantPattern string 116 }{ 117 {wrapArgs(TestNativeFuncStrRepr), `<func\(\*T\) .*grumpy\.TestNativeFuncStrRepr at 0x[a-f0-9]+>`}, 118 {wrapArgs(func() {}), `<func\(\) .*grumpy\.TestNativeFuncStrRepr\.\w+ at 0x[a-f0-9]+>`}, 119 {wrapArgs(Repr), `<func\(\*Frame, \*Object\) .*grumpy\.Repr at 0x[a-f0-9]+>`}, 120 } 121 for _, cas := range cases { 122 re := regexp.MustCompile(cas.wantPattern) 123 fun := wrapFuncForTest(func(f *Frame, o *Object) *BaseException { 124 s, raised := ToStr(f, o) 125 if raised != nil { 126 return raised 127 } 128 if !re.MatchString(s.Value()) { 129 t.Errorf("str(%v) = %v, want %v", o, s, re) 130 } 131 s, raised = Repr(f, o) 132 if raised != nil { 133 return raised 134 } 135 if !re.MatchString(s.Value()) { 136 t.Errorf("repr(%v) = %v, want %v", o, s, re) 137 } 138 return nil 139 }) 140 if err := runInvokeTestCase(fun, &invokeTestCase{args: cas.args, want: None}); err != "" { 141 t.Error(err) 142 } 143 } 144 } 145 146 func TestNativeNew(t *testing.T) { 147 fun := wrapFuncForTest(func(f *Frame, t *Type, args ...*Object) (*Tuple, *BaseException) { 148 o, raised := t.Call(f, args, nil) 149 if raised != nil { 150 return nil, raised 151 } 152 return newTestTuple(o, o.Type()), nil 153 }) 154 type testBool bool 155 testBoolType := getNativeType(reflect.TypeOf(testBool(false))) 156 type testFloat float32 157 testFloatType := getNativeType(reflect.TypeOf(testFloat(0))) 158 type testString string 159 testStringType := getNativeType(reflect.TypeOf(testString(""))) 160 cases := []invokeTestCase{ 161 {args: wrapArgs(testBoolType), want: newTestTuple(false, testBoolType).ToObject()}, 162 {args: wrapArgs(testBoolType, ""), want: newTestTuple(false, testBoolType).ToObject()}, 163 {args: wrapArgs(testBoolType, 123), want: newTestTuple(true, testBoolType).ToObject()}, 164 {args: wrapArgs(testBoolType, "foo", "bar"), wantExc: mustCreateException(TypeErrorType, "testBool() takes at most 1 argument (2 given)")}, 165 {args: wrapArgs(testFloatType), want: newTestTuple(0.0, testFloatType).ToObject()}, 166 {args: wrapArgs(testFloatType, 3.14), want: newTestTuple(3.14, testFloatType).ToObject()}, 167 {args: wrapArgs(testFloatType, "foo", "bar"), wantExc: mustCreateException(TypeErrorType, "'__new__' of 'float' requires 0 or 1 arguments")}, 168 {args: wrapArgs(testStringType), want: newTestTuple("", testStringType).ToObject()}, 169 {args: wrapArgs(testStringType, "foo"), want: newTestTuple("foo", testStringType).ToObject()}, 170 {args: wrapArgs(testStringType, "foo", "bar"), wantExc: mustCreateException(TypeErrorType, "str() takes at most 1 argument (2 given)")}, 171 } 172 for _, cas := range cases { 173 if err := runInvokeTestCase(fun, &cas); err != "" { 174 t.Error(err) 175 } 176 } 177 } 178 179 func TestNativeSliceIter(t *testing.T) { 180 fun := wrapFuncForTest(func(f *Frame, slice interface{}) (*Object, *BaseException) { 181 o, raised := WrapNative(f, reflect.ValueOf(slice)) 182 if raised != nil { 183 return nil, raised 184 } 185 return TupleType.Call(f, []*Object{o}, nil) 186 }) 187 o := newObject(ObjectType) 188 cases := []invokeTestCase{ 189 {args: wrapArgs([]int{}), want: NewTuple().ToObject()}, 190 {args: wrapArgs([]string{"foo", "bar"}), want: newTestTuple("foo", "bar").ToObject()}, 191 {args: wrapArgs([]*Object{True.ToObject(), o}), want: newTestTuple(true, o).ToObject()}, 192 } 193 for _, cas := range cases { 194 if err := runInvokeTestCase(fun, &cas); err != "" { 195 t.Error(err) 196 } 197 } 198 } 199 200 func TestSliceIteratorIter(t *testing.T) { 201 iter := newSliceIterator(reflect.ValueOf([]*Object{})) 202 cas := &invokeTestCase{args: wrapArgs(iter), want: iter} 203 if err := runInvokeMethodTestCase(sliceIteratorType, "__iter__", cas); err != "" { 204 t.Error(err) 205 } 206 } 207 208 func TestWrapNative(t *testing.T) { 209 o := newObject(ObjectType) 210 d := NewDict() 211 i := 0 212 n := &native{Object{typ: nativeType}, reflect.ValueOf(&i)} 213 cases := []struct { 214 value interface{} 215 want *Object 216 wantExc *BaseException 217 }{ 218 {true, True.ToObject(), nil}, 219 {True, True.ToObject(), nil}, 220 {123, NewInt(123).ToObject(), nil}, 221 {int8(10), NewInt(10).ToObject(), nil}, 222 {float32(0.5), NewFloat(0.5).ToObject(), nil}, 223 {NewFloat(3.14), NewFloat(3.14).ToObject(), nil}, 224 {uint(MaxInt), NewInt(MaxInt).ToObject(), nil}, 225 {"foobar", NewStr("foobar").ToObject(), nil}, 226 {NewStr("foo"), NewStr("foo").ToObject(), nil}, 227 {uint64(MaxInt) + 100, NewLong(new(big.Int).SetUint64(uint64(MaxInt) + 100)).ToObject(), nil}, 228 {o, o, nil}, 229 {d, d.ToObject(), nil}, 230 {(*Object)(nil), None, nil}, 231 {uintptr(123), NewInt(123).ToObject(), nil}, 232 {n, n.ToObject(), nil}, 233 {(chan int)(nil), None, nil}, 234 {[]rune("hola"), NewUnicode("hola").ToObject(), nil}, 235 {big.NewInt(12345), NewLong(big.NewInt(12345)).ToObject(), nil}, 236 {*big.NewInt(12345), NewLong(big.NewInt(12345)).ToObject(), nil}, 237 } 238 for _, cas := range cases { 239 fun := wrapFuncForTest(func(f *Frame) (*Object, *BaseException) { 240 return WrapNative(f, reflect.ValueOf(cas.value)) 241 }) 242 testCase := invokeTestCase{want: cas.want, wantExc: cas.wantExc} 243 if err := runInvokeTestCase(fun, &testCase); err != "" { 244 t.Error(err) 245 } 246 } 247 } 248 249 func TestWrapNativeFunc(t *testing.T) { 250 foo := func() int { return 42 } 251 wrappedFoo := mustNotRaise(WrapNative(NewRootFrame(), reflect.ValueOf(foo))) 252 if err := runInvokeTestCase(wrappedFoo, &invokeTestCase{want: NewInt(42).ToObject()}); err != "" { 253 t.Error(err) 254 } 255 } 256 257 func TestWrapNativeInterface(t *testing.T) { 258 // This seems to be the simplest way to get a reflect.Value that has 259 // Interface kind. 260 iVal := reflect.ValueOf(func() error { return errors.New("foo") }).Call(nil)[0] 261 if iVal.Kind() != reflect.Interface { 262 t.Fatalf("iVal.Kind() = %v, want interface", iVal.Kind()) 263 } 264 o := mustNotRaise(WrapNative(NewRootFrame(), iVal)) 265 cas := &invokeTestCase{args: wrapArgs(o), want: NewStr("foo").ToObject()} 266 if err := runInvokeMethodTestCase(o.typ, "Error", cas); err != "" { 267 t.Error(err) 268 } 269 // Also test the nil interface case. 270 nilVal := reflect.ValueOf(func() error { return nil }).Call(nil)[0] 271 if nilVal.Kind() != reflect.Interface { 272 t.Fatalf("nilVal.Kind() = %v, want interface", nilVal.Kind()) 273 } 274 if o := mustNotRaise(WrapNative(NewRootFrame(), nilVal)); o != None { 275 t.Errorf("WrapNative(%v) = %v, want None", nilVal, o) 276 } 277 } 278 279 func TestWrapNativeOpaque(t *testing.T) { 280 type fooStruct struct{} 281 foo := &fooStruct{} 282 fooVal := reflect.ValueOf(foo) 283 fun := wrapFuncForTest(func(f *Frame) *BaseException { 284 o, raised := WrapNative(f, fooVal) 285 if raised != nil { 286 return raised 287 } 288 if !o.isInstance(nativeType) { 289 t.Errorf("WrapNative(%v) = %v, want %v", fooVal, o, foo) 290 } else if v := toNativeUnsafe(o).value; v.Type() != reflect.TypeOf(foo) { 291 t.Errorf("WrapNative(%v) = %v, want %v", fooVal, v, foo) 292 } else if got := v.Interface().(*fooStruct); got != foo { 293 t.Errorf("WrapNative(%v) = %v, want %v", fooVal, got, foo) 294 } 295 return nil 296 }) 297 if err := runInvokeTestCase(fun, &invokeTestCase{want: None}); err != "" { 298 t.Error(err) 299 } 300 } 301 302 func TestGetNativeTypeCaches(t *testing.T) { 303 foo := []struct{}{} 304 typ := getNativeType(reflect.TypeOf(foo)) 305 if got := getNativeType(reflect.TypeOf(foo)); got != typ { 306 t.Errorf("getNativeType(foo) = %v, want %v", got, typ) 307 } 308 } 309 310 func TestGetNativeTypeFunc(t *testing.T) { 311 if typ := getNativeType(reflect.TypeOf(func() {})); !typ.isSubclass(nativeFuncType) { 312 t.Errorf("getNativeType(func() {}) = %v, want a subclass of func", typ) 313 } else if name := typ.Name(); name != "func()" { 314 t.Errorf(`%v.__name__ == %q, want "func()"`, typ, name) 315 } 316 } 317 318 type testNativeType struct { 319 data int64 320 } 321 322 func (n *testNativeType) Int64() int64 { 323 return n.data 324 } 325 326 func TestGetNativeTypeMethods(t *testing.T) { 327 fun := wrapFuncForTest(func(f *Frame, o *Object) (*Object, *BaseException) { 328 if raised := Assert(f, GetBool(o.isInstance(nativeType)).ToObject(), nil); raised != nil { 329 return nil, raised 330 } 331 int64Method, raised := GetAttr(f, o.Type().ToObject(), NewStr("Int64"), nil) 332 if raised != nil { 333 return nil, raised 334 } 335 return int64Method.Call(f, []*Object{o}, nil) 336 }) 337 cas := invokeTestCase{args: wrapArgs(&testNativeType{12}), want: NewInt(12).ToObject()} 338 if err := runInvokeTestCase(fun, &cas); err != "" { 339 t.Error(err) 340 } 341 } 342 343 func TestGetNativeTypeSlice(t *testing.T) { 344 if typ := getNativeType(reflect.TypeOf([]int{})); !typ.isSubclass(nativeSliceType) { 345 t.Errorf("getNativeType([]int) = %v, want a subclass of slice", typ) 346 } else if name := typ.Name(); name != "[]int" { 347 t.Errorf(`%v.__name__ == %q, want "func()"`, typ, name) 348 } 349 } 350 351 func TestGetNativeTypeTypedefs(t *testing.T) { 352 type testBool bool 353 type testInt int 354 type testFloat float32 355 type testString string 356 cases := []struct { 357 rtype reflect.Type 358 super *Type 359 }{ 360 {reflect.TypeOf(testBool(true)), BoolType}, 361 {reflect.TypeOf(testFloat(3.14)), FloatType}, 362 {reflect.TypeOf(testInt(42)), IntType}, 363 {reflect.TypeOf(testString("foo")), StrType}, 364 } 365 for _, cas := range cases { 366 if typ := getNativeType(cas.rtype); typ == cas.super || !typ.isSubclass(cas.super) { 367 t.Errorf("getNativeType(%v) = %v, want a subclass of %v", cas.rtype, typ, cas.super) 368 } 369 } 370 } 371 372 func TestGetNativeTypeBigInts(t *testing.T) { 373 cases := []struct { 374 rtype reflect.Type 375 typ *Type 376 }{ 377 {reflect.TypeOf(big.Int{}), LongType}, 378 {reflect.TypeOf((*big.Int)(nil)), LongType}, 379 } 380 for _, cas := range cases { 381 if typ := getNativeType(cas.rtype); typ != cas.typ { 382 t.Errorf("getNativeType(%v) = %v, want %v", cas.rtype, typ, cas.typ) 383 } 384 } 385 } 386 387 func TestMaybeConvertValue(t *testing.T) { 388 type fooStruct struct{} 389 foo := &fooStruct{} 390 fooNative := &native{Object{typ: nativeType}, reflect.ValueOf(&foo)} 391 cases := []struct { 392 o *Object 393 expectedRType reflect.Type 394 want interface{} 395 wantExc *BaseException 396 }{ 397 {NewInt(42).ToObject(), reflect.TypeOf(int(0)), 42, nil}, 398 {NewFloat(0.5).ToObject(), reflect.TypeOf(float32(0)), float32(0.5), nil}, 399 {fooNative.ToObject(), reflect.TypeOf(&fooStruct{}), foo, nil}, 400 {None, reflect.TypeOf((*int)(nil)), (*int)(nil), nil}, 401 {None, reflect.TypeOf(""), nil, mustCreateException(TypeErrorType, "an string is required")}, 402 } 403 for _, cas := range cases { 404 fun := wrapFuncForTest(func(f *Frame) *BaseException { 405 got, raised := maybeConvertValue(f, cas.o, cas.expectedRType) 406 if raised != nil { 407 return raised 408 } 409 if !got.IsValid() || !reflect.DeepEqual(got.Interface(), cas.want) { 410 t.Errorf("maybeConvertValue(%v, %v) = %v, want %v", cas.o, nativeTypeName(cas.expectedRType), got, cas.want) 411 } 412 return nil 413 }) 414 testCase := invokeTestCase{} 415 if cas.wantExc != nil { 416 testCase.wantExc = cas.wantExc 417 } else { 418 testCase.want = None 419 } 420 if err := runInvokeTestCase(fun, &testCase); err != "" { 421 t.Error(err) 422 } 423 } 424 } 425 426 func TestNativeTypedefNative(t *testing.T) { 427 fun := wrapFuncForTest(func(f *Frame, o *Object, wantType reflect.Type) (bool, *BaseException) { 428 val, raised := ToNative(f, o) 429 if raised != nil { 430 return false, raised 431 } 432 return val.Type() == wantType, nil 433 }) 434 type testBool bool 435 testBoolRType := reflect.TypeOf(testBool(false)) 436 type testInt int 437 testIntRType := reflect.TypeOf(testInt(0)) 438 cases := []invokeTestCase{ 439 {args: wrapArgs(mustNotRaise(getNativeType(testBoolRType).Call(NewRootFrame(), wrapArgs(true), nil)), testBoolRType), want: True.ToObject()}, 440 {args: wrapArgs(mustNotRaise(getNativeType(testIntRType).Call(NewRootFrame(), wrapArgs(123), nil)), testIntRType), want: True.ToObject()}, 441 } 442 for _, cas := range cases { 443 if err := runInvokeTestCase(fun, &cas); err != "" { 444 t.Error(err) 445 } 446 } 447 } 448 449 func TestNativeTypeName(t *testing.T) { 450 type fooStruct struct{} 451 cases := []struct { 452 rtype reflect.Type 453 want string 454 }{ 455 {reflect.TypeOf([4]int{}), "[4]int"}, 456 {reflect.TypeOf(make(chan *string)), "chan *string"}, 457 {reflect.TypeOf(func() {}), "func()"}, 458 {reflect.TypeOf(func(int, string) {}), "func(int, string)"}, 459 {reflect.TypeOf(func() int { return 0 }), "func() int"}, 460 {reflect.TypeOf(func() (int, float32) { return 0, 0.0 }), "func() (int, float32)"}, 461 {reflect.TypeOf(map[int]fooStruct{}), "map[int]fooStruct"}, 462 {reflect.TypeOf(&fooStruct{}), "*fooStruct"}, 463 {reflect.TypeOf([]byte{}), "[]uint8"}, 464 {reflect.TypeOf(struct{}{}), "anonymous struct"}, 465 } 466 for _, cas := range cases { 467 if got := nativeTypeName(cas.rtype); got != cas.want { 468 t.Errorf("nativeTypeName(%v) = %q, want %q", cas.rtype, got, cas.want) 469 } 470 } 471 } 472 473 func TestNewNativeFieldChecksInstanceType(t *testing.T) { 474 f := NewRootFrame() 475 476 // Given a native object 477 native, raised := WrapNative(f, reflect.ValueOf(struct{ foo string }{})) 478 if raised != nil { 479 t.Fatal("Unexpected exception:", raised) 480 } 481 482 // When its field property is assigned to a different type 483 property, raised := native.typ.Dict().GetItemString(f, "foo") 484 if raised != nil { 485 t.Fatal("Unexpected exception:", raised) 486 } 487 if raised := IntType.Dict().SetItemString(f, "foo", property); raised != nil { 488 t.Fatal("Unexpected exception:", raised) 489 } 490 491 // And we try to access that property on an object of the new type 492 _, raised = GetAttr(f, NewInt(1).ToObject(), NewStr("foo"), nil) 493 494 // Then expect a TypeError was raised 495 if raised == nil || raised.Type() != TypeErrorType { 496 t.Fatal("Wanted TypeError; got:", raised) 497 } 498 } 499 500 func TestNativeSliceGetItem(t *testing.T) { 501 testRange := make([]int, 20) 502 for i := 0; i < len(testRange); i++ { 503 testRange[i] = i 504 } 505 badIndexType := newTestClass("badIndex", []*Type{ObjectType}, newStringDict(map[string]*Object{ 506 "__index__": newBuiltinFunction("__index__", func(f *Frame, _ Args, _ KWArgs) (*Object, *BaseException) { 507 return nil, f.RaiseType(ValueErrorType, "wut") 508 }).ToObject(), 509 })) 510 cases := []invokeTestCase{ 511 {args: wrapArgs(testRange, 0), want: NewInt(0).ToObject()}, 512 {args: wrapArgs(testRange, 19), want: NewInt(19).ToObject()}, 513 {args: wrapArgs([]struct{}{}, 101), wantExc: mustCreateException(IndexErrorType, "index out of range")}, 514 {args: wrapArgs([]bool{true}, None), wantExc: mustCreateException(TypeErrorType, "native slice indices must be integers, not NoneType")}, 515 {args: wrapArgs(testRange, newObject(badIndexType)), wantExc: mustCreateException(ValueErrorType, "wut")}, 516 } 517 for _, cas := range cases { 518 if err := runInvokeTestCase(wrapFuncForTest(GetItem), &cas); err != "" { 519 t.Error(err) 520 } 521 } 522 } 523 524 func TestNativeSliceGetItemSlice(t *testing.T) { 525 fun := wrapFuncForTest(func(f *Frame, o *Object, slice *Slice, want interface{}) *BaseException { 526 item, raised := GetItem(f, o, slice.ToObject()) 527 if raised != nil { 528 return raised 529 } 530 val, raised := ToNative(f, item) 531 if raised != nil { 532 return raised 533 } 534 v := val.Interface() 535 msg := fmt.Sprintf("%v[%v] = %v, want %v", o, slice, v, want) 536 return Assert(f, GetBool(reflect.DeepEqual(v, want)).ToObject(), NewStr(msg).ToObject()) 537 }) 538 type fooStruct struct { 539 Bar int 540 } 541 cases := []invokeTestCase{ 542 {args: wrapArgs([]string{}, newTestSlice(50, 100), []string{}), want: None}, 543 {args: wrapArgs([]int{1, 2, 3, 4, 5}, newTestSlice(1, 3, None), []int{2, 3}), want: None}, 544 {args: wrapArgs([]fooStruct{fooStruct{1}, fooStruct{10}}, newTestSlice(-1, None, None), []fooStruct{fooStruct{10}}), want: None}, 545 {args: wrapArgs([]int{1, 2, 3, 4, 5}, newTestSlice(1, None, 2), []int{2, 4}), want: None}, 546 {args: wrapArgs([]float64{1.0, 2.0, 3.0, 4.0, 5.0}, newTestSlice(big.NewInt(1), None, 2), []float64{2.0, 4.0}), want: None}, 547 {args: wrapArgs([]string{"1", "2", "3", "4", "5"}, newTestSlice(1, big.NewInt(5), 2), []string{"2", "4"}), want: None}, 548 {args: wrapArgs([]int{1, 2, 3, 4, 5}, newTestSlice(1, None, big.NewInt(2)), []int{2, 4}), want: None}, 549 {args: wrapArgs([]int16{1, 2, 3, 4, 5}, newTestSlice(1.0, 3, None), None), wantExc: mustCreateException(TypeErrorType, errBadSliceIndex)}, 550 {args: wrapArgs([]byte{1, 2, 3}, newTestSlice(1, None, 0), None), wantExc: mustCreateException(ValueErrorType, "slice step cannot be zero")}, 551 } 552 for _, cas := range cases { 553 if err := runInvokeTestCase(fun, &cas); err != "" { 554 t.Error(err) 555 } 556 } 557 } 558 559 func TestNativeSliceLen(t *testing.T) { 560 cases := []invokeTestCase{ 561 {args: wrapArgs([]string{"foo", "bar"}), want: NewInt(2).ToObject()}, 562 {args: wrapArgs(make([]int, 100)), want: NewInt(100).ToObject()}, 563 } 564 for _, cas := range cases { 565 if err := runInvokeTestCase(wrapFuncForTest(Len), &cas); err != "" { 566 t.Error(err) 567 } 568 } 569 } 570 571 func TestNativeSliceStrRepr(t *testing.T) { 572 slice := make([]*Object, 2) 573 o := mustNotRaise(WrapNative(NewRootFrame(), reflect.ValueOf(slice))) 574 slice[0] = o 575 slice[1] = NewStr("foo").ToObject() 576 cases := []invokeTestCase{ 577 {args: wrapArgs([]string{"foo", "bar"}), want: NewStr("[]string{'foo', 'bar'}").ToObject()}, 578 {args: wrapArgs([]uint16{123}), want: NewStr("[]uint16{123}").ToObject()}, 579 {args: wrapArgs(o), want: NewStr("[]*Object{[]*Object{...}, 'foo'}").ToObject()}, 580 } 581 for _, cas := range cases { 582 if err := runInvokeTestCase(wrapFuncForTest(ToStr), &cas); err != "" { 583 t.Error(err) 584 } 585 if err := runInvokeTestCase(wrapFuncForTest(Repr), &cas); err != "" { 586 t.Error(err) 587 } 588 } 589 } 590 591 func TestNativeSliceSetItemSlice(t *testing.T) { 592 fun := wrapFuncForTest(func(f *Frame, o, index, value *Object, want interface{}) *BaseException { 593 originalStr := o.String() 594 if raised := SetItem(f, o, index, value); raised != nil { 595 return raised 596 } 597 val, raised := ToNative(f, o) 598 if raised != nil { 599 return raised 600 } 601 v := val.Interface() 602 msg := fmt.Sprintf("%v[%v] = %v -> %v, want %v", originalStr, index, value, o, want) 603 return Assert(f, GetBool(reflect.DeepEqual(v, want)).ToObject(), NewStr(msg).ToObject()) 604 }) 605 type fooStruct struct { 606 bar []int 607 } 608 foo := fooStruct{[]int{1, 2, 3}} 609 bar := mustNotRaise(WrapNative(NewRootFrame(), reflect.ValueOf(foo).Field(0))) 610 cases := []invokeTestCase{ 611 {args: wrapArgs([]string{"foo", "bar"}, 1, "baz", []string{"foo", "baz"}), want: None}, 612 {args: wrapArgs([]uint16{1, 2, 3}, newTestSlice(1), newTestList(4), []uint16{4, 2, 3}), want: None}, 613 {args: wrapArgs([]int{1, 2, 4, 5}, newTestSlice(1, None, 2), newTestTuple(10, 20), []int{1, 10, 4, 20}), want: None}, 614 {args: wrapArgs([]float64{}, newTestSlice(4, 8, 0), NewList(), None), wantExc: mustCreateException(ValueErrorType, "slice step cannot be zero")}, 615 {args: wrapArgs([]string{"foo", "bar"}, -100, None, None), wantExc: mustCreateException(IndexErrorType, "index out of range")}, 616 {args: wrapArgs([]int{}, 101, None, None), wantExc: mustCreateException(IndexErrorType, "index out of range")}, 617 {args: wrapArgs([]bool{true}, None, false, None), wantExc: mustCreateException(TypeErrorType, "native slice indices must be integers, not NoneType")}, 618 {args: wrapArgs([]int8{1, 2, 3}, newTestSlice(0), []int8{0}, []int8{0, 1, 2, 3}), wantExc: mustCreateException(ValueErrorType, "attempt to assign sequence of size 1 to slice of size 0")}, 619 {args: wrapArgs([]int{1, 2, 3}, newTestSlice(2, None), newTestList("foo"), None), wantExc: mustCreateException(TypeErrorType, "an int is required")}, 620 {args: wrapArgs(bar, 1, 42, None), wantExc: mustCreateException(TypeErrorType, "cannot set slice element")}, 621 {args: wrapArgs(bar, newTestSlice(1), newTestList(42), None), wantExc: mustCreateException(TypeErrorType, "cannot set slice element")}, 622 {args: wrapArgs([]string{"foo", "bar"}, 1, 123.0, None), wantExc: mustCreateException(TypeErrorType, "an string is required")}, 623 {args: wrapArgs([]string{"foo", "bar"}, 1, 123.0, None), wantExc: mustCreateException(TypeErrorType, "an string is required")}, 624 } 625 for _, cas := range cases { 626 if err := runInvokeTestCase(fun, &cas); err != "" { 627 t.Error(err) 628 } 629 } 630 } 631 632 func TestNativeStructFieldGet(t *testing.T) { 633 fun := wrapFuncForTest(func(f *Frame, o *Object, attr *Str) (*Object, *BaseException) { 634 return GetAttr(f, o, attr, nil) 635 }) 636 type fooStruct struct { 637 bar int 638 Baz float64 639 } 640 cases := []invokeTestCase{ 641 {args: wrapArgs(fooStruct{bar: 1}, "bar"), want: NewInt(1).ToObject()}, 642 {args: wrapArgs(&fooStruct{Baz: 3.14}, "Baz"), want: NewFloat(3.14).ToObject()}, 643 {args: wrapArgs(fooStruct{}, "qux"), wantExc: mustCreateException(AttributeErrorType, `'fooStruct' object has no attribute 'qux'`)}, 644 } 645 for _, cas := range cases { 646 if err := runInvokeTestCase(fun, &cas); err != "" { 647 t.Error(err) 648 } 649 } 650 } 651 652 func TestNativeStructFieldSet(t *testing.T) { 653 fun := wrapFuncForTest(func(f *Frame, o *Object, attr *Str, value *Object) (*Object, *BaseException) { 654 if raised := SetAttr(f, o, attr, value); raised != nil { 655 return nil, raised 656 } 657 return GetAttr(f, o, attr, nil) 658 }) 659 type fooStruct struct { 660 bar int 661 Baz float64 662 } 663 cases := []invokeTestCase{ 664 {args: wrapArgs(&fooStruct{}, "Baz", 1.5), want: NewFloat(1.5).ToObject()}, 665 {args: wrapArgs(fooStruct{}, "bar", 123), wantExc: mustCreateException(TypeErrorType, `cannot set field 'bar' of type 'fooStruct'`)}, 666 {args: wrapArgs(fooStruct{}, "qux", "abc"), wantExc: mustCreateException(AttributeErrorType, `'fooStruct' has no attribute 'qux'`)}, 667 {args: wrapArgs(&fooStruct{}, "Baz", "abc"), wantExc: mustCreateException(TypeErrorType, "an float64 is required")}, 668 } 669 for _, cas := range cases { 670 if err := runInvokeTestCase(fun, &cas); err != "" { 671 t.Error(err) 672 } 673 } 674 } 675 676 func wrapArgs(elems ...interface{}) Args { 677 f := NewRootFrame() 678 argc := len(elems) 679 result := make(Args, argc, argc) 680 var raised *BaseException 681 for i, elem := range elems { 682 if result[i], raised = WrapNative(f, reflect.ValueOf(elem)); raised != nil { 683 panic(raised) 684 } 685 } 686 return result 687 } 688 689 func wrapKWArgs(elems ...interface{}) KWArgs { 690 if len(elems)%2 != 0 { 691 panic("invalid kwargs") 692 } 693 numItems := len(elems) / 2 694 kwargs := make(KWArgs, numItems, numItems) 695 f := NewRootFrame() 696 for i := 0; i < numItems; i++ { 697 kwargs[i].Name = elems[i*2].(string) 698 kwargs[i].Value = mustNotRaise(WrapNative(f, reflect.ValueOf(elems[i*2+1]))) 699 } 700 return kwargs 701 }