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