blob: 7f383424368be936f026c21e76e4b2775d63f7b3 [file] [log] [blame]
//===-- TestOptionValue.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 "lldb/Interpreter/OptionValues.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
using namespace lldb_private;
class Callback {
public:
virtual void Invoke() const {}
void operator()() const { Invoke(); }
protected:
~Callback() = default;
};
class MockCallback final : public Callback {
public:
MOCK_CONST_METHOD0(Invoke, void());
};
// Test a single-value class.
TEST(OptionValueString, DeepCopy) {
OptionValueString str;
str.SetValueFromString("ab");
MockCallback callback;
str.SetValueChangedCallback([&callback] { callback(); });
EXPECT_CALL(callback, Invoke());
auto copy_sp = str.DeepCopy(nullptr);
// Test that the base class data members are copied/set correctly.
ASSERT_TRUE(copy_sp);
ASSERT_EQ(copy_sp->GetParent().get(), nullptr);
ASSERT_TRUE(copy_sp->OptionWasSet());
ASSERT_EQ(copy_sp->GetStringValue(), "ab");
// Trigger the callback.
copy_sp->SetValueFromString("c", eVarSetOperationAppend);
ASSERT_EQ(copy_sp->GetStringValue(), "abc");
}
// Test an aggregate class.
TEST(OptionValueArgs, DeepCopy) {
OptionValueArgs args;
args.SetValueFromString("A B");
MockCallback callback;
args.SetValueChangedCallback([&callback] { callback(); });
EXPECT_CALL(callback, Invoke());
auto copy_sp = args.DeepCopy(nullptr);
// Test that the base class data members are copied/set correctly.
ASSERT_TRUE(copy_sp);
ASSERT_EQ(copy_sp->GetParent(), nullptr);
ASSERT_TRUE(copy_sp->OptionWasSet());
auto *args_copy_ptr = copy_sp->GetAsArgs();
ASSERT_EQ(args_copy_ptr->GetSize(), 2U);
ASSERT_EQ((*args_copy_ptr)[0]->GetParent(), copy_sp);
ASSERT_EQ((*args_copy_ptr)[0]->GetStringValue(), "A");
ASSERT_EQ((*args_copy_ptr)[1]->GetParent(), copy_sp);
ASSERT_EQ((*args_copy_ptr)[1]->GetStringValue(), "B");
// Trigger the callback.
copy_sp->SetValueFromString("C", eVarSetOperationAppend);
ASSERT_TRUE(args_copy_ptr);
ASSERT_EQ(args_copy_ptr->GetSize(), 3U);
ASSERT_EQ((*args_copy_ptr)[2]->GetStringValue(), "C");
}
class TestProperties : public OptionValueProperties {
public:
static std::shared_ptr<TestProperties> CreateGlobal() {
auto props_sp = std::make_shared<TestProperties>();
const bool is_global = false;
auto dict_sp = std::make_shared<OptionValueDictionary>(1 << eTypeUInt64);
props_sp->AppendProperty(ConstString("dict"), ConstString(), is_global,
dict_sp);
auto file_list_sp = std::make_shared<OptionValueFileSpecList>();
props_sp->AppendProperty(ConstString("file-list"), ConstString(), is_global,
file_list_sp);
return props_sp;
}
void SetDictionaryChangedCallback(const MockCallback &callback) {
SetValueChangedCallback(m_dict_index, [&callback] { callback(); });
}
void SetFileListChangedCallback(const MockCallback &callback) {
SetValueChangedCallback(m_file_list_index, [&callback] { callback(); });
}
OptionValueDictionary *GetDictionary() {
return GetPropertyAtIndexAsOptionValueDictionary(nullptr, m_dict_index);
}
OptionValueFileSpecList *GetFileList() {
return GetPropertyAtIndexAsOptionValueFileSpecList(nullptr, true,
m_file_list_index);
}
private:
lldb::OptionValueSP Clone() const {
return std::make_shared<TestProperties>(*this);
}
uint32_t m_dict_index = 0;
uint32_t m_file_list_index = 1;
};
// Test a user-defined propery class.
TEST(TestProperties, DeepCopy) {
auto props_sp = TestProperties::CreateGlobal();
props_sp->GetDictionary()->SetValueFromString("A=1 B=2");
props_sp->GetFileList()->SetValueFromString("path/to/file");
MockCallback callback;
props_sp->SetDictionaryChangedCallback(callback);
props_sp->SetFileListChangedCallback(callback);
EXPECT_CALL(callback, Invoke()).Times(2);
auto copy_sp = props_sp->DeepCopy(nullptr);
// Test that the base class data members are copied/set correctly.
ASSERT_TRUE(copy_sp);
ASSERT_EQ(copy_sp->GetParent(), nullptr);
// This cast is safe only if the class overrides Clone().
auto *props_copy_ptr = static_cast<TestProperties *>(copy_sp.get());
ASSERT_TRUE(props_copy_ptr);
// Test the first child.
auto dict_copy_ptr = props_copy_ptr->GetDictionary();
ASSERT_TRUE(dict_copy_ptr);
ASSERT_EQ(dict_copy_ptr->GetParent(), copy_sp);
ASSERT_TRUE(dict_copy_ptr->OptionWasSet());
ASSERT_EQ(dict_copy_ptr->GetNumValues(), 2U);
auto value_ptr = dict_copy_ptr->GetValueForKey(ConstString("A"));
ASSERT_TRUE(value_ptr);
ASSERT_EQ(value_ptr->GetParent().get(), dict_copy_ptr);
ASSERT_EQ(value_ptr->GetUInt64Value(), 1U);
value_ptr = dict_copy_ptr->GetValueForKey(ConstString("B"));
ASSERT_TRUE(value_ptr);
ASSERT_EQ(value_ptr->GetParent().get(), dict_copy_ptr);
ASSERT_EQ(value_ptr->GetUInt64Value(), 2U);
// Test the second child.
auto file_list_copy_ptr = props_copy_ptr->GetFileList();
ASSERT_TRUE(file_list_copy_ptr);
ASSERT_EQ(file_list_copy_ptr->GetParent(), copy_sp);
ASSERT_TRUE(file_list_copy_ptr->OptionWasSet());
auto file_list_copy = file_list_copy_ptr->GetCurrentValue();
ASSERT_EQ(file_list_copy.GetSize(), 1U);
ASSERT_EQ(file_list_copy.GetFileSpecAtIndex(0), FileSpec("path/to/file"));
// Trigger the callback first time.
dict_copy_ptr->SetValueFromString("C=3", eVarSetOperationAppend);
// Trigger the callback second time.
file_list_copy_ptr->SetValueFromString("0 another/path", eVarSetOperationReplace);
}