this repo has no description
at trunk 884 lines 29 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "debugging.h" 3 4#include <iostream> 5 6#include "gmock/gmock-matchers.h" 7#include "gtest/gtest.h" 8 9#include "bytecode.h" 10#include "dict-builtins.h" 11#include "test-utils.h" 12 13namespace py { 14namespace testing { 15 16using DebuggingTests = RuntimeFixture; 17 18static RawObject makeTestCode(Thread* thread) { 19 Runtime* runtime = thread->runtime(); 20 HandleScope scope(thread); 21 const byte bytes_array[] = {LOAD_CONST, 0, LOAD_ATTR, 0, RETURN_VALUE, 0}; 22 Bytes bytes(&scope, runtime->newBytesWithAll(bytes_array)); 23 Object const0(&scope, runtime->newStrFromCStr("const0")); 24 Tuple consts(&scope, runtime->newTupleWith1(const0)); 25 Object name0(&scope, runtime->newStrFromCStr("name0")); 26 Tuple names(&scope, runtime->newTupleWith1(name0)); 27 Object argument0(&scope, runtime->newStrFromCStr("argument0")); 28 Object varargs(&scope, runtime->newStrFromCStr("varargs")); 29 Object varkeyargs(&scope, runtime->newStrFromCStr("varkeyargs")); 30 Object variable0(&scope, runtime->newStrFromCStr("variable0")); 31 Tuple varnames(&scope, runtime->newTupleWith4(argument0, varargs, varkeyargs, 32 variable0)); 33 Object freevar0(&scope, runtime->newStrFromCStr("freevar0")); 34 Tuple freevars(&scope, runtime->newTupleWith1(freevar0)); 35 Object cellvar0(&scope, runtime->newStrFromCStr("cellvar0")); 36 Object cellvar1(&scope, runtime->newStrFromCStr("cellvar1")); 37 Object cellvar2(&scope, runtime->newStrFromCStr("cellvar2")); 38 Tuple cellvars(&scope, runtime->newTupleWith3(cellvar0, cellvar1, cellvar2)); 39 Str filename(&scope, runtime->newStrFromCStr("filename0")); 40 Str name(&scope, runtime->newStrFromCStr("name0")); 41 DCHECK(freevars.length() != cellvars.length(), 42 "it's helpful for debugging if they are different lengths"); 43 Object lnotab(&scope, Bytes::empty()); 44 word argcount = 1; 45 word posonlyargcount = 0; 46 word kwonlyargcount = 0; 47 word nlocals = 4; 48 word stacksize = 1; 49 word flags = Code::kNested | Code::kOptimized | Code::kNewlocals | 50 Code::kVarargs | Code::kVarkeyargs; 51 return runtime->newCode(argcount, posonlyargcount, kwonlyargcount, nlocals, 52 stacksize, flags, bytes, consts, names, varnames, 53 freevars, cellvars, filename, name, 0, lnotab); 54} 55 56static RawObject makeTestFunction(Thread* thread) { 57 HandleScope scope(thread); 58 Runtime* runtime = thread->runtime(); 59 Object qualname(&scope, runtime->newStrFromCStr("footype.baz")); 60 Code code(&scope, makeTestCode(thread)); 61 Module module(&scope, findMainModule(runtime)); 62 Function func(&scope, 63 runtime->newFunctionWithCode(thread, qualname, code, module)); 64 func.setEntry(reinterpret_cast<Function::Entry>(100)); 65 func.setEntryEx(reinterpret_cast<Function::Entry>(200)); 66 func.setEntryKw(reinterpret_cast<Function::Entry>(300)); 67 Dict annotations(&scope, runtime->newDict()); 68 Str return_name(&scope, runtime->newStrFromCStr("return")); 69 Object int_type(&scope, runtime->typeAt(LayoutId::kInt)); 70 dictAtPutByStr(thread, annotations, return_name, int_type); 71 func.setAnnotations(*annotations); 72 func.setClosure(runtime->emptyTuple()); 73 Dict kw_defaults(&scope, runtime->newDict()); 74 Str name0(&scope, runtime->newStrFromCStr("name0")); 75 Object none(&scope, NoneType::object()); 76 dictAtPutByStr(thread, kw_defaults, name0, none); 77 func.setKwDefaults(*kw_defaults); 78 Object num(&scope, runtime->newInt(-9)); 79 Tuple defaults(&scope, runtime->newTupleWith1(num)); 80 func.setDefaults(*defaults); 81 func.setIntrinsic(reinterpret_cast<void*>(0x12340)); 82 func.setModuleName(runtime->newStrFromCStr("barmodule")); 83 func.setName(runtime->newStrFromCStr("baz")); 84 Dict attrs(&scope, runtime->newDict()); 85 Str attr_name(&scope, runtime->newStrFromCStr("funcattr0")); 86 Object attr_value(&scope, runtime->newInt(4)); 87 dictAtPutByStr(thread, attrs, attr_name, attr_value); 88 func.setDict(*attrs); 89 return *func; 90} 91 92TEST_F(DebuggingTests, DumpExtendedCode) { 93 HandleScope scope(thread_); 94 Object code(&scope, makeTestCode(thread_)); 95 96 std::stringstream ss; 97 dumpExtended(ss, *code); 98 EXPECT_EQ(ss.str(), 99 R"(code "name0": 100 flags: optimized newlocals varargs varkeyargs nested 101 argcount: 1 102 posonlyargcount: 0 103 kwonlyargcount: 0 104 nlocals: 4 105 stacksize: 1 106 filename: "filename0" 107 consts: ("const0",) 108 names: ("name0",) 109 cellvars: ("cellvar0", "cellvar1", "cellvar2") 110 freevars: ("freevar0",) 111 varnames: ("argument0", "varargs", "varkeyargs", "variable0") 112 0 LOAD_CONST 0 113 2 LOAD_ATTR 0 114 4 RETURN_VALUE 0 115)"); 116} 117 118TEST_F(DebuggingTests, DumpExtendedFunction) { 119 Thread* thread = Thread::current(); 120 HandleScope scope(thread); 121 Object func(&scope, makeTestFunction(thread)); 122 std::stringstream ss; 123 dumpExtended(ss, *func); 124 EXPECT_EQ(ss.str(), R"(function "baz": 125 qualname: "footype.baz" 126 module: "barmodule" 127 annotations: {"return": <type "int">} 128 closure: () 129 defaults: (-9,) 130 kwdefaults: {"name0": None} 131 intrinsic: 0x12340 132 dict: {"funcattr0": 4} 133 flags: optimized newlocals varargs varkeyargs nested interpreted 134 code: code "name0": 135 flags: optimized newlocals varargs varkeyargs nested 136 argcount: 1 137 posonlyargcount: 0 138 kwonlyargcount: 0 139 nlocals: 4 140 stacksize: 1 141 filename: "filename0" 142 consts: ("const0",) 143 names: ("name0",) 144 cellvars: ("cellvar0", "cellvar1", "cellvar2") 145 freevars: ("freevar0",) 146 varnames: ("argument0", "varargs", "varkeyargs", "variable0") 147 0 LOAD_CONST 0 148 2 LOAD_ATTR 0 149 4 RETURN_VALUE 0 150 Rewritten bytecode: 151 0 [ 0] LOAD_CONST 0 152 4 [ 1] LOAD_ATTR_ANAMORPHIC 0 153 8 [ 0] RETURN_VALUE 0 154)"); 155} 156 157TEST_F(DebuggingTests, DumpExtendedInstance) { 158 HandleScope scope(thread_); 159 ASSERT_FALSE(runFromCStr(runtime_, R"( 160class C: 161 def __init__(self): 162 self.foo = 5 163 self.bar = "hello" 164i = C() 165i.baz = () 166)") 167 .isError()); 168 Object i(&scope, mainModuleAt(runtime_, "i")); 169 ASSERT_TRUE(i.isInstance()); 170 std::stringstream ss; 171 dumpExtended(ss, *i); 172 std::stringstream expected; 173 expected << "heap object with layout " << static_cast<word>(i.layoutId()) 174 << R"( (<type "C">): 175 (in-object) "foo" = 5 176 (in-object) "bar" = "hello" 177 (overflow) "baz" = () 178)"; 179 EXPECT_EQ(ss.str(), expected.str()); 180} 181 182TEST_F(DebuggingTests, DumpExtendedInstanceWithOverflowDict) { 183 HandleScope scope(thread_); 184 Function func(&scope, makeTestFunction(thread_)); 185 std::stringstream ss; 186 dumpExtendedInstance(ss, RawInstance::cast(*func)); 187 std::stringstream expected; 188 word raw_flags = 189 SmallInt::cast(func.instanceVariableAt(RawFunction::kFlagsOffset)) 190 .value(); 191 word entry_asm = 192 SmallInt::cast(func.instanceVariableAt(RawFunction::kEntryAsmOffset)) 193 .value(); 194 expected << "heap object with layout " << static_cast<word>(func.layoutId()) 195 << R"( (<type "function">): 196 (in-object) "__code__" = <code "name0"> 197 (in-object) "_function__flags" = )" 198 << raw_flags << R"( 199 (in-object) "_function__argcount" = 1 200 (in-object) "_function__total_args" = 3 201 (in-object) "_function__total_vars" = 5 202 (in-object) "_function__stack_size" = 2 203 (in-object) "__doc__" = "const0" 204 (in-object) "__name__" = "baz" 205 (in-object) "__qualname__" = "footype.baz" 206 (in-object) "__module__" = "barmodule" 207 (in-object) "__module_object__" = <module "__main__"> 208 (in-object) "_function__defaults" = (-9,) 209 (in-object) "_function__annotations" = {"return": <type "int">} 210 (in-object) "_function__kw_defaults" = {"name0": None} 211 (in-object) "_function__closure" = () 212 (in-object) "_function__entry" = 50 213 (in-object) "_function__entry_kw" = 150 214 (in-object) "_function__entry_ex" = 100 215 (in-object) "_function__entry_asm" = )" 216 << entry_asm << R"( 217 (in-object) "_function__rewritten_bytecode" = b'd\x00\x00\x00\xff\x00\x01\x00S\x00\x00\x00' 218 (in-object) "_function__caches" = mutabletuple(None, None, None, None) 219 (in-object) "_function__dict" = {"funcattr0": 4} 220 (in-object) "_function__intrinsic" = 37280 221 overflow dict: {"funcattr0": 4} 222)"; 223 EXPECT_EQ(ss.str(), expected.str()); 224} 225 226TEST_F(DebuggingTests, DumpExtendedInstanceWithInvalidLayout) { 227 HandleScope scope(thread_); 228 Instance instance(&scope, runtime_->newList()); 229 LayoutId old_id = instance.layoutId(); 230 // Temporarily set an invalid layout id... 231 instance.setHeader( 232 instance.header().withLayoutId(static_cast<LayoutId>(9999))); 233 std::stringstream ss; 234 dumpExtendedInstance(ss, *instance); 235 instance.setHeader(instance.header().withLayoutId(old_id)); 236 EXPECT_EQ(ss.str(), "heap object with layout 9999\n"); 237} 238 239TEST_F(DebuggingTests, DumpExtendedInstanceWithLayoutWithoutType) { 240 HandleScope scope(thread_); 241 Instance instance(&scope, runtime_->newList()); 242 Layout layout(&scope, runtime_->layoutOf(*instance)); 243 Object old_type(&scope, layout.describedType()); 244 // Temporarily set an invalid type... 245 layout.setDescribedType(NoneType::object()); 246 std::stringstream ss; 247 dumpExtendedInstance(ss, *instance); 248 layout.setDescribedType(*old_type); 249 std::stringstream expected; 250 expected << "heap object with layout " << static_cast<word>(LayoutId::kList) 251 << '\n'; 252 EXPECT_EQ(ss.str(), expected.str()); 253} 254 255TEST_F(DebuggingTests, DumpExtendedLayout) { 256 HandleScope scope(thread_); 257 // Create a new layout with several overflow attributes 258 Object attr(&scope, runtime_->newStrFromCStr("myattr")); 259 Object attr2(&scope, runtime_->newStrFromCStr("myattr2")); 260 Object attr3(&scope, runtime_->newStrFromCStr("myattr3")); 261 MutableTuple overflow(&scope, runtime_->newMutableTuple(3)); 262 Object* overflow_names[] = {&attr, &attr2, &attr3}; 263 for (word i = 0; i < overflow.length(); i++) { 264 Object info(&scope, AttributeInfo(i, 0).asSmallInt()); 265 overflow.atPut(i, runtime_->newTupleWith2(*overflow_names[i], info)); 266 } 267 Layout layout(&scope, layoutCreateEmpty(thread_)); 268 layout.setOverflowAttributes(overflow.becomeImmutable()); 269 270 // Set some in-object attributes 271 Object inobj1(&scope, runtime_->newStrFromCStr("foo")); 272 Object inobj2(&scope, runtime_->newStrFromCStr("bar")); 273 MutableTuple inobj(&scope, runtime_->newMutableTuple(2)); 274 Object* inobj_names[] = {&inobj1, &inobj2}; 275 for (word i = 0; i < inobj.length(); i++) { 276 Object info(&scope, AttributeInfo(i, 0).asSmallInt()); 277 inobj.atPut(i, runtime_->newTupleWith2(*inobj_names[i], info)); 278 } 279 layout.setInObjectAttributes(inobj.becomeImmutable()); 280 layout.setNumInObjectAttributes(9); 281 layout.setId(static_cast<LayoutId>(103)); 282 283 Type type(&scope, runtime_->typeAt(LayoutId::kObject)); 284 layout.setDescribedType(*type); 285 286 std::stringstream ss; 287 dumpExtended(ss, *layout); 288 EXPECT_EQ(ss.str(), R"(layout 103: 289 described type: <type "object"> 290 num in-object attributes: 9 291 "foo" @ 0 292 "bar" @ 1 293 overflow tuple: 294 "myattr" @ 0 295 "myattr2" @ 1 296 "myattr3" @ 2 297)"); 298} 299 300TEST_F(DebuggingTests, DumpExtendedLayoutWithSealedLayout) { 301 HandleScope scope(thread_); 302 Layout layout(&scope, layoutCreateEmpty(thread_)); 303 layout.setOverflowAttributes(NoneType::object()); 304 // Set some in-object attributes 305 Object inobj1(&scope, runtime_->newStrFromCStr("foo")); 306 Object inobj2(&scope, runtime_->newStrFromCStr("bar")); 307 MutableTuple inobj(&scope, runtime_->newMutableTuple(2)); 308 Object* inobj_names[] = {&inobj1, &inobj2}; 309 for (word i = 0; i < inobj.length(); i++) { 310 Object info(&scope, AttributeInfo(i, 0).asSmallInt()); 311 inobj.atPut(i, runtime_->newTupleWith2(*inobj_names[i], info)); 312 } 313 layout.setInObjectAttributes(*inobj); 314 layout.setId(static_cast<LayoutId>(13)); 315 layout.setNumInObjectAttributes(2); 316 317 std::stringstream ss; 318 dumpExtended(ss, *layout); 319 EXPECT_EQ(ss.str(), R"(layout 13: 320 described type: None 321 num in-object attributes: 2 322 "foo" @ 0 323 "bar" @ 1 324 sealed 325)"); 326} 327 328TEST_F(DebuggingTests, DumpExtendedLayoutWithDictOverflow) { 329 HandleScope scope(thread_); 330 Layout layout(&scope, layoutCreateEmpty(thread_)); 331 layout.setOverflowAttributes(SmallInt::fromWord(654321)); 332 layout.setInObjectAttributes(runtime_->emptyTuple()); 333 layout.setNumInObjectAttributes(0); 334 layout.setId(static_cast<LayoutId>(1234)); 335 336 std::stringstream ss; 337 dumpExtended(ss, *layout); 338 EXPECT_EQ(ss.str(), R"(layout 1234: 339 described type: None 340 num in-object attributes: 0 341 overflow dict @ 654321 342)"); 343} 344 345TEST_F(DebuggingTests, DumpExtendedType) { 346 HandleScope scope(thread_); 347 ASSERT_FALSE(runFromCStr(runtime_, R"( 348class A: 349 pass 350class B(bytes): 351 pass 352class C(A, B): 353 def __init__(self): 354 self.x = 0 355 self.y = 1 356)") 357 .isError()); 358 Object c(&scope, mainModuleAt(runtime_, "C")); 359 ASSERT_TRUE(c.isType()); 360 361 std::stringstream ss; 362 dumpExtended(ss, *c); 363 std::stringstream expected; 364 expected << R"(type "C": 365 bases: (<type "A">, <type "B">) 366 mro: (<type "C">, <type "A">, <type "B">, <type "bytes">, <type "object">) 367 flags: 368 builtin base: <layout )" 369 << static_cast<word>(LayoutId::kBytes) << R"( ("bytes")> 370 layout )" 371 << static_cast<word>( 372 Layout::cast(Type::cast(*c).instanceLayout()).id()) 373 << R"(: 374 described type: <type "C"> 375 num in-object attributes: 3 376 "_UserBytes__value" @ 0 377 overflow tuple: 378)"; 379 EXPECT_EQ(ss.str(), expected.str()); 380} 381 382TEST_F(DebuggingTests, DumpExtendedTypePrintsFlags) { 383 HandleScope scope(thread_); 384 Type type(&scope, runtime_->newType()); 385 word flags = Type::Flag::kIsAbstract | Type::Flag::kHasCustomDict | 386 Type::Flag::kHasNativeData | Type::Flag::kHasCycleGC | 387 Type::Flag::kHasDefaultDealloc | Type::Flag::kHasSlots | 388 Type::Flag::kIsFixedAttributeBase; 389 type.setFlagsAndBuiltinBase(static_cast<Type::Flag>(flags), 390 LayoutId::kUserWarning); 391 392 std::stringstream ss; 393 dumpExtended(ss, *type); 394 word builtin_base = static_cast<word>(LayoutId::kUserWarning); 395 std::stringstream expected; 396 expected << R"(type None: 397 bases: None 398 mro: None 399 flags: abstract has_custom_dict has_native_data has_cycle_gc has_default_dealloc has_slots is_fixed_attribute_base 400 builtin base: <layout )" 401 << builtin_base << R"( ("UserWarning")> 402 layout: None 403)"; 404 EXPECT_EQ(ss.str(), expected.str()); 405} 406 407TEST_F(DebuggingTests, 408 DumpExtendedPrefersSimpleDumperOverDumpExtendedInstance) { 409 HandleScope scope(thread_); 410 List list(&scope, runtime_->newList()); 411 std::stringstream ss; 412 dumpExtended(ss, *list); 413 EXPECT_EQ(ss.str(), "[]\n"); 414} 415 416TEST_F(DebuggingTests, FormatBool) { 417 std::stringstream ss; 418 ss << Bool::trueObj() << ';' << Bool::falseObj(); 419 EXPECT_EQ(ss.str(), "True;False"); 420} 421 422TEST_F(DebuggingTests, FormatBoundMethod) { 423 HandleScope scope(thread_); 424 ASSERT_FALSE(runFromCStr(runtime_, R"( 425class C: 426 def foo(): 427 pass 428bound_method = C().foo 429)") 430 .isError()); 431 Object bound_method(&scope, mainModuleAt(runtime_, "bound_method")); 432 ASSERT_TRUE(bound_method.isBoundMethod()); 433 std::stringstream ss; 434 ss << bound_method; 435 EXPECT_EQ(ss.str(), "<bound_method <function \"C.foo\">, <\"C\" object>>"); 436} 437 438TEST_F(DebuggingTests, FormatBoundMethodWithCallable) { 439 HandleScope scope(thread_); 440 ASSERT_FALSE(runFromCStr(runtime_, R"( 441class C: 442 def __call__(self): 443 pass 444from types import MethodType 445bound_method = MethodType(C(), 42) 446)") 447 .isError()); 448 Object bound_method(&scope, mainModuleAt(runtime_, "bound_method")); 449 ASSERT_TRUE(bound_method.isBoundMethod()); 450 std::stringstream ss; 451 ss << bound_method; 452 EXPECT_EQ(ss.str(), "<bound_method <\"C\" object>, 42>"); 453} 454 455TEST_F(DebuggingTests, FormatBytes) { 456 std::stringstream ss; 457 const byte bytes[] = {'h', 'e', 'l', 'l', 'o', 0, 'w', '2', 458 0xa4, '"', '\'', '\t', '\r', '\n', '\\'}; 459 ss << runtime_->newBytesWithAll(bytes); 460 EXPECT_EQ(ss.str(), R"(b'hello\x00w2\xa4"\'\t\r\n\\')"); 461} 462 463TEST_F(DebuggingTests, FormatBytearray) { 464 ASSERT_FALSE(runFromCStr(runtime_, "ba = bytearray(b\"foo'\")").isError()); 465 HandleScope scope(thread_); 466 Object bytearray(&scope, mainModuleAt(runtime_, "ba")); 467 ASSERT_TRUE(bytearray.isBytearray()); 468 std::stringstream ss; 469 ss << bytearray; 470 EXPECT_EQ(ss.str(), R"(bytearray(b'foo\''))"); 471} 472 473TEST_F(DebuggingTests, FormatCode) { 474 HandleScope scope(thread_); 475 Code code(&scope, newCodeWithBytes(View<byte>(nullptr, 0))); 476 code.setName(runtime_->newStrFromCStr("foobar")); 477 std::stringstream ss; 478 ss << code; 479 EXPECT_EQ(ss.str(), "<code \"foobar\">"); 480} 481 482TEST_F(DebuggingTests, FormatDict) { 483 HandleScope scope(thread_); 484 Dict dict(&scope, runtime_->newDict()); 485 Str key0(&scope, runtime_->newStrFromCStr("hello")); 486 Object key1(&scope, NoneType::object()); 487 Object hash_obj(&scope, Interpreter::hash(thread_, key1)); 488 ASSERT_FALSE(hash_obj.isErrorException()); 489 word hash = SmallInt::cast(*hash_obj).value(); 490 Object value0(&scope, runtime_->newInt(88)); 491 Object value1(&scope, runtime_->emptyTuple()); 492 dictAtPutByStr(thread_, dict, key0, value0); 493 ASSERT_TRUE(dictAtPut(thread_, dict, key1, hash, value1).isNoneType()); 494 std::stringstream ss; 495 ss << dict; 496 EXPECT_TRUE(ss.str() == R"({"hello": 88, None: ()})" || 497 ss.str() == R"({None: (), "hello": 88}")"); 498} 499 500TEST_F(DebuggingTests, FormatError) { 501 std::stringstream ss; 502 ss << Error::error(); 503 EXPECT_EQ(ss.str(), "Error"); 504 505 ss.str(""); 506 ss << Error::exception(); 507 EXPECT_EQ(ss.str(), "Error<Exception>"); 508 509 ss.str(""); 510 ss << Error::notFound(); 511 EXPECT_EQ(ss.str(), "Error<NotFound>"); 512 513 ss.str(""); 514 ss << Error::noMoreItems(); 515 EXPECT_EQ(ss.str(), "Error<NoMoreItems>"); 516 517 ss.str(""); 518 ss << Error::outOfMemory(); 519 EXPECT_EQ(ss.str(), "Error<OutOfMemory>"); 520 521 ss.str(""); 522 ss << Error::outOfBounds(); 523 EXPECT_EQ(ss.str(), "Error<OutOfBounds>"); 524} 525 526TEST_F(DebuggingTests, FormatFloat) { 527 std::stringstream ss; 528 ss << runtime_->newFloat(42.42); 529 EXPECT_EQ(ss.str(), "0x1.535c28f5c28f6p+5"); 530} 531 532TEST_F(DebuggingTests, FormatFunction) { 533 HandleScope scope(thread_); 534 std::stringstream ss; 535 Object function(&scope, moduleAtByCStr(runtime_, "builtins", "callable")); 536 ASSERT_TRUE(function.isFunction()); 537 ss << function; 538 EXPECT_EQ(ss.str(), R"(<function "callable">)"); 539} 540 541TEST_F(DebuggingTests, FormatLargeInt) { 542 std::stringstream ss; 543 const uword digits[] = {0x12345, kMaxUword}; 544 ss << runtime_->newLargeIntWithDigits(digits); 545 EXPECT_EQ(ss.str(), "largeint([0x0000000000012345, 0xffffffffffffffff])"); 546} 547 548TEST_F(DebuggingTests, FormatLargeStr) { 549 HandleScope scope(thread_); 550 std::stringstream ss; 551 Object str(&scope, runtime_->newStrFromCStr("hello world")); 552 EXPECT_TRUE(str.isLargeStr()); 553 ss << str; 554 EXPECT_EQ(ss.str(), "\"hello world\""); 555} 556 557TEST_F(DebuggingTests, FormatLayout) { 558 HandleScope scope(thread_); 559 Layout layout(&scope, layoutCreateEmpty(thread_)); 560 layout.setId(static_cast<LayoutId>(101)); 561 Type type(&scope, runtime_->typeAt(LayoutId::kFloat)); 562 layout.setDescribedType(*type); 563 564 std::stringstream ss; 565 ss << layout; 566 EXPECT_EQ(ss.str(), "<layout 101 (\"float\")>"); 567} 568 569TEST_F(DebuggingTests, FormatList) { 570 HandleScope scope(thread_); 571 List list(&scope, runtime_->newList()); 572 Object o0(&scope, NoneType::object()); 573 Object o1(&scope, runtime_->newInt(17)); 574 runtime_->listAdd(thread_, list, o0); 575 runtime_->listAdd(thread_, list, o1); 576 std::stringstream ss; 577 ss << list; 578 EXPECT_EQ(ss.str(), "[None, 17]"); 579} 580 581TEST_F(DebuggingTests, FormatModule) { 582 HandleScope scope(thread_); 583 Object name(&scope, runtime_->newStrFromCStr("foomodule")); 584 Object module(&scope, runtime_->newModule(name)); 585 std::stringstream ss; 586 ss << module; 587 EXPECT_EQ(ss.str(), R"(<module "foomodule">)"); 588} 589 590TEST_F(DebuggingTests, FormatNone) { 591 std::stringstream ss; 592 ss << NoneType::object(); 593 EXPECT_EQ(ss.str(), "None"); 594} 595 596TEST_F(DebuggingTests, FormatObjectWithBuiltinClass) { 597 std::stringstream ss; 598 ss << NotImplementedType::object(); 599 EXPECT_EQ(ss.str(), R"(<"NotImplementedType" object>)"); 600} 601 602TEST_F(DebuggingTests, FormatObjectWithUserDefinedClass) { 603 HandleScope scope(thread_); 604 ASSERT_FALSE(runFromCStr(runtime_, R"( 605class Foo: 606 pass 607foo = Foo() 608)") 609 .isError()); 610 Object foo(&scope, mainModuleAt(runtime_, "foo")); 611 std::stringstream ss; 612 ss << foo; 613 EXPECT_EQ(ss.str(), R"(<"Foo" object>)"); 614} 615 616TEST_F(DebuggingTests, FormatObjectWithTypeWithoutName) { 617 HandleScope scope(thread_); 618 Object obj(&scope, NotImplementedType::object()); 619 // Phabricate a nameless type... 620 Type::cast(runtime_->typeOf(*obj)).setName(NoneType::object()); 621 622 std::stringstream ss; 623 std::stringstream expected; 624 ss << obj; 625 expected << "<object with LayoutId " << static_cast<word>(obj.layoutId()) 626 << ">"; 627 EXPECT_EQ(ss.str(), expected.str()); 628} 629 630TEST_F(DebuggingTests, FormatObjectWithInvalidLayoutId) { 631 HandleScope scope(thread_); 632 Object object(&scope, runtime_->newList()); 633 LayoutId old_id = object.layoutId(); 634 // Temporary set an invalid layout id. 635 HeapObject::cast(*object).setHeader( 636 HeapObject::cast(*object).header().withLayoutId( 637 static_cast<LayoutId>(9999))); 638 std::stringstream ss; 639 ss << object; 640 HeapObject::cast(*object).setHeader( 641 HeapObject::cast(*object).header().withLayoutId(old_id)); 642 EXPECT_EQ(ss.str(), "<object with LayoutId 9999>"); 643} 644 645TEST_F(DebuggingTests, FormatObjectWithLayoutWithInvalidType) { 646 HandleScope scope(thread_); 647 Layout layout(&scope, runtime_->layoutAt(LayoutId::kObject)); 648 Object object(&scope, runtime_->newInstance(layout)); 649 Object old_type(&scope, layout.describedType()); 650 // Temporary set an invalid layout id. 651 layout.setDescribedType(NoneType::object()); 652 std::stringstream ss; 653 ss << object; 654 layout.setDescribedType(*old_type); 655 656 std::stringstream expected; 657 expected << "<object with LayoutId " << static_cast<word>(LayoutId::kObject) 658 << '>'; 659 EXPECT_EQ(ss.str(), expected.str()); 660} 661 662TEST_F(DebuggingTests, FormatSmallInt) { 663 std::stringstream ss; 664 ss << SmallInt::fromWord(-42) << ';' 665 << SmallInt::fromWord(SmallInt::kMinValue) << ';' 666 << SmallInt::fromWord(SmallInt::kMaxValue); 667 std::stringstream expected; 668 expected << "-42;" << SmallInt::kMinValue << ";" << SmallInt::kMaxValue; 669 EXPECT_EQ(ss.str(), expected.str()); 670} 671 672TEST_F(DebuggingTests, FormatSmallStr) { 673 HandleScope scope(thread_); 674 std::stringstream ss; 675 Object str(&scope, runtime_->newStrFromCStr("aa")); 676 EXPECT_TRUE(str.isSmallStr()); 677 ss << str; 678 EXPECT_EQ(ss.str(), "\"aa\""); 679} 680 681TEST_F(DebuggingTests, FormatMutableTuple) { 682 HandleScope scope(thread_); 683 MutableTuple tuple(&scope, runtime_->newMutableTuple(2)); 684 tuple.atPut(0, Bool::trueObj()); 685 tuple.atPut(1, runtime_->newStrFromCStr("hey")); 686 std::stringstream ss; 687 ss << tuple; 688 EXPECT_EQ(ss.str(), R"(mutabletuple(True, "hey"))"); 689} 690 691TEST_F(DebuggingTests, FormatTuple) { 692 HandleScope scope(thread_); 693 Object true_obj(&scope, Bool::trueObj()); 694 Object hey(&scope, runtime_->newStrFromCStr("hey")); 695 Tuple tuple(&scope, runtime_->newTupleWith2(true_obj, hey)); 696 std::stringstream ss; 697 ss << tuple; 698 EXPECT_EQ(ss.str(), R"((True, "hey"))"); 699} 700 701TEST_F(DebuggingTests, FormatTupleWithoutElements) { 702 std::stringstream ss; 703 ss << runtime_->emptyTuple(); 704 EXPECT_EQ(ss.str(), "()"); 705} 706 707TEST_F(DebuggingTests, FormatTupleWithOneElement) { 708 HandleScope scope(thread_); 709 Object obj(&scope, runtime_->newInt(77)); 710 Tuple tuple(&scope, runtime_->newTupleWith1(obj)); 711 std::stringstream ss; 712 ss << tuple; 713 EXPECT_EQ(ss.str(), "(77,)"); 714} 715 716TEST_F(DebuggingTests, FormatType) { 717 HandleScope scope(thread_); 718 ASSERT_FALSE(runFromCStr(runtime_, R"( 719class MyClass: 720 pass 721)") 722 .isError()); 723 Object my_class(&scope, mainModuleAt(runtime_, "MyClass")); 724 std::stringstream ss; 725 ss << my_class; 726 EXPECT_EQ(ss.str(), "<type \"MyClass\">"); 727} 728 729TEST_F(DebuggingTests, FormatForwardedObjects) { 730 HandleScope scope(thread_); 731 List list1(&scope, runtime_->newList()); 732 Int i(&scope, runtime_->newInt(1234)); 733 runtime_->listAdd(thread_, list1, i); 734 Tuple tuple(&scope, runtime_->newTupleWith1(list1)); 735 736 i = runtime_->newInt(5678); 737 List list2(&scope, runtime_->newList()); 738 runtime_->listAdd(thread_, list2, i); 739 list1.forwardTo(*list2); 740 std::ostringstream ss; 741 ss << tuple; 742 EXPECT_EQ(ss.str(), "(<Forward to> [5678],)"); 743 744 ss.str(""); 745 dumpExtended(ss, *tuple); 746 EXPECT_EQ(ss.str(), "(<Forward to> [5678],)\n"); 747} 748 749TEST_F(DebuggingTests, FormatFrame) { 750 HandleScope scope(thread_); 751 ASSERT_FALSE(runFromCStr(runtime_, R"( 752def func(arg0, arg1): 753 hello = "world" 754 return arg0 + arg1 755)") 756 .isError()); 757 Function func(&scope, mainModuleAt(runtime_, "func")); 758 759 Object empty_tuple(&scope, runtime_->emptyTuple()); 760 Str name(&scope, runtime_->newStrFromCStr("_bytearray_check")); 761 Code code(&scope, 762 runtime_->newBuiltinCode(/*argcount=*/0, /*posonlyargcount=*/0, 763 /*kwonlyargcount=*/0, 764 /*flags=*/0, /*function=*/nullptr, 765 /*parameter_names=*/empty_tuple, name)); 766 Str qualname(&scope, runtime_->newStrFromCStr("test._bytearray_check")); 767 Module module(&scope, findMainModule(runtime_)); 768 Function builtin( 769 &scope, runtime_->newFunctionWithCode(thread_, qualname, code, module)); 770 771 Frame* root = thread_->currentFrame(); 772 ASSERT_TRUE(root->isSentinel()); 773 root->setVirtualPC(8 * kCodeUnitScale); 774 thread_->stackPush(NoneType::object()); 775 thread_->stackPush(*builtin); 776 thread_->pushNativeFrame(0); 777 778 Function function(&scope, makeTestFunction(thread_)); 779 thread_->stackPush(*function); 780 thread_->stackPush(runtime_->newStrFromCStr("foo bar")); 781 thread_->stackPush(runtime_->emptyTuple()); 782 thread_->stackPush(runtime_->newDict()); 783 Frame* frame1 = thread_->pushCallFrame(*function); 784 frame1->setVirtualPC(42 * kCodeUnitScale); 785 frame1->setLocal(3, runtime_->newStrFromCStr("bar foo")); 786 frame1->setLocal(4, runtime_->newInt(88)); 787 frame1->setLocal(5, runtime_->newInt(-99)); // cellvar0 788 frame1->setLocal(6, runtime_->newInt(12)); // cellvar1 789 frame1->setLocal(7, runtime_->newInt(34)); // cellvar2 790 791 thread_->stackPush(runtime_->newInt(-8)); 792 thread_->stackPush(runtime_->newStrFromCStr("baz bam")); 793 thread_->stackPush(*func); 794 thread_->stackPush(runtime_->newInt(-9)); 795 thread_->stackPush(runtime_->newInt(17)); 796 Frame* frame2 = thread_->pushCallFrame(*func); 797 frame2->setVirtualPC(4 * kCodeUnitScale); 798 frame2->setLocal(2, runtime_->newStrFromCStr("world")); 799 800 std::stringstream ss; 801 ss << thread_->currentFrame(); 802 EXPECT_EQ(ss.str(), R"(- initial frame 803 pc: 16 804 stack: 805 0: None 806- function: <function "test._bytearray_check"> 807 code: "_bytearray_check" 808 pc: n/a (native) 809- function: <function "footype.baz"> 810 code: "name0" 811 pc: 84 ("filename0":0) 812 locals: 813 0 "argument0": "foo bar" 814 1 "varargs": () 815 2 "varkeyargs": {} 816 3 "variable0": "bar foo" 817 4 "freevar0": 88 818 5 "cellvar0": -99 819 6 "cellvar1": 12 820 7 "cellvar2": 34 821 stack: 822 1: -8 823 0: "baz bam" 824- function: <function "func"> 825 code: "func" 826 pc: 8 ("<test string>":4) 827 locals: 828 0 "arg0": -9 829 1 "arg1": 17 830 2 "hello": "world" 831)"); 832} 833 834TEST_F(DebuggingTests, FormatFrameNullptr) { 835 std::stringstream ss; 836 ss << static_cast<Frame*>(nullptr); 837 EXPECT_EQ(ss.str(), "<nullptr>"); 838} 839 840TEST_F(DebuggingTests, FormatValueCellWithValue) { 841 HandleScope scope(thread_); 842 Object value(&scope, runtime_->newInt(42)); 843 Object value_cell(&scope, runtime_->newValueCell()); 844 ValueCell::cast(*value_cell).setValue(*value); 845 std::stringstream ss; 846 ss << value_cell; 847 EXPECT_EQ(ss.str(), "<value_cell (42)>"); 848} 849 850TEST_F(DebuggingTests, FormatValueCellPlaceHolder) { 851 HandleScope scope(thread_); 852 Object value_cell(&scope, runtime_->newValueCell()); 853 ValueCell::cast(*value_cell).makePlaceholder(); 854 std::stringstream ss; 855 ss << value_cell; 856 EXPECT_EQ(ss.str(), "<value_cell placeholder>"); 857} 858 859TEST_F(DebuggingTests, FormatWeakLink) { 860 HandleScope scope(thread_); 861 Object referent(&scope, NoneType::object()); 862 Object prev(&scope, SmallInt::fromWord(1)); 863 Object next(&scope, SmallInt::fromWord(2)); 864 Object link(&scope, runtime_->newWeakLink(thread_, referent, prev, next)); 865 std::stringstream ss; 866 ss << link; 867 std::stringstream expected; 868 expected << "<_weaklink 0x" << std::hex << link.raw() << std::dec 869 << " referent=None, next=0x4, prev=0x2>"; 870 EXPECT_EQ(ss.str(), expected.str()); 871} 872 873TEST_F(DebuggingTests, FormatThreadDumpsPendingException) { 874 thread_->raiseWithFmt(LayoutId::kValueError, "foo"); 875 std::stringstream ss; 876 ss << thread_; 877 EXPECT_EQ(ss.str(), R"(pending exception type: <type "ValueError"> 878pending exception value: "foo" 879pending exception traceback: None 880)"); 881} 882 883} // namespace testing 884} // namespace py