Files
swift-mirror/unittests/Basic/FileSystemTests.cpp
Jordan Rose 60c3154d95 Add swift::moveFileIfDifferent.
Equivalent to llvm::sys::fs::rename, except that if the destination file
exists and has the same contents as the source file, the source file is
simply deleted and the destination file is not touched.

Used in next commit.

Swift SVN r28041
2015-05-01 17:40:28 +00:00

274 lines
8.3 KiB
C++

//===- FileSystemTests.cpp - for swift/Basic/FileSystem.h -----------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "swift/Basic/FileSystem.h"
#include "swift/Basic/LLVM.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include "gtest/gtest.h"
#define ASSERT_NO_ERROR(x) \
do if (std::error_code ASSERT_NO_ERROR_ec = x) { \
llvm::errs() << #x ": did not return errc::success.\n" \
<< "error number: " << ASSERT_NO_ERROR_ec.value() << "\n" \
<< "error message: " << ASSERT_NO_ERROR_ec.message() << "\n"; \
FAIL(); \
} while (0)
using namespace llvm::sys;
using namespace swift;
namespace {
TEST(FileSystem, MoveFileIfDifferentEmpty) {
// Create unique temporary directory for these tests
llvm::SmallString<128> dirPath;
ASSERT_NO_ERROR(fs::createUniqueDirectory("FileSystem-test", dirPath));
// Test 1: Move empty over nonexistent.
llvm::SmallString<128> sourceFile = dirPath;
path::append(sourceFile, "source.txt");
{
std::error_code error;
llvm::raw_fd_ostream emptyOut(sourceFile, error, fs::F_None);
ASSERT_NO_ERROR(error);
}
fs::UniqueID origID;
ASSERT_NO_ERROR(fs::getUniqueID(sourceFile, origID));
llvm::SmallString<128> destFile = dirPath;
path::append(destFile, "dest.txt");
ASSERT_FALSE(fs::exists(destFile));
ASSERT_NO_ERROR(moveFileIfDifferent(sourceFile, destFile));
ASSERT_TRUE(fs::exists(destFile));
ASSERT_FALSE(fs::exists(sourceFile));
fs::UniqueID destID;
ASSERT_NO_ERROR(fs::getUniqueID(destFile, destID));
ASSERT_EQ(origID, destID);
ASSERT_NO_ERROR(fs::rename(destFile, sourceFile));
// Test 2: Move empty over empty.
{
std::error_code error;
llvm::raw_fd_ostream emptyOut(destFile, error, fs::F_None);
ASSERT_NO_ERROR(error);
}
fs::UniqueID newID;
ASSERT_NO_ERROR(fs::getUniqueID(destFile, newID));
ASSERT_NE(origID, newID);
ASSERT_NO_ERROR(moveFileIfDifferent(sourceFile, destFile));
ASSERT_TRUE(fs::exists(destFile));
ASSERT_FALSE(fs::exists(sourceFile));
ASSERT_NO_ERROR(fs::getUniqueID(destFile, destID));
ASSERT_EQ(newID, destID);
ASSERT_NO_ERROR(fs::rename(destFile, sourceFile));
origID = destID;
// Test 3: Move empty over non-empty.
{
std::error_code error;
llvm::raw_fd_ostream nonEmptyOut(destFile, error, fs::F_None);
ASSERT_NO_ERROR(error);
nonEmptyOut << "a";
}
ASSERT_NO_ERROR(fs::getUniqueID(destFile, newID));
ASSERT_NE(origID, newID);
ASSERT_NO_ERROR(moveFileIfDifferent(sourceFile, destFile));
ASSERT_TRUE(fs::exists(destFile));
ASSERT_FALSE(fs::exists(sourceFile));
ASSERT_NO_ERROR(fs::getUniqueID(destFile, destID));
ASSERT_EQ(origID, destID);
ASSERT_NO_ERROR(fs::rename(destFile, sourceFile));
// Test 4: Move empty over self.
ASSERT_NO_ERROR(moveFileIfDifferent(sourceFile, sourceFile));
ASSERT_TRUE(fs::exists(sourceFile));
ASSERT_NO_ERROR(fs::getUniqueID(sourceFile, newID));
ASSERT_EQ(origID, newID);
// Clean up.
ASSERT_NO_ERROR(fs::remove(sourceFile, false));
ASSERT_NO_ERROR(fs::remove(dirPath, false));
}
TEST(FileSystem, MoveFileIfDifferentNonEmpty) {
// Create unique temporary directory for these tests
llvm::SmallString<128> dirPath;
ASSERT_NO_ERROR(fs::createUniqueDirectory("FileSystem-test", dirPath));
// Test 1: Move source over nonexistent.
llvm::SmallString<128> sourceFile = dirPath;
path::append(sourceFile, "source.txt");
{
std::error_code error;
llvm::raw_fd_ostream sourceOut(sourceFile, error, fs::F_None);
sourceOut << "original";
ASSERT_NO_ERROR(error);
}
fs::UniqueID origID;
ASSERT_NO_ERROR(fs::getUniqueID(sourceFile, origID));
llvm::SmallString<128> destFile = dirPath;
path::append(destFile, "dest.txt");
ASSERT_FALSE(fs::exists(destFile));
ASSERT_NO_ERROR(moveFileIfDifferent(sourceFile, destFile));
ASSERT_TRUE(fs::exists(destFile));
ASSERT_FALSE(fs::exists(sourceFile));
fs::UniqueID destID;
ASSERT_NO_ERROR(fs::getUniqueID(destFile, destID));
ASSERT_EQ(origID, destID);
ASSERT_NO_ERROR(fs::rename(destFile, sourceFile));
// Test 2: Move source over empty.
{
std::error_code error;
llvm::raw_fd_ostream emptyOut(destFile, error, fs::F_None);
ASSERT_NO_ERROR(error);
}
fs::UniqueID newID;
ASSERT_NO_ERROR(fs::getUniqueID(destFile, newID));
ASSERT_NE(origID, newID);
ASSERT_NO_ERROR(moveFileIfDifferent(sourceFile, destFile));
ASSERT_TRUE(fs::exists(destFile));
ASSERT_FALSE(fs::exists(sourceFile));
ASSERT_NO_ERROR(fs::getUniqueID(destFile, destID));
ASSERT_EQ(origID, destID);
ASSERT_NO_ERROR(fs::rename(destFile, sourceFile));
// Test 3: Move source over non-empty-but-different.
{
std::error_code error;
llvm::raw_fd_ostream nonEmptyOut(destFile, error, fs::F_None);
ASSERT_NO_ERROR(error);
nonEmptyOut << "different";
}
ASSERT_NO_ERROR(fs::getUniqueID(destFile, newID));
ASSERT_NE(origID, newID);
ASSERT_NO_ERROR(moveFileIfDifferent(sourceFile, destFile));
ASSERT_TRUE(fs::exists(destFile));
ASSERT_FALSE(fs::exists(sourceFile));
ASSERT_NO_ERROR(fs::getUniqueID(destFile, destID));
ASSERT_EQ(origID, destID);
ASSERT_NO_ERROR(fs::rename(destFile, sourceFile));
// Test 4: Move source over identical.
{
std::error_code error;
llvm::raw_fd_ostream nonEmptyOut(destFile, error, fs::F_None);
ASSERT_NO_ERROR(error);
nonEmptyOut << "original";
}
ASSERT_NO_ERROR(fs::getUniqueID(destFile, newID));
ASSERT_NE(origID, newID);
ASSERT_NO_ERROR(moveFileIfDifferent(sourceFile, destFile));
ASSERT_TRUE(fs::exists(destFile));
ASSERT_FALSE(fs::exists(sourceFile));
ASSERT_NO_ERROR(fs::getUniqueID(destFile, destID));
ASSERT_EQ(newID, destID);
ASSERT_NO_ERROR(fs::rename(destFile, sourceFile));
origID = newID;
// Test 5: Move source over self.
ASSERT_NO_ERROR(moveFileIfDifferent(sourceFile, sourceFile));
ASSERT_TRUE(fs::exists(sourceFile));
ASSERT_NO_ERROR(fs::getUniqueID(sourceFile, newID));
ASSERT_EQ(origID, newID);
// Clean up.
ASSERT_NO_ERROR(fs::remove(sourceFile, false));
ASSERT_NO_ERROR(fs::remove(dirPath, false));
}
TEST(FileSystem, MoveFileIfDifferentNonExistent) {
// Create unique temporary directory for these tests
llvm::SmallString<128> dirPath;
ASSERT_NO_ERROR(fs::createUniqueDirectory("FileSystem-test", dirPath));
llvm::SmallString<128> sourceFile = dirPath;
path::append(sourceFile, "source.txt");
llvm::SmallString<128> destFile = dirPath;
path::append(destFile, "dest.txt");
// Test 1: Nonexistent -> nonexistent.
ASSERT_TRUE((bool)moveFileIfDifferent(sourceFile, destFile));
{
std::error_code error;
llvm::raw_fd_ostream emptyOut(destFile, error, fs::F_None);
ASSERT_NO_ERROR(error);
}
// Test 2: Nonexistent -> present.
ASSERT_TRUE((bool)moveFileIfDifferent(sourceFile, destFile));
// Clean up.
ASSERT_NO_ERROR(fs::remove(destFile));
ASSERT_NO_ERROR(fs::remove(dirPath));
}
TEST(FileSystem, MoveFileIfDifferentInvalid) {
// Create unique temporary directory for these tests
llvm::SmallString<128> dirPath;
ASSERT_NO_ERROR(fs::createUniqueDirectory("FileSystem-test", dirPath));
llvm::SmallString<128> sourceFile = dirPath;
path::append(sourceFile, "source.txt");
{
std::error_code error;
llvm::raw_fd_ostream emptyOut(sourceFile, error, fs::F_None);
ASSERT_NO_ERROR(error);
}
// Test 1: Move a file over its parent directory.
ASSERT_TRUE((bool)moveFileIfDifferent(sourceFile, dirPath));
// Test 2: Move a file into a nonexistent directory.
llvm::SmallString<128> destFile = dirPath;
path::append(destFile, "nonexistent", "dest.txt");
ASSERT_TRUE((bool)moveFileIfDifferent(sourceFile, destFile));
// Clean up.
ASSERT_NO_ERROR(fs::remove(sourceFile, false));
ASSERT_NO_ERROR(fs::remove(dirPath, false));
}
} // anonymous namespace