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   MultilibSet MS;
258   MS.Maybe(Multilib("orange"));
259   MS.Maybe(Multilib("pear"));
260   MS.Maybe(Multilib("plum"));
261   ASSERT_EQ((int)MS.size(), 1 /* Default */ +
262                             1 /* pear */ +
263                             1 /* plum */ +
264                             1 /* pear/plum */ +
265                             1 /* orange */ +
266                             1 /* orange/pear */ +
267                             1 /* orange/plum */ +
268                             1 /* orange/pear/plum */ )
269       << "Size before filter was incorrect. Contents:\n" << MS;
270   MS.FilterOut([](const Multilib &M) {
271     return StringRef(M.gccSuffix()).startswith("/p");
272   });
273   ASSERT_EQ((int)MS.size(), 1 /* Default */ +
274                             1 /* orange */ +
275                             1 /* orange/pear */ +
276                             1 /* orange/plum */ +
277                             1 /* orange/pear/plum */ )
278       << "Size after filter was incorrect. Contents:\n" << MS;
279   for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) {
280     ASSERT_FALSE(StringRef(I->gccSuffix()).startswith("/p"))
281         << "The filter should have removed " << *I;
282   }
283 }
284 
TEST(MultilibTest,SetSelection1)285 TEST(MultilibTest, SetSelection1) {
286   MultilibSet MS1 = MultilibSet()
287     .Maybe(Multilib("64").flag("+m64"));
288 
289   Multilib::flags_list FlagM64;
290   FlagM64.push_back("+m64");
291   Multilib SelectionM64;
292   ASSERT_TRUE(MS1.select(FlagM64, SelectionM64))
293       << "Flag set was {\"+m64\"}, but selection not found";
294   ASSERT_TRUE(SelectionM64.gccSuffix() == "/64")
295       << "Selection picked " << SelectionM64 << " which was not expected";
296 
297   Multilib::flags_list FlagNoM64;
298   FlagNoM64.push_back("-m64");
299   Multilib SelectionNoM64;
300   ASSERT_TRUE(MS1.select(FlagNoM64, SelectionNoM64))
301       << "Flag set was {\"-m64\"}, but selection not found";
302   ASSERT_TRUE(SelectionNoM64.gccSuffix() == "")
303       << "Selection picked " << SelectionNoM64 << " which was not expected";
304 }
305 
TEST(MultilibTest,SetSelection2)306 TEST(MultilibTest, SetSelection2) {
307   MultilibSet MS2 = MultilibSet()
308     .Maybe(Multilib("el").flag("+EL"))
309     .Maybe(Multilib("sf").flag("+SF"));
310 
311   for (unsigned I = 0; I < 4; ++I) {
312     bool IsEL = I & 0x1;
313     bool IsSF = I & 0x2;
314     Multilib::flags_list Flags;
315     if (IsEL)
316       Flags.push_back("+EL");
317     else
318       Flags.push_back("-EL");
319 
320     if (IsSF)
321       Flags.push_back("+SF");
322     else
323       Flags.push_back("-SF");
324 
325     Multilib Selection;
326     ASSERT_TRUE(MS2.select(Flags, Selection)) << "Selection failed for "
327                                               << (IsEL ? "+EL" : "-EL") << " "
328                                               << (IsSF ? "+SF" : "-SF");
329 
330     std::string Suffix;
331     if (IsEL)
332       Suffix += "/el";
333     if (IsSF)
334       Suffix += "/sf";
335 
336     ASSERT_EQ(Selection.gccSuffix(), Suffix) << "Selection picked " << Selection
337                                              << " which was not expected ";
338   }
339 }
340 
TEST(MultilibTest,SetCombineWith)341 TEST(MultilibTest, SetCombineWith) {
342   MultilibSet Coffee;
343   Coffee.push_back(Multilib("coffee"));
344   MultilibSet Milk;
345   Milk.push_back(Multilib("milk"));
346   MultilibSet Latte;
347   ASSERT_EQ(Latte.size(), (unsigned)0);
348   Latte.combineWith(Coffee);
349   ASSERT_EQ(Latte.size(), (unsigned)1);
350   Latte.combineWith(Milk);
351   ASSERT_EQ(Latte.size(), (unsigned)2);
352 }
353