Mercurial > hg > CbC > CbC_llvm
diff clang-tools-extra/clangd/unittests/SourceCodeTests.cpp @ 221:79ff65ed7e25
LLVM12 Original
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 15 Jun 2021 19:15:29 +0900 |
parents | 0572611fdcc8 |
children | c4bab56944e8 |
line wrap: on
line diff
--- a/clang-tools-extra/clangd/unittests/SourceCodeTests.cpp Tue Jun 15 19:13:43 2021 +0900 +++ b/clang-tools-extra/clangd/unittests/SourceCodeTests.cpp Tue Jun 15 19:15:29 2021 +0900 @@ -27,6 +27,7 @@ namespace { using llvm::Failed; +using llvm::FailedWithMessage; using llvm::HasValue; MATCHER_P2(Pos, Line, Col, "") { @@ -71,6 +72,21 @@ EXPECT_EQ(lspLength("😂"), 1UL); } +TEST(SourceCodeTests, lspLengthBadUTF8) { + // Results are not well-defined if source file isn't valid UTF-8. + // However we shouldn't crash or return something totally wild. + const char *BadUTF8[] = {"\xa0", "\xff\xff\xff\xff\xff"}; + + for (OffsetEncoding Encoding : + {OffsetEncoding::UTF8, OffsetEncoding::UTF16, OffsetEncoding::UTF32}) { + WithContextValue UTF32(kCurrentOffsetEncoding, Encoding); + for (const char *Bad : BadUTF8) { + EXPECT_GE(lspLength(Bad), 0u); + EXPECT_LE(lspLength(Bad), strlen(Bad)); + } + } +} + // The = → 🡆 below are ASCII (1 byte), BMP (3 bytes), and astral (4 bytes). const char File[] = R"(0:0 = 0 1:0 → 8 @@ -774,6 +790,239 @@ EXPECT_TRUE(isHeaderFile("header.h", LangOpts)); } +TEST(SourceCodeTests, isKeywords) { + LangOptions LangOpts; + LangOpts.CPlusPlus20 = true; + EXPECT_TRUE(isKeyword("int", LangOpts)); + EXPECT_TRUE(isKeyword("return", LangOpts)); + EXPECT_TRUE(isKeyword("co_await", LangOpts)); + + // these are identifiers (not keywords!) with special meaning in some + // contexts. + EXPECT_FALSE(isKeyword("final", LangOpts)); + EXPECT_FALSE(isKeyword("override", LangOpts)); +} + +struct IncrementalTestStep { + llvm::StringRef Src; + llvm::StringRef Contents; +}; + +int rangeLength(llvm::StringRef Code, const Range &Rng) { + llvm::Expected<size_t> Start = positionToOffset(Code, Rng.start); + llvm::Expected<size_t> End = positionToOffset(Code, Rng.end); + assert(Start); + assert(End); + return *End - *Start; +} + +/// Send the changes one by one to updateDraft, verify the intermediate results. +void stepByStep(llvm::ArrayRef<IncrementalTestStep> Steps) { + std::string Code = Annotations(Steps.front().Src).code().str(); + + for (size_t I = 1; I < Steps.size(); I++) { + Annotations SrcBefore(Steps[I - 1].Src); + Annotations SrcAfter(Steps[I].Src); + llvm::StringRef Contents = Steps[I - 1].Contents; + TextDocumentContentChangeEvent Event{ + SrcBefore.range(), + rangeLength(SrcBefore.code(), SrcBefore.range()), + Contents.str(), + }; + + EXPECT_THAT_ERROR(applyChange(Code, Event), llvm::Succeeded()); + EXPECT_EQ(Code, SrcAfter.code()); + } +} + +TEST(ApplyEditsTest, Simple) { + // clang-format off + IncrementalTestStep Steps[] = + { + // Replace a range + { +R"cpp(static int +hello[[World]]() +{})cpp", + "Universe" + }, + // Delete a range + { +R"cpp(static int +hello[[Universe]]() +{})cpp", + "" + }, + // Add a range + { +R"cpp(static int +hello[[]]() +{})cpp", + "Monde" + }, + { +R"cpp(static int +helloMonde() +{})cpp", + "" + } + }; + // clang-format on + + stepByStep(Steps); +} + +TEST(ApplyEditsTest, MultiLine) { + // clang-format off + IncrementalTestStep Steps[] = + { + // Replace a range + { +R"cpp(static [[int +helloWorld]]() +{})cpp", +R"cpp(char +welcome)cpp" + }, + // Delete a range + { +R"cpp(static char[[ +welcome]]() +{})cpp", + "" + }, + // Add a range + { +R"cpp(static char[[]]() +{})cpp", + R"cpp( +cookies)cpp" + }, + // Replace the whole file + { +R"cpp([[static char +cookies() +{}]])cpp", + R"cpp(#include <stdio.h> +)cpp" + }, + // Delete the whole file + { + R"cpp([[#include <stdio.h> +]])cpp", + "", + }, + // Add something to an empty file + { + "[[]]", + R"cpp(int main() { +)cpp", + }, + { + R"cpp(int main() { +)cpp", + "" + } + }; + // clang-format on + + stepByStep(Steps); +} + +TEST(ApplyEditsTest, WrongRangeLength) { + std::string Code = "int main() {}\n"; + + TextDocumentContentChangeEvent Change; + Change.range.emplace(); + Change.range->start.line = 0; + Change.range->start.character = 0; + Change.range->end.line = 0; + Change.range->end.character = 2; + Change.rangeLength = 10; + + EXPECT_THAT_ERROR(applyChange(Code, Change), + FailedWithMessage("Change's rangeLength (10) doesn't match " + "the computed range length (2).")); +} + +TEST(ApplyEditsTest, EndBeforeStart) { + std::string Code = "int main() {}\n"; + + TextDocumentContentChangeEvent Change; + Change.range.emplace(); + Change.range->start.line = 0; + Change.range->start.character = 5; + Change.range->end.line = 0; + Change.range->end.character = 3; + + EXPECT_THAT_ERROR( + applyChange(Code, Change), + FailedWithMessage( + "Range's end position (0:3) is before start position (0:5)")); +} + +TEST(ApplyEditsTest, StartCharOutOfRange) { + std::string Code = "int main() {}\n"; + + TextDocumentContentChangeEvent Change; + Change.range.emplace(); + Change.range->start.line = 0; + Change.range->start.character = 100; + Change.range->end.line = 0; + Change.range->end.character = 100; + Change.text = "foo"; + + EXPECT_THAT_ERROR( + applyChange(Code, Change), + FailedWithMessage("utf-16 offset 100 is invalid for line 0")); +} + +TEST(ApplyEditsTest, EndCharOutOfRange) { + std::string Code = "int main() {}\n"; + + TextDocumentContentChangeEvent Change; + Change.range.emplace(); + Change.range->start.line = 0; + Change.range->start.character = 0; + Change.range->end.line = 0; + Change.range->end.character = 100; + Change.text = "foo"; + + EXPECT_THAT_ERROR( + applyChange(Code, Change), + FailedWithMessage("utf-16 offset 100 is invalid for line 0")); +} + +TEST(ApplyEditsTest, StartLineOutOfRange) { + std::string Code = "int main() {}\n"; + + TextDocumentContentChangeEvent Change; + Change.range.emplace(); + Change.range->start.line = 100; + Change.range->start.character = 0; + Change.range->end.line = 100; + Change.range->end.character = 0; + Change.text = "foo"; + + EXPECT_THAT_ERROR(applyChange(Code, Change), + FailedWithMessage("Line value is out of range (100)")); +} + +TEST(ApplyEditsTest, EndLineOutOfRange) { + std::string Code = "int main() {}\n"; + + TextDocumentContentChangeEvent Change; + Change.range.emplace(); + Change.range->start.line = 0; + Change.range->start.character = 0; + Change.range->end.line = 100; + Change.range->end.character = 0; + Change.text = "foo"; + + EXPECT_THAT_ERROR(applyChange(Code, Change), + FailedWithMessage("Line value is out of range (100)")); +} + } // namespace } // namespace clangd } // namespace clang