|
| 1 | +//===--- ModuleLoadingTests.cpp -------------------------------------------===// |
| 2 | +// |
| 3 | +// This source file is part of the Swift.org open source project |
| 4 | +// |
| 5 | +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| 6 | +// Licensed under Apache License v2.0 with Runtime Library Exception |
| 7 | +// |
| 8 | +// See https://swift.org/LICENSE.txt for license information |
| 9 | +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| 10 | +// |
| 11 | +//===----------------------------------------------------------------------===// |
| 12 | + |
| 13 | +#include "gtest/gtest.h" |
| 14 | +#include "swift/AST/ASTContext.h" |
| 15 | +#include "swift/Frontend/Frontend.h" |
| 16 | +#include "swift/Frontend/ParseableInterfaceModuleLoader.h" |
| 17 | +#include "swift/Frontend/PrintingDiagnosticConsumer.h" |
| 18 | +#include "swift/Serialization/Validation.h" |
| 19 | +#include "llvm/ADT/SmallString.h" |
| 20 | +#include "llvm/Support/VirtualFileSystem.h" |
| 21 | + |
| 22 | +using namespace swift; |
| 23 | + |
| 24 | +static std::string createFilename(StringRef base, StringRef name) { |
| 25 | + SmallString<256> path = base; |
| 26 | + llvm::sys::path::append(path, name); |
| 27 | + return llvm::Twine(path).str(); |
| 28 | +} |
| 29 | + |
| 30 | +static bool emitFileWithContents(StringRef path, StringRef contents, |
| 31 | + std::string *pathOut = nullptr) { |
| 32 | + int fd; |
| 33 | + if (llvm::sys::fs::openFileForWrite(path, fd)) |
| 34 | + return true; |
| 35 | + if (pathOut) |
| 36 | + *pathOut = path; |
| 37 | + llvm::raw_fd_ostream file(fd, /*shouldClose=*/true); |
| 38 | + file << contents; |
| 39 | + return false; |
| 40 | +} |
| 41 | + |
| 42 | +static bool emitFileWithContents(StringRef base, StringRef name, |
| 43 | + StringRef contents, |
| 44 | + std::string *pathOut = nullptr) { |
| 45 | + return emitFileWithContents(createFilename(base, name), contents, pathOut); |
| 46 | +} |
| 47 | + |
| 48 | +namespace unittest { |
| 49 | + |
| 50 | +class OpenTrackingFileSystem : public llvm::vfs::ProxyFileSystem { |
| 51 | + llvm::StringMap<unsigned> numberOfOpensPerFile; |
| 52 | +public: |
| 53 | + OpenTrackingFileSystem(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs) |
| 54 | + : llvm::vfs::ProxyFileSystem(fs) {} |
| 55 | + |
| 56 | + llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>> |
| 57 | + openFileForRead(const Twine &Path) override { |
| 58 | + numberOfOpensPerFile[Path.str()] += 1; |
| 59 | + return ProxyFileSystem::openFileForRead(Path); |
| 60 | + } |
| 61 | + |
| 62 | + unsigned numberOfOpens(StringRef path) { |
| 63 | + return numberOfOpensPerFile[path]; |
| 64 | + } |
| 65 | +}; |
| 66 | + |
| 67 | +class ParseableInterfaceModuleLoaderTest : public testing::Test { |
| 68 | +protected: |
| 69 | + void setupAndLoadParseableModule() { |
| 70 | + SmallString<256> tempDir; |
| 71 | + ASSERT_FALSE(llvm::sys::fs::createUniqueDirectory( |
| 72 | + "ParseableModuleBufferTests.emitModuleInMemory", tempDir)); |
| 73 | + SWIFT_DEFER { llvm::sys::fs::remove_directories(tempDir); }; |
| 74 | + |
| 75 | + auto cacheDir = createFilename(tempDir, "ModuleCache"); |
| 76 | + ASSERT_FALSE(llvm::sys::fs::create_directory(cacheDir)); |
| 77 | + |
| 78 | + auto prebuiltCacheDir = createFilename(tempDir, "PrebuiltModuleCache"); |
| 79 | + ASSERT_FALSE(llvm::sys::fs::create_directory(prebuiltCacheDir)); |
| 80 | + |
| 81 | + // Emit an interface file that we can attempt to compile. |
| 82 | + ASSERT_FALSE(emitFileWithContents(tempDir, "Library.swiftinterface", |
| 83 | + "// swift-interface-format-version: 1.0\n" |
| 84 | + "// swift-module-flags: -module-name TestModule -parse-stdlib\n" |
| 85 | + "public func foo()\n")); |
| 86 | + |
| 87 | + SourceManager sourceMgr; |
| 88 | + |
| 89 | + // Create a file system that tracks how many times a file has been opened. |
| 90 | + llvm::IntrusiveRefCntPtr<OpenTrackingFileSystem> fs( |
| 91 | + new OpenTrackingFileSystem(sourceMgr.getFileSystem())); |
| 92 | + |
| 93 | + sourceMgr.setFileSystem(fs); |
| 94 | + PrintingDiagnosticConsumer printingConsumer; |
| 95 | + DiagnosticEngine diags(sourceMgr); |
| 96 | + diags.addConsumer(printingConsumer); |
| 97 | + LangOptions langOpts; |
| 98 | + langOpts.Target = llvm::Triple(llvm::sys::getDefaultTargetTriple()); |
| 99 | + SearchPathOptions searchPathOpts; |
| 100 | + auto ctx = ASTContext::get(langOpts, searchPathOpts, sourceMgr, diags); |
| 101 | + |
| 102 | + auto loader = ParseableInterfaceModuleLoader::create( |
| 103 | + *ctx, cacheDir, prebuiltCacheDir, |
| 104 | + /*dependencyTracker*/nullptr, |
| 105 | + ModuleLoadingMode::PreferSerialized); |
| 106 | + |
| 107 | + Identifier moduleName = ctx->getIdentifier("TestModule"); |
| 108 | + |
| 109 | + std::unique_ptr<llvm::MemoryBuffer> moduleBuffer; |
| 110 | + std::unique_ptr<llvm::MemoryBuffer> moduleDocBuffer; |
| 111 | + |
| 112 | + auto error = |
| 113 | + loader->findModuleFilesInDirectory({moduleName, SourceLoc()}, tempDir, |
| 114 | + "Library.swiftmodule", "Library.swiftdoc", |
| 115 | + &moduleBuffer, &moduleDocBuffer); |
| 116 | + ASSERT_FALSE(error); |
| 117 | + ASSERT_FALSE(diags.hadAnyError()); |
| 118 | + |
| 119 | + ASSERT_NE(nullptr, moduleBuffer); |
| 120 | + |
| 121 | + // We should not have written a module doc file. |
| 122 | + ASSERT_EQ(nullptr, moduleDocBuffer); |
| 123 | + |
| 124 | + // Make sure the buffer identifier points to the written module. |
| 125 | + StringRef cachedModulePath = moduleBuffer->getBufferIdentifier(); |
| 126 | + ASSERT_TRUE(fs->exists(cachedModulePath)); |
| 127 | + |
| 128 | + // Assert that we've only opened this file once, to write it. |
| 129 | + ASSERT_EQ((unsigned)1, fs->numberOfOpens(cachedModulePath)); |
| 130 | + |
| 131 | + auto bufOrErr = fs->getBufferForFile(cachedModulePath); |
| 132 | + ASSERT_TRUE(bufOrErr); |
| 133 | + |
| 134 | + auto bufData = (*bufOrErr)->getBuffer(); |
| 135 | + auto validationInfo = serialization::validateSerializedAST(bufData); |
| 136 | + ASSERT_EQ(serialization::Status::Valid, validationInfo.status); |
| 137 | + ASSERT_EQ(bufData, moduleBuffer->getBuffer()); |
| 138 | + } |
| 139 | +}; |
| 140 | + |
| 141 | +TEST_F(ParseableInterfaceModuleLoaderTest, LoadModuleFromBuffer) { |
| 142 | + setupAndLoadParseableModule(); |
| 143 | +} |
| 144 | + |
| 145 | +} // end namespace unittest |
0 commit comments