1850dab0fSMichael Platings //===- unittests/Driver/MultilibBuilderTest.cpp --- MultilibBuilder tests 2850dab0fSMichael Platings //---------------===// 3850dab0fSMichael Platings // 4850dab0fSMichael Platings // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5850dab0fSMichael Platings // See https://llvm.org/LICENSE.txt for license information. 6850dab0fSMichael Platings // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7850dab0fSMichael Platings // 8850dab0fSMichael Platings //===----------------------------------------------------------------------===// 9850dab0fSMichael Platings // 10850dab0fSMichael Platings // Unit tests for MultilibBuilder and MultilibSetBuilder 11850dab0fSMichael Platings // 12850dab0fSMichael Platings //===----------------------------------------------------------------------===// 13850dab0fSMichael Platings 14850dab0fSMichael Platings #include "clang/Driver/MultilibBuilder.h" 15850dab0fSMichael Platings #include "../../lib/Driver/ToolChains/CommonArgs.h" 16*26bf0b4aSSimon Tatham #include "SimpleDiagnosticConsumer.h" 17850dab0fSMichael Platings #include "clang/Basic/LLVM.h" 18850dab0fSMichael Platings #include "llvm/ADT/ArrayRef.h" 19850dab0fSMichael Platings #include "llvm/ADT/StringRef.h" 20850dab0fSMichael Platings #include "llvm/ADT/StringSwitch.h" 21850dab0fSMichael Platings #include "gtest/gtest.h" 22850dab0fSMichael Platings 23850dab0fSMichael Platings using llvm::is_contained; 24850dab0fSMichael Platings using namespace clang; 25850dab0fSMichael Platings using namespace driver; 26850dab0fSMichael Platings 27850dab0fSMichael Platings TEST(MultilibBuilderTest, MultilibValidity) { 28850dab0fSMichael Platings 29850dab0fSMichael Platings ASSERT_TRUE(MultilibBuilder().isValid()) << "Empty multilib is not valid"; 30850dab0fSMichael Platings 31b4507dcaSMichael Platings ASSERT_TRUE(MultilibBuilder().flag("-foo").isValid()) 32850dab0fSMichael Platings << "Single indicative flag is not valid"; 33850dab0fSMichael Platings 34b4507dcaSMichael Platings ASSERT_TRUE(MultilibBuilder().flag("-foo", /*Disallow=*/true).isValid()) 35850dab0fSMichael Platings << "Single contraindicative flag is not valid"; 36850dab0fSMichael Platings 3747b431d6SMichael Platings ASSERT_FALSE( 38b4507dcaSMichael Platings MultilibBuilder().flag("-foo").flag("-foo", /*Disallow=*/true).isValid()) 39850dab0fSMichael Platings << "Conflicting flags should invalidate the Multilib"; 40850dab0fSMichael Platings 41b4507dcaSMichael Platings ASSERT_TRUE(MultilibBuilder().flag("-foo").flag("-foo").isValid()) 42850dab0fSMichael Platings << "Multilib should be valid even if it has the same flag " 43850dab0fSMichael Platings "twice"; 44850dab0fSMichael Platings 45b4507dcaSMichael Platings ASSERT_TRUE(MultilibBuilder() 46b4507dcaSMichael Platings .flag("-foo") 47b4507dcaSMichael Platings .flag("-foobar", /*Disallow=*/true) 48b4507dcaSMichael Platings .isValid()) 49850dab0fSMichael Platings << "Seemingly conflicting prefixes shouldn't actually conflict"; 50850dab0fSMichael Platings } 51850dab0fSMichael Platings 52850dab0fSMichael Platings TEST(MultilibBuilderTest, Construction1) { 53850dab0fSMichael Platings MultilibBuilder M("gcc64", "os64", "inc64"); 54850dab0fSMichael Platings ASSERT_TRUE(M.gccSuffix() == "/gcc64"); 55850dab0fSMichael Platings ASSERT_TRUE(M.osSuffix() == "/os64"); 56850dab0fSMichael Platings ASSERT_TRUE(M.includeSuffix() == "/inc64"); 57850dab0fSMichael Platings } 58850dab0fSMichael Platings 59850dab0fSMichael Platings TEST(MultilibBuilderTest, Construction3) { 6047b431d6SMichael Platings MultilibBuilder M = 61b4507dcaSMichael Platings MultilibBuilder().flag("-f1").flag("-f2").flag("-f3", /*Disallow=*/true); 62850dab0fSMichael Platings for (const std::string &A : M.flags()) { 63850dab0fSMichael Platings ASSERT_TRUE(llvm::StringSwitch<bool>(A) 64ce8fa36eSMichael Platings .Cases("-f1", "-f2", "!f3", true) 65850dab0fSMichael Platings .Default(false)); 66850dab0fSMichael Platings } 67850dab0fSMichael Platings } 68850dab0fSMichael Platings 69850dab0fSMichael Platings TEST(MultilibBuilderTest, SetConstruction1) { 70850dab0fSMichael Platings // Single maybe 71850dab0fSMichael Platings MultilibSet MS = MultilibSetBuilder() 72b4507dcaSMichael Platings .Maybe(MultilibBuilder("64").flag("-m64")) 73850dab0fSMichael Platings .makeMultilibSet(); 74850dab0fSMichael Platings ASSERT_TRUE(MS.size() == 2); 75850dab0fSMichael Platings for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) { 76850dab0fSMichael Platings if (I->gccSuffix() == "/64") 77850dab0fSMichael Platings ASSERT_TRUE(*I->flags().begin() == "-m64"); 78ce8fa36eSMichael Platings else if (I->gccSuffix() == "") 79ce8fa36eSMichael Platings ASSERT_TRUE(*I->flags().begin() == "!m64"); 80850dab0fSMichael Platings else 81850dab0fSMichael Platings FAIL() << "Unrecognized gccSufix: " << I->gccSuffix(); 82850dab0fSMichael Platings } 83850dab0fSMichael Platings } 84850dab0fSMichael Platings 85850dab0fSMichael Platings TEST(MultilibBuilderTest, SetConstruction2) { 86850dab0fSMichael Platings // Double maybe 87850dab0fSMichael Platings MultilibSet MS = MultilibSetBuilder() 88b4507dcaSMichael Platings .Maybe(MultilibBuilder("sof").flag("-sof")) 89b4507dcaSMichael Platings .Maybe(MultilibBuilder("el").flag("-EL")) 90850dab0fSMichael Platings .makeMultilibSet(); 91850dab0fSMichael Platings ASSERT_TRUE(MS.size() == 4); 92850dab0fSMichael Platings for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) { 93850dab0fSMichael Platings ASSERT_TRUE(llvm::StringSwitch<bool>(I->gccSuffix()) 94850dab0fSMichael Platings .Cases("", "/sof", "/el", "/sof/el", true) 95850dab0fSMichael Platings .Default(false)) 96850dab0fSMichael Platings << "Multilib " << *I << " wasn't expected"; 97850dab0fSMichael Platings ASSERT_TRUE(llvm::StringSwitch<bool>(I->gccSuffix()) 98ce8fa36eSMichael Platings .Case("", is_contained(I->flags(), "!sof")) 99ce8fa36eSMichael Platings .Case("/sof", is_contained(I->flags(), "-sof")) 100ce8fa36eSMichael Platings .Case("/el", is_contained(I->flags(), "!sof")) 101ce8fa36eSMichael Platings .Case("/sof/el", is_contained(I->flags(), "-sof")) 102850dab0fSMichael Platings .Default(false)) 103ce8fa36eSMichael Platings << "Multilib " << *I << " didn't have the appropriate {-,!}sof flag"; 104850dab0fSMichael Platings ASSERT_TRUE(llvm::StringSwitch<bool>(I->gccSuffix()) 105ce8fa36eSMichael Platings .Case("", is_contained(I->flags(), "!EL")) 106ce8fa36eSMichael Platings .Case("/sof", is_contained(I->flags(), "!EL")) 107ce8fa36eSMichael Platings .Case("/el", is_contained(I->flags(), "-EL")) 108ce8fa36eSMichael Platings .Case("/sof/el", is_contained(I->flags(), "-EL")) 109850dab0fSMichael Platings .Default(false)) 110ce8fa36eSMichael Platings << "Multilib " << *I << " didn't have the appropriate {-,!}EL flag"; 111850dab0fSMichael Platings } 112850dab0fSMichael Platings } 113850dab0fSMichael Platings 114850dab0fSMichael Platings TEST(MultilibBuilderTest, SetRegexFilter) { 115850dab0fSMichael Platings MultilibSetBuilder MB; 116850dab0fSMichael Platings MB.Maybe(MultilibBuilder("one")) 117850dab0fSMichael Platings .Maybe(MultilibBuilder("two")) 118850dab0fSMichael Platings .Maybe(MultilibBuilder("three")) 119850dab0fSMichael Platings .makeMultilibSet(); 120850dab0fSMichael Platings MultilibSet MS = MB.makeMultilibSet(); 121850dab0fSMichael Platings ASSERT_EQ(MS.size(), (unsigned)2 * 2 * 2) 122850dab0fSMichael Platings << "Size before filter was incorrect. Contents:\n" 123850dab0fSMichael Platings << MS; 124850dab0fSMichael Platings MB.FilterOut("/one/two/three"); 125850dab0fSMichael Platings MS = MB.makeMultilibSet(); 126850dab0fSMichael Platings ASSERT_EQ(MS.size(), (unsigned)2 * 2 * 2 - 1) 127850dab0fSMichael Platings << "Size after filter was incorrect. Contents:\n" 128850dab0fSMichael Platings << MS; 129850dab0fSMichael Platings for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) { 130850dab0fSMichael Platings ASSERT_TRUE(I->gccSuffix() != "/one/two/three") 131850dab0fSMichael Platings << "The filter should have removed " << *I; 132850dab0fSMichael Platings } 133850dab0fSMichael Platings } 134850dab0fSMichael Platings 135850dab0fSMichael Platings TEST(MultilibBuilderTest, SetFilterObject) { 136850dab0fSMichael Platings MultilibSet MS = MultilibSetBuilder() 137850dab0fSMichael Platings .Maybe(MultilibBuilder("orange")) 138850dab0fSMichael Platings .Maybe(MultilibBuilder("pear")) 139850dab0fSMichael Platings .Maybe(MultilibBuilder("plum")) 140850dab0fSMichael Platings .makeMultilibSet(); 141850dab0fSMichael Platings ASSERT_EQ((int)MS.size(), 1 /* Default */ + 1 /* pear */ + 1 /* plum */ + 142850dab0fSMichael Platings 1 /* pear/plum */ + 1 /* orange */ + 143850dab0fSMichael Platings 1 /* orange/pear */ + 1 /* orange/plum */ + 144850dab0fSMichael Platings 1 /* orange/pear/plum */) 145850dab0fSMichael Platings << "Size before filter was incorrect. Contents:\n" 146850dab0fSMichael Platings << MS; 147850dab0fSMichael Platings MS.FilterOut([](const Multilib &M) { 148f3dcc235SKazu Hirata return StringRef(M.gccSuffix()).starts_with("/p"); 149850dab0fSMichael Platings }); 150850dab0fSMichael Platings ASSERT_EQ((int)MS.size(), 1 /* Default */ + 1 /* orange */ + 151850dab0fSMichael Platings 1 /* orange/pear */ + 1 /* orange/plum */ + 152850dab0fSMichael Platings 1 /* orange/pear/plum */) 153850dab0fSMichael Platings << "Size after filter was incorrect. Contents:\n" 154850dab0fSMichael Platings << MS; 155850dab0fSMichael Platings for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) { 156f3dcc235SKazu Hirata ASSERT_FALSE(StringRef(I->gccSuffix()).starts_with("/p")) 157850dab0fSMichael Platings << "The filter should have removed " << *I; 158850dab0fSMichael Platings } 159850dab0fSMichael Platings } 160850dab0fSMichael Platings 161850dab0fSMichael Platings TEST(MultilibBuilderTest, SetSelection1) { 162850dab0fSMichael Platings MultilibSet MS1 = MultilibSetBuilder() 163b4507dcaSMichael Platings .Maybe(MultilibBuilder("64").flag("-m64")) 164850dab0fSMichael Platings .makeMultilibSet(); 165850dab0fSMichael Platings 166ce8fa36eSMichael Platings Multilib::flags_list FlagM64 = {"-m64"}; 167edc1130cSMichael Platings llvm::SmallVector<Multilib> SelectionM64; 168*26bf0b4aSSimon Tatham Driver TheDriver = diagnostic_test_driver(); 169*26bf0b4aSSimon Tatham ASSERT_TRUE(MS1.select(TheDriver, FlagM64, SelectionM64)) 170ce8fa36eSMichael Platings << "Flag set was {\"-m64\"}, but selection not found"; 171edc1130cSMichael Platings ASSERT_TRUE(SelectionM64.back().gccSuffix() == "/64") 172edc1130cSMichael Platings << "Selection picked " << SelectionM64.back() 173edc1130cSMichael Platings << " which was not expected"; 174850dab0fSMichael Platings 175ce8fa36eSMichael Platings Multilib::flags_list FlagNoM64 = {"!m64"}; 176edc1130cSMichael Platings llvm::SmallVector<Multilib> SelectionNoM64; 177*26bf0b4aSSimon Tatham ASSERT_TRUE(MS1.select(TheDriver, FlagNoM64, SelectionNoM64)) 178ce8fa36eSMichael Platings << "Flag set was {\"!m64\"}, but selection not found"; 179edc1130cSMichael Platings ASSERT_TRUE(SelectionNoM64.back().gccSuffix() == "") 180edc1130cSMichael Platings << "Selection picked " << SelectionNoM64.back() 181edc1130cSMichael Platings << " which was not expected"; 182850dab0fSMichael Platings } 183850dab0fSMichael Platings 184850dab0fSMichael Platings TEST(MultilibBuilderTest, SetSelection2) { 185850dab0fSMichael Platings MultilibSet MS2 = MultilibSetBuilder() 186b4507dcaSMichael Platings .Maybe(MultilibBuilder("el").flag("-EL")) 187b4507dcaSMichael Platings .Maybe(MultilibBuilder("sf").flag("-SF")) 188850dab0fSMichael Platings .makeMultilibSet(); 189850dab0fSMichael Platings 190850dab0fSMichael Platings for (unsigned I = 0; I < 4; ++I) { 191850dab0fSMichael Platings bool IsEL = I & 0x1; 192850dab0fSMichael Platings bool IsSF = I & 0x2; 193850dab0fSMichael Platings Multilib::flags_list Flags; 194850dab0fSMichael Platings if (IsEL) 195850dab0fSMichael Platings Flags.push_back("-EL"); 196ce8fa36eSMichael Platings else 197ce8fa36eSMichael Platings Flags.push_back("!EL"); 198850dab0fSMichael Platings 199850dab0fSMichael Platings if (IsSF) 200850dab0fSMichael Platings Flags.push_back("-SF"); 201ce8fa36eSMichael Platings else 202ce8fa36eSMichael Platings Flags.push_back("!SF"); 203850dab0fSMichael Platings 204edc1130cSMichael Platings llvm::SmallVector<Multilib> Selection; 205*26bf0b4aSSimon Tatham Driver TheDriver = diagnostic_test_driver(); 206*26bf0b4aSSimon Tatham ASSERT_TRUE(MS2.select(TheDriver, Flags, Selection)) 207ce8fa36eSMichael Platings << "Selection failed for " << (IsEL ? "-EL" : "!EL") << " " 208ce8fa36eSMichael Platings << (IsSF ? "-SF" : "!SF"); 209850dab0fSMichael Platings 210850dab0fSMichael Platings std::string Suffix; 211850dab0fSMichael Platings if (IsEL) 212850dab0fSMichael Platings Suffix += "/el"; 213850dab0fSMichael Platings if (IsSF) 214850dab0fSMichael Platings Suffix += "/sf"; 215850dab0fSMichael Platings 216edc1130cSMichael Platings ASSERT_EQ(Selection.back().gccSuffix(), Suffix) 217edc1130cSMichael Platings << "Selection picked " << Selection.back() 218edc1130cSMichael Platings << " which was not expected "; 219850dab0fSMichael Platings } 220850dab0fSMichael Platings } 221