forked from OSchip/llvm-project
1168 lines
30 KiB
C++
1168 lines
30 KiB
C++
//===-- ReproducerInstrumentationTest.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 "gmock/gmock.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
#include <cmath>
|
|
#include <limits>
|
|
|
|
#include "lldb/Utility/ReproducerInstrumentation.h"
|
|
|
|
using namespace lldb_private;
|
|
using namespace lldb_private::repro;
|
|
|
|
struct Foo {
|
|
int m = 1;
|
|
};
|
|
struct Bar {
|
|
double m = 2;
|
|
};
|
|
|
|
bool operator==(const Foo &LHS, const Foo &RHS) { return LHS.m == RHS.m; }
|
|
bool operator==(const Bar &LHS, const Bar &RHS) { return LHS.m == RHS.m; }
|
|
|
|
struct Pod {
|
|
bool a = true;
|
|
bool b = false;
|
|
char c = 'a';
|
|
float d = 1.1f;
|
|
int e = 2;
|
|
long long f = 3;
|
|
long g = 4;
|
|
short h = 5;
|
|
unsigned char i = 'b';
|
|
unsigned int j = 6;
|
|
unsigned long long k = 7;
|
|
unsigned long l = 8;
|
|
unsigned short m = 9;
|
|
|
|
Pod() {}
|
|
};
|
|
|
|
class TestingRegistry : public Registry {
|
|
public:
|
|
TestingRegistry();
|
|
};
|
|
|
|
static std::unique_ptr<TestingRegistry> g_registry;
|
|
static llvm::Optional<Serializer> g_serializer;
|
|
static llvm::Optional<Deserializer> g_deserializer;
|
|
|
|
class TestInstrumentationData : public InstrumentationData {
|
|
public:
|
|
TestInstrumentationData() : InstrumentationData() {}
|
|
TestInstrumentationData(Serializer &serializer, Registry ®istry)
|
|
: InstrumentationData(serializer, registry) {}
|
|
TestInstrumentationData(Deserializer &deserializer, Registry ®istry)
|
|
: InstrumentationData(deserializer, registry) {}
|
|
};
|
|
|
|
inline TestInstrumentationData GetTestInstrumentationData() {
|
|
assert(!(g_serializer && g_deserializer));
|
|
if (g_serializer)
|
|
return TestInstrumentationData(*g_serializer, *g_registry);
|
|
if (g_deserializer)
|
|
return TestInstrumentationData(*g_deserializer, *g_registry);
|
|
return TestInstrumentationData();
|
|
}
|
|
|
|
class TestInstrumentationDataRAII {
|
|
public:
|
|
TestInstrumentationDataRAII(llvm::raw_string_ostream &os) {
|
|
g_registry = std::make_unique<TestingRegistry>();
|
|
g_serializer.emplace(os);
|
|
g_deserializer.reset();
|
|
}
|
|
|
|
TestInstrumentationDataRAII(llvm::StringRef buffer) {
|
|
g_registry = std::make_unique<TestingRegistry>();
|
|
g_serializer.reset();
|
|
g_deserializer.emplace(buffer);
|
|
}
|
|
|
|
~TestInstrumentationDataRAII() { Reset(); }
|
|
|
|
void Reset() {
|
|
g_registry.reset();
|
|
g_serializer.reset();
|
|
g_deserializer.reset();
|
|
}
|
|
|
|
static std::unique_ptr<TestInstrumentationDataRAII>
|
|
GetRecordingData(llvm::raw_string_ostream &os) {
|
|
return std::make_unique<TestInstrumentationDataRAII>(os);
|
|
}
|
|
|
|
static std::unique_ptr<TestInstrumentationDataRAII>
|
|
GetReplayData(llvm::StringRef buffer) {
|
|
return std::make_unique<TestInstrumentationDataRAII>(buffer);
|
|
}
|
|
};
|
|
|
|
#define LLDB_GET_INSTRUMENTATION_DATA() GetTestInstrumentationData()
|
|
|
|
enum class Class {
|
|
Foo,
|
|
Bar,
|
|
};
|
|
|
|
class Instrumented {
|
|
public:
|
|
virtual ~Instrumented() = default;
|
|
virtual void Validate() = 0;
|
|
virtual bool IsA(Class c) = 0;
|
|
};
|
|
|
|
class InstrumentedFoo : public Instrumented {
|
|
public:
|
|
InstrumentedFoo() = default;
|
|
/// Instrumented methods.
|
|
/// {
|
|
InstrumentedFoo(int i);
|
|
InstrumentedFoo(const InstrumentedFoo &foo);
|
|
InstrumentedFoo &operator=(const InstrumentedFoo &foo);
|
|
void A(int a);
|
|
int GetA();
|
|
void B(int &b) const;
|
|
int &GetB();
|
|
int C(float *c);
|
|
float GetC();
|
|
int D(const char *d) const;
|
|
size_t GetD(char *buffer, size_t length);
|
|
static void E(double e);
|
|
double GetE();
|
|
static int F();
|
|
bool GetF();
|
|
void Validate() override;
|
|
//// }
|
|
virtual bool IsA(Class c) override { return c == Class::Foo; }
|
|
|
|
private:
|
|
int m_a = 0;
|
|
mutable int m_b = 0;
|
|
float m_c = 0;
|
|
mutable std::string m_d = {};
|
|
static double g_e;
|
|
static bool g_f;
|
|
mutable int m_called = 0;
|
|
};
|
|
|
|
class InstrumentedBar : public Instrumented {
|
|
public:
|
|
/// Instrumented methods.
|
|
/// {
|
|
InstrumentedBar();
|
|
InstrumentedFoo GetInstrumentedFoo();
|
|
InstrumentedFoo &GetInstrumentedFooRef();
|
|
InstrumentedFoo *GetInstrumentedFooPtr();
|
|
void SetInstrumentedFoo(InstrumentedFoo *foo);
|
|
void SetInstrumentedFoo(InstrumentedFoo &foo);
|
|
void Validate() override;
|
|
/// }
|
|
virtual bool IsA(Class c) override { return c == Class::Bar; }
|
|
|
|
private:
|
|
bool m_get_instrumend_foo_called = false;
|
|
InstrumentedFoo *m_foo_set_by_ptr = nullptr;
|
|
InstrumentedFoo *m_foo_set_by_ref = nullptr;
|
|
};
|
|
|
|
double InstrumentedFoo::g_e = 0;
|
|
bool InstrumentedFoo::g_f = false;
|
|
|
|
struct Validator {
|
|
enum Validation { valid, invalid };
|
|
Validator(Class clazz, Validation validation)
|
|
: clazz(clazz), validation(validation) {}
|
|
Class clazz;
|
|
Validation validation;
|
|
};
|
|
|
|
void ValidateObjects(std::vector<void *> objects,
|
|
std::vector<Validator> validators) {
|
|
ASSERT_EQ(validators.size(), objects.size());
|
|
for (size_t i = 0; i < validators.size(); ++i) {
|
|
Validator &validator = validators[i];
|
|
Instrumented *instrumented = static_cast<Instrumented *>(objects[i]);
|
|
EXPECT_TRUE(instrumented->IsA(validator.clazz));
|
|
switch (validator.validation) {
|
|
case Validator::valid:
|
|
instrumented->Validate();
|
|
break;
|
|
case Validator::invalid:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
InstrumentedFoo::InstrumentedFoo(int i) {
|
|
LLDB_RECORD_CONSTRUCTOR(InstrumentedFoo, (int), i);
|
|
}
|
|
|
|
InstrumentedFoo::InstrumentedFoo(const InstrumentedFoo &foo) {
|
|
LLDB_RECORD_CONSTRUCTOR(InstrumentedFoo, (const InstrumentedFoo &), foo);
|
|
}
|
|
|
|
InstrumentedFoo &InstrumentedFoo::operator=(const InstrumentedFoo &foo) {
|
|
LLDB_RECORD_METHOD(InstrumentedFoo &,
|
|
InstrumentedFoo, operator=,(const InstrumentedFoo &), foo);
|
|
return *this;
|
|
}
|
|
|
|
void InstrumentedFoo::A(int a) {
|
|
LLDB_RECORD_METHOD(void, InstrumentedFoo, A, (int), a);
|
|
B(a);
|
|
m_a = a;
|
|
}
|
|
|
|
int InstrumentedFoo::GetA() {
|
|
LLDB_RECORD_METHOD_NO_ARGS(int, InstrumentedFoo, GetA);
|
|
|
|
return m_a;
|
|
}
|
|
|
|
void InstrumentedFoo::B(int &b) const {
|
|
LLDB_RECORD_METHOD_CONST(void, InstrumentedFoo, B, (int &), b);
|
|
m_called++;
|
|
m_b = b;
|
|
}
|
|
|
|
int &InstrumentedFoo::GetB() {
|
|
LLDB_RECORD_METHOD_NO_ARGS(int &, InstrumentedFoo, GetB);
|
|
|
|
return m_b;
|
|
}
|
|
|
|
int InstrumentedFoo::C(float *c) {
|
|
LLDB_RECORD_METHOD(int, InstrumentedFoo, C, (float *), c);
|
|
m_c = *c;
|
|
return 1;
|
|
}
|
|
|
|
float InstrumentedFoo::GetC() {
|
|
LLDB_RECORD_METHOD_NO_ARGS(float, InstrumentedFoo, GetC);
|
|
|
|
return m_c;
|
|
}
|
|
|
|
int InstrumentedFoo::D(const char *d) const {
|
|
LLDB_RECORD_METHOD_CONST(int, InstrumentedFoo, D, (const char *), d);
|
|
m_d = std::string(d);
|
|
return 2;
|
|
}
|
|
|
|
size_t InstrumentedFoo::GetD(char *buffer, size_t length) {
|
|
LLDB_RECORD_CHAR_PTR_METHOD(size_t, InstrumentedFoo, GetD, (char *, size_t),
|
|
buffer, "", length);
|
|
::snprintf(buffer, length, "%s", m_d.c_str());
|
|
return m_d.size();
|
|
}
|
|
|
|
void InstrumentedFoo::E(double e) {
|
|
LLDB_RECORD_STATIC_METHOD(void, InstrumentedFoo, E, (double), e);
|
|
g_e = e;
|
|
}
|
|
|
|
double InstrumentedFoo::GetE() {
|
|
LLDB_RECORD_METHOD_NO_ARGS(double, InstrumentedFoo, GetE);
|
|
|
|
return g_e;
|
|
}
|
|
|
|
int InstrumentedFoo::F() {
|
|
LLDB_RECORD_STATIC_METHOD_NO_ARGS(int, InstrumentedFoo, F);
|
|
g_f = true;
|
|
return 3;
|
|
}
|
|
|
|
bool InstrumentedFoo::GetF() {
|
|
LLDB_RECORD_METHOD_NO_ARGS(bool, InstrumentedFoo, GetF);
|
|
|
|
return g_f;
|
|
}
|
|
|
|
void InstrumentedFoo::Validate() {
|
|
LLDB_RECORD_METHOD_NO_ARGS(void, InstrumentedFoo, Validate);
|
|
EXPECT_EQ(m_a, 100);
|
|
EXPECT_EQ(m_b, 200);
|
|
EXPECT_NEAR(m_c, 300.3, 0.01);
|
|
EXPECT_EQ(m_d, "bar");
|
|
EXPECT_NEAR(g_e, 400.4, 0.01);
|
|
EXPECT_EQ(g_f, true);
|
|
EXPECT_EQ(2, m_called);
|
|
}
|
|
|
|
InstrumentedBar::InstrumentedBar() {
|
|
LLDB_RECORD_CONSTRUCTOR_NO_ARGS(InstrumentedBar);
|
|
}
|
|
|
|
InstrumentedFoo InstrumentedBar::GetInstrumentedFoo() {
|
|
LLDB_RECORD_METHOD_NO_ARGS(InstrumentedFoo, InstrumentedBar,
|
|
GetInstrumentedFoo);
|
|
m_get_instrumend_foo_called = true;
|
|
return LLDB_RECORD_RESULT(InstrumentedFoo(0));
|
|
}
|
|
|
|
InstrumentedFoo &InstrumentedBar::GetInstrumentedFooRef() {
|
|
LLDB_RECORD_METHOD_NO_ARGS(InstrumentedFoo &, InstrumentedBar,
|
|
GetInstrumentedFooRef);
|
|
InstrumentedFoo *foo = new InstrumentedFoo(0);
|
|
m_get_instrumend_foo_called = true;
|
|
return LLDB_RECORD_RESULT(*foo);
|
|
}
|
|
|
|
InstrumentedFoo *InstrumentedBar::GetInstrumentedFooPtr() {
|
|
LLDB_RECORD_METHOD_NO_ARGS(InstrumentedFoo *, InstrumentedBar,
|
|
GetInstrumentedFooPtr);
|
|
InstrumentedFoo *foo = new InstrumentedFoo(0);
|
|
m_get_instrumend_foo_called = true;
|
|
return LLDB_RECORD_RESULT(foo);
|
|
}
|
|
|
|
void InstrumentedBar::SetInstrumentedFoo(InstrumentedFoo *foo) {
|
|
LLDB_RECORD_METHOD(void, InstrumentedBar, SetInstrumentedFoo,
|
|
(InstrumentedFoo *), foo);
|
|
m_foo_set_by_ptr = foo;
|
|
}
|
|
|
|
void InstrumentedBar::SetInstrumentedFoo(InstrumentedFoo &foo) {
|
|
LLDB_RECORD_METHOD(void, InstrumentedBar, SetInstrumentedFoo,
|
|
(InstrumentedFoo &), foo);
|
|
m_foo_set_by_ref = &foo;
|
|
}
|
|
|
|
void InstrumentedBar::Validate() {
|
|
LLDB_RECORD_METHOD_NO_ARGS(void, InstrumentedBar, Validate);
|
|
|
|
EXPECT_TRUE(m_get_instrumend_foo_called);
|
|
EXPECT_NE(m_foo_set_by_ptr, nullptr);
|
|
EXPECT_EQ(m_foo_set_by_ptr, m_foo_set_by_ref);
|
|
}
|
|
|
|
TestingRegistry::TestingRegistry() {
|
|
Registry &R = *this;
|
|
|
|
LLDB_REGISTER_CONSTRUCTOR(InstrumentedFoo, (int i));
|
|
LLDB_REGISTER_CONSTRUCTOR(InstrumentedFoo, (const InstrumentedFoo &));
|
|
LLDB_REGISTER_METHOD(InstrumentedFoo &,
|
|
InstrumentedFoo, operator=,(const InstrumentedFoo &));
|
|
LLDB_REGISTER_METHOD(void, InstrumentedFoo, A, (int));
|
|
LLDB_REGISTER_METHOD_CONST(void, InstrumentedFoo, B, (int &));
|
|
LLDB_REGISTER_METHOD(int, InstrumentedFoo, C, (float *));
|
|
LLDB_REGISTER_METHOD_CONST(int, InstrumentedFoo, D, (const char *));
|
|
LLDB_REGISTER_STATIC_METHOD(void, InstrumentedFoo, E, (double));
|
|
LLDB_REGISTER_STATIC_METHOD(int, InstrumentedFoo, F, ());
|
|
LLDB_REGISTER_METHOD(void, InstrumentedFoo, Validate, ());
|
|
|
|
LLDB_REGISTER_CONSTRUCTOR(InstrumentedBar, ());
|
|
LLDB_REGISTER_METHOD(InstrumentedFoo, InstrumentedBar, GetInstrumentedFoo,
|
|
());
|
|
LLDB_REGISTER_METHOD(InstrumentedFoo &, InstrumentedBar,
|
|
GetInstrumentedFooRef, ());
|
|
LLDB_REGISTER_METHOD(InstrumentedFoo *, InstrumentedBar,
|
|
GetInstrumentedFooPtr, ());
|
|
LLDB_REGISTER_METHOD(void, InstrumentedBar, SetInstrumentedFoo,
|
|
(InstrumentedFoo *));
|
|
LLDB_REGISTER_METHOD(void, InstrumentedBar, SetInstrumentedFoo,
|
|
(InstrumentedFoo &));
|
|
LLDB_REGISTER_METHOD(void, InstrumentedBar, Validate, ());
|
|
LLDB_REGISTER_METHOD(int, InstrumentedFoo, GetA, ());
|
|
LLDB_REGISTER_METHOD(int &, InstrumentedFoo, GetB, ());
|
|
LLDB_REGISTER_METHOD(float, InstrumentedFoo, GetC, ());
|
|
LLDB_REGISTER_METHOD(size_t, InstrumentedFoo, GetD, (char *, size_t));
|
|
LLDB_REGISTER_METHOD(double, InstrumentedFoo, GetE, ());
|
|
LLDB_REGISTER_METHOD(bool, InstrumentedFoo, GetF, ());
|
|
}
|
|
|
|
static const Pod p;
|
|
|
|
TEST(IndexToObjectTest, ObjectForIndex) {
|
|
IndexToObject index_to_object;
|
|
Foo foo;
|
|
Bar bar;
|
|
|
|
EXPECT_EQ(nullptr, index_to_object.GetObjectForIndex<Foo>(1));
|
|
EXPECT_EQ(nullptr, index_to_object.GetObjectForIndex<Bar>(2));
|
|
|
|
index_to_object.AddObjectForIndex<Foo>(1, foo);
|
|
index_to_object.AddObjectForIndex<Bar>(2, &bar);
|
|
|
|
EXPECT_EQ(&foo, index_to_object.GetObjectForIndex<Foo>(1));
|
|
EXPECT_EQ(&bar, index_to_object.GetObjectForIndex<Bar>(2));
|
|
}
|
|
|
|
TEST(DeserializerTest, HasData) {
|
|
{
|
|
Deserializer deserializer("");
|
|
EXPECT_FALSE(deserializer.HasData(1));
|
|
}
|
|
|
|
{
|
|
Deserializer deserializer("a");
|
|
EXPECT_TRUE(deserializer.HasData(1));
|
|
EXPECT_FALSE(deserializer.HasData(2));
|
|
}
|
|
}
|
|
|
|
TEST(SerializationRountripTest, SerializeDeserializePod) {
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
|
|
Serializer serializer(os);
|
|
serializer.SerializeAll(p.a, p.b, p.c, p.d, p.e, p.f, p.g, p.h, p.i, p.j, p.k,
|
|
p.l, p.m);
|
|
|
|
llvm::StringRef buffer(os.str());
|
|
Deserializer deserializer(buffer);
|
|
|
|
EXPECT_EQ(p.a, deserializer.Deserialize<bool>());
|
|
EXPECT_EQ(p.b, deserializer.Deserialize<bool>());
|
|
EXPECT_EQ(p.c, deserializer.Deserialize<char>());
|
|
EXPECT_EQ(p.d, deserializer.Deserialize<float>());
|
|
EXPECT_EQ(p.e, deserializer.Deserialize<int>());
|
|
EXPECT_EQ(p.f, deserializer.Deserialize<long long>());
|
|
EXPECT_EQ(p.g, deserializer.Deserialize<long>());
|
|
EXPECT_EQ(p.h, deserializer.Deserialize<short>());
|
|
EXPECT_EQ(p.i, deserializer.Deserialize<unsigned char>());
|
|
EXPECT_EQ(p.j, deserializer.Deserialize<unsigned int>());
|
|
EXPECT_EQ(p.k, deserializer.Deserialize<unsigned long long>());
|
|
EXPECT_EQ(p.l, deserializer.Deserialize<unsigned long>());
|
|
EXPECT_EQ(p.m, deserializer.Deserialize<unsigned short>());
|
|
}
|
|
|
|
TEST(SerializationRountripTest, SerializeDeserializePodPointers) {
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
|
|
Serializer serializer(os);
|
|
serializer.SerializeAll(&p.a, &p.b, &p.c, &p.d, &p.e, &p.f, &p.g, &p.h, &p.i,
|
|
&p.j, &p.k, &p.l, &p.m);
|
|
|
|
llvm::StringRef buffer(os.str());
|
|
Deserializer deserializer(buffer);
|
|
|
|
EXPECT_EQ(p.a, *deserializer.Deserialize<bool *>());
|
|
EXPECT_EQ(p.b, *deserializer.Deserialize<bool *>());
|
|
EXPECT_EQ(p.c, *deserializer.Deserialize<char *>());
|
|
EXPECT_EQ(p.d, *deserializer.Deserialize<float *>());
|
|
EXPECT_EQ(p.e, *deserializer.Deserialize<int *>());
|
|
EXPECT_EQ(p.f, *deserializer.Deserialize<long long *>());
|
|
EXPECT_EQ(p.g, *deserializer.Deserialize<long *>());
|
|
EXPECT_EQ(p.h, *deserializer.Deserialize<short *>());
|
|
EXPECT_EQ(p.i, *deserializer.Deserialize<unsigned char *>());
|
|
EXPECT_EQ(p.j, *deserializer.Deserialize<unsigned int *>());
|
|
EXPECT_EQ(p.k, *deserializer.Deserialize<unsigned long long *>());
|
|
EXPECT_EQ(p.l, *deserializer.Deserialize<unsigned long *>());
|
|
EXPECT_EQ(p.m, *deserializer.Deserialize<unsigned short *>());
|
|
}
|
|
|
|
TEST(SerializationRountripTest, SerializeDeserializePodReferences) {
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
|
|
Serializer serializer(os);
|
|
serializer.SerializeAll(p.a, p.b, p.c, p.d, p.e, p.f, p.g, p.h, p.i, p.j, p.k,
|
|
p.l, p.m);
|
|
|
|
llvm::StringRef buffer(os.str());
|
|
Deserializer deserializer(buffer);
|
|
|
|
EXPECT_EQ(p.a, deserializer.Deserialize<bool &>());
|
|
EXPECT_EQ(p.b, deserializer.Deserialize<bool &>());
|
|
EXPECT_EQ(p.c, deserializer.Deserialize<char &>());
|
|
EXPECT_EQ(p.d, deserializer.Deserialize<float &>());
|
|
EXPECT_EQ(p.e, deserializer.Deserialize<int &>());
|
|
EXPECT_EQ(p.f, deserializer.Deserialize<long long &>());
|
|
EXPECT_EQ(p.g, deserializer.Deserialize<long &>());
|
|
EXPECT_EQ(p.h, deserializer.Deserialize<short &>());
|
|
EXPECT_EQ(p.i, deserializer.Deserialize<unsigned char &>());
|
|
EXPECT_EQ(p.j, deserializer.Deserialize<unsigned int &>());
|
|
EXPECT_EQ(p.k, deserializer.Deserialize<unsigned long long &>());
|
|
EXPECT_EQ(p.l, deserializer.Deserialize<unsigned long &>());
|
|
EXPECT_EQ(p.m, deserializer.Deserialize<unsigned short &>());
|
|
}
|
|
|
|
TEST(SerializationRountripTest, SerializeDeserializeCString) {
|
|
const char *cstr = "string";
|
|
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
|
|
Serializer serializer(os);
|
|
serializer.SerializeAll(cstr);
|
|
|
|
llvm::StringRef buffer(os.str());
|
|
Deserializer deserializer(buffer);
|
|
|
|
EXPECT_STREQ(cstr, deserializer.Deserialize<const char *>());
|
|
}
|
|
|
|
TEST(SerializationRountripTest, SerializeDeserializeCStringNull) {
|
|
const char *cstr = nullptr;
|
|
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
|
|
Serializer serializer(os);
|
|
serializer.SerializeAll(cstr);
|
|
|
|
llvm::StringRef buffer(os.str());
|
|
Deserializer deserializer(buffer);
|
|
|
|
EXPECT_EQ(nullptr, deserializer.Deserialize<const char *>());
|
|
}
|
|
|
|
TEST(SerializationRountripTest, SerializeDeserializeCStringArray) {
|
|
const char *foo = "foo";
|
|
const char *bar = "bar";
|
|
const char *baz = "baz";
|
|
const char *arr[4] = {foo, bar, baz, nullptr};
|
|
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
|
|
Serializer serializer(os);
|
|
serializer.SerializeAll(static_cast<const char **>(arr));
|
|
|
|
llvm::StringRef buffer(os.str());
|
|
Deserializer deserializer(buffer);
|
|
|
|
const char **deserialized = deserializer.Deserialize<const char **>();
|
|
EXPECT_STREQ("foo", deserialized[0]);
|
|
EXPECT_STREQ("bar", deserialized[1]);
|
|
EXPECT_STREQ("baz", deserialized[2]);
|
|
}
|
|
|
|
TEST(SerializationRountripTest, SerializeDeserializeCStringArrayNullptrElem) {
|
|
const char *arr[1] = {nullptr};
|
|
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
|
|
Serializer serializer(os);
|
|
serializer.SerializeAll(static_cast<const char **>(arr));
|
|
|
|
llvm::StringRef buffer(os.str());
|
|
Deserializer deserializer(buffer);
|
|
|
|
const char **deserialized = deserializer.Deserialize<const char **>();
|
|
EXPECT_EQ(nullptr, deserialized);
|
|
}
|
|
|
|
TEST(SerializationRountripTest, SerializeDeserializeCStringArrayNullptr) {
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
|
|
Serializer serializer(os);
|
|
serializer.SerializeAll(static_cast<const char **>(nullptr));
|
|
|
|
llvm::StringRef buffer(os.str());
|
|
Deserializer deserializer(buffer);
|
|
|
|
const char **deserialized = deserializer.Deserialize<const char **>();
|
|
EXPECT_EQ(nullptr, deserialized);
|
|
}
|
|
|
|
TEST(SerializationRountripTest, SerializeDeserializeObjectPointer) {
|
|
Foo foo;
|
|
Bar bar;
|
|
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
|
|
unsigned sequence = 123;
|
|
|
|
Serializer serializer(os);
|
|
serializer.SerializeAll(sequence, static_cast<unsigned>(1));
|
|
serializer.SerializeAll(sequence, static_cast<unsigned>(2));
|
|
serializer.SerializeAll(&foo, &bar);
|
|
|
|
llvm::StringRef buffer(os.str());
|
|
Deserializer deserializer(buffer);
|
|
|
|
deserializer.HandleReplayResult(&foo);
|
|
deserializer.HandleReplayResult(&bar);
|
|
|
|
EXPECT_EQ(foo, *deserializer.Deserialize<Foo *>());
|
|
EXPECT_EQ(bar, *deserializer.Deserialize<Bar *>());
|
|
}
|
|
|
|
TEST(SerializationRountripTest, SerializeDeserializeObjectReference) {
|
|
Foo foo;
|
|
Bar bar;
|
|
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
|
|
unsigned sequence = 123;
|
|
|
|
Serializer serializer(os);
|
|
serializer.SerializeAll(sequence, static_cast<unsigned>(1));
|
|
serializer.SerializeAll(sequence, static_cast<unsigned>(2));
|
|
serializer.SerializeAll(foo, bar);
|
|
|
|
llvm::StringRef buffer(os.str());
|
|
Deserializer deserializer(buffer);
|
|
|
|
deserializer.HandleReplayResult(&foo);
|
|
deserializer.HandleReplayResult(&bar);
|
|
|
|
EXPECT_EQ(foo, deserializer.Deserialize<Foo &>());
|
|
EXPECT_EQ(bar, deserializer.Deserialize<Bar &>());
|
|
}
|
|
|
|
TEST(RecordReplayTest, InstrumentedFoo) {
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
|
|
{
|
|
auto data = TestInstrumentationDataRAII::GetRecordingData(os);
|
|
|
|
int b = 200;
|
|
float c = 300.3f;
|
|
double e = 400.4;
|
|
|
|
InstrumentedFoo foo(0);
|
|
foo.A(100);
|
|
foo.B(b);
|
|
foo.C(&c);
|
|
foo.D("bar");
|
|
InstrumentedFoo::E(e);
|
|
InstrumentedFoo::F();
|
|
foo.Validate();
|
|
}
|
|
|
|
TestingRegistry registry;
|
|
Deserializer deserializer(os.str());
|
|
registry.Replay(deserializer);
|
|
|
|
ValidateObjects(deserializer.GetAllObjects(),
|
|
{{Class::Foo, Validator::valid}});
|
|
}
|
|
|
|
TEST(RecordReplayTest, InstrumentedFooSameThis) {
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
|
|
{
|
|
auto data = TestInstrumentationDataRAII::GetRecordingData(os);
|
|
|
|
int b = 200;
|
|
float c = 300.3f;
|
|
double e = 400.4;
|
|
|
|
InstrumentedFoo *foo = new InstrumentedFoo(0);
|
|
foo->A(100);
|
|
foo->B(b);
|
|
foo->C(&c);
|
|
foo->D("bar");
|
|
InstrumentedFoo::E(e);
|
|
InstrumentedFoo::F();
|
|
foo->Validate();
|
|
foo->~InstrumentedFoo();
|
|
|
|
InstrumentedFoo *foo2 = new (foo) InstrumentedFoo(0);
|
|
foo2->A(100);
|
|
foo2->B(b);
|
|
foo2->C(&c);
|
|
foo2->D("bar");
|
|
InstrumentedFoo::E(e);
|
|
InstrumentedFoo::F();
|
|
foo2->Validate();
|
|
delete foo2;
|
|
}
|
|
|
|
TestingRegistry registry;
|
|
Deserializer deserializer(os.str());
|
|
registry.Replay(deserializer);
|
|
|
|
ValidateObjects(deserializer.GetAllObjects(),
|
|
{{Class::Foo, Validator::valid}});
|
|
}
|
|
|
|
TEST(RecordReplayTest, InstrumentedBar) {
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
|
|
{
|
|
auto data = TestInstrumentationDataRAII::GetRecordingData(os);
|
|
|
|
InstrumentedBar bar;
|
|
InstrumentedFoo foo = bar.GetInstrumentedFoo();
|
|
|
|
int b = 200;
|
|
float c = 300.3f;
|
|
double e = 400.4;
|
|
|
|
foo.A(100);
|
|
foo.B(b);
|
|
foo.C(&c);
|
|
foo.D("bar");
|
|
InstrumentedFoo::E(e);
|
|
InstrumentedFoo::F();
|
|
foo.Validate();
|
|
|
|
bar.SetInstrumentedFoo(foo);
|
|
bar.SetInstrumentedFoo(&foo);
|
|
bar.Validate();
|
|
}
|
|
|
|
TestingRegistry registry;
|
|
Deserializer deserializer(os.str());
|
|
registry.Replay(deserializer);
|
|
|
|
ValidateObjects(
|
|
deserializer.GetAllObjects(),
|
|
{
|
|
{Class::Bar, Validator::valid}, // bar
|
|
{Class::Foo, Validator::invalid}, // bar.GetInstrumentedFoo()
|
|
{Class::Foo, Validator::valid}, // foo
|
|
});
|
|
}
|
|
|
|
TEST(RecordReplayTest, InstrumentedBarRef) {
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
|
|
{
|
|
auto data = TestInstrumentationDataRAII::GetRecordingData(os);
|
|
|
|
InstrumentedBar bar;
|
|
InstrumentedFoo &foo = bar.GetInstrumentedFooRef();
|
|
|
|
int b = 200;
|
|
float c = 300.3f;
|
|
double e = 400.4;
|
|
|
|
foo.A(100);
|
|
foo.B(b);
|
|
foo.C(&c);
|
|
foo.D("bar");
|
|
InstrumentedFoo::E(e);
|
|
InstrumentedFoo::F();
|
|
foo.Validate();
|
|
|
|
bar.SetInstrumentedFoo(foo);
|
|
bar.SetInstrumentedFoo(&foo);
|
|
bar.Validate();
|
|
}
|
|
|
|
TestingRegistry registry;
|
|
Deserializer deserializer(os.str());
|
|
registry.Replay(deserializer);
|
|
|
|
ValidateObjects(
|
|
deserializer.GetAllObjects(),
|
|
{{Class::Bar, Validator::valid}, {Class::Foo, Validator::valid}});
|
|
}
|
|
|
|
TEST(RecordReplayTest, InstrumentedBarPtr) {
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
|
|
{
|
|
auto data = TestInstrumentationDataRAII::GetRecordingData(os);
|
|
|
|
InstrumentedBar bar;
|
|
InstrumentedFoo &foo = *(bar.GetInstrumentedFooPtr());
|
|
|
|
int b = 200;
|
|
float c = 300.3f;
|
|
double e = 400.4;
|
|
|
|
foo.A(100);
|
|
foo.B(b);
|
|
foo.C(&c);
|
|
foo.D("bar");
|
|
InstrumentedFoo::E(e);
|
|
InstrumentedFoo::F();
|
|
foo.Validate();
|
|
|
|
bar.SetInstrumentedFoo(foo);
|
|
bar.SetInstrumentedFoo(&foo);
|
|
bar.Validate();
|
|
}
|
|
|
|
TestingRegistry registry;
|
|
Deserializer deserializer(os.str());
|
|
registry.Replay(deserializer);
|
|
|
|
ValidateObjects(
|
|
deserializer.GetAllObjects(),
|
|
{{Class::Bar, Validator::valid}, {Class::Foo, Validator::valid}});
|
|
}
|
|
|
|
TEST(PassiveReplayTest, InstrumentedFoo) {
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
|
|
{
|
|
auto data = TestInstrumentationDataRAII::GetRecordingData(os);
|
|
|
|
int b = 200;
|
|
float c = 300.3f;
|
|
double e = 400.4;
|
|
|
|
InstrumentedFoo foo(0);
|
|
foo.A(100);
|
|
foo.B(b);
|
|
foo.C(&c);
|
|
foo.D("bar");
|
|
InstrumentedFoo::E(e);
|
|
InstrumentedFoo::F();
|
|
foo.Validate();
|
|
|
|
EXPECT_EQ(foo.GetA(), 100);
|
|
EXPECT_EQ(foo.GetB(), 200);
|
|
EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
|
|
char buffer[100];
|
|
foo.GetD(buffer, 100);
|
|
EXPECT_STREQ(buffer, "bar");
|
|
EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
|
|
EXPECT_EQ(foo.GetF(), true);
|
|
}
|
|
|
|
std::string buffer = os.str();
|
|
|
|
{
|
|
auto data = TestInstrumentationDataRAII::GetReplayData(buffer);
|
|
|
|
int b = 999;
|
|
float c = 999.9f;
|
|
double e = 999.9;
|
|
|
|
InstrumentedFoo foo(9);
|
|
foo.A(999);
|
|
foo.B(b);
|
|
foo.C(&c);
|
|
foo.D("999");
|
|
InstrumentedFoo::E(e);
|
|
InstrumentedFoo::F();
|
|
foo.Validate();
|
|
|
|
EXPECT_EQ(foo.GetA(), 100);
|
|
EXPECT_EQ(foo.GetB(), 200);
|
|
EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
|
|
char buffer[100];
|
|
foo.GetD(buffer, 100);
|
|
EXPECT_STREQ(buffer, "bar");
|
|
EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
|
|
EXPECT_EQ(foo.GetF(), true);
|
|
}
|
|
}
|
|
|
|
TEST(PassiveReplayTest, InstrumentedFooInvalid) {
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
|
|
{
|
|
auto data = TestInstrumentationDataRAII::GetRecordingData(os);
|
|
|
|
int b = 200;
|
|
float c = 300.3f;
|
|
double e = 400.4;
|
|
|
|
InstrumentedFoo foo(0);
|
|
foo.A(100);
|
|
foo.B(b);
|
|
foo.C(&c);
|
|
foo.D("bar");
|
|
InstrumentedFoo::E(e);
|
|
InstrumentedFoo::F();
|
|
foo.Validate();
|
|
|
|
EXPECT_EQ(foo.GetA(), 100);
|
|
EXPECT_EQ(foo.GetB(), 200);
|
|
EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
|
|
EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
|
|
EXPECT_EQ(foo.GetF(), true);
|
|
}
|
|
|
|
std::string buffer = os.str();
|
|
|
|
{
|
|
auto data = TestInstrumentationDataRAII::GetReplayData(buffer);
|
|
|
|
int b = 999;
|
|
float c = 999.9f;
|
|
double e = 999.9;
|
|
|
|
InstrumentedFoo foo(9);
|
|
foo.A(999);
|
|
foo.B(b);
|
|
foo.C(&c);
|
|
foo.D("999");
|
|
InstrumentedFoo::E(e);
|
|
InstrumentedFoo::F();
|
|
foo.Validate();
|
|
|
|
EXPECT_EQ(foo.GetA(), 100);
|
|
// Detect divergence.
|
|
EXPECT_DEATH(foo.GetA(), "");
|
|
}
|
|
}
|
|
|
|
TEST(PassiveReplayTest, InstrumentedBar) {
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
|
|
{
|
|
auto data = TestInstrumentationDataRAII::GetRecordingData(os);
|
|
|
|
InstrumentedBar bar;
|
|
InstrumentedFoo foo = bar.GetInstrumentedFoo();
|
|
|
|
int b = 200;
|
|
float c = 300.3f;
|
|
double e = 400.4;
|
|
|
|
foo.A(100);
|
|
foo.B(b);
|
|
foo.C(&c);
|
|
foo.D("bar");
|
|
InstrumentedFoo::E(e);
|
|
InstrumentedFoo::F();
|
|
foo.Validate();
|
|
|
|
EXPECT_EQ(foo.GetA(), 100);
|
|
EXPECT_EQ(foo.GetB(), 200);
|
|
EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
|
|
char buffer[100];
|
|
foo.GetD(buffer, 100);
|
|
EXPECT_STREQ(buffer, "bar");
|
|
EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
|
|
EXPECT_EQ(foo.GetF(), true);
|
|
|
|
bar.SetInstrumentedFoo(foo);
|
|
bar.SetInstrumentedFoo(&foo);
|
|
bar.Validate();
|
|
}
|
|
|
|
std::string buffer = os.str();
|
|
|
|
{
|
|
auto data = TestInstrumentationDataRAII::GetReplayData(buffer);
|
|
|
|
InstrumentedBar bar;
|
|
InstrumentedFoo foo = bar.GetInstrumentedFoo();
|
|
|
|
int b = 99;
|
|
float c = 999.9f;
|
|
double e = 999.9;
|
|
|
|
foo.A(999);
|
|
foo.B(b);
|
|
foo.C(&c);
|
|
foo.D("999");
|
|
InstrumentedFoo::E(e);
|
|
InstrumentedFoo::F();
|
|
foo.Validate();
|
|
|
|
EXPECT_EQ(foo.GetA(), 100);
|
|
EXPECT_EQ(foo.GetB(), 200);
|
|
EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
|
|
char buffer[100];
|
|
foo.GetD(buffer, 100);
|
|
EXPECT_STREQ(buffer, "bar");
|
|
EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
|
|
EXPECT_EQ(foo.GetF(), true);
|
|
|
|
bar.SetInstrumentedFoo(foo);
|
|
bar.SetInstrumentedFoo(&foo);
|
|
bar.Validate();
|
|
}
|
|
}
|
|
|
|
TEST(PassiveReplayTest, InstrumentedBarRef) {
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
|
|
{
|
|
auto data = TestInstrumentationDataRAII::GetRecordingData(os);
|
|
|
|
InstrumentedBar bar;
|
|
InstrumentedFoo &foo = bar.GetInstrumentedFooRef();
|
|
|
|
int b = 200;
|
|
float c = 300.3f;
|
|
double e = 400.4;
|
|
|
|
foo.A(100);
|
|
foo.B(b);
|
|
foo.C(&c);
|
|
foo.D("bar");
|
|
InstrumentedFoo::E(e);
|
|
InstrumentedFoo::F();
|
|
foo.Validate();
|
|
|
|
EXPECT_EQ(foo.GetA(), 100);
|
|
EXPECT_EQ(foo.GetB(), 200);
|
|
EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
|
|
char buffer[100];
|
|
foo.GetD(buffer, 100);
|
|
EXPECT_STREQ(buffer, "bar");
|
|
EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
|
|
EXPECT_EQ(foo.GetF(), true);
|
|
|
|
bar.SetInstrumentedFoo(foo);
|
|
bar.SetInstrumentedFoo(&foo);
|
|
bar.Validate();
|
|
}
|
|
|
|
std::string buffer = os.str();
|
|
|
|
{
|
|
auto data = TestInstrumentationDataRAII::GetReplayData(buffer);
|
|
|
|
InstrumentedBar bar;
|
|
InstrumentedFoo &foo = bar.GetInstrumentedFooRef();
|
|
|
|
int b = 99;
|
|
float c = 999.9f;
|
|
double e = 999.9;
|
|
|
|
foo.A(999);
|
|
foo.B(b);
|
|
foo.C(&c);
|
|
foo.D("999");
|
|
InstrumentedFoo::E(e);
|
|
InstrumentedFoo::F();
|
|
foo.Validate();
|
|
|
|
EXPECT_EQ(foo.GetA(), 100);
|
|
EXPECT_EQ(foo.GetB(), 200);
|
|
EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
|
|
char buffer[100];
|
|
foo.GetD(buffer, 100);
|
|
EXPECT_STREQ(buffer, "bar");
|
|
EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
|
|
EXPECT_EQ(foo.GetF(), true);
|
|
|
|
bar.SetInstrumentedFoo(foo);
|
|
bar.SetInstrumentedFoo(&foo);
|
|
bar.Validate();
|
|
}
|
|
}
|
|
|
|
TEST(PassiveReplayTest, InstrumentedBarPtr) {
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
|
|
{
|
|
auto data = TestInstrumentationDataRAII::GetRecordingData(os);
|
|
|
|
InstrumentedBar bar;
|
|
InstrumentedFoo &foo = *(bar.GetInstrumentedFooPtr());
|
|
|
|
int b = 200;
|
|
float c = 300.3f;
|
|
double e = 400.4;
|
|
|
|
foo.A(100);
|
|
foo.B(b);
|
|
foo.C(&c);
|
|
foo.D("bar");
|
|
InstrumentedFoo::E(e);
|
|
InstrumentedFoo::F();
|
|
foo.Validate();
|
|
|
|
EXPECT_EQ(foo.GetA(), 100);
|
|
EXPECT_EQ(foo.GetB(), 200);
|
|
EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
|
|
char buffer[100];
|
|
foo.GetD(buffer, 100);
|
|
EXPECT_STREQ(buffer, "bar");
|
|
EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
|
|
EXPECT_EQ(foo.GetF(), true);
|
|
|
|
bar.SetInstrumentedFoo(foo);
|
|
bar.SetInstrumentedFoo(&foo);
|
|
bar.Validate();
|
|
}
|
|
|
|
std::string buffer = os.str();
|
|
|
|
{
|
|
auto data = TestInstrumentationDataRAII::GetReplayData(buffer);
|
|
|
|
InstrumentedBar bar;
|
|
InstrumentedFoo &foo = *(bar.GetInstrumentedFooPtr());
|
|
|
|
int b = 99;
|
|
float c = 999.9f;
|
|
double e = 999.9;
|
|
|
|
foo.A(999);
|
|
foo.B(b);
|
|
foo.C(&c);
|
|
foo.D("999");
|
|
InstrumentedFoo::E(e);
|
|
InstrumentedFoo::F();
|
|
foo.Validate();
|
|
|
|
EXPECT_EQ(foo.GetA(), 100);
|
|
EXPECT_EQ(foo.GetB(), 200);
|
|
EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
|
|
char buffer[100];
|
|
foo.GetD(buffer, 100);
|
|
EXPECT_STREQ(buffer, "bar");
|
|
EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
|
|
EXPECT_EQ(foo.GetF(), true);
|
|
|
|
bar.SetInstrumentedFoo(foo);
|
|
bar.SetInstrumentedFoo(&foo);
|
|
bar.Validate();
|
|
}
|
|
}
|
|
|
|
TEST(RecordReplayTest, ValidSequence) {
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
|
|
{
|
|
auto data = TestInstrumentationDataRAII::GetRecordingData(os);
|
|
|
|
unsigned sequence = 1;
|
|
int (*f)() = &lldb_private::repro::invoke<int (*)()>::method<
|
|
InstrumentedFoo::F>::record;
|
|
unsigned id = g_registry->GetID(uintptr_t(f));
|
|
g_serializer->SerializeAll(sequence, id);
|
|
|
|
unsigned result = 0;
|
|
g_serializer->SerializeAll(sequence, result);
|
|
}
|
|
|
|
TestingRegistry registry;
|
|
Deserializer deserializer(os.str());
|
|
registry.Replay(deserializer);
|
|
}
|
|
|
|
TEST(RecordReplayTest, InvalidSequence) {
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
|
|
{
|
|
auto data = TestInstrumentationDataRAII::GetRecordingData(os);
|
|
|
|
unsigned sequence = 1;
|
|
int (*f)() = &lldb_private::repro::invoke<int (*)()>::method<
|
|
InstrumentedFoo::F>::record;
|
|
unsigned id = g_registry->GetID(uintptr_t(f));
|
|
g_serializer->SerializeAll(sequence, id);
|
|
|
|
unsigned result = 0;
|
|
unsigned invalid_sequence = 2;
|
|
g_serializer->SerializeAll(invalid_sequence, result);
|
|
}
|
|
|
|
TestingRegistry registry;
|
|
Deserializer deserializer(os.str());
|
|
EXPECT_DEATH(registry.Replay(deserializer), "");
|
|
}
|