| //===-- 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), ""); |
| } |