this repo has no description
at trunk 970 lines 36 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "test-utils.h" 3 4#include <cmath> 5#include <cstdint> 6#include <cstring> 7#include <fstream> 8#include <functional> 9#include <iostream> 10#include <memory> 11#include <sstream> 12 13#include "attributedict.h" 14#include "builtins-module.h" 15#include "bytearray-builtins.h" 16#include "bytes-builtins.h" 17#include "compile-utils.h" 18#include "debugging.h" 19#include "exception-builtins.h" 20#include "frame.h" 21#include "handles.h" 22#include "ic.h" 23#include "int-builtins.h" 24#include "module-builtins.h" 25#include "modules.h" 26#include "os.h" 27#include "runtime.h" 28#include "set-builtins.h" 29#include "str-builtins.h" 30#include "sys-module.h" 31#include "thread.h" 32#include "type-builtins.h" 33#include "utils.h" 34 35namespace py { 36 37namespace testing { 38 39static RawObject initializeSysWithDefaults(Thread* thread) { 40 HandleScope scope(thread); 41 Runtime* runtime = thread->runtime(); 42 unique_c_ptr<char> path(OS::executablePath()); 43 Str executable(&scope, runtime->newStrFromCStr(path.get())); 44 List python_path(&scope, runtime->newList()); 45 MutableTuple data( 46 &scope, runtime->newMutableTuple(static_cast<word>(SysFlag::kNumFlags))); 47 data.atPut(static_cast<word>(SysFlag::kDebug), SmallInt::fromWord(0)); 48 data.atPut(static_cast<word>(SysFlag::kInspect), SmallInt::fromWord(0)); 49 data.atPut(static_cast<word>(SysFlag::kInteractive), SmallInt::fromWord(0)); 50 data.atPut(static_cast<word>(SysFlag::kOptimize), SmallInt::fromWord(0)); 51 data.atPut(static_cast<word>(SysFlag::kDontWriteBytecode), 52 SmallInt::fromWord(0)); 53 data.atPut(static_cast<word>(SysFlag::kNoUserSite), SmallInt::fromWord(1)); 54 data.atPut(static_cast<word>(SysFlag::kNoSite), SmallInt::fromWord(1)); 55 data.atPut(static_cast<word>(SysFlag::kIgnoreEnvironment), 56 SmallInt::fromWord(1)); 57 data.atPut(static_cast<word>(SysFlag::kVerbose), SmallInt::fromWord(0)); 58 data.atPut(static_cast<word>(SysFlag::kBytesWarning), SmallInt::fromWord(0)); 59 data.atPut(static_cast<word>(SysFlag::kQuiet), SmallInt::fromWord(0)); 60 data.atPut(static_cast<word>(SysFlag::kHashRandomization), 61 SmallInt::fromWord(1)); 62 data.atPut(static_cast<word>(SysFlag::kIsolated), SmallInt::fromWord(0)); 63 data.atPut(static_cast<word>(SysFlag::kDevMode), Bool::falseObj()); 64 data.atPut(static_cast<word>(SysFlag::kUTF8Mode), SmallInt::fromWord(1)); 65 static_assert(static_cast<word>(SysFlag::kNumFlags) == 15, 66 "unexpected flag count"); 67 Tuple flags_data(&scope, data.becomeImmutable()); 68 List warnoptions(&scope, runtime->newList()); 69 return initializeSys(thread, executable, python_path, flags_data, warnoptions, 70 /*extend_python_path_with_stdlib=*/true); 71} 72 73bool useCppInterpreter() { 74 const char* pyro_cpp_interpreter = std::getenv("PYRO_CPP_INTERPRETER"); 75 return pyro_cpp_interpreter != nullptr && 76 ::strcmp(pyro_cpp_interpreter, "1") == 0; 77} 78 79Runtime* createTestRuntime() { 80 bool use_cpp_interpreter = useCppInterpreter(); 81 word heap_size = 128 * kMiB; 82 Interpreter* interpreter = 83 use_cpp_interpreter ? createCppInterpreter() : createAsmInterpreter(); 84 RandomState random_state = randomState(); 85 Runtime* runtime = 86 new Runtime(heap_size, interpreter, random_state, StdioState::kBuffered); 87 Thread* thread = Thread::current(); 88 CHECK(initializeSysWithDefaults(thread).isNoneType(), 89 "initializeSys() failed"); 90 CHECK(runtime->initialize(thread).isNoneType(), 91 "Runtime::initialize() failed"); 92 return runtime; 93} 94 95Value::Type Value::type() const { return type_; } 96 97bool Value::boolVal() const { 98 DCHECK(type() == Type::Bool, "expected bool"); 99 return bool_; 100} 101 102word Value::intVal() const { 103 DCHECK(type() == Type::Int, "expected int"); 104 return int_; 105} 106 107double Value::floatVal() const { 108 DCHECK(type() == Type::Float, "expected float"); 109 return float_; 110} 111 112const char* Value::strVal() const { 113 DCHECK(type() == Type::Str, "expected str"); 114 return str_; 115} 116 117template <typename T1, typename T2> 118::testing::AssertionResult badListValue(const char* actual_expr, word i, 119 const T1& actual, const T2& expected) { 120 return ::testing::AssertionFailure() 121 << "Value of: " << actual_expr << '[' << i << "]\n" 122 << " Actual: " << actual << '\n' 123 << "Expected: " << expected; 124} 125 126::testing::AssertionResult AssertPyListEqual( 127 const char* actual_expr, const char* /* expected_expr */, 128 const Object& actual, const std::vector<Value>& expected) { 129 Thread* thread = Thread::current(); 130 Runtime* runtime = thread->runtime(); 131 132 if (!actual.isList()) { 133 return ::testing::AssertionFailure() 134 << " Type of: " << actual_expr << "\n" 135 << " Actual: " << typeName(runtime, *actual) << "\n" 136 << "Expected: list"; 137 } 138 139 HandleScope scope(thread); 140 List list(&scope, *actual); 141 if (static_cast<size_t>(list.numItems()) != expected.size()) { 142 return ::testing::AssertionFailure() 143 << "Length of: " << actual_expr << "\n" 144 << " Actual: " << list.numItems() << "\n" 145 << " Expected: " << expected.size(); 146 } 147 148 for (size_t i = 0; i < expected.size(); i++) { 149 Object actual_item(&scope, list.at(i)); 150 const Value& expected_item = expected[i]; 151 152 auto bad_type = [&](const char* expected_type) { 153 return ::testing::AssertionFailure() 154 << " Type of: " << actual_expr << '[' << i << "]\n" 155 << " Actual: " << typeName(runtime, *actual_item) << '\n' 156 << "Expected: " << expected_type; 157 }; 158 159 switch (expected_item.type()) { 160 case Value::Type::None: { 161 if (!actual_item.isNoneType()) return bad_type("RawNoneType"); 162 break; 163 } 164 165 case Value::Type::Bool: { 166 if (!actual_item.isBool()) return bad_type("bool"); 167 auto const actual_val = Bool::cast(*actual_item) == Bool::trueObj(); 168 auto const expected_val = expected_item.boolVal(); 169 if (actual_val != expected_val) { 170 return badListValue(actual_expr, i, actual_val ? "True" : "False", 171 expected_val ? "True" : "False"); 172 } 173 break; 174 } 175 176 case Value::Type::Int: { 177 if (!actual_item.isInt()) return bad_type("int"); 178 Int actual_val(&scope, *actual_item); 179 Int expected_val(&scope, runtime->newInt(expected_item.intVal())); 180 if (actual_val.compare(*expected_val) != 0) { 181 // TODO(bsimmers): Support multi-digit values when we can print them. 182 return badListValue(actual_expr, i, actual_val.digitAt(0), 183 expected_item.intVal()); 184 } 185 break; 186 } 187 188 case Value::Type::Float: { 189 if (!actual_item.isFloat()) return bad_type("float"); 190 auto const actual_val = Float::cast(*actual_item).value(); 191 auto const expected_val = expected_item.floatVal(); 192 if (std::abs(actual_val - expected_val) >= DBL_EPSILON) { 193 return badListValue(actual_expr, i, actual_val, expected_val); 194 } 195 break; 196 } 197 198 case Value::Type::Str: { 199 if (!actual_item.isStr()) return bad_type("str"); 200 Str actual_val(&scope, *actual_item); 201 const char* expected_val = expected_item.strVal(); 202 if (!actual_val.equalsCStr(expected_val)) { 203 return badListValue(actual_expr, i, actual_val, expected_val); 204 } 205 break; 206 } 207 } 208 } 209 210 return ::testing::AssertionSuccess(); 211} 212 213RawObject callFunction(const Function& func, const Tuple& args) { 214 Thread* thread = Thread::current(); 215 thread->stackPush(*func); 216 word args_length = args.length(); 217 for (word i = 0; i < args_length; i++) { 218 thread->stackPush(args.at(i)); 219 } 220 return Interpreter::call(thread, args_length); 221} 222 223bool tupleContains(const Tuple& object_array, const Object& key) { 224 for (word i = 0; i < object_array.length(); i++) { 225 if (object_array.at(i) == *key) { 226 return true; 227 } 228 } 229 return false; 230} 231 232bool listContains(const Object& list_obj, const Object& key) { 233 Thread* thread = Thread::current(); 234 HandleScope scope(thread); 235 if (!thread->runtime()->isInstanceOfList(*list_obj)) { 236 return false; 237 } 238 List list(&scope, *list_obj); 239 for (word i = 0, num_items = list.numItems(); i < num_items; i++) { 240 if (list.at(i) == *key) { 241 return true; 242 } 243 } 244 return false; 245} 246 247bool setIncludes(Thread* thread, const SetBase& set, const Object& key) { 248 HandleScope scope(thread); 249 Object hash_obj(&scope, Interpreter::hash(thread, key)); 250 CHECK(hash_obj.isSmallInt(), "key must be hashable"); 251 word hash = SmallInt::cast(*hash_obj).value(); 252 return setIncludes(thread, set, key, hash); 253} 254 255void setHashAndAdd(Thread* thread, const SetBase& set, const Object& value) { 256 HandleScope scope(thread); 257 Object hash_obj(&scope, Interpreter::hash(thread, value)); 258 CHECK(hash_obj.isSmallInt(), "value must be hashable"); 259 word hash = SmallInt::cast(*hash_obj).value(); 260 setAdd(thread, set, value, hash); 261} 262 263static RawObject findModuleByCStr(Runtime* runtime, const char* name) { 264 HandleScope scope(Thread::current()); 265 Object key(&scope, runtime->newStrFromCStr(name)); 266 return runtime->findModule(key); 267} 268 269RawObject findMainModule(Runtime* runtime) { 270 return findModuleByCStr(runtime, "__main__"); 271} 272 273RawObject mainModuleAt(Runtime* runtime, const char* name) { 274 return moduleAtByCStr(runtime, "__main__", name); 275} 276 277RawObject moduleAtByCStr(Runtime* runtime, const char* module_name, 278 const char* name) { 279 Thread* thread = Thread::current(); 280 HandleScope scope(thread); 281 Object mod_obj(&scope, findModuleByCStr(runtime, module_name)); 282 if (mod_obj.isNoneType()) { 283 return Error::notFound(); 284 } 285 Module module(&scope, *mod_obj); 286 Object name_obj(&scope, Runtime::internStrFromCStr(thread, name)); 287 return moduleAt(module, name_obj); 288} 289 290std::string typeName(Runtime* runtime, RawObject obj) { 291 if (obj.layoutId() == LayoutId::kError) return "Error"; 292 RawStr name = Str::cast(Type::cast(runtime->typeOf(obj)).name()); 293 word length = name.length(); 294 std::string result(length, '\0'); 295 name.copyTo(reinterpret_cast<byte*>(&result[0]), length); 296 return result; 297} 298 299RawObject typeValueCellAt(RawType type, RawObject name) { 300 RawObject result = NoneType::object(); 301 if (!attributeValueCellAt(type, name, &result)) return Error::notFound(); 302 return result; 303} 304 305static RawCode newCodeHelper(Thread* thread, View<byte> bytes, 306 const Tuple& consts, const Tuple& names, 307 Locals* locals, word flags) { 308 HandleScope scope(thread); 309 Runtime* runtime = thread->runtime(); 310 word argcount = 0; 311 word posonlyargcount = 0; 312 word kwonlyargcount = 0; 313 word nlocals = 0; 314 word stacksize = 20; 315 Tuple varnames_tuple(&scope, runtime->emptyTuple()); 316 if (locals != nullptr) { 317 argcount = locals->argcount; 318 posonlyargcount = locals->posonlyargcount; 319 kwonlyargcount = locals->kwonlyargcount; 320 nlocals = argcount + kwonlyargcount + locals->varcount; 321 if (locals->varargs) { 322 nlocals++; 323 flags |= Code::Flags::kVarargs; 324 } 325 if (locals->varkeyargs) { 326 nlocals++; 327 flags |= Code::Flags::kVarkeyargs; 328 } 329 MutableTuple varnames(&scope, runtime->newMutableTuple(nlocals)); 330 word idx = 0; 331 for (word i = 0; i < locals->argcount; i++) { 332 varnames.atPut(idx++, runtime->newStrFromFmt("arg%w", i)); 333 } 334 if (locals->varargs) { 335 varnames.atPut(idx++, runtime->newStrFromCStr("args")); 336 } 337 if (locals->varkeyargs) { 338 varnames.atPut(idx++, runtime->newStrFromCStr("kwargs")); 339 } 340 for (word i = 0; i < locals->varcount; i++) { 341 varnames.atPut(idx++, runtime->newStrFromFmt("var%w", i)); 342 } 343 CHECK(idx == nlocals, "local count mismatch"); 344 varnames_tuple = varnames.becomeImmutable(); 345 } 346 347 Bytes code(&scope, runtime->newBytesWithAll(bytes)); 348 Tuple empty_tuple(&scope, runtime->emptyTuple()); 349 Object empty_string(&scope, Str::empty()); 350 Object empty_bytes(&scope, Bytes::empty()); 351 return Code::cast(runtime->newCode(/*argcount=*/argcount, 352 /*posonlyargcount=*/posonlyargcount, 353 /*kwonlyargcount=*/kwonlyargcount, 354 /*nlocals=*/nlocals, 355 /*stacksize=*/stacksize, 356 /*flags=*/flags, code, consts, names, 357 varnames_tuple, 358 /*freevars=*/empty_tuple, 359 /*cellvars=*/empty_tuple, 360 /*filename=*/empty_string, 361 /*name=*/empty_string, 362 /*firstlineno=*/0, 363 /*lnotab=*/empty_bytes)); 364} 365 366RawCode newCodeWithBytesConstsNames(View<byte> bytes, const Tuple& consts, 367 const Tuple& names) { 368 Thread* thread = Thread::current(); 369 word flags = Code::Flags::kOptimized | Code::Flags::kNewlocals; 370 return newCodeHelper(thread, bytes, consts, names, /*locals=*/nullptr, flags); 371} 372 373RawCode newCodeWithBytesConstsNamesFlags(View<byte> bytes, const Tuple& consts, 374 const Tuple& names, word flags) { 375 Thread* thread = Thread::current(); 376 return newCodeHelper(thread, bytes, consts, names, /*locals=*/nullptr, flags); 377} 378 379RawCode newCodeWithBytesConstsNamesLocals(View<byte> bytes, const Tuple& consts, 380 const Tuple& names, Locals* locals) { 381 Thread* thread = Thread::current(); 382 word flags = Code::Flags::kOptimized | Code::Flags::kNewlocals; 383 return newCodeHelper(thread, bytes, consts, names, locals, flags); 384} 385 386RawCode newCodeWithBytesConsts(View<byte> bytes, const Tuple& consts) { 387 Thread* thread = Thread::current(); 388 HandleScope scope(thread); 389 Tuple names(&scope, thread->runtime()->emptyTuple()); 390 return newCodeWithBytesConstsNames(bytes, consts, names); 391} 392 393RawCode newCodeWithBytes(View<byte> bytes) { 394 Thread* thread = Thread::current(); 395 HandleScope scope(thread); 396 Tuple consts(&scope, thread->runtime()->emptyTuple()); 397 return newCodeWithBytesConsts(bytes, consts); 398} 399 400RawFunction newEmptyFunction() { 401 Thread* thread = Thread::current(); 402 HandleScope scope(thread); 403 Runtime* runtime = thread->runtime(); 404 Code code(&scope, newCodeWithBytes(View<byte>(nullptr, 0))); 405 Object qualname(&scope, Str::empty()); 406 Module main(&scope, findMainModule(runtime)); 407 return Function::cast( 408 runtime->newFunctionWithCode(thread, qualname, code, main)); 409} 410 411RawBytes newBytesFromCStr(Thread* thread, const char* str) { 412 return Bytes::cast(thread->runtime()->newBytesWithAll( 413 View<byte>(reinterpret_cast<const byte*>(str), std::strlen(str)))); 414} 415 416RawBytearray newBytearrayFromCStr(Thread* thread, const char* str) { 417 HandleScope scope(thread); 418 Runtime* runtime = thread->runtime(); 419 Bytearray result(&scope, runtime->newBytearray()); 420 runtime->bytearrayExtend( 421 thread, result, 422 View<byte>(reinterpret_cast<const byte*>(str), std::strlen(str))); 423 return *result; 424} 425 426RawLargeInt newLargeIntWithDigits(View<uword> digits) { 427 Thread* thread = Thread::current(); 428 HandleScope scope(thread); 429 LargeInt result(&scope, thread->runtime()->createLargeInt(digits.length())); 430 for (word i = 0, e = digits.length(); i < e; ++i) { 431 result.digitAtPut(i, digits.get(i)); 432 } 433 return *result; 434} 435 436RawObject newMemoryView(View<byte> bytes, const char* format, 437 ReadOnly read_only) { 438 Thread* thread = Thread::current(); 439 HandleScope scope(thread); 440 Runtime* runtime = thread->runtime(); 441 Bytes bytes_obj(&scope, runtime->newBytesWithAll(bytes)); 442 if (read_only == ReadOnly::ReadWrite) { 443 bytes_obj = runtime->mutableBytesFromBytes(thread, bytes_obj); 444 } 445 MemoryView result(&scope, 446 runtime->newMemoryView(thread, bytes_obj, bytes_obj, 447 bytes_obj.length(), read_only)); 448 result.setFormat(Str::cast(runtime->newStrFromCStr(format))); 449 return *result; 450} 451 452RawTuple newTupleWithNone(word length) { 453 Thread* thread = Thread::current(); 454 HandleScope scope(thread); 455 MutableTuple tuple(&scope, thread->runtime()->newMutableTuple(length)); 456 tuple.fill(NoneType::object()); 457 return Tuple::cast(tuple.becomeImmutable()); 458} 459 460RawObject newWeakRefWithCallback(Runtime* runtime, Thread* thread, 461 const Object& referent, 462 const Object& callback) { 463 HandleScope scope(thread); 464 WeakRef ref(&scope, runtime->newWeakRef(thread, referent)); 465 ref.setCallback(runtime->newBoundMethod(callback, ref)); 466 return *ref; 467} 468 469RawObject setFromRange(word start, word stop) { 470 Thread* thread = Thread::current(); 471 HandleScope scope(thread); 472 Set result(&scope, thread->runtime()->newSet()); 473 Object value(&scope, NoneType::object()); 474 Object hash_obj(&scope, NoneType::object()); 475 for (word i = start; i < stop; i++) { 476 value = SmallInt::fromWord(i); 477 hash_obj = Interpreter::hash(thread, value); 478 if (hash_obj.isErrorException()) return *hash_obj; 479 word hash = SmallInt::cast(*hash_obj).value(); 480 setAdd(thread, result, value, hash); 481 } 482 return *result; 483} 484 485RawObject runBuiltinImpl(BuiltinFunction function, 486 View<std::reference_wrapper<const Object>> args) { 487 Thread* thread = Thread::current(); 488 HandleScope scope(thread); 489 // Push an empty function so we have one at the expected place in the stack. 490 word args_length = args.length(); 491 Runtime* runtime = thread->runtime(); 492 Tuple parameter_names(&scope, runtime->emptyTuple()); 493 if (args_length > 0) { 494 MutableTuple parameter_names_mut(&scope, 495 runtime->newMutableTuple(args_length)); 496 for (word i = 0; i < args_length; i++) { 497 parameter_names_mut.atPut(i, runtime->newStrFromFmt("arg%w", i)); 498 } 499 parameter_names = parameter_names_mut.becomeImmutable(); 500 } 501 502 Object name(&scope, Runtime::internStrFromCStr(thread, "<anonymous>")); 503 Code code(&scope, runtime->newBuiltinCode(args_length, /*posonlyargcount=*/0, 504 /*kwonlyargcount=*/0, 505 /*flags=*/0, function, 506 parameter_names, name)); 507 Module main(&scope, findMainModule(runtime)); 508 Function function_obj(&scope, 509 runtime->newFunctionWithCode(thread, name, code, main)); 510 511 thread->stackPush(*function_obj); 512 for (word i = 0; i < args_length; i++) { 513 thread->stackPush(*args.get(i).get()); 514 } 515 return Interpreter::call(thread, args_length); 516} 517 518RawObject runBuiltin(BuiltinFunction function) { 519 return runBuiltinImpl(function, 520 View<std::reference_wrapper<const Object>>{nullptr, 0}); 521} 522 523RawObject runCode(const Code& code) { 524 Thread* thread = Thread::current(); 525 HandleScope scope(thread); 526 Runtime* runtime = thread->runtime(); 527 Module main(&scope, findMainModule(runtime)); 528 Object qualname(&scope, Runtime::internStrFromCStr(thread, "<anonymous>")); 529 Function function(&scope, 530 runtime->newFunctionWithCode(thread, qualname, code, main)); 531 return Interpreter::call0(thread, function); 532} 533 534RawObject runCodeNoBytecodeRewriting(const Code& code) { 535 Thread* thread = Thread::current(); 536 HandleScope scope(thread); 537 Runtime* runtime = thread->runtime(); 538 Module main(&scope, findMainModule(runtime)); 539 Object qualname(&scope, Runtime::internStrFromCStr(thread, "<anonymous>")); 540 Bytes bytecode(&scope, code.code()); 541 code.setCode(runtime->newBytes(0, 0)); 542 543 Function function(&scope, 544 runtime->newFunctionWithCode(thread, qualname, code, main)); 545 MutableBytes rewritten_bytecode( 546 &scope, runtime->newMutableBytesUninitialized(bytecode.length())); 547 rewritten_bytecode.replaceFromWithBytes(0, *bytecode, bytecode.length()); 548 function.setRewrittenBytecode(*rewritten_bytecode); 549 return Interpreter::call0(thread, function); 550} 551 552RawObject runFromCStr(Runtime* runtime, const char* c_str) { 553 Thread* thread = Thread::current(); 554 HandleScope scope(thread); 555 Object str(&scope, runtime->newStrFromCStr(c_str)); 556 Object filename(&scope, runtime->newStrFromCStr("<test string>")); 557 Code code(&scope, compile(thread, str, filename, ID(exec), /*flags=*/0, 558 /*optimize=*/0)); 559 Module main_module(&scope, findMainModule(runtime)); 560 Object result(&scope, executeModule(thread, code, main_module)); 561 562 // Barebones emulation of the top-level SystemExit handling, to allow for 563 // testing of handleSystemExit(). 564 DCHECK(thread->isErrorValueOk(*result), "error/exception mismatch"); 565 if (result.isError()) { 566 Type type(&scope, thread->pendingExceptionType()); 567 if (type.builtinBase() == LayoutId::kSystemExit) handleSystemExit(thread); 568 } 569 return *result; 570} 571 572void addBuiltin(const char* name_cstr, BuiltinFunction function, 573 View<const char*> parameter_names, word flags) { 574 Thread* thread = Thread::current(); 575 Runtime* runtime = thread->runtime(); 576 HandleScope scope(thread); 577 Module main(&scope, findMainModule(runtime)); 578 word num_parameters = parameter_names.length(); 579 Object parameter_names_tuple(&scope, NoneType::object()); 580 if (num_parameters > 0) { 581 MutableTuple parameter_names_mtuple( 582 &scope, runtime->newMutableTuple(num_parameters)); 583 for (word i = 0; i < num_parameters; i++) { 584 parameter_names_mtuple.atPut( 585 i, Runtime::internStrFromCStr(thread, parameter_names.get(i))); 586 } 587 parameter_names_tuple = parameter_names_mtuple.becomeImmutable(); 588 } else { 589 parameter_names_tuple = runtime->emptyTuple(); 590 } 591 Object name(&scope, Runtime::internStrFromCStr(thread, name_cstr)); 592 word argcount = num_parameters - ((flags & Code::Flags::kVarargs) != 0) - 593 ((flags & Code::Flags::kVarkeyargs) != 0); 594 Code code(&scope, runtime->newBuiltinCode( 595 /*argcount=*/argcount, /*posonlyargcount=*/0, 596 /*kwonlyargcount=*/0, flags, function, 597 /*parameter_names=*/parameter_names_tuple, name)); 598 Function function_obj(&scope, 599 runtime->newFunctionWithCode(thread, name, code, main)); 600 moduleAtPut(thread, main, name, function_obj); 601} 602 603// Equivalent to evaluating "list(range(start, stop))" in Python 604RawObject listFromRange(word start, word stop) { 605 Thread* thread = Thread::current(); 606 HandleScope scope(thread); 607 List result(&scope, thread->runtime()->newList()); 608 Object value(&scope, NoneType::object()); 609 for (word i = start; i < stop; i++) { 610 value = SmallInt::fromWord(i); 611 thread->runtime()->listAdd(thread, result, value); 612 } 613 return *result; 614} 615 616RawObject icLookupAttr(RawMutableTuple caches, word index, LayoutId layout_id) { 617 word i = index * kIcPointersPerEntry; 618 bool is_found = false; 619 if (caches.at(i + kIcEntryValueOffset).isTuple()) { 620 return icLookupPolymorphic(caches, index, layout_id, &is_found); 621 } 622 return icLookupMonomorphic(caches, index, layout_id, &is_found); 623} 624 625RawObject icLookupBinaryOp(RawMutableTuple caches, word index, 626 LayoutId left_layout_id, LayoutId right_layout_id, 627 BinaryOpFlags* flags_out) { 628 word i = index * kIcPointersPerEntry; 629 if (caches.at(i + kIcEntryValueOffset).isTuple()) { 630 return icLookupBinOpPolymorphic(caches, index, left_layout_id, 631 right_layout_id, flags_out); 632 } 633 return icLookupBinOpMonomorphic(caches, index, left_layout_id, 634 right_layout_id, flags_out); 635} 636 637::testing::AssertionResult containsBytecode(const Function& function, 638 Bytecode bc) { 639 Thread* thread = Thread::current(); 640 HandleScope scope(thread); 641 MutableBytes bytecode(&scope, function.rewrittenBytecode()); 642 for (word i = 0, num_opcodes = rewrittenBytecodeLength(bytecode); 643 i < num_opcodes;) { 644 BytecodeOp bco = nextBytecodeOp(bytecode, &i); 645 if (bco.bc == bc) { 646 return ::testing::AssertionSuccess(); 647 } 648 } 649 unique_c_ptr<char> name(Str::cast(function.name()).toCStr()); 650 return ::testing::AssertionFailure() 651 << "opcode " << kBytecodeNames[static_cast<word>(bc)] 652 << " not found in '" << name.get() << "'"; 653} 654 655::testing::AssertionResult isBytearrayEqualsBytes(const Object& result, 656 View<byte> expected) { 657 Thread* thread = Thread::current(); 658 HandleScope scope(thread); 659 Runtime* runtime = thread->runtime(); 660 if (result.isError()) { 661 if (result.isErrorException()) { 662 Type type(&scope, thread->pendingExceptionType()); 663 unique_c_ptr<char> name(Str::cast(type.name()).toCStr()); 664 return ::testing::AssertionFailure() 665 << "pending '" << name.get() << "' exception"; 666 } 667 return ::testing::AssertionFailure() << "is an " << result; 668 } 669 if (!runtime->isInstanceOfBytearray(*result)) { 670 return ::testing::AssertionFailure() 671 << "is a '" << typeName(runtime, *result) << "'"; 672 } 673 Bytearray result_array(&scope, *result); 674 Bytes result_bytes(&scope, bytearrayAsBytes(thread, result_array)); 675 Bytes expected_bytes(&scope, runtime->newBytesWithAll(expected)); 676 if (result_bytes.compare(*expected_bytes) != 0) { 677 return ::testing::AssertionFailure() 678 << "bytearray(" << result_bytes << ") is not equal to bytearray(" 679 << expected_bytes << ")"; 680 } 681 return ::testing::AssertionSuccess(); 682} 683 684::testing::AssertionResult isBytearrayEqualsCStr(const Object& result, 685 const char* expected) { 686 return isBytearrayEqualsBytes( 687 result, View<byte>(reinterpret_cast<const byte*>(expected), 688 static_cast<word>(std::strlen(expected)))); 689} 690 691::testing::AssertionResult isBytesEqualsBytes(const Object& result, 692 View<byte> expected) { 693 Thread* thread = Thread::current(); 694 HandleScope scope(thread); 695 Runtime* runtime = thread->runtime(); 696 if (result.isError()) { 697 if (result.isErrorException()) { 698 Type type(&scope, thread->pendingExceptionType()); 699 unique_c_ptr<char> name(Str::cast(type.name()).toCStr()); 700 return ::testing::AssertionFailure() 701 << "pending '" << name.get() << "' exception"; 702 } 703 return ::testing::AssertionFailure() << "is an " << result; 704 } 705 if (!runtime->isInstanceOfBytes(*result)) { 706 return ::testing::AssertionFailure() 707 << "is a '" << typeName(runtime, *result) << "'"; 708 } 709 Bytes result_bytes(&scope, bytesUnderlying(*result)); 710 Bytes expected_bytes(&scope, runtime->newBytesWithAll(expected)); 711 if (result_bytes.compare(*expected_bytes) != 0) { 712 return ::testing::AssertionFailure() 713 << result_bytes << " is not equal to " << expected_bytes; 714 } 715 return ::testing::AssertionSuccess(); 716} 717 718::testing::AssertionResult isMutableBytesEqualsBytes(const Object& result, 719 View<byte> expected) { 720 if (!result.isError() && !result.isMutableBytes()) { 721 return ::testing::AssertionFailure() 722 << "is a '" << typeName(Thread::current()->runtime(), *result) 723 << "'"; 724 } 725 return isBytesEqualsBytes(result, expected); 726} 727 728::testing::AssertionResult isBytesEqualsCStr(const Object& result, 729 const char* expected) { 730 return isBytesEqualsBytes( 731 result, View<byte>(reinterpret_cast<const byte*>(expected), 732 static_cast<word>(std::strlen(expected)))); 733} 734 735::testing::AssertionResult isStrEquals(const Object& str1, const Object& str2) { 736 Thread* thread = Thread::current(); 737 HandleScope scope(thread); 738 Runtime* runtime = thread->runtime(); 739 if (!runtime->isInstanceOfStr(*str1)) { 740 return ::testing::AssertionFailure() 741 << "is a '" << typeName(runtime, *str1) << "'"; 742 } 743 if (!runtime->isInstanceOfStr(*str2)) { 744 return ::testing::AssertionFailure() 745 << "is a '" << typeName(runtime, *str2) << "'"; 746 } 747 Str s1(&scope, strUnderlying(*str1)); 748 Str s2(&scope, strUnderlying(*str2)); 749 if (!s1.equals(*s2)) { 750 unique_c_ptr<char> s2_ptr(s2.toCStr()); 751 return ::testing::AssertionFailure() 752 << "is not equal to '" << s2_ptr.get() << "'"; 753 } 754 return ::testing::AssertionSuccess(); 755} 756 757::testing::AssertionResult isStrEqualsCStr(RawObject obj, const char* c_str) { 758 Thread* thread = Thread::current(); 759 HandleScope scope(thread); 760 Object str_obj(&scope, obj); 761 Runtime* runtime = thread->runtime(); 762 if (!runtime->isInstanceOfStr(*str_obj)) { 763 return ::testing::AssertionFailure() 764 << "is a '" << typeName(runtime, *str_obj) << "'"; 765 } 766 Str str(&scope, strUnderlying(*str_obj)); 767 if (!str.equalsCStr(c_str)) { 768 unique_c_ptr<char> str_ptr(str.toCStr()); 769 return ::testing::AssertionFailure() 770 << "'" << str_ptr.get() << "' is not equal to '" << c_str << "'"; 771 } 772 return ::testing::AssertionSuccess(); 773} 774 775::testing::AssertionResult isSymbolIdEquals(SymbolId result, 776 SymbolId expected) { 777 if (result == expected) return ::testing::AssertionSuccess(); 778 const char* result_name = result == SymbolId::kInvalid 779 ? "<Invalid>" 780 : Symbols::predefinedSymbolAt(result); 781 return ::testing::AssertionFailure() 782 << "Expected '" << Symbols::predefinedSymbolAt(expected) 783 << "', but got '" << result_name << "'"; 784} 785 786::testing::AssertionResult isFloatEqualsDouble(RawObject obj, double expected) { 787 Thread* thread = Thread::current(); 788 HandleScope scope(thread); 789 Runtime* runtime = thread->runtime(); 790 if (obj.isError()) { 791 if (obj.isErrorException()) { 792 Type type(&scope, thread->pendingExceptionType()); 793 Str type_name(&scope, type.name()); 794 return ::testing::AssertionFailure() 795 << "pending " << type_name << " exception"; 796 } 797 return ::testing::AssertionFailure() << "is an " << obj; 798 } 799 if (!runtime->isInstanceOfFloat(obj)) { 800 return ::testing::AssertionFailure() 801 << "is a '" << typeName(runtime, obj) << "'"; 802 } 803 double value = floatUnderlying(obj).value(); 804 // Test with memcmp instead of ==, so we can differentiate -0, and 0 or test 805 // for NaNs. 806 if (value != expected) { 807 return ::testing::AssertionFailure() << value << " is not " << expected; 808 } 809 return ::testing::AssertionSuccess(); 810} 811 812::testing::AssertionResult isIntEqualsWord(RawObject obj, word value) { 813 Thread* thread = Thread::current(); 814 HandleScope scope(thread); 815 Runtime* runtime = thread->runtime(); 816 if (obj.isError()) { 817 if (obj.isErrorException()) { 818 Type type(&scope, thread->pendingExceptionType()); 819 Str type_name(&scope, type.name()); 820 return ::testing::AssertionFailure() 821 << "pending " << type_name << " exception"; 822 } 823 return ::testing::AssertionFailure() << "is an " << obj; 824 } 825 if (!runtime->isInstanceOfInt(obj)) { 826 return ::testing::AssertionFailure() 827 << "is a '" << typeName(runtime, obj) << "'"; 828 } 829 Object object(&scope, obj); 830 Int value_int(&scope, intUnderlying(*object)); 831 if (value_int.numDigits() > 1 || value_int.asWord() != value) { 832 return ::testing::AssertionFailure() 833 << value_int << " is not equal to " << value; 834 } 835 return ::testing::AssertionSuccess(); 836} 837 838::testing::AssertionResult isIntEqualsDigits(RawObject obj, 839 View<uword> digits) { 840 Thread* thread = Thread::current(); 841 HandleScope scope(thread); 842 Runtime* runtime = thread->runtime(); 843 if (obj.isError()) { 844 if (obj.isErrorException()) { 845 Type type(&scope, thread->pendingExceptionType()); 846 Str type_name(&scope, type.name()); 847 return ::testing::AssertionFailure() 848 << "pending " << type_name << " exception"; 849 } 850 return ::testing::AssertionFailure() << "is an " << obj; 851 } 852 if (!runtime->isInstanceOfInt(obj)) { 853 return ::testing::AssertionFailure() 854 << "is a '" << typeName(runtime, obj) << "'"; 855 } 856 Int expected(&scope, newLargeIntWithDigits(digits)); 857 Object value_obj(&scope, obj); 858 Int value_int(&scope, intUnderlying(*value_obj)); 859 if (expected.compare(*value_int) != 0) { 860 return ::testing::AssertionFailure() 861 << value_int << " is not equal to " << expected; 862 } 863 return ::testing::AssertionSuccess(); 864} 865 866RawObject layoutCreateEmpty(Thread* thread) { 867 HandleScope scope(thread); 868 Runtime* runtime = thread->runtime(); 869 LayoutId id = runtime->reserveLayoutId(thread); 870 Layout result(&scope, runtime->newLayout(id)); 871 runtime->layoutSetTupleOverflow(*result); 872 runtime->layoutAtPut(id, *result); 873 return *result; 874} 875 876::testing::AssertionResult raised(RawObject return_value, LayoutId layout_id) { 877 return raisedWithStr(return_value, layout_id, nullptr); 878} 879 880::testing::AssertionResult raisedWithStr(RawObject return_value, 881 LayoutId layout_id, 882 const char* message) { 883 Thread* thread = Thread::current(); 884 Runtime* runtime = thread->runtime(); 885 HandleScope scope(thread); 886 Object return_value_obj(&scope, return_value); 887 888 if (!return_value_obj.isError()) { 889 Type type(&scope, runtime->typeOf(*return_value_obj)); 890 Str name(&scope, type.name()); 891 return ::testing::AssertionFailure() 892 << "call returned " << name << ", not Error"; 893 } 894 895 if (!thread->hasPendingException()) { 896 return ::testing::AssertionFailure() << "no exception pending"; 897 } 898 899 Type expected_type(&scope, runtime->typeAt(layout_id)); 900 Type exception_type(&scope, thread->pendingExceptionType()); 901 if (!typeIsSubclass(*exception_type, *expected_type)) { 902 Str expected_name(&scope, expected_type.name()); 903 Str actual_name(&scope, exception_type.name()); 904 return ::testing::AssertionFailure() 905 << "\npending exception has type:\n " << actual_name 906 << "\nexpected:\n " << expected_name << "\n"; 907 } 908 909 if (message == nullptr) return ::testing::AssertionSuccess(); 910 911 Object exc_value(&scope, thread->pendingExceptionValue()); 912 if (!runtime->isInstanceOfStr(*exc_value)) { 913 if (runtime->isInstanceOfBaseException(*exc_value)) { 914 BaseException exc(&scope, *exc_value); 915 Tuple args(&scope, exc.args()); 916 if (args.length() == 0) { 917 return ::testing::AssertionFailure() 918 << "pending exception args tuple is empty"; 919 } 920 exc_value = args.at(0); 921 } 922 923 if (!runtime->isInstanceOfStr(*exc_value)) { 924 return ::testing::AssertionFailure() 925 << "pending exception value is not str"; 926 } 927 } 928 929 Str exc_msg(&scope, *exc_value); 930 if (!exc_msg.equalsCStr(message)) { 931 return ::testing::AssertionFailure() 932 << "\npending exception value:\n '" << exc_msg 933 << "'\nexpected:\n '" << message << "'\n"; 934 } 935 936 return ::testing::AssertionSuccess(); 937} 938 939TemporaryDirectory::TemporaryDirectory() { 940 const char* tmpdir = std::getenv("TMPDIR"); 941 if (tmpdir == nullptr) { 942 tmpdir = "/tmp"; 943 } 944 const char format[] = "%s/PyroTest.XXXXXXXX"; 945 word length = std::snprintf(nullptr, 0, format, tmpdir) + 1; 946 std::unique_ptr<char[]> buffer(new char[length]); 947 std::snprintf(buffer.get(), length, format, tmpdir); 948 char* result = ::mkdtemp(buffer.get()); 949 CHECK(result != nullptr, "failed to create temporary directory"); 950 path = buffer.get(); 951 CHECK(!path.empty(), "must not be empty"); 952 if (path.back() != '/') path += "/"; 953} 954 955TemporaryDirectory::~TemporaryDirectory() { 956 std::string cleanup = "rm -rf " + path; 957 CHECK(system(cleanup.c_str()) == 0, "failed to cleanup temporary directory"); 958} 959 960void writeFile(const std::string& path, const std::string& contents) { 961 CHECK(!path.empty() && path.front() == '/', "Should be an absolute path"); 962 std::ofstream of(path); 963 CHECK(of.good(), "file creation failed"); 964 of << contents; 965 CHECK(of.good(), "file write failed"); 966 of.close(); 967} 968 969} // namespace testing 970} // namespace py