1*7f68a716SGreg Bedwell //===- llvm/unittest/Support/ReplaceFileTest.cpp - unit tests -------------===// 2*7f68a716SGreg Bedwell // 3*7f68a716SGreg Bedwell // The LLVM Compiler Infrastructure 4*7f68a716SGreg Bedwell // 5*7f68a716SGreg Bedwell // This file is distributed under the University of Illinois Open Source 6*7f68a716SGreg Bedwell // License. See LICENSE.TXT for details. 7*7f68a716SGreg Bedwell // 8*7f68a716SGreg Bedwell //===----------------------------------------------------------------------===// 9*7f68a716SGreg Bedwell 10*7f68a716SGreg Bedwell #include "llvm/Support/Errc.h" 11*7f68a716SGreg Bedwell #include "llvm/Support/ErrorHandling.h" 12*7f68a716SGreg Bedwell #include "llvm/Support/FileSystem.h" 13*7f68a716SGreg Bedwell #include "llvm/Support/MemoryBuffer.h" 14*7f68a716SGreg Bedwell #include "llvm/Support/Path.h" 15*7f68a716SGreg Bedwell #include "llvm/Support/Process.h" 16*7f68a716SGreg Bedwell #include "gtest/gtest.h" 17*7f68a716SGreg Bedwell 18*7f68a716SGreg Bedwell using namespace llvm; 19*7f68a716SGreg Bedwell using namespace llvm::sys; 20*7f68a716SGreg Bedwell 21*7f68a716SGreg Bedwell #define ASSERT_NO_ERROR(x) \ 22*7f68a716SGreg Bedwell do { \ 23*7f68a716SGreg Bedwell if (std::error_code ASSERT_NO_ERROR_ec = x) { \ 24*7f68a716SGreg Bedwell errs() << #x ": did not return errc::success.\n" \ 25*7f68a716SGreg Bedwell << "error number: " << ASSERT_NO_ERROR_ec.value() << "\n" \ 26*7f68a716SGreg Bedwell << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n"; \ 27*7f68a716SGreg Bedwell } \ 28*7f68a716SGreg Bedwell } while (false) 29*7f68a716SGreg Bedwell 30*7f68a716SGreg Bedwell namespace { 31*7f68a716SGreg Bedwell std::error_code CreateFileWithContent(const SmallString<128> &FilePath, 32*7f68a716SGreg Bedwell const StringRef &content) { 33*7f68a716SGreg Bedwell int FD = 0; 34*7f68a716SGreg Bedwell if (std::error_code ec = fs::openFileForWrite(FilePath, FD, fs::F_None)) 35*7f68a716SGreg Bedwell return ec; 36*7f68a716SGreg Bedwell 37*7f68a716SGreg Bedwell const bool ShouldClose = true; 38*7f68a716SGreg Bedwell raw_fd_ostream OS(FD, ShouldClose); 39*7f68a716SGreg Bedwell OS << content; 40*7f68a716SGreg Bedwell 41*7f68a716SGreg Bedwell return std::error_code(); 42*7f68a716SGreg Bedwell } 43*7f68a716SGreg Bedwell 44*7f68a716SGreg Bedwell class ScopedFD { 45*7f68a716SGreg Bedwell int FD; 46*7f68a716SGreg Bedwell 47*7f68a716SGreg Bedwell ScopedFD(const ScopedFD &) = delete; 48*7f68a716SGreg Bedwell ScopedFD &operator=(const ScopedFD &) = delete; 49*7f68a716SGreg Bedwell 50*7f68a716SGreg Bedwell public: 51*7f68a716SGreg Bedwell explicit ScopedFD(int Descriptor) : FD(Descriptor) {} 52*7f68a716SGreg Bedwell ~ScopedFD() { Process::SafelyCloseFileDescriptor(FD); } 53*7f68a716SGreg Bedwell }; 54*7f68a716SGreg Bedwell 55*7f68a716SGreg Bedwell TEST(rename, FileOpenedForReadingCanBeReplaced) { 56*7f68a716SGreg Bedwell // Create unique temporary directory for this test. 57*7f68a716SGreg Bedwell SmallString<128> TestDirectory; 58*7f68a716SGreg Bedwell ASSERT_NO_ERROR(fs::createUniqueDirectory( 59*7f68a716SGreg Bedwell "FileOpenedForReadingCanBeReplaced-test", TestDirectory)); 60*7f68a716SGreg Bedwell 61*7f68a716SGreg Bedwell // Add a couple of files to the test directory. 62*7f68a716SGreg Bedwell SmallString<128> SourceFileName(TestDirectory); 63*7f68a716SGreg Bedwell path::append(SourceFileName, "source"); 64*7f68a716SGreg Bedwell 65*7f68a716SGreg Bedwell SmallString<128> TargetFileName(TestDirectory); 66*7f68a716SGreg Bedwell path::append(TargetFileName, "target"); 67*7f68a716SGreg Bedwell 68*7f68a716SGreg Bedwell ASSERT_NO_ERROR(CreateFileWithContent(SourceFileName, "!!source!!")); 69*7f68a716SGreg Bedwell ASSERT_NO_ERROR(CreateFileWithContent(TargetFileName, "!!target!!")); 70*7f68a716SGreg Bedwell 71*7f68a716SGreg Bedwell { 72*7f68a716SGreg Bedwell // Open the target file for reading. 73*7f68a716SGreg Bedwell int ReadFD = 0; 74*7f68a716SGreg Bedwell ASSERT_NO_ERROR(fs::openFileForRead(TargetFileName, ReadFD)); 75*7f68a716SGreg Bedwell ScopedFD EventuallyCloseIt(ReadFD); 76*7f68a716SGreg Bedwell 77*7f68a716SGreg Bedwell // Confirm we can replace the file while it is open. 78*7f68a716SGreg Bedwell EXPECT_TRUE(!fs::rename(SourceFileName, TargetFileName)); 79*7f68a716SGreg Bedwell 80*7f68a716SGreg Bedwell // We should still be able to read the old data through the existing 81*7f68a716SGreg Bedwell // descriptor. 82*7f68a716SGreg Bedwell auto Buffer = MemoryBuffer::getOpenFile(ReadFD, TargetFileName, -1); 83*7f68a716SGreg Bedwell ASSERT_TRUE(static_cast<bool>(Buffer)); 84*7f68a716SGreg Bedwell EXPECT_EQ(Buffer.get()->getBuffer(), "!!target!!"); 85*7f68a716SGreg Bedwell 86*7f68a716SGreg Bedwell // The source file should no longer exist 87*7f68a716SGreg Bedwell EXPECT_FALSE(fs::exists(SourceFileName)); 88*7f68a716SGreg Bedwell } 89*7f68a716SGreg Bedwell 90*7f68a716SGreg Bedwell { 91*7f68a716SGreg Bedwell // If we obtain a new descriptor for the target file, we should find that it 92*7f68a716SGreg Bedwell // contains the content that was in the source file. 93*7f68a716SGreg Bedwell int ReadFD = 0; 94*7f68a716SGreg Bedwell ASSERT_NO_ERROR(fs::openFileForRead(TargetFileName, ReadFD)); 95*7f68a716SGreg Bedwell ScopedFD EventuallyCloseIt(ReadFD); 96*7f68a716SGreg Bedwell auto Buffer = MemoryBuffer::getOpenFile(ReadFD, TargetFileName, -1); 97*7f68a716SGreg Bedwell ASSERT_TRUE(static_cast<bool>(Buffer)); 98*7f68a716SGreg Bedwell 99*7f68a716SGreg Bedwell EXPECT_EQ(Buffer.get()->getBuffer(), "!!source!!"); 100*7f68a716SGreg Bedwell } 101*7f68a716SGreg Bedwell 102*7f68a716SGreg Bedwell // Rename the target file back to the source file name to confirm that rename 103*7f68a716SGreg Bedwell // still works if the destination does not already exist. 104*7f68a716SGreg Bedwell EXPECT_TRUE(!fs::rename(TargetFileName, SourceFileName)); 105*7f68a716SGreg Bedwell EXPECT_FALSE(fs::exists(TargetFileName)); 106*7f68a716SGreg Bedwell ASSERT_TRUE(fs::exists(SourceFileName)); 107*7f68a716SGreg Bedwell 108*7f68a716SGreg Bedwell // Clean up. 109*7f68a716SGreg Bedwell ASSERT_NO_ERROR(fs::remove(SourceFileName)); 110*7f68a716SGreg Bedwell ASSERT_NO_ERROR(fs::remove(TestDirectory.str())); 111*7f68a716SGreg Bedwell } 112*7f68a716SGreg Bedwell 113*7f68a716SGreg Bedwell } // anonymous namespace 114