1 | //===- unittests/Driver/MultilibBuilderTest.cpp --- MultilibBuilder tests |
2 | //---------------===// |
3 | // |
4 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
5 | // See https://llvm.org/LICENSE.txt for license information. |
6 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
7 | // |
8 | //===----------------------------------------------------------------------===// |
9 | // |
10 | // Unit tests for MultilibBuilder and MultilibSetBuilder |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "clang/Driver/MultilibBuilder.h" |
15 | #include "../../lib/Driver/ToolChains/CommonArgs.h" |
16 | #include "clang/Basic/LLVM.h" |
17 | #include "llvm/ADT/ArrayRef.h" |
18 | #include "llvm/ADT/StringRef.h" |
19 | #include "llvm/ADT/StringSwitch.h" |
20 | #include "gtest/gtest.h" |
21 | |
22 | using llvm::is_contained; |
23 | using namespace clang; |
24 | using namespace driver; |
25 | |
26 | TEST(MultilibBuilderTest, MultilibValidity) { |
27 | |
28 | ASSERT_TRUE(MultilibBuilder().isValid()) << "Empty multilib is not valid" ; |
29 | |
30 | ASSERT_TRUE(MultilibBuilder().flag("-foo" ).isValid()) |
31 | << "Single indicative flag is not valid" ; |
32 | |
33 | ASSERT_TRUE(MultilibBuilder().flag("-foo" , /*Disallow=*/true).isValid()) |
34 | << "Single contraindicative flag is not valid" ; |
35 | |
36 | ASSERT_FALSE( |
37 | MultilibBuilder().flag("-foo" ).flag("-foo" , /*Disallow=*/true).isValid()) |
38 | << "Conflicting flags should invalidate the Multilib" ; |
39 | |
40 | ASSERT_TRUE(MultilibBuilder().flag("-foo" ).flag("-foo" ).isValid()) |
41 | << "Multilib should be valid even if it has the same flag " |
42 | "twice" ; |
43 | |
44 | ASSERT_TRUE(MultilibBuilder() |
45 | .flag("-foo" ) |
46 | .flag("-foobar" , /*Disallow=*/true) |
47 | .isValid()) |
48 | << "Seemingly conflicting prefixes shouldn't actually conflict" ; |
49 | } |
50 | |
51 | TEST(MultilibBuilderTest, Construction1) { |
52 | MultilibBuilder M("gcc64" , "os64" , "inc64" ); |
53 | ASSERT_TRUE(M.gccSuffix() == "/gcc64" ); |
54 | ASSERT_TRUE(M.osSuffix() == "/os64" ); |
55 | ASSERT_TRUE(M.includeSuffix() == "/inc64" ); |
56 | } |
57 | |
58 | TEST(MultilibBuilderTest, Construction3) { |
59 | MultilibBuilder M = |
60 | MultilibBuilder().flag(Flag: "-f1" ).flag(Flag: "-f2" ).flag(Flag: "-f3" , /*Disallow=*/true); |
61 | for (const std::string &A : M.flags()) { |
62 | ASSERT_TRUE(llvm::StringSwitch<bool>(A) |
63 | .Cases("-f1" , "-f2" , "!f3" , true) |
64 | .Default(false)); |
65 | } |
66 | } |
67 | |
68 | TEST(MultilibBuilderTest, SetConstruction1) { |
69 | // Single maybe |
70 | MultilibSet MS = MultilibSetBuilder() |
71 | .Maybe(M: MultilibBuilder("64" ).flag(Flag: "-m64" )) |
72 | .makeMultilibSet(); |
73 | ASSERT_TRUE(MS.size() == 2); |
74 | for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) { |
75 | if (I->gccSuffix() == "/64" ) |
76 | ASSERT_TRUE(*I->flags().begin() == "-m64" ); |
77 | else if (I->gccSuffix() == "" ) |
78 | ASSERT_TRUE(*I->flags().begin() == "!m64" ); |
79 | else |
80 | FAIL() << "Unrecognized gccSufix: " << I->gccSuffix(); |
81 | } |
82 | } |
83 | |
84 | TEST(MultilibBuilderTest, SetConstruction2) { |
85 | // Double maybe |
86 | MultilibSet MS = MultilibSetBuilder() |
87 | .Maybe(M: MultilibBuilder("sof" ).flag(Flag: "-sof" )) |
88 | .Maybe(M: MultilibBuilder("el" ).flag(Flag: "-EL" )) |
89 | .makeMultilibSet(); |
90 | ASSERT_TRUE(MS.size() == 4); |
91 | for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) { |
92 | ASSERT_TRUE(llvm::StringSwitch<bool>(I->gccSuffix()) |
93 | .Cases("" , "/sof" , "/el" , "/sof/el" , true) |
94 | .Default(false)) |
95 | << "Multilib " << *I << " wasn't expected" ; |
96 | ASSERT_TRUE(llvm::StringSwitch<bool>(I->gccSuffix()) |
97 | .Case("" , is_contained(I->flags(), "!sof" )) |
98 | .Case("/sof" , is_contained(I->flags(), "-sof" )) |
99 | .Case("/el" , is_contained(I->flags(), "!sof" )) |
100 | .Case("/sof/el" , is_contained(I->flags(), "-sof" )) |
101 | .Default(false)) |
102 | << "Multilib " << *I << " didn't have the appropriate {-,!}sof flag" ; |
103 | ASSERT_TRUE(llvm::StringSwitch<bool>(I->gccSuffix()) |
104 | .Case("" , is_contained(I->flags(), "!EL" )) |
105 | .Case("/sof" , is_contained(I->flags(), "!EL" )) |
106 | .Case("/el" , is_contained(I->flags(), "-EL" )) |
107 | .Case("/sof/el" , is_contained(I->flags(), "-EL" )) |
108 | .Default(false)) |
109 | << "Multilib " << *I << " didn't have the appropriate {-,!}EL flag" ; |
110 | } |
111 | } |
112 | |
113 | TEST(MultilibBuilderTest, SetRegexFilter) { |
114 | MultilibSetBuilder MB; |
115 | MB.Maybe(M: MultilibBuilder("one" )) |
116 | .Maybe(M: MultilibBuilder("two" )) |
117 | .Maybe(M: MultilibBuilder("three" )) |
118 | .makeMultilibSet(); |
119 | MultilibSet MS = MB.makeMultilibSet(); |
120 | ASSERT_EQ(MS.size(), (unsigned)2 * 2 * 2) |
121 | << "Size before filter was incorrect. Contents:\n" |
122 | << MS; |
123 | MB.FilterOut(Regex: "/one/two/three" ); |
124 | MS = MB.makeMultilibSet(); |
125 | ASSERT_EQ(MS.size(), (unsigned)2 * 2 * 2 - 1) |
126 | << "Size after filter was incorrect. Contents:\n" |
127 | << MS; |
128 | for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) { |
129 | ASSERT_TRUE(I->gccSuffix() != "/one/two/three" ) |
130 | << "The filter should have removed " << *I; |
131 | } |
132 | } |
133 | |
134 | TEST(MultilibBuilderTest, SetFilterObject) { |
135 | MultilibSet MS = MultilibSetBuilder() |
136 | .Maybe(M: MultilibBuilder("orange" )) |
137 | .Maybe(M: MultilibBuilder("pear" )) |
138 | .Maybe(M: MultilibBuilder("plum" )) |
139 | .makeMultilibSet(); |
140 | ASSERT_EQ((int)MS.size(), 1 /* Default */ + 1 /* pear */ + 1 /* plum */ + |
141 | 1 /* pear/plum */ + 1 /* orange */ + |
142 | 1 /* orange/pear */ + 1 /* orange/plum */ + |
143 | 1 /* orange/pear/plum */) |
144 | << "Size before filter was incorrect. Contents:\n" |
145 | << MS; |
146 | MS.FilterOut(F: [](const Multilib &M) { |
147 | return StringRef(M.gccSuffix()).starts_with(Prefix: "/p" ); |
148 | }); |
149 | ASSERT_EQ((int)MS.size(), 1 /* Default */ + 1 /* orange */ + |
150 | 1 /* orange/pear */ + 1 /* orange/plum */ + |
151 | 1 /* orange/pear/plum */) |
152 | << "Size after filter was incorrect. Contents:\n" |
153 | << MS; |
154 | for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) { |
155 | ASSERT_FALSE(StringRef(I->gccSuffix()).starts_with("/p" )) |
156 | << "The filter should have removed " << *I; |
157 | } |
158 | } |
159 | |
160 | TEST(MultilibBuilderTest, SetSelection1) { |
161 | MultilibSet MS1 = MultilibSetBuilder() |
162 | .Maybe(M: MultilibBuilder("64" ).flag(Flag: "-m64" )) |
163 | .makeMultilibSet(); |
164 | |
165 | Multilib::flags_list FlagM64 = {"-m64" }; |
166 | llvm::SmallVector<Multilib> SelectionM64; |
167 | ASSERT_TRUE(MS1.select(FlagM64, SelectionM64)) |
168 | << "Flag set was {\"-m64\"}, but selection not found" ; |
169 | ASSERT_TRUE(SelectionM64.back().gccSuffix() == "/64" ) |
170 | << "Selection picked " << SelectionM64.back() |
171 | << " which was not expected" ; |
172 | |
173 | Multilib::flags_list FlagNoM64 = {"!m64" }; |
174 | llvm::SmallVector<Multilib> SelectionNoM64; |
175 | ASSERT_TRUE(MS1.select(FlagNoM64, SelectionNoM64)) |
176 | << "Flag set was {\"!m64\"}, but selection not found" ; |
177 | ASSERT_TRUE(SelectionNoM64.back().gccSuffix() == "" ) |
178 | << "Selection picked " << SelectionNoM64.back() |
179 | << " which was not expected" ; |
180 | } |
181 | |
182 | TEST(MultilibBuilderTest, SetSelection2) { |
183 | MultilibSet MS2 = MultilibSetBuilder() |
184 | .Maybe(M: MultilibBuilder("el" ).flag(Flag: "-EL" )) |
185 | .Maybe(M: MultilibBuilder("sf" ).flag(Flag: "-SF" )) |
186 | .makeMultilibSet(); |
187 | |
188 | for (unsigned I = 0; I < 4; ++I) { |
189 | bool IsEL = I & 0x1; |
190 | bool IsSF = I & 0x2; |
191 | Multilib::flags_list Flags; |
192 | if (IsEL) |
193 | Flags.push_back(x: "-EL" ); |
194 | else |
195 | Flags.push_back(x: "!EL" ); |
196 | |
197 | if (IsSF) |
198 | Flags.push_back(x: "-SF" ); |
199 | else |
200 | Flags.push_back(x: "!SF" ); |
201 | |
202 | llvm::SmallVector<Multilib> Selection; |
203 | ASSERT_TRUE(MS2.select(Flags, Selection)) |
204 | << "Selection failed for " << (IsEL ? "-EL" : "!EL" ) << " " |
205 | << (IsSF ? "-SF" : "!SF" ); |
206 | |
207 | std::string Suffix; |
208 | if (IsEL) |
209 | Suffix += "/el" ; |
210 | if (IsSF) |
211 | Suffix += "/sf" ; |
212 | |
213 | ASSERT_EQ(Selection.back().gccSuffix(), Suffix) |
214 | << "Selection picked " << Selection.back() |
215 | << " which was not expected " ; |
216 | } |
217 | } |
218 | |