175 lines · cpp
1//===-- TestOptionValue.cpp -------- -------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Interpreter/OptionValues.h"10#include "gmock/gmock.h"11#include "gtest/gtest.h"12 13using namespace lldb_private;14 15class Callback {16public:17 virtual void Invoke() const {}18 void operator()() const { Invoke(); }19 20protected:21 ~Callback() = default;22};23 24class MockCallback final : public Callback {25public:26 MOCK_CONST_METHOD0(Invoke, void());27};28 29// Test a single-value class.30TEST(OptionValueString, DeepCopy) {31 OptionValueString str;32 str.SetValueFromString("ab");33 34 MockCallback callback;35 str.SetValueChangedCallback([&callback] { callback(); });36 EXPECT_CALL(callback, Invoke());37 38 auto copy_sp = str.DeepCopy(nullptr);39 40 // Test that the base class data members are copied/set correctly.41 ASSERT_TRUE(copy_sp);42 ASSERT_EQ(copy_sp->GetParent().get(), nullptr);43 ASSERT_TRUE(copy_sp->OptionWasSet());44 ASSERT_EQ(copy_sp->GetValueAs<llvm::StringRef>(), "ab");45 46 // Trigger the callback.47 copy_sp->SetValueFromString("c", eVarSetOperationAppend);48 ASSERT_EQ(copy_sp->GetValueAs<llvm::StringRef>(), "abc");49}50 51// Test an aggregate class.52TEST(OptionValueArgs, DeepCopy) {53 OptionValueArgs args;54 args.SetValueFromString("A B");55 56 MockCallback callback;57 args.SetValueChangedCallback([&callback] { callback(); });58 EXPECT_CALL(callback, Invoke());59 60 auto copy_sp = args.DeepCopy(nullptr);61 62 // Test that the base class data members are copied/set correctly.63 ASSERT_TRUE(copy_sp);64 ASSERT_EQ(copy_sp->GetParent(), nullptr);65 ASSERT_TRUE(copy_sp->OptionWasSet());66 67 auto *args_copy_ptr = copy_sp->GetAsArgs();68 ASSERT_EQ(args_copy_ptr->GetSize(), 2U);69 ASSERT_EQ((*args_copy_ptr)[0]->GetParent(), copy_sp);70 ASSERT_EQ((*args_copy_ptr)[0]->GetValueAs<llvm::StringRef>(), "A");71 ASSERT_EQ((*args_copy_ptr)[1]->GetParent(), copy_sp);72 ASSERT_EQ((*args_copy_ptr)[1]->GetValueAs<llvm::StringRef>(), "B");73 74 // Trigger the callback.75 copy_sp->SetValueFromString("C", eVarSetOperationAppend);76 ASSERT_TRUE(args_copy_ptr);77 ASSERT_EQ(args_copy_ptr->GetSize(), 3U);78 ASSERT_EQ((*args_copy_ptr)[2]->GetValueAs<llvm::StringRef>(), "C");79}80 81class TestProperties : public OptionValueProperties {82public:83 static std::shared_ptr<TestProperties> CreateGlobal() {84 auto props_sp = std::make_shared<TestProperties>();85 const bool is_global = false;86 87 auto dict_sp = std::make_shared<OptionValueDictionary>(1 << eTypeUInt64);88 props_sp->AppendProperty("dict", "", is_global, dict_sp);89 90 auto file_list_sp = std::make_shared<OptionValueFileSpecList>();91 props_sp->AppendProperty("file-list", "", is_global, file_list_sp);92 return props_sp;93 }94 95 void SetDictionaryChangedCallback(const MockCallback &callback) {96 SetValueChangedCallback(m_dict_index, [&callback] { callback(); });97 }98 99 void SetFileListChangedCallback(const MockCallback &callback) {100 SetValueChangedCallback(m_file_list_index, [&callback] { callback(); });101 }102 103 OptionValueDictionary *GetDictionary() {104 return GetPropertyAtIndexAsOptionValueDictionary(m_dict_index);105 }106 107 OptionValueFileSpecList *GetFileList() {108 return GetPropertyAtIndexAsOptionValueFileSpecList(m_file_list_index);109 }110 111private:112 lldb::OptionValueSP Clone() const override {113 return std::make_shared<TestProperties>(*this);114 }115 116 uint32_t m_dict_index = 0;117 uint32_t m_file_list_index = 1;118};119 120// Test a user-defined propery class.121TEST(TestProperties, DeepCopy) {122 auto props_sp = TestProperties::CreateGlobal();123 props_sp->GetDictionary()->SetValueFromString("A=1 B=2");124 props_sp->GetFileList()->SetValueFromString("path/to/file");125 126 MockCallback callback;127 props_sp->SetDictionaryChangedCallback(callback);128 props_sp->SetFileListChangedCallback(callback);129 EXPECT_CALL(callback, Invoke()).Times(2);130 131 auto copy_sp = props_sp->DeepCopy(nullptr);132 133 // Test that the base class data members are copied/set correctly.134 ASSERT_TRUE(copy_sp);135 ASSERT_EQ(copy_sp->GetParent(), nullptr);136 137 // This cast is safe only if the class overrides Clone().138 auto *props_copy_ptr = static_cast<TestProperties *>(copy_sp.get());139 ASSERT_TRUE(props_copy_ptr);140 141 // Test the first child.142 auto dict_copy_ptr = props_copy_ptr->GetDictionary();143 ASSERT_TRUE(dict_copy_ptr);144 ASSERT_EQ(dict_copy_ptr->GetParent(), copy_sp);145 ASSERT_TRUE(dict_copy_ptr->OptionWasSet());146 ASSERT_EQ(dict_copy_ptr->GetNumValues(), 2U);147 148 auto value_ptr = dict_copy_ptr->GetValueForKey("A");149 ASSERT_TRUE(value_ptr);150 ASSERT_EQ(value_ptr->GetParent().get(), dict_copy_ptr);151 ASSERT_EQ(value_ptr->GetValueAs<uint64_t>(), 1U);152 153 value_ptr = dict_copy_ptr->GetValueForKey("B");154 ASSERT_TRUE(value_ptr);155 ASSERT_EQ(value_ptr->GetParent().get(), dict_copy_ptr);156 ASSERT_EQ(value_ptr->GetValueAs<uint64_t>(), 2U);157 158 // Test the second child.159 auto file_list_copy_ptr = props_copy_ptr->GetFileList();160 ASSERT_TRUE(file_list_copy_ptr);161 ASSERT_EQ(file_list_copy_ptr->GetParent(), copy_sp);162 ASSERT_TRUE(file_list_copy_ptr->OptionWasSet());163 164 auto file_list_copy = file_list_copy_ptr->GetCurrentValue();165 ASSERT_EQ(file_list_copy.GetSize(), 1U);166 ASSERT_EQ(file_list_copy.GetFileSpecAtIndex(0), FileSpec("path/to/file"));167 168 // Trigger the callback first time.169 dict_copy_ptr->SetValueFromString("C=3", eVarSetOperationAppend);170 171 // Trigger the callback second time.172 file_list_copy_ptr->SetValueFromString("0 another/path",173 eVarSetOperationReplace);174}175