xref: /llvm-project/lldb/unittests/Interpreter/TestOptionValue.cpp (revision 2014572d9a6839745a920ec19ebfa73814548061)
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 
13 using namespace lldb_private;
14 
15 class Callback {
16 public:
Invoke() const17   virtual void Invoke() const {}
operator ()() const18   void operator()() const { Invoke(); }
19 
20 protected:
21   ~Callback() = default;
22 };
23 
24 class MockCallback final : public Callback {
25 public:
26   MOCK_CONST_METHOD0(Invoke, void());
27 };
28 
29 // Test a single-value class.
TEST(OptionValueString,DeepCopy)30 TEST(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.
TEST(OptionValueArgs,DeepCopy)52 TEST(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 
81 class TestProperties : public OptionValueProperties {
82 public:
CreateGlobal()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 
SetDictionaryChangedCallback(const MockCallback & callback)95   void SetDictionaryChangedCallback(const MockCallback &callback) {
96     SetValueChangedCallback(m_dict_index, [&callback] { callback(); });
97   }
98 
SetFileListChangedCallback(const MockCallback & callback)99   void SetFileListChangedCallback(const MockCallback &callback) {
100     SetValueChangedCallback(m_file_list_index, [&callback] { callback(); });
101   }
102 
GetDictionary()103   OptionValueDictionary *GetDictionary() {
104     return GetPropertyAtIndexAsOptionValueDictionary(m_dict_index);
105   }
106 
GetFileList()107   OptionValueFileSpecList *GetFileList() {
108     return GetPropertyAtIndexAsOptionValueFileSpecList(m_file_list_index);
109   }
110 
111 private:
Clone() const112   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.
TEST(TestProperties,DeepCopy)121 TEST(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