1 //===-- ReproducerTest.cpp ------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "gmock/gmock.h"
10 #include "gtest/gtest.h"
11
12 #include "lldb/Utility/FileSpec.h"
13 #include "lldb/Utility/Reproducer.h"
14 #include "lldb/Utility/ReproducerProvider.h"
15 #include "llvm/ADT/ScopeExit.h"
16 #include "llvm/Support/Error.h"
17 #include "llvm/Testing/Support/Error.h"
18
19 using namespace llvm;
20 using namespace lldb_private;
21 using namespace lldb_private::repro;
22
23 class DummyProvider : public repro::Provider<DummyProvider> {
24 public:
25 struct Info {
26 static const char *name;
27 static const char *file;
28 };
29
DummyProvider(const FileSpec & directory)30 DummyProvider(const FileSpec &directory) : Provider(directory) {}
31
32 static char ID;
33 };
34
35 class YamlMultiProvider
36 : public MultiProvider<YamlRecorder, YamlMultiProvider> {
37 public:
38 struct Info {
39 static const char *name;
40 static const char *file;
41 };
42
YamlMultiProvider(const FileSpec & directory)43 YamlMultiProvider(const FileSpec &directory) : MultiProvider(directory) {}
44
45 static char ID;
46 };
47
48 const char *DummyProvider::Info::name = "dummy";
49 const char *DummyProvider::Info::file = "dummy.yaml";
50 const char *YamlMultiProvider::Info::name = "mutli";
51 const char *YamlMultiProvider::Info::file = "mutli.yaml";
52 char DummyProvider::ID = 0;
53 char YamlMultiProvider::ID = 0;
54
55 class DummyReproducer : public Reproducer {
56 public:
DummyReproducer()57 DummyReproducer() : Reproducer(){};
58
59 using Reproducer::SetCapture;
60 };
61
62 struct YamlData {
YamlDataYamlData63 YamlData() : i(-1) {}
YamlDataYamlData64 YamlData(int i) : i(i) {}
65 int i;
66 };
67
operator ==(const YamlData & LHS,const YamlData & RHS)68 inline bool operator==(const YamlData &LHS, const YamlData &RHS) {
69 return LHS.i == RHS.i;
70 }
71
72 LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(YamlData)
73
74 namespace llvm {
75 namespace yaml {
76 template <> struct MappingTraits<YamlData> {
mappingllvm::yaml::MappingTraits77 static void mapping(IO &io, YamlData &Y) { io.mapRequired("i", Y.i); };
78 };
79 } // namespace yaml
80 } // namespace llvm
81
TEST(ReproducerTest,SetCapture)82 TEST(ReproducerTest, SetCapture) {
83 DummyReproducer reproducer;
84
85 // Initially both generator and loader are unset.
86 EXPECT_EQ(nullptr, reproducer.GetGenerator());
87 EXPECT_EQ(nullptr, reproducer.GetLoader());
88
89 // Enable capture and check that means we have a generator.
90 EXPECT_THAT_ERROR(
91 reproducer.SetCapture(FileSpec("//bogus/path", FileSpec::Style::posix)),
92 Succeeded());
93 EXPECT_NE(nullptr, reproducer.GetGenerator());
94 EXPECT_EQ(FileSpec("//bogus/path", FileSpec::Style::posix),
95 reproducer.GetGenerator()->GetRoot());
96 EXPECT_EQ(FileSpec("//bogus/path", FileSpec::Style::posix),
97 reproducer.GetReproducerPath());
98
99 // Ensure that we cannot enable replay.
100 EXPECT_EQ(nullptr, reproducer.GetLoader());
101
102 // Ensure we can disable the generator again.
103 EXPECT_THAT_ERROR(reproducer.SetCapture(llvm::None), Succeeded());
104 EXPECT_EQ(nullptr, reproducer.GetGenerator());
105 EXPECT_EQ(nullptr, reproducer.GetLoader());
106 }
107
TEST(GeneratorTest,Create)108 TEST(GeneratorTest, Create) {
109 DummyReproducer reproducer;
110
111 EXPECT_THAT_ERROR(
112 reproducer.SetCapture(FileSpec("//bogus/path", FileSpec::Style::posix)),
113 Succeeded());
114 auto &generator = *reproducer.GetGenerator();
115
116 auto *provider = generator.Create<DummyProvider>();
117 EXPECT_NE(nullptr, provider);
118 EXPECT_EQ(FileSpec("//bogus/path", FileSpec::Style::posix),
119 provider->GetRoot());
120 }
121
TEST(GeneratorTest,Get)122 TEST(GeneratorTest, Get) {
123 DummyReproducer reproducer;
124
125 EXPECT_THAT_ERROR(
126 reproducer.SetCapture(FileSpec("//bogus/path", FileSpec::Style::posix)),
127 Succeeded());
128 auto &generator = *reproducer.GetGenerator();
129
130 auto *provider = generator.Create<DummyProvider>();
131 EXPECT_NE(nullptr, provider);
132
133 auto *provider_alt = generator.Get<DummyProvider>();
134 EXPECT_EQ(provider, provider_alt);
135 }
136
TEST(GeneratorTest,GetOrCreate)137 TEST(GeneratorTest, GetOrCreate) {
138 DummyReproducer reproducer;
139
140 EXPECT_THAT_ERROR(
141 reproducer.SetCapture(FileSpec("//bogus/path", FileSpec::Style::posix)),
142 Succeeded());
143 auto &generator = *reproducer.GetGenerator();
144
145 auto &provider = generator.GetOrCreate<DummyProvider>();
146 EXPECT_EQ(FileSpec("//bogus/path", FileSpec::Style::posix),
147 provider.GetRoot());
148
149 auto &provider_alt = generator.GetOrCreate<DummyProvider>();
150 EXPECT_EQ(&provider, &provider_alt);
151 }
152
TEST(GeneratorTest,YamlMultiProvider)153 TEST(GeneratorTest, YamlMultiProvider) {
154 SmallString<128> root;
155 std::error_code ec = llvm::sys::fs::createUniqueDirectory("reproducer", root);
156 ASSERT_FALSE(static_cast<bool>(ec));
157
158 auto cleanup = llvm::make_scope_exit(
159 [&] { EXPECT_FALSE(llvm::sys::fs::remove_directories(root.str())); });
160
161 YamlData data0(0);
162 YamlData data1(1);
163 YamlData data2(2);
164 YamlData data3(3);
165
166 {
167 DummyReproducer reproducer;
168 EXPECT_THAT_ERROR(reproducer.SetCapture(FileSpec(root.str())), Succeeded());
169
170 auto &generator = *reproducer.GetGenerator();
171 auto *provider = generator.Create<YamlMultiProvider>();
172 ASSERT_NE(nullptr, provider);
173
174 auto *recorder = provider->GetNewRecorder();
175 ASSERT_NE(nullptr, recorder);
176 recorder->Record(data0);
177 recorder->Record(data1);
178
179 recorder = provider->GetNewRecorder();
180 ASSERT_NE(nullptr, recorder);
181 recorder->Record(data2);
182 recorder->Record(data3);
183
184 generator.Keep();
185 }
186 }
187