From 733988cdfe5d47e97e8126b4597ea04f0ae9ec85 Mon Sep 17 00:00:00 2001 From: David Farler Date: Thu, 23 Feb 2017 13:07:58 -0800 Subject: [PATCH] [Syntax] Add Trivia C++ unit tests https://bugs.swift.org/browse/SR-4053 --- include/swift/Syntax/Trivia.h | 59 +++++-- lib/Syntax/Trivia.cpp | 6 - unittests/Syntax/CMakeLists.txt | 1 + unittests/Syntax/TriviaTests.cpp | 263 +++++++++++++++++++++++++++++++ 4 files changed, 310 insertions(+), 19 deletions(-) create mode 100644 unittests/Syntax/TriviaTests.cpp diff --git a/include/swift/Syntax/Trivia.h b/include/swift/Syntax/Trivia.h index c2bad1122d8e0..5e4760cfeee8a 100644 --- a/include/swift/Syntax/Trivia.h +++ b/include/swift/Syntax/Trivia.h @@ -120,9 +120,6 @@ enum class TriviaKind { /// A backtick '`' character, used to escape identifiers. Backtick, - - /// A semicolon ';' character, used for delimiting statements. - Semicolon }; /// A contiguous stretch of a single kind of trivia. The constiuent part of @@ -187,11 +184,6 @@ struct TriviaPiece { return TriviaPiece {TriviaKind::Backtick, 1, OwnedString{}}; } - /// Return a piece of trivia for some number of semicolons in a row. - static TriviaPiece semicolon(unsigned Count) { - return TriviaPiece {TriviaKind::Semicolon, Count, OwnedString{}}; - } - void accumulateAbsolutePosition(AbsolutePosition &Pos) const; /// Print a debug representation of this trivia piece to the provided output @@ -200,6 +192,16 @@ struct TriviaPiece { /// Print this piece of trivia to the provided output stream. void print(llvm::raw_ostream &OS) const; + + bool operator==(const TriviaPiece &Other) const { + return Kind == Other.Kind && + Count == Other.Count && + Text.str().compare(Other.Text.str()) == 0; + } + + bool operator!=(const TriviaPiece &Other) const { + return !(*this == Other); + } }; using TriviaList = std::deque; @@ -233,6 +235,7 @@ struct Trivia { /// /// Precondition: !empty() const TriviaPiece &front() const { + assert(!empty()); return Pieces.front(); } @@ -240,6 +243,7 @@ struct Trivia { /// /// Precondition: !empty() const TriviaPiece &back() const { + assert(!empty()); return Pieces.back(); } @@ -247,6 +251,7 @@ struct Trivia { /// /// Precondition: !empty() void pop_back() { + assert(!empty()); Pieces.pop_back(); } @@ -283,41 +288,74 @@ struct Trivia { return find(Kind) != end(); } + bool operator==(const Trivia &Other) const { + if (Pieces.size() != Other.size()) { + return false; + } + + for (size_t i = 0; i < Pieces.size(); ++i) { + if (Pieces[i] != Other.Pieces[i]) { + return false; + } + } + + return true; + } + + bool operator!=(const Trivia &Other) const { + return !(*this == Other); + } + /// Return a collection of trivia of some number of space characters in a row. static Trivia spaces(unsigned Count) { + if (Count == 0) { + return {}; + } return {{ TriviaPiece {TriviaKind::Space, Count, OwnedString{}} }}; } /// Return a collection of trivia of some number of tab characters in a row. static Trivia tabs(unsigned Count) { + if (Count == 0) { + return {}; + } return {{ TriviaPiece {TriviaKind::Tab, Count, OwnedString{}} }}; } /// Return a collection of trivia of some number of newline characters // in a row. static Trivia newlines(unsigned Count) { + if (Count == 0) { + return {}; + } return {{ TriviaPiece {TriviaKind::Newline, Count, OwnedString{}} }}; } /// Return a collection of trivia with a single line of ('//') // developer comment. static Trivia lineComment(const OwnedString Text) { + assert(Text.str().startswith("//")); return {{ TriviaPiece {TriviaKind::LineComment, 1, Text} }}; } /// Return a collection of trivia with a block comment ('/* ... */') static Trivia blockComment(const OwnedString Text) { + assert(Text.str().startswith("/*")); + assert(Text.str().endswith("*/")); return {{ TriviaPiece {TriviaKind::BlockComment, 1, Text} }}; } /// Return a collection of trivia with a single line of ('///') doc comment. static Trivia docLineComment(const OwnedString Text) { + assert(Text.str().startswith("///")); return {{ TriviaPiece {TriviaKind::DocLineComment, 1, Text} }}; } /// Return a collection of trivia with a documentation block // comment ('/** ... */') static Trivia docBlockComment(const OwnedString Text) { + assert(Text.str().startswith("/**")); + assert(Text.str().endswith("*/")); return {{ TriviaPiece {TriviaKind::DocBlockComment, 1, Text} }}; } @@ -326,11 +364,6 @@ struct Trivia { static Trivia backtick() { return {{ TriviaPiece {TriviaKind::Backtick, 1, OwnedString{}} }}; } - - /// Return a piece of trivia for some number of semicolons in a row. - static Trivia semicolon() { - return {{ TriviaPiece {TriviaKind::Semicolon, 1, OwnedString{}} }}; - } }; } } diff --git a/lib/Syntax/Trivia.cpp b/lib/Syntax/Trivia.cpp index ed745196acd7e..ce1008cb5bb1a 100644 --- a/lib/Syntax/Trivia.cpp +++ b/lib/Syntax/Trivia.cpp @@ -80,9 +80,6 @@ void TriviaPiece::dump(llvm::raw_ostream &OS, unsigned Indent) const { case TriviaKind::Backtick: OS << "backtick " << Count; break; - case TriviaKind::Semicolon: - OS << "semicolon " << Count; - break; } OS << ')'; } @@ -100,7 +97,6 @@ void TriviaPiece::accumulateAbsolutePosition(AbsolutePosition &Pos) const { break; case TriviaKind::Space: case TriviaKind::Backtick: - case TriviaKind::Semicolon: case TriviaKind::Tab: case TriviaKind::VerticalTab: case TriviaKind::Formfeed: @@ -135,8 +131,6 @@ void TriviaPiece::print(llvm::raw_ostream &OS) const { case TriviaKind::Backtick: printRepeated(OS, '`', Count); break; - case TriviaKind::Semicolon: - printRepeated(OS, ';', Count); } } diff --git a/unittests/Syntax/CMakeLists.txt b/unittests/Syntax/CMakeLists.txt index f310da5252e3a..bdb109f7a5b9b 100644 --- a/unittests/Syntax/CMakeLists.txt +++ b/unittests/Syntax/CMakeLists.txt @@ -5,6 +5,7 @@ add_swift_unittest(SwiftSyntaxTests RawSyntaxTests.cpp StmtSyntaxTests.cpp ThreadSafeCachingTests.cpp + TriviaTests.cpp TypeSyntaxTests.cpp) target_link_libraries(SwiftSyntaxTests diff --git a/unittests/Syntax/TriviaTests.cpp b/unittests/Syntax/TriviaTests.cpp new file mode 100644 index 0000000000000..beca54f3798a0 --- /dev/null +++ b/unittests/Syntax/TriviaTests.cpp @@ -0,0 +1,263 @@ +#include "swift/Syntax/Trivia.h" +#include "llvm/ADT/SmallString.h" +#include "gtest/gtest.h" + +using namespace swift; +using namespace swift::syntax; + +TEST(TriviaTests, Empty) { + { + llvm::SmallString<1> Scratch; + llvm::raw_svector_ostream OS(Scratch); + Trivia::spaces(0).print(OS); + ASSERT_EQ(OS.str().str(), ""); + } + { + llvm::SmallString<1> Scratch; + llvm::raw_svector_ostream OS(Scratch); + Trivia::tabs(0).print(OS); + ASSERT_EQ(OS.str().str(), ""); + } + { + llvm::SmallString<1> Scratch; + llvm::raw_svector_ostream OS(Scratch); + Trivia::newlines(0).print(OS); + ASSERT_EQ(OS.str().str(), ""); + } +#ifndef NDEBUG + ASSERT_DEATH({ + llvm::SmallString<1> Scratch; + llvm::raw_svector_ostream OS(Scratch); + Trivia::lineComment("").print(OS); + ASSERT_EQ(OS.str().str(), ""); + }, ""); + ASSERT_DEATH({ + llvm::SmallString<1> Scratch; + llvm::raw_svector_ostream OS(Scratch); + Trivia::blockComment("").print(OS); + ASSERT_EQ(OS.str().str(), ""); + }, ""); + ASSERT_DEATH({ + llvm::SmallString<1> Scratch; + llvm::raw_svector_ostream OS(Scratch); + Trivia::docLineComment("").print(OS); + ASSERT_EQ(OS.str().str(), ""); + }, ""); + ASSERT_DEATH({ + llvm::SmallString<1> Scratch; + llvm::raw_svector_ostream OS(Scratch); + Trivia::docBlockComment("").print(OS); + ASSERT_EQ(OS.str().str(), ""); + }, ""); +#endif + { + llvm::SmallString<1> Scratch; + llvm::raw_svector_ostream OS(Scratch); + Trivia().print(OS); + ASSERT_EQ(OS.str().str(), ""); + } +} + +TEST(TriviaTests, EmptyEquivalence) { + ASSERT_EQ(Trivia(), Trivia::spaces(0)); + ASSERT_TRUE(Trivia().empty()); + ASSERT_TRUE((Trivia() + Trivia()).empty()); + ASSERT_EQ(Trivia(), Trivia::tabs(0)); + ASSERT_EQ(Trivia(), Trivia::newlines(0)); + ASSERT_EQ(Trivia() + Trivia(), Trivia()); +} + +TEST(TriviaTests, Backtick) { + llvm::SmallString<1> Scratch; + llvm::raw_svector_ostream OS(Scratch); + Trivia::backtick().print(OS); + ASSERT_EQ(OS.str().str(), "`"); +} + +TEST(TriviaTests, PrintingSpaces) { + llvm::SmallString<4> Scratch; + llvm::raw_svector_ostream OS(Scratch); + Trivia::spaces(4).print(OS); + ASSERT_EQ(OS.str().str(), " "); +} + +TEST(TriviaTests, PrintingTabs) { + llvm::SmallString<4> Scratch; + llvm::raw_svector_ostream OS(Scratch); + Trivia::tabs(4).print(OS); + ASSERT_EQ(OS.str().str(), "\t\t\t\t"); +} + +TEST(TriviaTests, PrintingNewlines) { + llvm::SmallString<4> Scratch; + llvm::raw_svector_ostream OS(Scratch); + Trivia::newlines(4).print(OS); + ASSERT_EQ(OS.str().str(), "\n\n\n\n"); +} + +TEST(TriviaTests, PrintingLineComments) { + llvm::SmallString<256> Scratch; + llvm::raw_svector_ostream OS(Scratch); + auto Lines = Trivia::lineComment("// Line 1") + + Trivia::newlines(1) + + Trivia::lineComment("// Line 2"); + Lines.print(OS); + ASSERT_EQ(OS.str().str(), "// Line 1\n// Line 2"); +} + +TEST(TriviaTests, PrintingBlockComments) { + llvm::SmallString<256> Scratch; + llvm::raw_svector_ostream OS(Scratch); + Trivia::blockComment("/* Block Line 1\n\n Block Line 2 */").print(OS); + ASSERT_EQ(OS.str().str(), "/* Block Line 1\n\n Block Line 2 */"); +} + +TEST(TriviaTests, PrintingDocLineComments) { + llvm::SmallString<256> Scratch; + llvm::raw_svector_ostream OS(Scratch); + auto Lines = Trivia::lineComment("/// Line 1") + + Trivia::newlines(1) + + Trivia::lineComment("/// Line 2"); + Lines.print(OS); + ASSERT_EQ(OS.str().str(), "/// Line 1\n/// Line 2"); +} + +TEST(TriviaTests, PrintingDocBlockComments) { + llvm::SmallString<256> Scratch; + llvm::raw_svector_ostream OS(Scratch); + Trivia::blockComment("/** Block Line 1\n\n Block Line 2 */").print(OS); + ASSERT_EQ(OS.str().str(), "/** Block Line 1\n\n Block Line 2 */"); +} + +TEST(TriviaTests, PrintingCombinations) { + { + llvm::SmallString<4> Scratch; + llvm::raw_svector_ostream OS(Scratch); + (Trivia() + Trivia()).print(OS); + ASSERT_EQ(OS.str().str(), ""); + } + + { + llvm::SmallString<4> Scratch; + llvm::raw_svector_ostream OS(Scratch); + (Trivia::newlines(2) + Trivia::spaces(2)).print(OS); + ASSERT_EQ(OS.str().str(), "\n\n "); + } + + { + llvm::SmallString<48> Scratch; + llvm::raw_svector_ostream OS(Scratch); + auto CCCCombo = Trivia::spaces(1) + + Trivia::tabs(1) + + Trivia::newlines(1) + + Trivia::backtick(); + CCCCombo.print(OS); + ASSERT_EQ(OS.str().str(), " \t\n`"); + } + + { + // Combos with comments + } +} + +TEST(TriviaTests, Contains) { + ASSERT_FALSE(Trivia().contains(TriviaKind::Backtick)); + ASSERT_FALSE(Trivia().contains(TriviaKind::BlockComment)); + ASSERT_FALSE(Trivia().contains(TriviaKind::DocBlockComment)); + ASSERT_FALSE(Trivia().contains(TriviaKind::DocLineComment)); + ASSERT_FALSE(Trivia().contains(TriviaKind::Formfeed)); + ASSERT_FALSE(Trivia().contains(TriviaKind::LineComment)); + ASSERT_FALSE(Trivia().contains(TriviaKind::Newline)); + ASSERT_FALSE(Trivia().contains(TriviaKind::Space)); + + ASSERT_TRUE(Trivia::backtick().contains(TriviaKind::Backtick)); + ASSERT_TRUE(Trivia::blockComment("/**/").contains(TriviaKind::BlockComment)); + ASSERT_TRUE(Trivia::docBlockComment("/***/") + .contains(TriviaKind::DocBlockComment)); + ASSERT_TRUE(Trivia::docLineComment("///") + .contains(TriviaKind::DocLineComment)); + ASSERT_TRUE(Trivia::lineComment("//").contains(TriviaKind::LineComment)); + ASSERT_TRUE(Trivia::newlines(1).contains(TriviaKind::Newline)); + ASSERT_TRUE(Trivia::spaces(1).contains(TriviaKind::Space)); + + auto Combo = Trivia::spaces(1) + Trivia::backtick() + Trivia::newlines(3) + + Trivia::spaces(1); + + ASSERT_TRUE(Combo.contains(TriviaKind::Space)); + ASSERT_TRUE(Combo.contains(TriviaKind::Newline)); + ASSERT_TRUE(Combo.contains(TriviaKind::Backtick)); + ASSERT_FALSE(Combo.contains(TriviaKind::Tab)); + ASSERT_FALSE(Combo.contains(TriviaKind::LineComment)); + ASSERT_FALSE(Combo.contains(TriviaKind::Formfeed)); +} + +TEST(TriviaTests, Iteration) { + + llvm::SmallString<6> WholeScratch; + llvm::raw_svector_ostream WholeOS(WholeScratch); + auto Triv = Trivia::spaces(2) + Trivia::newlines(2) + Trivia::spaces(2); + Triv.print(WholeOS); + + llvm::SmallString<6> PiecesScratch; + llvm::raw_svector_ostream PiecesOS(PiecesScratch); + for (const auto &Piece : Triv) { + Piece.print(PiecesOS); + } + + ASSERT_EQ(WholeOS.str().str(), PiecesOS.str().str()); +} + +TEST(TriviaTests, push_back) { + llvm::SmallString<3> Scratch; + llvm::raw_svector_ostream OS(Scratch); + Trivia Triv; + Triv.push_back(TriviaPiece::backtick()); + Triv.push_back(TriviaPiece::backtick()); + Triv.push_back(TriviaPiece::backtick()); + Triv.print(OS); + ASSERT_EQ(OS.str().str(), "```"); +} + +TEST(TriviaTests, push_front) { + llvm::SmallString<3> Scratch; + llvm::raw_svector_ostream OS(Scratch); + Trivia Triv; + Triv.push_back(TriviaPiece::backtick()); + Triv.push_front(TriviaPiece::spaces(1)); + Triv.push_back(TriviaPiece::spaces(1)); + Triv.push_front(TriviaPiece::backtick()); + Triv.print(OS); + ASSERT_EQ(OS.str().str(), "` ` "); +} + +TEST(TriviaTests, front) { +#ifndef NDEBUG + ASSERT_DEATH({ + Trivia().front(); + }, ""); +#endif + + ASSERT_EQ(Trivia::spaces(1).front(), TriviaPiece::spaces(1)); + + ASSERT_EQ((Trivia::spaces(1) + Trivia::newlines(1)).front(), + TriviaPiece::spaces(1)); +} + +TEST(TriviaTests, back) { +#ifndef NDEBUG + ASSERT_DEATH({ + Trivia().back(); + }, ""); +#endif + ASSERT_EQ(Trivia::spaces(1).back(), TriviaPiece::spaces(1)); + ASSERT_EQ((Trivia::spaces(1) + Trivia::newlines(1)).back(), + TriviaPiece::newlines(1)); +} + +TEST(TriviaTests, size) { + ASSERT_EQ(Trivia().size(), 0); + ASSERT_EQ(Trivia::spaces(1).size(), 1); + + // Trivia doesn't currently coalesce on its own. + ASSERT_EQ((Trivia::spaces(1) + Trivia::spaces(1)).size(), 2); +}