19379d19fSRaphael Isemann //===-- CppModuleConfigurationTest.cpp ---------------------------*- C++-*-===// 29379d19fSRaphael Isemann // 39379d19fSRaphael Isemann // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 49379d19fSRaphael Isemann // See https://llvm.org/LICENSE.txt for license information. 59379d19fSRaphael Isemann // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 69379d19fSRaphael Isemann // 79379d19fSRaphael Isemann //===----------------------------------------------------------------------===// 89379d19fSRaphael Isemann 99379d19fSRaphael Isemann #include "Plugins/ExpressionParser/Clang/CppModuleConfiguration.h" 109379d19fSRaphael Isemann #include "Plugins/ExpressionParser/Clang/ClangHost.h" 119379d19fSRaphael Isemann #include "lldb/Host/FileSystem.h" 129379d19fSRaphael Isemann #include "lldb/Host/HostInfo.h" 139379d19fSRaphael Isemann 149379d19fSRaphael Isemann #include "gmock/gmock.h" 159379d19fSRaphael Isemann #include "gtest/gtest.h" 169379d19fSRaphael Isemann 179379d19fSRaphael Isemann using namespace lldb_private; 189379d19fSRaphael Isemann 199379d19fSRaphael Isemann namespace { 209379d19fSRaphael Isemann struct CppModuleConfigurationTest : public testing::Test { 219379d19fSRaphael Isemann static void SetUpTestCase() { 229379d19fSRaphael Isemann // Getting the resource directory uses those subsystems, so we should 239379d19fSRaphael Isemann // initialize them. 249379d19fSRaphael Isemann FileSystem::Initialize(); 259379d19fSRaphael Isemann HostInfo::Initialize(); 269379d19fSRaphael Isemann } 279379d19fSRaphael Isemann static void TearDownTestCase() { 289379d19fSRaphael Isemann HostInfo::Terminate(); 299379d19fSRaphael Isemann FileSystem::Terminate(); 309379d19fSRaphael Isemann } 319379d19fSRaphael Isemann }; 329379d19fSRaphael Isemann } // namespace 339379d19fSRaphael Isemann 349379d19fSRaphael Isemann /// Returns the Clang resource include directory. 359379d19fSRaphael Isemann static std::string ResourceInc() { 369379d19fSRaphael Isemann llvm::SmallString<256> resource_dir; 379379d19fSRaphael Isemann llvm::sys::path::append(resource_dir, GetClangResourceDir().GetPath(), 389379d19fSRaphael Isemann "include"); 399379d19fSRaphael Isemann return resource_dir.str().str(); 409379d19fSRaphael Isemann } 419379d19fSRaphael Isemann 429379d19fSRaphael Isemann /// Utility function turningn a list of paths into a FileSpecList. 439379d19fSRaphael Isemann static FileSpecList makeFiles(llvm::ArrayRef<std::string> paths) { 449379d19fSRaphael Isemann FileSpecList result; 459379d19fSRaphael Isemann for (const std::string &path : paths) 46*1a2805b8SRaphael Isemann result.Append(FileSpec(path, FileSpec::Style::posix)); 479379d19fSRaphael Isemann return result; 489379d19fSRaphael Isemann } 499379d19fSRaphael Isemann 509379d19fSRaphael Isemann TEST_F(CppModuleConfigurationTest, Linux) { 519379d19fSRaphael Isemann // Test the average Linux configuration. 529379d19fSRaphael Isemann std::string libcpp = "/usr/include/c++/v1"; 539379d19fSRaphael Isemann std::string usr = "/usr/include"; 549379d19fSRaphael Isemann CppModuleConfiguration config( 559379d19fSRaphael Isemann makeFiles({usr + "/bits/types.h", libcpp + "/vector"})); 569379d19fSRaphael Isemann EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std")); 579379d19fSRaphael Isemann EXPECT_THAT(config.GetIncludeDirs(), 589379d19fSRaphael Isemann testing::ElementsAre(libcpp, ResourceInc(), usr)); 599379d19fSRaphael Isemann } 609379d19fSRaphael Isemann 619379d19fSRaphael Isemann TEST_F(CppModuleConfigurationTest, Sysroot) { 629379d19fSRaphael Isemann // Test that having a sysroot for the whole system works fine. 639379d19fSRaphael Isemann std::string libcpp = "/home/user/sysroot/usr/include/c++/v1"; 649379d19fSRaphael Isemann std::string usr = "/home/user/sysroot/usr/include"; 659379d19fSRaphael Isemann CppModuleConfiguration config( 669379d19fSRaphael Isemann makeFiles({usr + "/bits/types.h", libcpp + "/vector"})); 679379d19fSRaphael Isemann EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std")); 689379d19fSRaphael Isemann EXPECT_THAT(config.GetIncludeDirs(), 699379d19fSRaphael Isemann testing::ElementsAre(libcpp, ResourceInc(), usr)); 709379d19fSRaphael Isemann } 719379d19fSRaphael Isemann 729379d19fSRaphael Isemann TEST_F(CppModuleConfigurationTest, LinuxLocalLibCpp) { 739379d19fSRaphael Isemann // Test that a locally build libc++ is detected. 749379d19fSRaphael Isemann std::string libcpp = "/home/user/llvm-build/include/c++/v1"; 759379d19fSRaphael Isemann std::string usr = "/usr/include"; 769379d19fSRaphael Isemann CppModuleConfiguration config( 779379d19fSRaphael Isemann makeFiles({usr + "/bits/types.h", libcpp + "/vector"})); 789379d19fSRaphael Isemann EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std")); 799379d19fSRaphael Isemann EXPECT_THAT(config.GetIncludeDirs(), 809379d19fSRaphael Isemann testing::ElementsAre(libcpp, ResourceInc(), usr)); 819379d19fSRaphael Isemann } 829379d19fSRaphael Isemann 839379d19fSRaphael Isemann TEST_F(CppModuleConfigurationTest, UnrelatedLibrary) { 849379d19fSRaphael Isemann // Test that having an unrelated library in /usr/include doesn't break. 859379d19fSRaphael Isemann std::string libcpp = "/home/user/llvm-build/include/c++/v1"; 869379d19fSRaphael Isemann std::string usr = "/usr/include"; 879379d19fSRaphael Isemann CppModuleConfiguration config(makeFiles( 889379d19fSRaphael Isemann {usr + "/bits/types.h", libcpp + "/vector", usr + "/boost/vector"})); 899379d19fSRaphael Isemann EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std")); 909379d19fSRaphael Isemann EXPECT_THAT(config.GetIncludeDirs(), 919379d19fSRaphael Isemann testing::ElementsAre(libcpp, ResourceInc(), usr)); 929379d19fSRaphael Isemann } 939379d19fSRaphael Isemann 949379d19fSRaphael Isemann TEST_F(CppModuleConfigurationTest, Xcode) { 959379d19fSRaphael Isemann // Test detection of libc++ coming from Xcode with generic platform names. 969379d19fSRaphael Isemann std::string p = "/Applications/Xcode.app/Contents/Developer/"; 979379d19fSRaphael Isemann std::string libcpp = p + "Toolchains/B.xctoolchain/usr/include/c++/v1"; 989379d19fSRaphael Isemann std::string usr = 999379d19fSRaphael Isemann p + "Platforms/A.platform/Developer/SDKs/OSVers.sdk/usr/include"; 1009379d19fSRaphael Isemann CppModuleConfiguration config( 1019379d19fSRaphael Isemann makeFiles({libcpp + "/unordered_map", usr + "/stdio.h"})); 1029379d19fSRaphael Isemann EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std")); 1039379d19fSRaphael Isemann EXPECT_THAT(config.GetIncludeDirs(), 1049379d19fSRaphael Isemann testing::ElementsAre(libcpp, ResourceInc(), usr)); 1059379d19fSRaphael Isemann } 1069379d19fSRaphael Isemann 1079379d19fSRaphael Isemann TEST_F(CppModuleConfigurationTest, LibCppV2) { 1089379d19fSRaphael Isemann // Test that a "v2" of libc++ is still correctly detected. 1099379d19fSRaphael Isemann CppModuleConfiguration config( 1109379d19fSRaphael Isemann makeFiles({"/usr/include/bits/types.h", "/usr/include/c++/v2/vector"})); 1119379d19fSRaphael Isemann EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std")); 1129379d19fSRaphael Isemann EXPECT_THAT(config.GetIncludeDirs(), 1139379d19fSRaphael Isemann testing::ElementsAre("/usr/include/c++/v2", ResourceInc(), 1149379d19fSRaphael Isemann "/usr/include")); 1159379d19fSRaphael Isemann } 1169379d19fSRaphael Isemann 1179379d19fSRaphael Isemann TEST_F(CppModuleConfigurationTest, UnknownLibCppFile) { 1189379d19fSRaphael Isemann // Test that having some unknown file in the libc++ path doesn't break 1199379d19fSRaphael Isemann // anything. 1209379d19fSRaphael Isemann CppModuleConfiguration config(makeFiles( 1219379d19fSRaphael Isemann {"/usr/include/bits/types.h", "/usr/include/c++/v1/non_existing_file"})); 1229379d19fSRaphael Isemann EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std")); 1239379d19fSRaphael Isemann EXPECT_THAT(config.GetIncludeDirs(), 1249379d19fSRaphael Isemann testing::ElementsAre("/usr/include/c++/v1", ResourceInc(), 1259379d19fSRaphael Isemann "/usr/include")); 1269379d19fSRaphael Isemann } 1279379d19fSRaphael Isemann 1289379d19fSRaphael Isemann TEST_F(CppModuleConfigurationTest, MissingUsrInclude) { 1299379d19fSRaphael Isemann // Test that we don't load 'std' if we can't find the C standard library. 1309379d19fSRaphael Isemann CppModuleConfiguration config(makeFiles({"/usr/include/c++/v1/vector"})); 1319379d19fSRaphael Isemann EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre()); 1329379d19fSRaphael Isemann EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre()); 1339379d19fSRaphael Isemann } 1349379d19fSRaphael Isemann 1359379d19fSRaphael Isemann TEST_F(CppModuleConfigurationTest, MissingLibCpp) { 1369379d19fSRaphael Isemann // Test that we don't load 'std' if we don't have a libc++. 1379379d19fSRaphael Isemann CppModuleConfiguration config(makeFiles({"/usr/include/bits/types.h"})); 1389379d19fSRaphael Isemann EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre()); 1399379d19fSRaphael Isemann EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre()); 1409379d19fSRaphael Isemann } 1419379d19fSRaphael Isemann 1429379d19fSRaphael Isemann TEST_F(CppModuleConfigurationTest, IgnoreLibStdCpp) { 1439379d19fSRaphael Isemann // Test that we don't do anything bad when we encounter libstdc++ paths. 1449379d19fSRaphael Isemann CppModuleConfiguration config(makeFiles( 1459379d19fSRaphael Isemann {"/usr/include/bits/types.h", "/usr/include/c++/8.0.1/vector"})); 1469379d19fSRaphael Isemann EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre()); 1479379d19fSRaphael Isemann EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre()); 1489379d19fSRaphael Isemann } 1499379d19fSRaphael Isemann 1509379d19fSRaphael Isemann TEST_F(CppModuleConfigurationTest, AmbiguousCLib) { 1519379d19fSRaphael Isemann // Test that we don't do anything when we are not sure where the 1529379d19fSRaphael Isemann // right C standard library is. 1539379d19fSRaphael Isemann CppModuleConfiguration config( 1549379d19fSRaphael Isemann makeFiles({"/usr/include/bits/types.h", "/usr/include/c++/v1/vector", 1559379d19fSRaphael Isemann "/sysroot/usr/include/bits/types.h"})); 1569379d19fSRaphael Isemann EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre()); 1579379d19fSRaphael Isemann EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre()); 1589379d19fSRaphael Isemann } 1599379d19fSRaphael Isemann 1609379d19fSRaphael Isemann TEST_F(CppModuleConfigurationTest, AmbiguousLibCpp) { 1619379d19fSRaphael Isemann // Test that we don't do anything when we are not sure where the 1629379d19fSRaphael Isemann // right libc++ is. 1639379d19fSRaphael Isemann CppModuleConfiguration config( 1649379d19fSRaphael Isemann makeFiles({"/usr/include/bits/types.h", "/usr/include/c++/v1/vector", 1659379d19fSRaphael Isemann "/usr/include/c++/v2/vector"})); 1669379d19fSRaphael Isemann EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre()); 1679379d19fSRaphael Isemann EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre()); 1689379d19fSRaphael Isemann } 169