Skip to content

[lldb][Test] Add C++ tests for DumpValueObjectOptions and enums #93158

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lldb/unittests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ add_subdirectory(tools)
add_subdirectory(UnwindAssembly)
add_subdirectory(Utility)
add_subdirectory(Thread)
add_subdirectory(ValueObject)

if(LLDB_CAN_USE_DEBUGSERVER AND LLDB_TOOL_DEBUGSERVER_BUILD AND NOT LLDB_USE_SYSTEM_DEBUGSERVER)
add_subdirectory(debugserver)
Expand Down
10 changes: 10 additions & 0 deletions lldb/unittests/ValueObject/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
add_lldb_unittest(LLDBValueObjectTests
DumpValueObjectOptionsTests.cpp

LINK_LIBS
lldbPluginPlatformLinux
lldbPluginScriptInterpreterNone

LINK_COMPONENTS
Support
)
176 changes: 176 additions & 0 deletions lldb/unittests/ValueObject/DumpValueObjectOptionsTests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
//===-- DumpValueObjectOptionsTests.cpp -----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "Plugins/Platform/Linux/PlatformLinux.h"
#include "Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h"
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "TestingSupport/SubsystemRAII.h"
#include "TestingSupport/Symbol/ClangTestUtils.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/DumpValueObjectOptions.h"

#include "gtest/gtest.h"

using namespace lldb;
using namespace lldb_private;

struct MockProcess : Process {
MockProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp)
: Process(target_sp, listener_sp) {}

llvm::StringRef GetPluginName() override { return "mock process"; }

bool CanDebug(lldb::TargetSP target, bool plugin_specified_by_name) override {
return false;
};

Status DoDestroy() override { return {}; }

void RefreshStateAfterStop() override {}

bool DoUpdateThreadList(ThreadList &old_thread_list,
ThreadList &new_thread_list) override {
return false;
};

size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
Status &error) override {
// No need to read memory in these tests.
return size;
}
};

class ValueObjectMockProcessTest : public ::testing::Test {
public:
void SetUp() override {
ArchSpec arch("i386-pc-linux");
Platform::SetHostPlatform(
platform_linux::PlatformLinux::CreateInstance(true, &arch));
m_debugger_sp = Debugger::CreateInstance();
ASSERT_TRUE(m_debugger_sp);
m_debugger_sp->GetTargetList().CreateTarget(*m_debugger_sp, "", arch,
eLoadDependentsNo,
m_platform_sp, m_target_sp);
ASSERT_TRUE(m_target_sp);
ASSERT_TRUE(m_target_sp->GetArchitecture().IsValid());
ASSERT_TRUE(m_platform_sp);
m_listener_sp = Listener::MakeListener("dummy");
m_process_sp = std::make_shared<MockProcess>(m_target_sp, m_listener_sp);
ASSERT_TRUE(m_process_sp);
m_exe_ctx = ExecutionContext(m_process_sp);

m_holder = std::make_unique<clang_utils::TypeSystemClangHolder>("test");
m_type_system = m_holder->GetAST();
}

CompilerType
MakeEnumType(const std::vector<std::pair<const char *, int>> enumerators) {
CompilerType uint_type = m_type_system->GetBuiltinTypeForEncodingAndBitSize(
lldb::eEncodingUint, 32);
CompilerType enum_type = m_type_system->CreateEnumerationType(
"TestEnum", m_type_system->GetTranslationUnitDecl(),
OptionalClangModuleID(), Declaration(), uint_type, false);

m_type_system->StartTagDeclarationDefinition(enum_type);
Declaration decl;
for (auto [name, value] : enumerators)
m_type_system->AddEnumerationValueToEnumerationType(enum_type, decl, name,
value, 32);
m_type_system->CompleteTagDeclarationDefinition(enum_type);

return enum_type;
}

void TestDumpValueObject(
CompilerType enum_type,
const std::vector<
std::tuple<uint32_t, DumpValueObjectOptions, const char *>> &tests) {
StreamString strm;
ConstString var_name("test_var");
ByteOrder endian = endian::InlHostByteOrder();
ExecutionContextScope *exe_scope = m_exe_ctx.GetBestExecutionContextScope();
for (auto [value, options, expected] : tests) {
DataExtractor data_extractor{&value, sizeof(value), endian, 4};
ValueObjectConstResult::Create(exe_scope, enum_type, var_name,
data_extractor)
->Dump(strm, options);
ASSERT_STREQ(strm.GetString().str().c_str(), expected);
strm.Clear();
}
}

ExecutionContext m_exe_ctx;
TypeSystemClang *m_type_system;

private:
SubsystemRAII<FileSystem, HostInfo, platform_linux::PlatformLinux,
ScriptInterpreterNone>
m_subsystems;

std::unique_ptr<clang_utils::TypeSystemClangHolder> m_holder;
lldb::DebuggerSP m_debugger_sp;
lldb::TargetSP m_target_sp;
lldb::PlatformSP m_platform_sp;
lldb::ListenerSP m_listener_sp;
lldb::ProcessSP m_process_sp;
};

