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-exception
6//
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(value: "ab");
33
34 MockCallback callback;
35 str.SetValueChangedCallback([&callback] { callback(); });
36 EXPECT_CALL(callback, Invoke());
37
38 auto copy_sp = str.DeepCopy(new_parent: 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(value: "c", op: 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(value: "A B");
55
56 MockCallback callback;
57 args.SetValueChangedCallback([&callback] { callback(); });
58 EXPECT_CALL(callback, Invoke());
59
60 auto copy_sp = args.DeepCopy(new_parent: 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(value: "C", op: 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>(args: 1 << eTypeUInt64);
88 props_sp->AppendProperty(name: "dict", desc: "", is_global, value_sp: dict_sp);
89
90 auto file_list_sp = std::make_shared<OptionValueFileSpecList>();
91 props_sp->AppendProperty(name: "file-list", desc: "", is_global, value_sp: file_list_sp);
92 return props_sp;
93 }
94
95 void SetDictionaryChangedCallback(const MockCallback &callback) {
96 SetValueChangedCallback(property_idx: m_dict_index, callback: [&callback] { callback(); });
97 }
98
99 void SetFileListChangedCallback(const MockCallback &callback) {
100 SetValueChangedCallback(property_idx: m_file_list_index, callback: [&callback] { callback(); });
101 }
102
103 OptionValueDictionary *GetDictionary() {
104 return GetPropertyAtIndexAsOptionValueDictionary(idx: m_dict_index);
105 }
106
107 OptionValueFileSpecList *GetFileList() {
108 return GetPropertyAtIndexAsOptionValueFileSpecList(idx: m_file_list_index);
109 }
110
111private:
112 lldb::OptionValueSP Clone() const override {
113 return std::make_shared<TestProperties>(args: *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(value: "A=1 B=2");
124 props_sp->GetFileList()->SetValueFromString(value: "path/to/file");
125
126 MockCallback callback;
127 props_sp->SetDictionaryChangedCallback(callback);
128 props_sp->SetFileListChangedCallback(callback);
129 EXPECT_CALL(callback, Invoke()).Times(n: 2);
130
131 auto copy_sp = props_sp->DeepCopy(new_parent: 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(key: "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(key: "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(value: "C=3", op: eVarSetOperationAppend);
170
171 // Trigger the callback second time.
172 file_list_copy_ptr->SetValueFromString(value: "0 another/path",
173 op: eVarSetOperationReplace);
174}
175

source code of lldb/unittests/Interpreter/TestOptionValue.cpp