diff options
author | dim <dim@FreeBSD.org> | 2013-12-22 00:07:40 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2013-12-22 00:07:40 +0000 |
commit | 952eddef9aff85b1e92626e89baaf7a360e2ac85 (patch) | |
tree | df8df0b0067b381eab470a3b8f28d14a552a6340 /unittests/Tooling/RefactoringTest.cpp | |
parent | ea266cad53e3d49771fa38103913d3ec7a166694 (diff) | |
download | FreeBSD-src-952eddef9aff85b1e92626e89baaf7a360e2ac85.zip FreeBSD-src-952eddef9aff85b1e92626e89baaf7a360e2ac85.tar.gz |
Vendor import of clang release_34 branch r197841 (effectively, 3.4 RC3):
https://llvm.org/svn/llvm-project/cfe/branches/release_34@197841
Diffstat (limited to 'unittests/Tooling/RefactoringTest.cpp')
-rw-r--r-- | unittests/Tooling/RefactoringTest.cpp | 193 |
1 files changed, 175 insertions, 18 deletions
diff --git a/unittests/Tooling/RefactoringTest.cpp b/unittests/Tooling/RefactoringTest.cpp index 3e0d728..8c7bfa1 100644 --- a/unittests/Tooling/RefactoringTest.cpp +++ b/unittests/Tooling/RefactoringTest.cpp @@ -120,6 +120,21 @@ TEST_F(ReplacementTest, CanApplyReplacements) { EXPECT_EQ("line1\nreplaced\nother\nline4", Context.getRewrittenText(ID)); } +// FIXME: Remove this test case when Replacements is implemented as std::vector +// instead of std::set. The other ReplacementTest tests will need to be updated +// at that point as well. +TEST_F(ReplacementTest, VectorCanApplyReplacements) { + FileID ID = Context.createInMemoryFile("input.cpp", + "line1\nline2\nline3\nline4"); + std::vector<Replacement> Replaces; + Replaces.push_back(Replacement(Context.Sources, Context.getLocation(ID, 2, 1), + 5, "replaced")); + Replaces.push_back( + Replacement(Context.Sources, Context.getLocation(ID, 3, 1), 5, "other")); + EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite)); + EXPECT_EQ("line1\nreplaced\nother\nline4", Context.getRewrittenText(ID)); +} + TEST_F(ReplacementTest, SkipsDuplicateReplacements) { FileID ID = Context.createInMemoryFile("input.cpp", "line1\nline2\nline3\nline4"); @@ -151,37 +166,87 @@ TEST_F(ReplacementTest, ApplyAllFailsIfOneApplyFails) { EXPECT_EQ("z", Context.getRewrittenText(IDz)); } +TEST(ShiftedCodePositionTest, FindsNewCodePosition) { + Replacements Replaces; + Replaces.insert(Replacement("", 0, 1, "")); + Replaces.insert(Replacement("", 4, 3, " ")); + // Assume ' int i;' is turned into 'int i;' and cursor is located at '|'. + EXPECT_EQ(0u, shiftedCodePosition(Replaces, 0)); // |int i; + EXPECT_EQ(0u, shiftedCodePosition(Replaces, 1)); // |nt i; + EXPECT_EQ(1u, shiftedCodePosition(Replaces, 2)); // i|t i; + EXPECT_EQ(2u, shiftedCodePosition(Replaces, 3)); // in| i; + EXPECT_EQ(3u, shiftedCodePosition(Replaces, 4)); // int| i; + EXPECT_EQ(4u, shiftedCodePosition(Replaces, 5)); // int | i; + EXPECT_EQ(4u, shiftedCodePosition(Replaces, 6)); // int |i; + EXPECT_EQ(4u, shiftedCodePosition(Replaces, 7)); // int |; + EXPECT_EQ(5u, shiftedCodePosition(Replaces, 8)); // int i| +} + +// FIXME: Remove this test case when Replacements is implemented as std::vector +// instead of std::set. The other ReplacementTest tests will need to be updated +// at that point as well. +TEST(ShiftedCodePositionTest, VectorFindsNewCodePositionWithInserts) { + std::vector<Replacement> Replaces; + Replaces.push_back(Replacement("", 0, 1, "")); + Replaces.push_back(Replacement("", 4, 3, " ")); + // Assume ' int i;' is turned into 'int i;' and cursor is located at '|'. + EXPECT_EQ(0u, shiftedCodePosition(Replaces, 0)); // |int i; + EXPECT_EQ(0u, shiftedCodePosition(Replaces, 1)); // |nt i; + EXPECT_EQ(1u, shiftedCodePosition(Replaces, 2)); // i|t i; + EXPECT_EQ(2u, shiftedCodePosition(Replaces, 3)); // in| i; + EXPECT_EQ(3u, shiftedCodePosition(Replaces, 4)); // int| i; + EXPECT_EQ(4u, shiftedCodePosition(Replaces, 5)); // int | i; + EXPECT_EQ(4u, shiftedCodePosition(Replaces, 6)); // int |i; + EXPECT_EQ(4u, shiftedCodePosition(Replaces, 7)); // int |; + EXPECT_EQ(5u, shiftedCodePosition(Replaces, 8)); // int i| +} + +TEST(ShiftedCodePositionTest, FindsNewCodePositionWithInserts) { + Replacements Replaces; + Replaces.insert(Replacement("", 4, 0, "\"\n\"")); + // Assume '"12345678"' is turned into '"1234"\n"5678"'. + EXPECT_EQ(4u, shiftedCodePosition(Replaces, 4)); // "123|5678" + EXPECT_EQ(8u, shiftedCodePosition(Replaces, 5)); // "1234|678" +} + class FlushRewrittenFilesTest : public ::testing::Test { - public: - FlushRewrittenFilesTest() { - std::string ErrorInfo; - TemporaryDirectory = llvm::sys::Path::GetTemporaryDirectory(&ErrorInfo); - assert(ErrorInfo.empty()); - } +public: + FlushRewrittenFilesTest() {} ~FlushRewrittenFilesTest() { - std::string ErrorInfo; - TemporaryDirectory.eraseFromDisk(true, &ErrorInfo); - assert(ErrorInfo.empty()); + for (llvm::StringMap<std::string>::iterator I = TemporaryFiles.begin(), + E = TemporaryFiles.end(); + I != E; ++I) { + llvm::StringRef Name = I->second; + llvm::error_code EC = llvm::sys::fs::remove(Name); + (void)EC; + assert(!EC); + } } FileID createFile(llvm::StringRef Name, llvm::StringRef Content) { - SmallString<1024> Path(TemporaryDirectory.str()); - llvm::sys::path::append(Path, Name); - std::string ErrorInfo; - llvm::raw_fd_ostream OutStream(Path.c_str(), - ErrorInfo, llvm::raw_fd_ostream::F_Binary); - assert(ErrorInfo.empty()); + SmallString<1024> Path; + int FD; + llvm::error_code EC = + llvm::sys::fs::createTemporaryFile(Name, "", FD, Path); + assert(!EC); + (void)EC; + + llvm::raw_fd_ostream OutStream(FD, true); OutStream << Content; OutStream.close(); const FileEntry *File = Context.Files.getFile(Path); assert(File != NULL); + + StringRef Found = TemporaryFiles.GetOrCreateValue(Name, Path.str()).second; + assert(Found == Path); + (void)Found; return Context.Sources.createFileID(File, SourceLocation(), SrcMgr::C_User); } std::string getFileContentFromDisk(llvm::StringRef Name) { - SmallString<1024> Path(TemporaryDirectory.str()); - llvm::sys::path::append(Path, Name); + std::string Path = TemporaryFiles.lookup(Name); + assert(!Path.empty()); // We need to read directly from the FileManager without relaying through // a FileEntry, as otherwise we'd read through an already opened file // descriptor, which might not see the changes made. @@ -190,7 +255,7 @@ class FlushRewrittenFilesTest : public ::testing::Test { return Context.Files.getBufferForFile(Path, NULL)->getBuffer(); } - llvm::sys::Path TemporaryDirectory; + llvm::StringMap<std::string> TemporaryFiles; RewriterTestContext Context; }; @@ -301,5 +366,97 @@ TEST(Replacement, TemplatedFunctionCall) { expectReplacementAt(CallToF.Replace, "input.cc", 43, 8); } +TEST(Range, overlaps) { + EXPECT_TRUE(Range(10, 10).overlapsWith(Range(0, 11))); + EXPECT_TRUE(Range(0, 11).overlapsWith(Range(10, 10))); + EXPECT_FALSE(Range(10, 10).overlapsWith(Range(0, 10))); + EXPECT_FALSE(Range(0, 10).overlapsWith(Range(10, 10))); + EXPECT_TRUE(Range(0, 10).overlapsWith(Range(2, 6))); + EXPECT_TRUE(Range(2, 6).overlapsWith(Range(0, 10))); +} + +TEST(Range, contains) { + EXPECT_TRUE(Range(0, 10).contains(Range(0, 10))); + EXPECT_TRUE(Range(0, 10).contains(Range(2, 6))); + EXPECT_FALSE(Range(2, 6).contains(Range(0, 10))); + EXPECT_FALSE(Range(0, 10).contains(Range(0, 11))); +} + +TEST(DeduplicateTest, removesDuplicates) { + std::vector<Replacement> Input; + Input.push_back(Replacement("fileA", 50, 0, " foo ")); + Input.push_back(Replacement("fileA", 10, 3, " bar ")); + Input.push_back(Replacement("fileA", 10, 2, " bar ")); // Length differs + Input.push_back(Replacement("fileA", 9, 3, " bar ")); // Offset differs + Input.push_back(Replacement("fileA", 50, 0, " foo ")); // Duplicate + Input.push_back(Replacement("fileA", 51, 3, " bar ")); + Input.push_back(Replacement("fileB", 51, 3, " bar ")); // Filename differs! + Input.push_back(Replacement("fileA", 51, 3, " moo ")); // Replacement text + // differs! + + std::vector<Replacement> Expected; + Expected.push_back(Replacement("fileA", 9, 3, " bar ")); + Expected.push_back(Replacement("fileA", 10, 2, " bar ")); + Expected.push_back(Replacement("fileA", 10, 3, " bar ")); + Expected.push_back(Replacement("fileA", 50, 0, " foo ")); + Expected.push_back(Replacement("fileA", 51, 3, " bar ")); + Expected.push_back(Replacement("fileA", 51, 3, " moo ")); + Expected.push_back(Replacement("fileB", 51, 3, " bar ")); + + std::vector<Range> Conflicts; // Ignored for this test + deduplicate(Input, Conflicts); + + ASSERT_TRUE(Expected == Input); +} + +TEST(DeduplicateTest, detectsConflicts) { + { + std::vector<Replacement> Input; + Input.push_back(Replacement("fileA", 0, 5, " foo ")); + Input.push_back(Replacement("fileA", 0, 5, " foo ")); // Duplicate not a + // conflict. + Input.push_back(Replacement("fileA", 2, 6, " bar ")); + Input.push_back(Replacement("fileA", 7, 3, " moo ")); + + std::vector<Range> Conflicts; + deduplicate(Input, Conflicts); + + // One duplicate is removed and the remaining three items form one + // conflicted range. + ASSERT_EQ(3u, Input.size()); + ASSERT_EQ(1u, Conflicts.size()); + ASSERT_EQ(0u, Conflicts.front().getOffset()); + ASSERT_EQ(3u, Conflicts.front().getLength()); + } + { + std::vector<Replacement> Input; + + // Expected sorted order is shown. It is the sorted order to which the + // returned conflict info refers to. + Input.push_back(Replacement("fileA", 0, 5, " foo ")); // 0 + Input.push_back(Replacement("fileA", 5, 5, " bar ")); // 1 + Input.push_back(Replacement("fileA", 6, 0, " bar ")); // 3 + Input.push_back(Replacement("fileA", 5, 5, " moo ")); // 2 + Input.push_back(Replacement("fileA", 7, 2, " bar ")); // 4 + Input.push_back(Replacement("fileA", 15, 5, " golf ")); // 5 + Input.push_back(Replacement("fileA", 16, 5, " bag ")); // 6 + Input.push_back(Replacement("fileA", 10, 3, " club ")); // 7 + + // #3 is special in that it is completely contained by another conflicting + // Replacement. #4 ensures #3 hasn't messed up the conflicting range size. + + std::vector<Range> Conflicts; + deduplicate(Input, Conflicts); + + // No duplicates + ASSERT_EQ(8u, Input.size()); + ASSERT_EQ(2u, Conflicts.size()); + ASSERT_EQ(1u, Conflicts[0].getOffset()); + ASSERT_EQ(4u, Conflicts[0].getLength()); + ASSERT_EQ(6u, Conflicts[1].getOffset()); + ASSERT_EQ(2u, Conflicts[1].getLength()); + } +} + } // end namespace tooling } // end namespace clang |