1 //===-- HighlighterTest.cpp -------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "gtest/gtest.h" 11 12 #include "lldb/Core/Highlighter.h" 13 14 #include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" 15 #include "Plugins/Language/Go/GoLanguage.h" 16 #include "Plugins/Language/Java/JavaLanguage.h" 17 #include "Plugins/Language/OCaml/OCamlLanguage.h" 18 #include "Plugins/Language/ObjC/ObjCLanguage.h" 19 #include "Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h" 20 21 using namespace lldb_private; 22 23 namespace { 24 class HighlighterTest : public testing::Test { 25 public: 26 static void SetUpTestCase(); 27 static void TearDownTestCase(); 28 }; 29 } // namespace 30 31 void HighlighterTest::SetUpTestCase() { 32 // The HighlighterManager uses the language plugins under the hood, so we 33 // have to initialize them here for our test process. 34 CPlusPlusLanguage::Initialize(); 35 GoLanguage::Initialize(); 36 JavaLanguage::Initialize(); 37 ObjCLanguage::Initialize(); 38 ObjCPlusPlusLanguage::Initialize(); 39 OCamlLanguage::Initialize(); 40 } 41 42 void HighlighterTest::TearDownTestCase() { 43 CPlusPlusLanguage::Terminate(); 44 GoLanguage::Terminate(); 45 JavaLanguage::Terminate(); 46 ObjCLanguage::Terminate(); 47 ObjCPlusPlusLanguage::Terminate(); 48 OCamlLanguage::Terminate(); 49 } 50 51 static std::string getName(lldb::LanguageType type) { 52 HighlighterManager m; 53 return m.getHighlighterFor(type, "").GetName().str(); 54 } 55 56 static std::string getName(llvm::StringRef path) { 57 HighlighterManager m; 58 return m.getHighlighterFor(lldb::eLanguageTypeUnknown, path).GetName().str(); 59 } 60 61 TEST_F(HighlighterTest, HighlighterSelectionType) { 62 EXPECT_EQ(getName(lldb::eLanguageTypeC_plus_plus), "clang"); 63 EXPECT_EQ(getName(lldb::eLanguageTypeC_plus_plus_03), "clang"); 64 EXPECT_EQ(getName(lldb::eLanguageTypeC_plus_plus_11), "clang"); 65 EXPECT_EQ(getName(lldb::eLanguageTypeC_plus_plus_14), "clang"); 66 EXPECT_EQ(getName(lldb::eLanguageTypeObjC), "clang"); 67 EXPECT_EQ(getName(lldb::eLanguageTypeObjC_plus_plus), "clang"); 68 69 EXPECT_EQ(getName(lldb::eLanguageTypeUnknown), "none"); 70 EXPECT_EQ(getName(lldb::eLanguageTypeJulia), "none"); 71 EXPECT_EQ(getName(lldb::eLanguageTypeJava), "none"); 72 EXPECT_EQ(getName(lldb::eLanguageTypeHaskell), "none"); 73 } 74 75 TEST_F(HighlighterTest, HighlighterSelectionPath) { 76 EXPECT_EQ(getName("myfile.cc"), "clang"); 77 EXPECT_EQ(getName("moo.cpp"), "clang"); 78 EXPECT_EQ(getName("mar.cxx"), "clang"); 79 EXPECT_EQ(getName("foo.C"), "clang"); 80 EXPECT_EQ(getName("bar.CC"), "clang"); 81 EXPECT_EQ(getName("a/dir.CC"), "clang"); 82 EXPECT_EQ(getName("/a/dir.hpp"), "clang"); 83 EXPECT_EQ(getName("header.h"), "clang"); 84 85 EXPECT_EQ(getName(""), "none"); 86 EXPECT_EQ(getName("/dev/null"), "none"); 87 EXPECT_EQ(getName("Factory.java"), "none"); 88 EXPECT_EQ(getName("poll.py"), "none"); 89 EXPECT_EQ(getName("reducer.hs"), "none"); 90 } 91 92 TEST_F(HighlighterTest, FallbackHighlighter) { 93 HighlighterManager mgr; 94 const Highlighter &h = 95 mgr.getHighlighterFor(lldb::eLanguageTypePascal83, "foo.pas"); 96 97 HighlightStyle style; 98 style.identifier.Set("[", "]"); 99 style.semicolons.Set("<", ">"); 100 101 const char *code = "program Hello;"; 102 std::string output = h.Highlight(style, code, llvm::Optional<size_t>()); 103 104 EXPECT_STREQ(output.c_str(), code); 105 } 106 107 static std::string 108 highlightDefault(llvm::StringRef code, HighlightStyle style, 109 llvm::Optional<size_t> cursor = llvm::Optional<size_t>()) { 110 HighlighterManager mgr; 111 return mgr.getDefaultHighlighter().Highlight(style, code, cursor); 112 } 113 114 TEST_F(HighlighterTest, DefaultHighlighter) { 115 const char *code = "int my_main() { return 22; } \n"; 116 117 HighlightStyle style; 118 EXPECT_EQ(code, highlightDefault(code, style)); 119 } 120 121 TEST_F(HighlighterTest, DefaultHighlighterWithCursor) { 122 HighlightStyle style; 123 style.selected.Set("<c>", "</c>"); 124 EXPECT_EQ("<c>a</c> bc", highlightDefault("a bc", style, 0)); 125 EXPECT_EQ("a<c> </c>bc", highlightDefault("a bc", style, 1)); 126 EXPECT_EQ("a <c>b</c>c", highlightDefault("a bc", style, 2)); 127 EXPECT_EQ("a b<c>c</c>", highlightDefault("a bc", style, 3)); 128 } 129 130 TEST_F(HighlighterTest, DefaultHighlighterWithCursorOutOfBounds) { 131 HighlightStyle style; 132 style.selected.Set("<c>", "</c>"); 133 EXPECT_EQ("a bc", highlightDefault("a bc", style, 4)); 134 } 135 //------------------------------------------------------------------------------ 136 // Tests highlighting with the Clang highlighter. 137 //------------------------------------------------------------------------------ 138 139 static std::string 140 highlightC(llvm::StringRef code, HighlightStyle style, 141 llvm::Optional<size_t> cursor = llvm::Optional<size_t>()) { 142 HighlighterManager mgr; 143 const Highlighter &h = mgr.getHighlighterFor(lldb::eLanguageTypeC, "main.c"); 144 return h.Highlight(style, code, cursor); 145 } 146 147 TEST_F(HighlighterTest, ClangEmptyInput) { 148 HighlightStyle s; 149 EXPECT_EQ("", highlightC("", s)); 150 } 151 152 TEST_F(HighlighterTest, ClangScalarLiterals) { 153 HighlightStyle s; 154 s.scalar_literal.Set("<scalar>", "</scalar>"); 155 156 EXPECT_EQ(" int i = <scalar>22</scalar>;", highlightC(" int i = 22;", s)); 157 } 158 159 TEST_F(HighlighterTest, ClangStringLiterals) { 160 HighlightStyle s; 161 s.string_literal.Set("<str>", "</str>"); 162 163 EXPECT_EQ("const char *f = 22 + <str>\"foo\"</str>;", 164 highlightC("const char *f = 22 + \"foo\";", s)); 165 } 166 167 TEST_F(HighlighterTest, ClangUnterminatedString) { 168 HighlightStyle s; 169 s.string_literal.Set("<str>", "</str>"); 170 171 EXPECT_EQ(" f = \"", highlightC(" f = \"", s)); 172 } 173 174 TEST_F(HighlighterTest, Keywords) { 175 HighlightStyle s; 176 s.keyword.Set("<k>", "</k>"); 177 178 EXPECT_EQ(" <k>return</k> 1; ", highlightC(" return 1; ", s)); 179 } 180 181 TEST_F(HighlighterTest, Colons) { 182 HighlightStyle s; 183 s.colon.Set("<c>", "</c>"); 184 185 EXPECT_EQ("foo<c>:</c><c>:</c>bar<c>:</c>", highlightC("foo::bar:", s)); 186 } 187 188 TEST_F(HighlighterTest, ClangBraces) { 189 HighlightStyle s; 190 s.braces.Set("<b>", "</b>"); 191 192 EXPECT_EQ("a<b>{</b><b>}</b>", highlightC("a{}", s)); 193 } 194 195 TEST_F(HighlighterTest, ClangSquareBrackets) { 196 HighlightStyle s; 197 s.square_brackets.Set("<sb>", "</sb>"); 198 199 EXPECT_EQ("a<sb>[</sb><sb>]</sb>", highlightC("a[]", s)); 200 } 201 202 TEST_F(HighlighterTest, ClangCommas) { 203 HighlightStyle s; 204 s.comma.Set("<comma>", "</comma>"); 205 206 EXPECT_EQ(" bool f = foo()<comma>,</comma> 1;", 207 highlightC(" bool f = foo(), 1;", s)); 208 } 209 210 TEST_F(HighlighterTest, ClangPPDirectives) { 211 HighlightStyle s; 212 s.pp_directive.Set("<pp>", "</pp>"); 213 214 EXPECT_EQ("<pp>#</pp><pp>include</pp><pp> </pp><pp>\"foo\"</pp><pp> </pp>//c", 215 highlightC("#include \"foo\" //c", s)); 216 } 217 218 TEST_F(HighlighterTest, ClangComments) { 219 HighlightStyle s; 220 s.comment.Set("<cc>", "</cc>"); 221 222 EXPECT_EQ(" <cc>/*com */</cc> <cc>// com /*n*/</cc>", 223 highlightC(" /*com */ // com /*n*/", s)); 224 } 225 226 TEST_F(HighlighterTest, ClangOperators) { 227 HighlightStyle s; 228 s.operators.Set("[", "]"); 229 230 EXPECT_EQ(" 1[+]2[/]a[*]f[&]x[|][~]l", highlightC(" 1+2/a*f&x|~l", s)); 231 } 232 233 TEST_F(HighlighterTest, ClangIdentifiers) { 234 HighlightStyle s; 235 s.identifier.Set("<id>", "</id>"); 236 237 EXPECT_EQ(" <id>foo</id> <id>c</id> = <id>bar</id>(); return 1;", 238 highlightC(" foo c = bar(); return 1;", s)); 239 } 240 241 TEST_F(HighlighterTest, ClangCursorPos) { 242 HighlightStyle s; 243 s.selected.Set("<c>", "</c>"); 244 245 EXPECT_EQ("<c> </c>foo c = bar(); return 1;", 246 highlightC(" foo c = bar(); return 1;", s, 0)); 247 EXPECT_EQ(" <c>foo</c> c = bar(); return 1;", 248 highlightC(" foo c = bar(); return 1;", s, 1)); 249 EXPECT_EQ(" <c>foo</c> c = bar(); return 1;", 250 highlightC(" foo c = bar(); return 1;", s, 2)); 251 EXPECT_EQ(" <c>foo</c> c = bar(); return 1;", 252 highlightC(" foo c = bar(); return 1;", s, 3)); 253 EXPECT_EQ(" foo<c> </c>c = bar(); return 1;", 254 highlightC(" foo c = bar(); return 1;", s, 4)); 255 EXPECT_EQ(" foo <c>c</c> = bar(); return 1;", 256 highlightC(" foo c = bar(); return 1;", s, 5)); 257 } 258 259 TEST_F(HighlighterTest, ClangCursorPosEndOfLine) { 260 HighlightStyle s; 261 s.selected.Set("<c>", "</c>"); 262 263 EXPECT_EQ("f", highlightC("f", s, 1)); 264 } 265 266 TEST_F(HighlighterTest, ClangCursorOutOfBounds) { 267 HighlightStyle s; 268 s.selected.Set("<c>", "</c>"); 269 EXPECT_EQ("f", highlightC("f", s, 2)); 270 EXPECT_EQ("f", highlightC("f", s, 3)); 271 EXPECT_EQ("f", highlightC("f", s, 4)); 272 } 273 274 TEST_F(HighlighterTest, ClangCursorPosBeforeOtherToken) { 275 HighlightStyle s; 276 s.selected.Set("<c>", "</c>"); 277 s.identifier.Set("<id>", "</id>"); 278 279 EXPECT_EQ("<c> </c><id>foo</id> <id>c</id> = <id>bar</id>(); return 1;", 280 highlightC(" foo c = bar(); return 1;", s, 0)); 281 } 282 283 TEST_F(HighlighterTest, ClangCursorPosAfterOtherToken) { 284 HighlightStyle s; 285 s.selected.Set("<c>", "</c>"); 286 s.identifier.Set("<id>", "</id>"); 287 288 EXPECT_EQ(" <id>foo</id><c> </c><id>c</id> = <id>bar</id>(); return 1;", 289 highlightC(" foo c = bar(); return 1;", s, 4)); 290 } 291 292 TEST_F(HighlighterTest, ClangCursorPosInOtherToken) { 293 HighlightStyle s; 294 s.selected.Set("<c>", "</c>"); 295 s.identifier.Set("<id>", "</id>"); 296 297 EXPECT_EQ(" <id><c>foo</c></id> <id>c</id> = <id>bar</id>(); return 1;", 298 highlightC(" foo c = bar(); return 1;", s, 1)); 299 EXPECT_EQ(" <id><c>foo</c></id> <id>c</id> = <id>bar</id>(); return 1;", 300 highlightC(" foo c = bar(); return 1;", s, 2)); 301 EXPECT_EQ(" <id><c>foo</c></id> <id>c</id> = <id>bar</id>(); return 1;", 302 highlightC(" foo c = bar(); return 1;", s, 3)); 303 } 304