TEST_F(ValueObjectMockProcessTest, Enum) {
// This is not a bitfield-like enum, so values are printed as decimal by
// default. Also we only show the enumerator name if the value is an
// exact match.
TestDumpValueObject(
MakeEnumType({{"test_2", 2}, {"test_3", 3}}),
{{0, {}, "(TestEnum) test_var = 0\n"},
{1, {}, "(TestEnum) test_var = 1\n"},
{2, {}, "(TestEnum) test_var = test_2\n"},
{3, {}, "(TestEnum) test_var = test_3\n"},
{4, {}, "(TestEnum) test_var = 4\n"},
{5, {}, "(TestEnum) test_var = 5\n"},
{1, DumpValueObjectOptions().SetHideRootName(true), "(TestEnum) 1\n"},
{1, DumpValueObjectOptions().SetHideRootType(true), "test_var = 1\n"},
{1, DumpValueObjectOptions().SetHideRootName(true).SetHideRootType(true),
"1\n"},
{1, DumpValueObjectOptions().SetHideName(true), "(TestEnum) 1\n"},
{1, DumpValueObjectOptions().SetHideValue(true),
"(TestEnum) test_var =\n"},
{1, DumpValueObjectOptions().SetHideName(true).SetHideValue(true),
"(TestEnum) \n"}});
}

TEST_F(ValueObjectMockProcessTest, BitFieldLikeEnum) {
// These enumerators set individual bits in the value, as if it were a flag
// set. lldb treats this as a "bitfield like enum". This means we show values
// as hex, a value of 0 shows nothing, and values with no exact enumerator are
// shown as combinations of the other values.
TestDumpValueObject(
MakeEnumType({{"test_2", 2}, {"test_4", 4}}),
{
{0, {}, "(TestEnum) test_var =\n"},
{1, {}, "(TestEnum) test_var = 0x1\n"},
{2, {}, "(TestEnum) test_var = test_2\n"},
{4, {}, "(TestEnum) test_var = test_4\n"},
{6, {}, "(TestEnum) test_var = test_2 | test_4\n"},
{7, {}, "(TestEnum) test_var = test_2 | test_4 | 0x1\n"},
{8, {}, "(TestEnum) test_var = 0x8\n"},
{1, DumpValueObjectOptions().SetHideRootName(true),
"(TestEnum) 0x1\n"},
{1, DumpValueObjectOptions().SetHideRootType(true),
"test_var = 0x1\n"},
{1,
DumpValueObjectOptions().SetHideRootName(true).SetHideRootType(true),
"0x1\n"},
{1, DumpValueObjectOptions().SetHideName(true), "(TestEnum) 0x1\n"},
{1, DumpValueObjectOptions().SetHideValue(true),
"(TestEnum) test_var =\n"},
{1, DumpValueObjectOptions().SetHideName(true).SetHideValue(true),
"(TestEnum) \n"},
});
}
Loading