1 //===- unittests/Driver/MultilibTest.cpp --- Multilib tests ---------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // Unit tests for Multilib and MultilibSet
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "clang/Driver/Multilib.h"
15 #include "clang/Basic/LLVM.h"
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/ADT/StringSwitch.h"
18 #include "gtest/gtest.h"
19
20 using namespace clang::driver;
21 using namespace clang;
22
TEST(MultilibTest,MultilibValidity)23 TEST(MultilibTest, MultilibValidity) {
24
25 ASSERT_TRUE(Multilib().isValid()) << "Empty multilib is not valid";
26
27 ASSERT_TRUE(Multilib().flag("+foo").isValid())
28 << "Single indicative flag is not valid";
29
30 ASSERT_TRUE(Multilib().flag("-foo").isValid())
31 << "Single contraindicative flag is not valid";
32
33 ASSERT_FALSE(Multilib().flag("+foo").flag("-foo").isValid())
34 << "Conflicting flags should invalidate the Multilib";
35
36 ASSERT_TRUE(Multilib().flag("+foo").flag("+foo").isValid())
37 << "Multilib should be valid even if it has the same flag twice";
38
39 ASSERT_TRUE(Multilib().flag("+foo").flag("-foobar").isValid())
40 << "Seemingly conflicting prefixes shouldn't actually conflict";
41 }
42
TEST(MultilibTest,OpEqReflexivity1)43 TEST(MultilibTest, OpEqReflexivity1) {
44 Multilib M;
45 ASSERT_TRUE(M == M) << "Multilib::operator==() is not reflexive";
46 }
47
TEST(MultilibTest,OpEqReflexivity2)48 TEST(MultilibTest, OpEqReflexivity2) {
49 ASSERT_TRUE(Multilib() == Multilib())
50 << "Separately constructed default multilibs are not equal";
51 }
52
TEST(MultilibTest,OpEqReflexivity3)53 TEST(MultilibTest, OpEqReflexivity3) {
54 Multilib M1, M2;
55 M1.flag("+foo");
56 M2.flag("+foo");
57 ASSERT_TRUE(M1 == M2) << "Multilibs with the same flag should be the same";
58 }
59
TEST(MultilibTest,OpEqInequivalence1)60 TEST(MultilibTest, OpEqInequivalence1) {
61 Multilib M1, M2;
62 M1.flag("+foo");
63 M2.flag("-foo");
64 ASSERT_FALSE(M1 == M2) << "Multilibs with conflicting flags are not the same";
65 ASSERT_FALSE(M2 == M1)
66 << "Multilibs with conflicting flags are not the same (commuted)";
67 }
68
TEST(MultilibTest,OpEqInequivalence2)69 TEST(MultilibTest, OpEqInequivalence2) {
70 Multilib M1, M2;
71 M2.flag("+foo");
72 ASSERT_FALSE(M1 == M2) << "Flags make Multilibs different";
73 }
74
TEST(MultilibTest,OpEqEquivalence1)75 TEST(MultilibTest, OpEqEquivalence1) {
76 Multilib M1, M2;
77 M1.flag("+foo");
78 M2.flag("+foo").flag("+foo");
79 ASSERT_TRUE(M1 == M2) << "Flag duplication shouldn't affect equivalence";
80 ASSERT_TRUE(M2 == M1)
81 << "Flag duplication shouldn't affect equivalence (commuted)";
82 }
83
TEST(MultilibTest,OpEqEquivalence2)84 TEST(MultilibTest, OpEqEquivalence2) {
85 Multilib M1("64");
86 Multilib M2;
87 M2.gccSuffix("/64");
88 ASSERT_TRUE(M1 == M2)
89 << "Constructor argument must match Multilib::gccSuffix()";
90 ASSERT_TRUE(M2 == M1)
91 << "Constructor argument must match Multilib::gccSuffix() (commuted)";
92 }
93
TEST(MultilibTest,OpEqEquivalence3)94 TEST(MultilibTest, OpEqEquivalence3) {
95 Multilib M1("", "32");
96 Multilib M2;
97 M2.osSuffix("/32");
98 ASSERT_TRUE(M1 == M2)
99 << "Constructor argument must match Multilib::osSuffix()";
100 ASSERT_TRUE(M2 == M1)
101 << "Constructor argument must match Multilib::osSuffix() (commuted)";
102 }
103
TEST(MultilibTest,OpEqEquivalence4)104 TEST(MultilibTest, OpEqEquivalence4) {
105 Multilib M1("", "", "16");
106 Multilib M2;
107 M2.includeSuffix("/16");
108 ASSERT_TRUE(M1 == M2)
109 << "Constructor argument must match Multilib::includeSuffix()";
110 ASSERT_TRUE(M2 == M1)
111 << "Constructor argument must match Multilib::includeSuffix() (commuted)";
112 }
113
TEST(MultilibTest,OpEqInequivalence3)114 TEST(MultilibTest, OpEqInequivalence3) {
115 Multilib M1("foo");
116 Multilib M2("bar");
117 ASSERT_FALSE(M1 == M2) << "Differing gccSuffixes should be different";
118 ASSERT_FALSE(M2 == M1)
119 << "Differing gccSuffixes should be different (commuted)";
120 }
121
TEST(MultilibTest,OpEqInequivalence4)122 TEST(MultilibTest, OpEqInequivalence4) {
123 Multilib M1("", "foo");
124 Multilib M2("", "bar");
125 ASSERT_FALSE(M1 == M2) << "Differing osSuffixes should be different";
126 ASSERT_FALSE(M2 == M1)
127 << "Differing osSuffixes should be different (commuted)";
128 }
129
TEST(MultilibTest,OpEqInequivalence5)130 TEST(MultilibTest, OpEqInequivalence5) {
131 Multilib M1("", "", "foo");
132 Multilib M2("", "", "bar");
133 ASSERT_FALSE(M1 == M2) << "Differing includeSuffixes should be different";
134 ASSERT_FALSE(M2 == M1)
135 << "Differing includeSuffixes should be different (commuted)";
136 }
137
TEST(MultilibTest,Construction1)138 TEST(MultilibTest, Construction1) {
139 Multilib M("gcc64", "os64", "inc64");
140 ASSERT_TRUE(M.gccSuffix() == "/gcc64");
141 ASSERT_TRUE(M.osSuffix() == "/os64");
142 ASSERT_TRUE(M.includeSuffix() == "/inc64");
143 }
144
TEST(MultilibTest,Construction2)145 TEST(MultilibTest, Construction2) {
146 Multilib M1;
147 Multilib M2("");
148 Multilib M3("", "");
149 Multilib M4("", "", "");
150 ASSERT_TRUE(M1 == M2)
151 << "Default arguments to Multilib constructor broken (first argument)";
152 ASSERT_TRUE(M1 == M3)
153 << "Default arguments to Multilib constructor broken (second argument)";
154 ASSERT_TRUE(M1 == M4)
155 << "Default arguments to Multilib constructor broken (third argument)";
156 }
157
TEST(MultilibTest,Construction3)158 TEST(MultilibTest, Construction3) {
159 Multilib M = Multilib().flag("+f1").flag("+f2").flag("-f3");
160 for (Multilib::flags_list::const_iterator I = M.flags().begin(),
161 E = M.flags().end();
162 I != E; ++I) {
163 ASSERT_TRUE(llvm::StringSwitch<bool>(*I)
164 .Cases("+f1", "+f2", "-f3", true)
165 .Default(false));
166 }
167 }
168
hasFlag(const Multilib & M,StringRef Flag)169 static bool hasFlag(const Multilib &M, StringRef Flag) {
170 for (Multilib::flags_list::const_iterator I = M.flags().begin(),
171 E = M.flags().end();
172 I != E; ++I) {
173 if (*I == Flag)
174 return true;
175 else if (StringRef(*I).substr(1) == Flag.substr(1))
176 return false;
177 }
178 return false;
179 }
180
TEST(MultilibTest,SetConstruction1)181 TEST(MultilibTest, SetConstruction1) {
182 // Single maybe
183 MultilibSet MS;
184 ASSERT_TRUE(MS.size() == 0);
185 MS.Maybe(Multilib("64").flag("+m64"));
186 ASSERT_TRUE(MS.size() == 2);
187 for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) {
188 if (I->gccSuffix() == "/64")
189 ASSERT_TRUE(I->flags()[0] == "+m64");
190 else if (I->gccSuffix() == "")
191 ASSERT_TRUE(I->flags()[0] == "-m64");
192 else
193 FAIL() << "Unrecognized gccSufix: " << I->gccSuffix();
194 }
195 }
196
TEST(MultilibTest,SetConstruction2)197 TEST(MultilibTest, SetConstruction2) {
198 // Double maybe
199 MultilibSet MS;
200 MS.Maybe(Multilib("sof").flag("+sof"));
201 MS.Maybe(Multilib("el").flag("+EL"));
202 ASSERT_TRUE(MS.size() == 4);
203 for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) {
204 ASSERT_TRUE(I->isValid()) << "Multilb " << *I << " should be valid";
205 ASSERT_TRUE(llvm::StringSwitch<bool>(I->gccSuffix())
206 .Cases("", "/sof", "/el", "/sof/el", true)
207 .Default(false))
208 << "Multilib " << *I << " wasn't expected";
209 ASSERT_TRUE(llvm::StringSwitch<bool>(I->gccSuffix())
210 .Case("", hasFlag(*I, "-sof"))
211 .Case("/sof", hasFlag(*I, "+sof"))
212 .Case("/el", hasFlag(*I, "-sof"))
213 .Case("/sof/el", hasFlag(*I, "+sof"))
214 .Default(false))
215 << "Multilib " << *I << " didn't have the appropriate {+,-}sof flag";
216 ASSERT_TRUE(llvm::StringSwitch<bool>(I->gccSuffix())
217 .Case("", hasFlag(*I, "-EL"))
218 .Case("/sof", hasFlag(*I, "-EL"))
219 .Case("/el", hasFlag(*I, "+EL"))
220 .Case("/sof/el", hasFlag(*I, "+EL"))
221 .Default(false))
222 << "Multilib " << *I << " didn't have the appropriate {+,-}EL flag";
223 }
224 }
225
TEST(MultilibTest,SetPushback)226 TEST(MultilibTest, SetPushback) {
227 MultilibSet MS;
228 MS.push_back(Multilib("one"));
229 MS.push_back(Multilib("two"));
230 ASSERT_TRUE(MS.size() == 2);
231 for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) {
232 ASSERT_TRUE(llvm::StringSwitch<bool>(I->gccSuffix())
233 .Cases("/one", "/two", true)
234 .Default(false));
235 }
236 MS.clear();
237 ASSERT_TRUE(MS.size() == 0);
238 }
239
TEST(MultilibTest,SetRegexFilter)240 TEST(MultilibTest, SetRegexFilter) {
241 MultilibSet MS;
242 MS.Maybe(Multilib("one"));
243 MS.Maybe(Multilib("two"));
244 MS.Maybe(Multilib("three"));
245 ASSERT_EQ(MS.size(), (unsigned)2 * 2 * 2)
246 << "Size before filter was incorrect. Contents:\n" << MS;
247 MS.FilterOut("/one/two/three");
248 ASSERT_EQ(MS.size(), (unsigned)2 * 2 * 2 - 1)
249 << "Size after filter was incorrect. Contents:\n" << MS;
250 for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) {
251 ASSERT_TRUE(I->gccSuffix() != "/one/two/three")
252 << "The filter should have removed " << *I;
253 }
254 }
255
TEST(MultilibTest,SetFilterObject)256 TEST(MultilibTest, SetFilterObject) {
257 // Filter object
258 struct StartsWithP : public MultilibSet::FilterCallback {
259 bool operator()(const Multilib &M) const override {
260 return StringRef(M.gccSuffix()).startswith("/p");
261 }
262 };
263 MultilibSet MS;
264 MS.Maybe(Multilib("orange"));
265 MS.Maybe(Multilib("pear"));
266 MS.Maybe(Multilib("plum"));
267 ASSERT_EQ((int)MS.size(), 1 /* Default */ +
268 1 /* pear */ +
269 1 /* plum */ +
270 1 /* pear/plum */ +
271 1 /* orange */ +
272 1 /* orange/pear */ +
273 1 /* orange/plum */ +
274 1 /* orange/pear/plum */ )
275 << "Size before filter was incorrect. Contents:\n" << MS;
276 MS.FilterOut(StartsWithP());
277 ASSERT_EQ((int)MS.size(), 1 /* Default */ +
278 1 /* orange */ +
279 1 /* orange/pear */ +
280 1 /* orange/plum */ +
281 1 /* orange/pear/plum */ )
282 << "Size after filter was incorrect. Contents:\n" << MS;
283 for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) {
284 ASSERT_FALSE(StringRef(I->gccSuffix()).startswith("/p"))
285 << "The filter should have removed " << *I;
286 }
287 }
288
TEST(MultilibTest,SetSelection1)289 TEST(MultilibTest, SetSelection1) {
290 MultilibSet MS1 = MultilibSet()
291 .Maybe(Multilib("64").flag("+m64"));
292
293 Multilib::flags_list FlagM64;
294 FlagM64.push_back("+m64");
295 Multilib SelectionM64;
296 ASSERT_TRUE(MS1.select(FlagM64, SelectionM64))
297 << "Flag set was {\"+m64\"}, but selection not found";
298 ASSERT_TRUE(SelectionM64.gccSuffix() == "/64")
299 << "Selection picked " << SelectionM64 << " which was not expected";
300
301 Multilib::flags_list FlagNoM64;
302 FlagNoM64.push_back("-m64");
303 Multilib SelectionNoM64;
304 ASSERT_TRUE(MS1.select(FlagNoM64, SelectionNoM64))
305 << "Flag set was {\"-m64\"}, but selection not found";
306 ASSERT_TRUE(SelectionNoM64.gccSuffix() == "")
307 << "Selection picked " << SelectionNoM64 << " which was not expected";
308 }
309
TEST(MultilibTest,SetSelection2)310 TEST(MultilibTest, SetSelection2) {
311 MultilibSet MS2 = MultilibSet()
312 .Maybe(Multilib("el").flag("+EL"))
313 .Maybe(Multilib("sf").flag("+SF"));
314
315 for (unsigned I = 0; I < 4; ++I) {
316 bool IsEL = I & 0x1;
317 bool IsSF = I & 0x2;
318 Multilib::flags_list Flags;
319 if (IsEL)
320 Flags.push_back("+EL");
321 else
322 Flags.push_back("-EL");
323
324 if (IsSF)
325 Flags.push_back("+SF");
326 else
327 Flags.push_back("-SF");
328
329 Multilib Selection;
330 ASSERT_TRUE(MS2.select(Flags, Selection)) << "Selection failed for "
331 << (IsEL ? "+EL" : "-EL") << " "
332 << (IsSF ? "+SF" : "-SF");
333
334 std::string Suffix;
335 if (IsEL)
336 Suffix += "/el";
337 if (IsSF)
338 Suffix += "/sf";
339
340 ASSERT_EQ(Selection.gccSuffix(), Suffix) << "Selection picked " << Selection
341 << " which was not expected ";
342 }
343 }
344
TEST(MultilibTest,SetCombineWith)345 TEST(MultilibTest, SetCombineWith) {
346 MultilibSet Coffee;
347 Coffee.push_back(Multilib("coffee"));
348 MultilibSet Milk;
349 Milk.push_back(Multilib("milk"));
350 MultilibSet Latte;
351 ASSERT_EQ(Latte.size(), (unsigned)0);
352 Latte.combineWith(Coffee);
353 ASSERT_EQ(Latte.size(), (unsigned)1);
354 Latte.combineWith(Milk);
355 ASSERT_EQ(Latte.size(), (unsigned)2);
356 }
357