blob: ce259c5969e09287f99a504699a29394ec7d980f [file] [log] [blame]
//===-- 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 &registry)
: InstrumentationData(serializer, registry) {}
TestInstrumentationData(Deserializer &deserializer, Registry &registry)
: 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), "");
}