#include "Test/Test.h" #include "Compiler/Compilation.h" #include "llvm/Support/ToolOutputFile.h" namespace clice::testing { namespace { using namespace std::literals; auto buildPCM = [](llvm::StringRef file, llvm::StringRef code) { llvm::SmallString<128> outPath; fs::createUniquePath(llvm::Twine(file) + "%%%%%%.pcm", outPath, true); std::string path = file.str(); CompilationParams params; params.output_file = outPath; params.arguments = { "clang++", "-std=c++20", "-xc++", path.c_str(), }; params.add_remapped_file(file, code); params.add_remapped_file("./test.h", "export int foo2();"); PCMInfo pcm; if(!compile(params, pcm)) { llvm::errs() << "Failed to build PCM\n"; std::abort(); } return pcm; }; auto scan = [](llvm::StringRef content) { CompilationParams params; params.arguments = { "clang++", "-std=c++20", "-xc++", "main.ixx", }; params.add_remapped_file("main.ixx", content); params.add_remapped_file("./test.h", "export module A"); auto info = scanModule(params); if(!info) { /// std::println("Fail to scan module: {}", info.error()); std::abort(); } return std::move(*info); }; suite<"Module"> module = [] { test("Scan") = [&] { /// Simple case. const char* content = R"( export module A; import B; )"; auto info = scan(content); expect(that % info.isInterfaceUnit == true); expect(that % info.name == "A"sv); expect(that % info.mods.size() == 1); expect(that % info.mods[0] == "B"sv); /// FIXME: Fix standard library search path(resource dir). /// With global module fragment and private module fragment. /// content = R"( /// module; /// #include /// export module A; /// import B; /// import C; /// module : private; ///)"; /// info = scan(content); /// expect(that % info.isInterfaceUnit == true); /// expect(that % info.name == "A"); /// expect(that % info.mods.size() == 2); /// expect(that % info.mods[0] == "B"); /// expect(that % info.mods[1] == "C"); /// With module partition. /// content = R"( /// module; /// #include /// export module A:B; /// import B; /// import C; /// module : private; ///)"; /// info = scan(content); /// expect(that % info.isInterfaceUnit == true); /// expect(that % info.name == "A:B"); /// expect(that % info.mods.size() == 2); /// expect(that % info.mods[0] == "B"); /// expect(that % info.mods[1] == "C"); content = R"( module A; import B; import C; )"; info = scan(content); expect(that % info.isInterfaceUnit == false); expect(that % info.name == "A"sv); expect(that % info.mods.size() == 2); expect(that % info.mods[0] == "B"sv); expect(that % info.mods[1] == "C"sv); }; test("Normal") = [&] { const char* content = R"( export module A; )"; auto pcm = buildPCM("A.ixx", content); // expect(that % pcm.isInterfaceUnit == true); // expect(that % pcm.name == "A"); // expect(that % pcm.mods.size() == 0); }; }; // TEST(Module, ScanModuleName) { // CompilationParams params; // // /// Test module name not in condition directive. // params.content = "export module A;"; // ASSERT_EQ(scanModuleName(params), "A"); // // params.content = "export module A.B.C.D;"; // ASSERT_EQ(scanModuleName(params), "A.B.C.D"); // // params.content = "export module A:B;"; // ASSERT_EQ(scanModuleName(params), "A:B"); // // params.content = R"( // module; // #ifdef TEST // #include // #endif // export module A; //)"; // ASSERT_EQ(scanModuleName(params), "A"); // // /// Test non-module interface unit. // params.content = "module A;"; // ASSERT_EQ(scanModuleName(params), ""); // // params.content = ""; // ASSERT_EQ(scanModuleName(params), ""); // // /// Test module name in condition directive. // params.content = R"( // #ifdef TEST // export module A; // #else // export module B; // #endif //)"; // params.srcPath = "main.cppm"; // params.command = "clang++ -std=c++20 -x c++ main.cppm -DTEST"; // ASSERT_EQ(scanModuleName(params), "A"); // // params.command = "clang++ -std=c++20 -x c++ main.cppm"; // ASSERT_EQ(scanModuleName(params), "B"); // } } // namespace } // namespace clice::testing