Clang Project

clang_source_code/unittests/Driver/MultilibTest.cpp
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
19using namespace clang::driver;
20using namespace clang;
21
22TEST(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
42TEST(MultilibTest, OpEqReflexivity1) {
43  Multilib M;
44  ASSERT_TRUE(M == M) << "Multilib::operator==() is not reflexive";
45}
46
47TEST(MultilibTest, OpEqReflexivity2) {
48  ASSERT_TRUE(Multilib() == Multilib())
49      << "Separately constructed default multilibs are not equal";
50}
51
52TEST(MultilibTest, OpEqReflexivity3) {
53  Multilib M1M2;
54  M1.flag("+foo");
55  M2.flag("+foo");
56  ASSERT_TRUE(M1 == M2) << "Multilibs with the same flag should be the same";
57}
58
59TEST(MultilibTest, OpEqInequivalence1) {
60  Multilib M1M2;
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
68TEST(MultilibTest, OpEqInequivalence2) {
69  Multilib M1M2;
70  M2.flag("+foo");
71  ASSERT_FALSE(M1 == M2) << "Flags make Multilibs different";
72}
73
74TEST(MultilibTest, OpEqEquivalence1) {
75  Multilib M1M2;
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
83TEST(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
93TEST(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
103TEST(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
113TEST(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
121TEST(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
129TEST(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
137TEST(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
144TEST(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
157TEST(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
168static bool hasFlag(const Multilib &MStringRef 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
180TEST(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
196TEST(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
225TEST(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
239TEST(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
255TEST(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
284TEST(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(FlagM64SelectionM64))
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(FlagNoM64SelectionNoM64))
300      << "Flag set was {\"-m64\"}, but selection not found";
301  ASSERT_TRUE(SelectionNoM64.gccSuffix() == "")
302      << "Selection picked " << SelectionNoM64 << " which was not expected";
303}
304
305TEST(MultilibTest, SetSelection2) {
306  MultilibSet MS2 = MultilibSet()
307    .Maybe(Multilib("el").flag("+EL"))
308    .Maybe(Multilib("sf").flag("+SF"));
309
310  for (unsigned I = 0I < 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(FlagsSelection)) << "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
340TEST(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