this repo has no description
at trunk 867 lines 38 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include <memory> 3 4#include "cpython-data.h" 5#include "gtest/gtest.h" 6 7#include "api-handle.h" 8#include "dict-builtins.h" 9#include "function-utils.h" 10#include "runtime.h" 11#include "test-utils.h" 12 13namespace py { 14namespace testing { 15 16using MethodTrampolinesTest = RuntimeFixture; 17 18static PyObject* capiFunctionNoArgs(PyObject* self, PyObject* args) { 19 Runtime* runtime = Thread::current()->runtime(); 20 runtime->collectGarbage(); 21 ApiHandle* handle = ApiHandle::fromPyObject(self); 22 EXPECT_GT(ApiHandle::refcnt(handle), 0); 23 EXPECT_TRUE(isStrEqualsCStr(ApiHandle::asObject(handle), "the self argument")); 24 EXPECT_EQ(args, nullptr); 25 return ApiHandle::newReference(runtime, SmallInt::fromWord(1230)); 26} 27 28static RawObject newFunctionNoArgs(Thread* thread) { 29 HandleScope scope(thread); 30 Runtime* runtime = thread->runtime(); 31 Object name(&scope, runtime->newStrFromCStr("foo")); 32 PyCFunction function_ptr = capiFunctionNoArgs; 33 return newExtensionFunction( 34 thread, name, reinterpret_cast<void*>(function_ptr), METH_NOARGS); 35} 36 37TEST_F(MethodTrampolinesTest, NoArgs) { 38 HandleScope scope(thread_); 39 Object function(&scope, newFunctionNoArgs(thread_)); 40 Object arg0(&scope, runtime_->newStrFromCStr("the self argument")); 41 EXPECT_TRUE( 42 isIntEqualsWord(Interpreter::call1(thread_, function, arg0), 1230)); 43} 44 45TEST_F(MethodTrampolinesTest, NoArgsWithoutSelfRaisesTypeError) { 46 HandleScope scope(thread_); 47 Function function(&scope, newFunctionNoArgs(thread_)); 48 EXPECT_TRUE(raisedWithStr(Interpreter::call0(thread_, function), 49 LayoutId::kTypeError, 50 "'foo' must be bound to an object")); 51} 52 53TEST_F(MethodTrampolinesTest, NoArgsWithTooManyArgsRaisesTypeError) { 54 HandleScope scope(thread_); 55 Function function(&scope, newFunctionNoArgs(thread_)); 56 Object arg0(&scope, runtime_->newStrFromCStr("the self argument")); 57 Object arg1(&scope, runtime_->newStrFromCStr("bar")); 58 EXPECT_TRUE(raisedWithStr(Interpreter::call2(thread_, function, arg0, arg1), 59 LayoutId::kTypeError, 60 "'foo' takes no arguments (1 given)")); 61} 62 63TEST_F(MethodTrampolinesTest, NoArgsKw) { 64 thread_->stackPush(newFunctionNoArgs(thread_)); 65 thread_->stackPush(runtime_->newStrFromCStr("the self argument")); 66 thread_->stackPush(runtime_->emptyTuple()); 67 EXPECT_TRUE(isIntEqualsWord(Interpreter::callKw(thread_, 1), 1230)); 68} 69 70TEST_F(MethodTrampolinesTest, NoArgsKwWithoutSelfRaisesTypeError) { 71 thread_->stackPush(newFunctionNoArgs(thread_)); 72 thread_->stackPush(runtime_->emptyTuple()); 73 EXPECT_TRUE(raisedWithStr(Interpreter::callKw(thread_, 0), 74 LayoutId::kTypeError, 75 "'foo' must be bound to an object")); 76} 77 78TEST_F(MethodTrampolinesTest, NoArgsKwWithTooManyArgsRaisesTypeError) { 79 thread_->stackPush(newFunctionNoArgs(thread_)); 80 thread_->stackPush(runtime_->newStrFromCStr("the self argument")); 81 thread_->stackPush(runtime_->newStrFromCStr("bar")); 82 thread_->stackPush(runtime_->emptyTuple()); 83 EXPECT_TRUE(raisedWithStr(Interpreter::callKw(thread_, 2), 84 LayoutId::kTypeError, 85 "'foo' takes no arguments (1 given)")); 86} 87 88TEST_F(MethodTrampolinesTest, NoArgsKwWithKeywordArgRaisesTypeError) { 89 HandleScope scope(thread_); 90 Object key(&scope, runtime_->newStrFromCStr("key")); 91 Tuple kw_names(&scope, runtime_->newTupleWith1(key)); 92 thread_->stackPush(newFunctionNoArgs(thread_)); 93 thread_->stackPush(runtime_->newStrFromCStr("the self argument")); 94 thread_->stackPush(runtime_->newStrFromCStr("value")); 95 thread_->stackPush(*kw_names); 96 EXPECT_TRUE(raisedWithStr(Interpreter::callKw(thread_, 2), 97 LayoutId::kTypeError, 98 "'foo' takes no keyword arguments")); 99} 100 101TEST_F(MethodTrampolinesTest, NoArgsExWithoutKwargs) { 102 HandleScope scope(thread_); 103 Object self(&scope, runtime_->newStrFromCStr("the self argument")); 104 Tuple args(&scope, runtime_->newTupleWith1(self)); 105 thread_->stackPush(newFunctionNoArgs(thread_)); 106 thread_->stackPush(*args); 107 EXPECT_TRUE(isIntEqualsWord(Interpreter::callEx(thread_, 0), 1230)); 108} 109 110TEST_F(MethodTrampolinesTest, NoArgsExWithKwargs) { 111 HandleScope scope(thread_); 112 Object self(&scope, runtime_->newStrFromCStr("the self argument")); 113 Tuple args(&scope, runtime_->newTupleWith1(self)); 114 thread_->stackPush(newFunctionNoArgs(thread_)); 115 thread_->stackPush(*args); 116 thread_->stackPush(runtime_->newDict()); 117 EXPECT_TRUE(isIntEqualsWord( 118 Interpreter::callEx(thread_, CallFunctionExFlag::VAR_KEYWORDS), 1230)); 119} 120 121TEST_F(MethodTrampolinesTest, NoArgsExWithoutSelfRaisesTypeError) { 122 thread_->stackPush(newFunctionNoArgs(thread_)); 123 thread_->stackPush(runtime_->emptyTuple()); 124 EXPECT_TRUE(raisedWithStr(Interpreter::callEx(thread_, 0), 125 LayoutId::kTypeError, 126 "'foo' must be bound to an object")); 127} 128 129TEST_F(MethodTrampolinesTest, NoArgsExWithArgRaisesTypeError) { 130 HandleScope scope(thread_); 131 Object self(&scope, runtime_->newStrFromCStr("the self argument")); 132 Object bar(&scope, runtime_->newStrFromCStr("bar")); 133 Object num(&scope, runtime_->newInt(88)); 134 Tuple args(&scope, runtime_->newTupleWith3(self, bar, num)); 135 thread_->stackPush(newFunctionNoArgs(thread_)); 136 thread_->stackPush(*args); 137 EXPECT_TRUE(raisedWithStr(Interpreter::callEx(thread_, 0), 138 LayoutId::kTypeError, 139 "'foo' takes no arguments (2 given)")); 140} 141 142TEST_F(MethodTrampolinesTest, NoArgsExWithKeywordArgRaisesTypeError) { 143 HandleScope scope(thread_); 144 Object self(&scope, runtime_->newStrFromCStr("the self argument")); 145 Tuple args(&scope, runtime_->newTupleWith1(self)); 146 Dict kwargs(&scope, runtime_->newDict()); 147 Object value(&scope, runtime_->newStrFromCStr("value")); 148 dictAtPutById(thread_, kwargs, ID(key), value); 149 thread_->stackPush(newFunctionNoArgs(thread_)); 150 thread_->stackPush(*args); 151 thread_->stackPush(*kwargs); 152 EXPECT_TRUE(raisedWithStr( 153 Interpreter::callEx(thread_, CallFunctionExFlag::VAR_KEYWORDS), 154 LayoutId::kTypeError, "'foo' takes no keyword arguments")); 155} 156 157static PyObject* capiFunctionOneArg(PyObject* self, PyObject* arg) { 158 Runtime* runtime = Thread::current()->runtime(); 159 runtime->collectGarbage(); 160 ApiHandle* handle = ApiHandle::fromPyObject(self); 161 EXPECT_GT(ApiHandle::refcnt(handle), 0); 162 EXPECT_TRUE(isStrEqualsCStr(ApiHandle::asObject(handle), "the self argument")); 163 ApiHandle* arg_handle = ApiHandle::fromPyObject(arg); 164 EXPECT_GT(ApiHandle::refcnt(arg_handle), 0); 165 EXPECT_TRUE(isFloatEqualsDouble(ApiHandle::asObject(arg_handle), 42.5)); 166 return ApiHandle::newReference(runtime, SmallInt::fromWord(1231)); 167} 168 169static RawObject newFunctionOneArg(Thread* thread) { 170 HandleScope scope(thread); 171 Runtime* runtime = thread->runtime(); 172 Object name(&scope, runtime->newStrFromCStr("foo")); 173 PyCFunction function_ptr = capiFunctionOneArg; 174 return newExtensionFunction(thread, name, 175 reinterpret_cast<void*>(function_ptr), METH_O); 176} 177 178TEST_F(MethodTrampolinesTest, OneArg) { 179 HandleScope scope(thread_); 180 Function function(&scope, newFunctionOneArg(thread_)); 181 Object arg0(&scope, runtime_->newStrFromCStr("the self argument")); 182 Object arg1(&scope, runtime_->newFloat(42.5)); 183 EXPECT_TRUE( 184 isIntEqualsWord(Interpreter::call2(thread_, function, arg0, arg1), 1231)); 185} 186 187TEST_F(MethodTrampolinesTest, OneArgWithoutSelfRaisesTypeError) { 188 HandleScope scope(thread_); 189 Function function(&scope, newFunctionOneArg(thread_)); 190 EXPECT_TRUE(raisedWithStr(Interpreter::call0(thread_, function), 191 LayoutId::kTypeError, 192 "'foo' must be bound to an object")); 193} 194 195TEST_F(MethodTrampolinesTest, OneArgWithTooManyArgsRaisesTypeError) { 196 HandleScope scope(thread_); 197 Function function(&scope, newFunctionOneArg(thread_)); 198 Object arg0(&scope, runtime_->newStrFromCStr("the self argument")); 199 Object arg1(&scope, runtime_->newFloat(42.5)); 200 Object arg2(&scope, runtime_->newInt(5)); 201 Object arg3(&scope, runtime_->newInt(7)); 202 EXPECT_TRUE(raisedWithStr( 203 Interpreter::call4(thread_, function, arg0, arg1, arg2, arg3), 204 LayoutId::kTypeError, "'foo' takes exactly one argument (3 given)")); 205} 206 207TEST_F(MethodTrampolinesTest, OneArgKw) { 208 thread_->stackPush(newFunctionOneArg(thread_)); 209 thread_->stackPush(runtime_->newStrFromCStr("the self argument")); 210 thread_->stackPush(runtime_->newFloat(42.5)); 211 thread_->stackPush(runtime_->emptyTuple()); 212 EXPECT_TRUE(isIntEqualsWord(Interpreter::callKw(thread_, 2), 1231)); 213} 214 215TEST_F(MethodTrampolinesTest, OneArgKwWithoutSelfRaisesTypeError) { 216 thread_->stackPush(newFunctionOneArg(thread_)); 217 thread_->stackPush(runtime_->emptyTuple()); 218 EXPECT_TRUE(raisedWithStr(Interpreter::callKw(thread_, 0), 219 LayoutId::kTypeError, 220 "'foo' must be bound to an object")); 221} 222 223TEST_F(MethodTrampolinesTest, OneArgKwWithTooManyArgsRaisesTypeError) { 224 thread_->stackPush(newFunctionOneArg(thread_)); 225 thread_->stackPush(runtime_->newStrFromCStr("the self argument")); 226 thread_->stackPush(runtime_->newFloat(42.5)); 227 thread_->stackPush(runtime_->newInt(5)); 228 thread_->stackPush(runtime_->emptyTuple()); 229 EXPECT_TRUE(raisedWithStr(Interpreter::callKw(thread_, 3), 230 LayoutId::kTypeError, 231 "'foo' takes exactly one argument (2 given)")); 232} 233 234TEST_F(MethodTrampolinesTest, OneArgKwWithKeywordArgRaisesTypeError) { 235 HandleScope scope(thread_); 236 Object key(&scope, runtime_->newStrFromCStr("key")); 237 Tuple kw_names(&scope, runtime_->newTupleWith1(key)); 238 thread_->stackPush(newFunctionOneArg(thread_)); 239 thread_->stackPush(runtime_->newFloat(42.5)); 240 thread_->stackPush(runtime_->newStrFromCStr("value")); 241 thread_->stackPush(*kw_names); 242 EXPECT_TRUE(raisedWithStr(Interpreter::callKw(thread_, 2), 243 LayoutId::kTypeError, 244 "'foo' takes no keyword arguments")); 245} 246 247TEST_F(MethodTrampolinesTest, OneArgExWithoutKwargs) { 248 HandleScope scope(thread_); 249 Object self(&scope, runtime_->newStrFromCStr("the self argument")); 250 Object num(&scope, runtime_->newFloat(42.5)); 251 Tuple args(&scope, runtime_->newTupleWith2(self, num)); 252 thread_->stackPush(newFunctionOneArg(thread_)); 253 thread_->stackPush(*args); 254 EXPECT_TRUE(isIntEqualsWord(Interpreter::callEx(thread_, 0), 1231)); 255} 256 257TEST_F(MethodTrampolinesTest, OneArgExWithKwargs) { 258 HandleScope scope(thread_); 259 Object self(&scope, runtime_->newStrFromCStr("the self argument")); 260 Object num(&scope, runtime_->newFloat(42.5)); 261 Tuple args(&scope, runtime_->newTupleWith2(self, num)); 262 thread_->stackPush(newFunctionOneArg(thread_)); 263 thread_->stackPush(*args); 264 thread_->stackPush(runtime_->newDict()); 265 EXPECT_TRUE(isIntEqualsWord( 266 Interpreter::callEx(thread_, CallFunctionExFlag::VAR_KEYWORDS), 1231)); 267} 268 269TEST_F(MethodTrampolinesTest, OneArgExWithoutSelfRaisesTypeError) { 270 thread_->stackPush(newFunctionOneArg(thread_)); 271 thread_->stackPush(runtime_->emptyTuple()); 272 EXPECT_TRUE(raisedWithStr(Interpreter::callEx(thread_, 0), 273 LayoutId::kTypeError, 274 "'foo' must be bound to an object")); 275} 276 277TEST_F(MethodTrampolinesTest, OneArgExWithTooFewArgsRaisesTypeError) { 278 HandleScope scope(thread_); 279 Object self(&scope, runtime_->newStrFromCStr("the self argument")); 280 Tuple args(&scope, runtime_->newTupleWith1(self)); 281 thread_->stackPush(newFunctionOneArg(thread_)); 282 thread_->stackPush(*args); 283 thread_->stackPush(runtime_->newDict()); 284 EXPECT_TRUE(raisedWithStr( 285 Interpreter::callEx(thread_, CallFunctionExFlag::VAR_KEYWORDS), 286 LayoutId::kTypeError, "'foo' takes exactly one argument (0 given)")); 287} 288 289TEST_F(MethodTrampolinesTest, OneArgExWithKeywordArgRaisesTypeError) { 290 HandleScope scope(thread_); 291 Object self(&scope, runtime_->newStrFromCStr("the self argument")); 292 Object num(&scope, runtime_->newFloat(42.5)); 293 Tuple args(&scope, runtime_->newTupleWith2(self, num)); 294 Dict kwargs(&scope, runtime_->newDict()); 295 Object value(&scope, runtime_->newStrFromCStr("value")); 296 dictAtPutById(thread_, kwargs, ID(key), value); 297 thread_->stackPush(newFunctionOneArg(thread_)); 298 thread_->stackPush(*args); 299 thread_->stackPush(*kwargs); 300 EXPECT_TRUE(raisedWithStr( 301 Interpreter::callEx(thread_, CallFunctionExFlag::VAR_KEYWORDS), 302 LayoutId::kTypeError, "'foo' takes no keyword arguments")); 303} 304 305static PyObject* capiFunctionVarArgs(PyObject* self, PyObject* args) { 306 Thread* thread = Thread::current(); 307 HandleScope scope(thread); 308 Runtime* runtime = thread->runtime(); 309 runtime->collectGarbage(); 310 ApiHandle* self_handle = ApiHandle::fromPyObject(self); 311 EXPECT_GT(ApiHandle::refcnt(self_handle), 0); 312 EXPECT_TRUE(isStrEqualsCStr(ApiHandle::asObject(self_handle), "the self argument")); 313 ApiHandle* args_handle = ApiHandle::fromPyObject(args); 314 EXPECT_GT(ApiHandle::refcnt(args_handle), 0); 315 Object args_obj(&scope, ApiHandle::asObject(args_handle)); 316 EXPECT_TRUE(args_obj.isTuple()); 317 Tuple args_tuple(&scope, *args_obj); 318 EXPECT_EQ(args_tuple.length(), 2); 319 EXPECT_TRUE(isIntEqualsWord(args_tuple.at(0), 88)); 320 EXPECT_TRUE(isIntEqualsWord(args_tuple.at(1), 33)); 321 return ApiHandle::newReference(runtime, SmallInt::fromWord(1239)); 322} 323 324static RawObject newFunctionVarArgs(Thread* thread) { 325 HandleScope scope(thread); 326 Runtime* runtime = thread->runtime(); 327 Object name(&scope, runtime->newStrFromCStr("foo")); 328 PyCFunction function_ptr = capiFunctionVarArgs; 329 return newExtensionFunction( 330 thread, name, reinterpret_cast<void*>(function_ptr), METH_VARARGS); 331} 332 333TEST_F(MethodTrampolinesTest, VarArgs) { 334 HandleScope scope(thread_); 335 Object function(&scope, newFunctionVarArgs(thread_)); 336 Object arg0(&scope, runtime_->newStrFromCStr("the self argument")); 337 Object arg1(&scope, runtime_->newInt(88)); 338 Object arg2(&scope, runtime_->newInt(33)); 339 EXPECT_TRUE(isIntEqualsWord( 340 Interpreter::call3(thread_, function, arg0, arg1, arg2), 1239)); 341} 342 343TEST_F(MethodTrampolinesTest, VarArgsWithoutSelfRaisesTypeError) { 344 HandleScope scope(thread_); 345 Object function(&scope, newFunctionVarArgs(thread_)); 346 EXPECT_TRUE(raisedWithStr(Interpreter::call0(thread_, function), 347 LayoutId::kTypeError, 348 "'foo' must be bound to an object")); 349} 350 351TEST_F(MethodTrampolinesTest, VarArgsKw) { 352 thread_->stackPush(newFunctionVarArgs(thread_)); 353 thread_->stackPush(runtime_->newStrFromCStr("the self argument")); 354 thread_->stackPush(runtime_->newInt(88)); 355 thread_->stackPush(runtime_->newInt(33)); 356 thread_->stackPush(runtime_->emptyTuple()); 357 EXPECT_TRUE(isIntEqualsWord(Interpreter::callKw(thread_, 3), 1239)); 358} 359 360TEST_F(MethodTrampolinesTest, VarArgsKwWithoutSelfRausesTypeError) { 361 thread_->stackPush(newFunctionVarArgs(thread_)); 362 thread_->stackPush(runtime_->emptyTuple()); 363 EXPECT_TRUE(raisedWithStr(Interpreter::callKw(thread_, 0), 364 LayoutId::kTypeError, 365 "'foo' must be bound to an object")); 366} 367 368TEST_F(MethodTrampolinesTest, VarArgsKwWithKeywordArgRausesTypeError) { 369 HandleScope scope(thread_); 370 Object key(&scope, runtime_->newStrFromCStr("key")); 371 Tuple kw_names(&scope, runtime_->newTupleWith1(key)); 372 thread_->stackPush(newFunctionVarArgs(thread_)); 373 thread_->stackPush(runtime_->newStrFromCStr("the self argument")); 374 thread_->stackPush(runtime_->newInt(88)); 375 thread_->stackPush(runtime_->newInt(33)); 376 thread_->stackPush(runtime_->newStrFromCStr("value")); 377 thread_->stackPush(*kw_names); 378 EXPECT_TRUE(raisedWithStr(Interpreter::callKw(thread_, 4), 379 LayoutId::kTypeError, 380 "'foo' takes no keyword arguments")); 381} 382 383TEST_F(MethodTrampolinesTest, VarArgsExWithoutKwargs) { 384 HandleScope scope(thread_); 385 Object self(&scope, runtime_->newStrFromCStr("the self argument")); 386 Object num1(&scope, runtime_->newInt(88)); 387 Object num2(&scope, runtime_->newInt(33)); 388 Tuple args(&scope, runtime_->newTupleWith3(self, num1, num2)); 389 thread_->stackPush(newFunctionVarArgs(thread_)); 390 thread_->stackPush(*args); 391 EXPECT_TRUE(isIntEqualsWord(Interpreter::callEx(thread_, 0), 1239)); 392} 393 394TEST_F(MethodTrampolinesTest, VarArgsExWithKwargs) { 395 HandleScope scope(thread_); 396 Object self(&scope, runtime_->newStrFromCStr("the self argument")); 397 Object num1(&scope, runtime_->newInt(88)); 398 Object num2(&scope, runtime_->newInt(33)); 399 Tuple args(&scope, runtime_->newTupleWith3(self, num1, num2)); 400 thread_->stackPush(newFunctionVarArgs(thread_)); 401 thread_->stackPush(*args); 402 thread_->stackPush(runtime_->newDict()); 403 EXPECT_TRUE(isIntEqualsWord( 404 Interpreter::callEx(thread_, CallFunctionExFlag::VAR_KEYWORDS), 1239)); 405} 406 407TEST_F(MethodTrampolinesTest, VarArgsExWithoutSelfRaisesTypeError) { 408 thread_->stackPush(newFunctionVarArgs(thread_)); 409 thread_->stackPush(runtime_->emptyTuple()); 410 EXPECT_TRUE(raisedWithStr(Interpreter::callEx(thread_, 0), 411 LayoutId::kTypeError, 412 "'foo' must be bound to an object")); 413} 414 415TEST_F(MethodTrampolinesTest, VarArgsExWithKeywordArgRaisesTypeError) { 416 HandleScope scope(thread_); 417 Object self(&scope, runtime_->newStrFromCStr("the self argument")); 418 Object num1(&scope, runtime_->newInt(88)); 419 Object num2(&scope, runtime_->newInt(33)); 420 Tuple args(&scope, runtime_->newTupleWith3(self, num1, num2)); 421 Dict kwargs(&scope, runtime_->newDict()); 422 Object value(&scope, runtime_->newStrFromCStr("value")); 423 dictAtPutById(thread_, kwargs, ID(key), value); 424 thread_->stackPush(newFunctionVarArgs(thread_)); 425 thread_->stackPush(*args); 426 thread_->stackPush(*kwargs); 427 EXPECT_TRUE(raisedWithStr( 428 Interpreter::callEx(thread_, CallFunctionExFlag::VAR_KEYWORDS), 429 LayoutId::kTypeError, "'foo' takes no keyword arguments")); 430} 431 432static PyObject* capiFunctionKeywordsNullKwargs(PyObject* self, PyObject* args, 433 PyObject* kwargs) { 434 Thread* thread = Thread::current(); 435 HandleScope scope(thread); 436 Runtime* runtime = thread->runtime(); 437 runtime->collectGarbage(); 438 ApiHandle* self_handle = ApiHandle::fromPyObject(self); 439 EXPECT_GT(ApiHandle::refcnt(self_handle), 0); 440 EXPECT_TRUE(isStrEqualsCStr(ApiHandle::asObject(self_handle), "the self argument")); 441 ApiHandle* args_handle = ApiHandle::fromPyObject(args); 442 EXPECT_GT(ApiHandle::refcnt(args_handle), 0); 443 Object args_obj(&scope, ApiHandle::asObject(args_handle)); 444 EXPECT_TRUE(args_obj.isTuple()); 445 Tuple args_tuple(&scope, *args_obj); 446 EXPECT_EQ(args_tuple.length(), 2); 447 EXPECT_TRUE(isIntEqualsWord(args_tuple.at(0), 17)); 448 EXPECT_TRUE(isIntEqualsWord(args_tuple.at(1), -8)); 449 EXPECT_EQ(kwargs, nullptr); 450 return ApiHandle::newReference(runtime, SmallInt::fromWord(1237)); 451} 452 453static RawObject newFunctionKeywordsNullKwargs(Thread* thread) { 454 HandleScope scope(thread); 455 Runtime* runtime = thread->runtime(); 456 Object name(&scope, runtime->newStrFromCStr("foo")); 457 PyCFunctionWithKeywords function_ptr = capiFunctionKeywordsNullKwargs; 458 return newExtensionFunction(thread, name, 459 reinterpret_cast<void*>(function_ptr), 460 METH_VARARGS | METH_KEYWORDS); 461} 462 463TEST_F(MethodTrampolinesTest, Keywords) { 464 HandleScope scope(thread_); 465 Object function(&scope, newFunctionKeywordsNullKwargs(thread_)); 466 Object arg0(&scope, runtime_->newStrFromCStr("the self argument")); 467 Object arg1(&scope, runtime_->newInt(17)); 468 Object arg2(&scope, runtime_->newInt(-8)); 469 EXPECT_TRUE(isIntEqualsWord( 470 Interpreter::call3(thread_, function, arg0, arg1, arg2), 1237)); 471} 472 473TEST_F(MethodTrampolinesTest, KeywordsWithoutSelfRaisesTypeError) { 474 HandleScope scope(thread_); 475 Object function(&scope, newFunctionKeywordsNullKwargs(thread_)); 476 EXPECT_TRUE(raisedWithStr(Interpreter::call0(thread_, function), 477 LayoutId::kTypeError, 478 "'foo' must be bound to an object")); 479} 480 481static PyObject* capiFunctionKeywords(PyObject* self, PyObject* args, 482 PyObject* kwargs) { 483 Thread* thread = Thread::current(); 484 HandleScope scope(thread); 485 Runtime* runtime = thread->runtime(); 486 runtime->collectGarbage(); 487 ApiHandle* self_handle = ApiHandle::fromPyObject(self); 488 EXPECT_GT(ApiHandle::refcnt(self_handle), 0); 489 EXPECT_TRUE(isStrEqualsCStr(ApiHandle::asObject(self_handle), "the self argument")); 490 ApiHandle* args_handle = ApiHandle::fromPyObject(args); 491 EXPECT_GT(ApiHandle::refcnt(args_handle), 0); 492 Object args_obj(&scope, ApiHandle::asObject(args_handle)); 493 EXPECT_TRUE(args_obj.isTuple()); 494 Tuple args_tuple(&scope, *args_obj); 495 EXPECT_EQ(args_tuple.length(), 2); 496 EXPECT_TRUE(isIntEqualsWord(args_tuple.at(0), 17)); 497 EXPECT_TRUE(isIntEqualsWord(args_tuple.at(1), -8)); 498 499 ApiHandle* kwargs_handle = ApiHandle::fromPyObject(kwargs); 500 EXPECT_GT(ApiHandle::refcnt(kwargs_handle), 0); 501 Object kwargs_obj(&scope, ApiHandle::asObject(kwargs_handle)); 502 EXPECT_TRUE(kwargs_obj.isDict()); 503 Dict kwargs_dict(&scope, *kwargs_obj); 504 EXPECT_EQ(kwargs_dict.numItems(), 1); 505 EXPECT_TRUE( 506 isStrEqualsCStr(dictAtById(thread, kwargs_dict, ID(key)), "value")); 507 return ApiHandle::newReference(runtime, SmallInt::fromWord(1237)); 508} 509 510static RawObject newFunctionKeywords(Thread* thread) { 511 HandleScope scope(thread); 512 Runtime* runtime = thread->runtime(); 513 Object name(&scope, runtime->newStrFromCStr("foo")); 514 PyCFunctionWithKeywords function_ptr = capiFunctionKeywords; 515 return newExtensionFunction(thread, name, 516 reinterpret_cast<void*>(function_ptr), 517 METH_VARARGS | METH_KEYWORDS); 518} 519 520TEST_F(MethodTrampolinesTest, KeywordsKw) { 521 HandleScope scope(thread_); 522 Object key(&scope, runtime_->newStrFromCStr("key")); 523 Tuple kw_names(&scope, runtime_->newTupleWith1(key)); 524 thread_->stackPush(newFunctionKeywords(thread_)); 525 thread_->stackPush(runtime_->newStrFromCStr("the self argument")); 526 thread_->stackPush(runtime_->newInt(17)); 527 thread_->stackPush(runtime_->newInt(-8)); 528 thread_->stackPush(runtime_->newStrFromCStr("value")); 529 thread_->stackPush(*kw_names); 530 EXPECT_TRUE(isIntEqualsWord(Interpreter::callKw(thread_, 4), 1237)); 531} 532 533TEST_F(MethodTrampolinesTest, KeywordsKwWithoutSelfRaisesTypeError) { 534 HandleScope scope(thread_); 535 Object key(&scope, runtime_->newStrFromCStr("key")); 536 Tuple kw_names(&scope, runtime_->newTupleWith1(key)); 537 thread_->stackPush(newFunctionKeywords(thread_)); 538 thread_->stackPush(runtime_->newStrFromCStr("value")); 539 thread_->stackPush(*kw_names); 540 EXPECT_TRUE(raisedWithStr(Interpreter::callKw(thread_, 1), 541 LayoutId::kTypeError, 542 "'foo' must be bound to an object")); 543} 544 545TEST_F(MethodTrampolinesTest, KeywordsExWithoutKwargs) { 546 HandleScope scope(thread_); 547 Object self(&scope, runtime_->newStrFromCStr("the self argument")); 548 Object num1(&scope, runtime_->newInt(17)); 549 Object num2(&scope, runtime_->newInt(-8)); 550 Tuple args(&scope, runtime_->newTupleWith3(self, num1, num2)); 551 thread_->stackPush(newFunctionKeywordsNullKwargs(thread_)); 552 thread_->stackPush(*args); 553 EXPECT_TRUE(isIntEqualsWord(Interpreter::callEx(thread_, 0), 1237)); 554} 555 556TEST_F(MethodTrampolinesTest, KeywordsExWithKwargs) { 557 HandleScope scope(thread_); 558 Object self(&scope, runtime_->newStrFromCStr("the self argument")); 559 Object num1(&scope, runtime_->newInt(17)); 560 Object num2(&scope, runtime_->newInt(-8)); 561 Tuple args(&scope, runtime_->newTupleWith3(self, num1, num2)); 562 Dict kwargs(&scope, runtime_->newDict()); 563 Object value(&scope, runtime_->newStrFromCStr("value")); 564 dictAtPutById(thread_, kwargs, ID(key), value); 565 thread_->stackPush(newFunctionKeywords(thread_)); 566 thread_->stackPush(*args); 567 thread_->stackPush(*kwargs); 568 EXPECT_TRUE(isIntEqualsWord( 569 Interpreter::callEx(thread_, CallFunctionExFlag::VAR_KEYWORDS), 1237)); 570} 571 572TEST_F(MethodTrampolinesTest, KeywordsExWithoutSelfRaisesTypeError) { 573 thread_->stackPush(newFunctionKeywordsNullKwargs(thread_)); 574 thread_->stackPush(runtime_->emptyTuple()); 575 EXPECT_TRUE(raisedWithStr(Interpreter::callEx(thread_, 0), 576 LayoutId::kTypeError, 577 "'foo' must be bound to an object")); 578} 579 580static PyObject* capiFunctionFast(PyObject* self, PyObject* const* args, 581 Py_ssize_t nargs) { 582 Runtime* runtime = Thread::current()->runtime(); 583 runtime->collectGarbage(); 584 ApiHandle* self_handle = ApiHandle::fromPyObject(self); 585 EXPECT_GT(ApiHandle::refcnt(self_handle), 0); 586 EXPECT_TRUE(isStrEqualsCStr(ApiHandle::asObject(ApiHandle::fromPyObject(self)), 587 "the self argument")); 588 EXPECT_EQ(nargs, 2); 589 ApiHandle* arg0_handle = ApiHandle::fromPyObject(args[0]); 590 EXPECT_GT(ApiHandle::refcnt(arg0_handle), 0); 591 ApiHandle* arg1_handle = ApiHandle::fromPyObject(args[1]); 592 EXPECT_GT(ApiHandle::refcnt(arg1_handle), 0); 593 EXPECT_TRUE(isFloatEqualsDouble(ApiHandle::asObject(arg0_handle), -13.)); 594 EXPECT_TRUE(isFloatEqualsDouble(ApiHandle::asObject(arg1_handle), 0.125)); 595 return ApiHandle::newReference(runtime, SmallInt::fromWord(1236)); 596} 597 598static RawObject newExtensionFunctionFast(Thread* thread) { 599 HandleScope scope(thread); 600 Runtime* runtime = thread->runtime(); 601 Object name(&scope, runtime->newStrFromCStr("foo")); 602 _PyCFunctionFast function_ptr = capiFunctionFast; 603 return newExtensionFunction( 604 thread, name, reinterpret_cast<void*>(function_ptr), METH_FASTCALL); 605} 606 607TEST_F(MethodTrampolinesTest, Fast) { 608 HandleScope scope(thread_); 609 Object function(&scope, newExtensionFunctionFast(thread_)); 610 Object arg0(&scope, runtime_->newStrFromCStr("the self argument")); 611 Object arg1(&scope, runtime_->newFloat(-13.)); 612 Object arg2(&scope, runtime_->newFloat(0.125)); 613 EXPECT_TRUE(isIntEqualsWord( 614 Interpreter::call3(thread_, function, arg0, arg1, arg2), 1236)); 615} 616 617TEST_F(MethodTrampolinesTest, FastWithoutSelfRaisesTypeError) { 618 HandleScope scope(thread_); 619 Object function(&scope, newExtensionFunctionFast(thread_)); 620 EXPECT_TRUE(raisedWithStr(Interpreter::call0(thread_, function), 621 LayoutId::kTypeError, 622 "'foo' must be bound to an object")); 623} 624 625TEST_F(MethodTrampolinesTest, FastKw) { 626 thread_->stackPush(newExtensionFunctionFast(thread_)); 627 thread_->stackPush(runtime_->newStrFromCStr("the self argument")); 628 thread_->stackPush(runtime_->newFloat(-13.)); 629 thread_->stackPush(runtime_->newFloat(0.125)); 630 thread_->stackPush(runtime_->emptyTuple()); 631 EXPECT_TRUE(isIntEqualsWord(Interpreter::callKw(thread_, 3), 1236)); 632} 633 634TEST_F(MethodTrampolinesTest, FastKwWithoutSelfRaisesTypeError) { 635 thread_->stackPush(newExtensionFunctionFast(thread_)); 636 thread_->stackPush(runtime_->emptyTuple()); 637 EXPECT_TRUE(raisedWithStr(Interpreter::callKw(thread_, 0), 638 LayoutId::kTypeError, 639 "'foo' must be bound to an object")); 640} 641 642TEST_F(MethodTrampolinesTest, FastKwWithKeywordRaisesTypeError) { 643 HandleScope scope(thread_); 644 Object key(&scope, runtime_->newStrFromCStr("key")); 645 Tuple kw_names(&scope, runtime_->newTupleWith1(key)); 646 thread_->stackPush(newExtensionFunctionFast(thread_)); 647 thread_->stackPush(runtime_->newStrFromCStr("the self argument")); 648 thread_->stackPush(runtime_->newFloat(-13.)); 649 thread_->stackPush(runtime_->newFloat(0.125)); 650 thread_->stackPush(runtime_->newStrFromCStr("value")); 651 thread_->stackPush(*kw_names); 652 EXPECT_TRUE(raisedWithStr(Interpreter::callKw(thread_, 4), 653 LayoutId::kTypeError, 654 "'foo' takes no keyword arguments")); 655} 656 657TEST_F(MethodTrampolinesTest, FastExWithoutKwargs) { 658 HandleScope scope(thread_); 659 Object self(&scope, runtime_->newStrFromCStr("the self argument")); 660 Object num1(&scope, runtime_->newFloat(-13.)); 661 Object num2(&scope, runtime_->newFloat(0.125)); 662 Tuple args(&scope, runtime_->newTupleWith3(self, num1, num2)); 663 thread_->stackPush(newExtensionFunctionFast(thread_)); 664 thread_->stackPush(*args); 665 EXPECT_TRUE(isIntEqualsWord(Interpreter::callEx(thread_, 0), 1236)); 666} 667 668TEST_F(MethodTrampolinesTest, FastExWithKwargs) { 669 HandleScope scope(thread_); 670 Object self(&scope, runtime_->newStrFromCStr("the self argument")); 671 Object num1(&scope, runtime_->newFloat(-13.)); 672 Object num2(&scope, runtime_->newFloat(0.125)); 673 Tuple args(&scope, runtime_->newTupleWith3(self, num1, num2)); 674 thread_->stackPush(newExtensionFunctionFast(thread_)); 675 thread_->stackPush(*args); 676 thread_->stackPush(runtime_->newDict()); 677 EXPECT_TRUE(isIntEqualsWord( 678 Interpreter::callEx(thread_, CallFunctionExFlag::VAR_KEYWORDS), 1236)); 679} 680 681TEST_F(MethodTrampolinesTest, FastExWithoutSelfRaisesTypeError) { 682 thread_->stackPush(newExtensionFunctionFast(thread_)); 683 thread_->stackPush(runtime_->emptyTuple()); 684 EXPECT_TRUE(raisedWithStr(Interpreter::callEx(thread_, 0), 685 LayoutId::kTypeError, 686 "'foo' must be bound to an object")); 687} 688 689TEST_F(MethodTrampolinesTest, FastExWithKeywordArgRaisesTypeError) { 690 HandleScope scope(thread_); 691 Object self(&scope, runtime_->newStrFromCStr("the self argument")); 692 Object num1(&scope, runtime_->newFloat(-13.)); 693 Object num2(&scope, runtime_->newFloat(0.125)); 694 Tuple args(&scope, runtime_->newTupleWith3(self, num1, num2)); 695 Dict kwargs(&scope, runtime_->newDict()); 696 Object value(&scope, runtime_->newStrFromCStr("value")); 697 dictAtPutById(thread_, kwargs, ID(key), value); 698 thread_->stackPush(newExtensionFunctionFast(thread_)); 699 thread_->stackPush(*args); 700 thread_->stackPush(*kwargs); 701 EXPECT_TRUE(raisedWithStr( 702 Interpreter::callEx(thread_, CallFunctionExFlag::VAR_KEYWORDS), 703 LayoutId::kTypeError, "'foo' takes no keyword arguments")); 704} 705 706static PyObject* capiFunctionFastWithKeywordsNullKwnames(PyObject* self, 707 PyObject* const* args, 708 Py_ssize_t nargs, 709 PyObject* kwnames) { 710 Runtime* runtime = Thread::current()->runtime(); 711 runtime->collectGarbage(); 712 ApiHandle* self_handle = ApiHandle::fromPyObject(self); 713 EXPECT_GT(ApiHandle::refcnt(self_handle), 0); 714 EXPECT_TRUE(isStrEqualsCStr(ApiHandle::asObject(ApiHandle::fromPyObject(self)), 715 "the self argument")); 716 EXPECT_EQ(nargs, 2); 717 ApiHandle* arg0_handle = ApiHandle::fromPyObject(args[0]); 718 EXPECT_GT(ApiHandle::refcnt(arg0_handle), 0); 719 ApiHandle* arg1_handle = ApiHandle::fromPyObject(args[1]); 720 EXPECT_GT(ApiHandle::refcnt(arg1_handle), 0); 721 EXPECT_TRUE(isFloatEqualsDouble(ApiHandle::asObject(arg0_handle), 42.5)); 722 EXPECT_TRUE(isFloatEqualsDouble(ApiHandle::asObject(arg1_handle), -8.8)); 723 EXPECT_EQ(kwnames, nullptr); 724 return ApiHandle::newReference(runtime, SmallInt::fromWord(1238)); 725} 726 727static RawObject newExtensionFunctionFastWithKeywordsNullKwnames( 728 Thread* thread) { 729 HandleScope scope(thread); 730 Runtime* runtime = thread->runtime(); 731 Object name(&scope, runtime->newStrFromCStr("foo")); 732 _PyCFunctionFastWithKeywords function_ptr = 733 capiFunctionFastWithKeywordsNullKwnames; 734 return newExtensionFunction(thread, name, 735 reinterpret_cast<void*>(function_ptr), 736 METH_FASTCALL | METH_KEYWORDS); 737} 738 739TEST_F(MethodTrampolinesTest, FastWithKeywords) { 740 HandleScope scope(thread_); 741 Object function(&scope, 742 newExtensionFunctionFastWithKeywordsNullKwnames(thread_)); 743 Object arg0(&scope, runtime_->newStrFromCStr("the self argument")); 744 Object arg1(&scope, runtime_->newFloat(42.5)); 745 Object arg2(&scope, runtime_->newFloat(-8.8)); 746 EXPECT_TRUE(isIntEqualsWord( 747 Interpreter::call3(thread_, function, arg0, arg1, arg2), 1238)); 748} 749 750TEST_F(MethodTrampolinesTest, FastWithKeywordsWithoutSelfRaisesTypeError) { 751 HandleScope scope(thread_); 752 Object function(&scope, 753 newExtensionFunctionFastWithKeywordsNullKwnames(thread_)); 754 EXPECT_TRUE(raisedWithStr(Interpreter::call0(thread_, function), 755 LayoutId::kTypeError, 756 "'foo' must be bound to an object")); 757} 758 759static PyObject* capiFunctionFastWithKeywords(PyObject* self, 760 PyObject* const* args, 761 Py_ssize_t nargs, 762 PyObject* kwnames) { 763 Thread* thread = Thread::current(); 764 HandleScope scope(thread); 765 Runtime* runtime = thread->runtime(); 766 runtime->collectGarbage(); 767 ApiHandle* self_handle = ApiHandle::fromPyObject(self); 768 EXPECT_GT(ApiHandle::refcnt(self_handle), 0); 769 EXPECT_TRUE(isStrEqualsCStr(ApiHandle::asObject(ApiHandle::fromPyObject(self)), 770 "the self argument")); 771 EXPECT_EQ(nargs, 2); 772 ApiHandle* arg0_handle = ApiHandle::fromPyObject(args[0]); 773 EXPECT_GT(ApiHandle::refcnt(arg0_handle), 0); 774 ApiHandle* arg1_handle = ApiHandle::fromPyObject(args[1]); 775 EXPECT_GT(ApiHandle::refcnt(arg1_handle), 0); 776 EXPECT_TRUE(isFloatEqualsDouble(ApiHandle::asObject(arg0_handle), 42.5)); 777 EXPECT_TRUE(isFloatEqualsDouble(ApiHandle::asObject(arg1_handle), -8.8)); 778 779 ApiHandle* kwnames_handle = ApiHandle::fromPyObject(kwnames); 780 EXPECT_GT(ApiHandle::refcnt(kwnames_handle), 0); 781 Object kwnames_obj(&scope, ApiHandle::asObject(kwnames_handle)); 782 EXPECT_TRUE(kwnames_obj.isTuple()); 783 Tuple kwnames_tuple(&scope, *kwnames_obj); 784 EXPECT_EQ(kwnames_tuple.length(), 2); 785 EXPECT_TRUE(isStrEqualsCStr(kwnames_tuple.at(0), "foo")); 786 EXPECT_TRUE(isStrEqualsCStr(kwnames_tuple.at(1), "bar")); 787 EXPECT_TRUE(isStrEqualsCStr(ApiHandle::asObject(ApiHandle::fromPyObject(args[2])), 788 "foo_value")); 789 EXPECT_TRUE(isStrEqualsCStr(ApiHandle::asObject(ApiHandle::fromPyObject(args[3])), 790 "bar_value")); 791 return ApiHandle::newReference(runtime, SmallInt::fromWord(1238)); 792} 793 794static RawObject newExtensionFunctionFastWithKeywords(Thread* thread) { 795 HandleScope scope(thread); 796 Runtime* runtime = thread->runtime(); 797 Object name(&scope, runtime->newStrFromCStr("foo")); 798 _PyCFunctionFastWithKeywords function_ptr = capiFunctionFastWithKeywords; 799 return newExtensionFunction(thread, name, 800 reinterpret_cast<void*>(function_ptr), 801 METH_FASTCALL | METH_KEYWORDS); 802} 803 804TEST_F(MethodTrampolinesTest, FastWithKeywordsKw) { 805 HandleScope scope(thread_); 806 Object foo(&scope, runtime_->newStrFromCStr("foo")); 807 Object bar(&scope, runtime_->newStrFromCStr("bar")); 808 Tuple kw_names(&scope, runtime_->newTupleWith2(foo, bar)); 809 thread_->stackPush(newExtensionFunctionFastWithKeywords(thread_)); 810 thread_->stackPush(runtime_->newStrFromCStr("the self argument")); 811 thread_->stackPush(runtime_->newFloat(42.5)); 812 thread_->stackPush(runtime_->newFloat(-8.8)); 813 thread_->stackPush(runtime_->newStrFromCStr("foo_value")); 814 thread_->stackPush(runtime_->newStrFromCStr("bar_value")); 815 thread_->stackPush(*kw_names); 816 EXPECT_TRUE(isIntEqualsWord(Interpreter::callKw(thread_, 5), 1238)); 817} 818 819TEST_F(MethodTrampolinesTest, FastWithKeywordsKwWihoutSelfRaisesTypeError) { 820 thread_->stackPush(newExtensionFunctionFastWithKeywords(thread_)); 821 thread_->stackPush(runtime_->emptyTuple()); 822 EXPECT_TRUE(raisedWithStr(Interpreter::callKw(thread_, 0), 823 LayoutId::kTypeError, 824 "'foo' must be bound to an object")); 825} 826 827TEST_F(MethodTrampolinesTest, FastWithKeywordsExWithoutKwargs) { 828 HandleScope scope(thread_); 829 Object self(&scope, runtime_->newStrFromCStr("the self argument")); 830 Object num1(&scope, runtime_->newFloat(42.5)); 831 Object num2(&scope, runtime_->newFloat(-8.8)); 832 Tuple args(&scope, runtime_->newTupleWith3(self, num1, num2)); 833 thread_->stackPush(newExtensionFunctionFastWithKeywordsNullKwnames(thread_)); 834 thread_->stackPush(*args); 835 EXPECT_TRUE(isIntEqualsWord(Interpreter::callEx(thread_, 0), 1238)); 836} 837 838TEST_F(MethodTrampolinesTest, FastWithKeywordsExWithKwargs) { 839 HandleScope scope(thread_); 840 Object self(&scope, runtime_->newStrFromCStr("the self argument")); 841 Object num1(&scope, runtime_->newFloat(42.5)); 842 Object num2(&scope, runtime_->newFloat(-8.8)); 843 Tuple args(&scope, runtime_->newTupleWith3(self, num1, num2)); 844 Dict kwargs(&scope, runtime_->newDict()); 845 Object foo(&scope, runtime_->newStrFromCStr("foo")); 846 Object foo_value(&scope, runtime_->newStrFromCStr("foo_value")); 847 dictAtPutByStr(thread_, kwargs, foo, foo_value); 848 Object bar(&scope, runtime_->newStrFromCStr("bar")); 849 Object bar_value(&scope, runtime_->newStrFromCStr("bar_value")); 850 dictAtPutByStr(thread_, kwargs, bar, bar_value); 851 thread_->stackPush(newExtensionFunctionFastWithKeywords(thread_)); 852 thread_->stackPush(*args); 853 thread_->stackPush(*kwargs); 854 EXPECT_TRUE(isIntEqualsWord( 855 Interpreter::callEx(thread_, CallFunctionExFlag::VAR_KEYWORDS), 1238)); 856} 857 858TEST_F(MethodTrampolinesTest, FastWithKeywordsExWithoutSelfRaisesTypeError) { 859 thread_->stackPush(newExtensionFunctionFastWithKeywords(thread_)); 860 thread_->stackPush(runtime_->emptyTuple()); 861 EXPECT_TRUE(raisedWithStr(Interpreter::callEx(thread_, 0), 862 LayoutId::kTypeError, 863 "'foo' must be bound to an object")); 864} 865 866} // namespace testing 867} // namespace py