328 lines · cpp
1//===- llvm/unittest/Support/DebugLogTest.cpp -----------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/Support/DebugLog.h"10#include "llvm/ADT/Sequence.h"11#include "llvm/Support/raw_ostream.h"12#include "gmock/gmock.h"13#include "gtest/gtest.h"14 15#include <string>16using namespace llvm;17using testing::Eq;18using testing::HasSubstr;19 20#ifndef NDEBUG21TEST(DebugLogTest, Basic) {22 llvm::DebugFlag = true;23 static const char *DT[] = {"A", "B"};24 25 // Clear debug types.26 setCurrentDebugTypes(DT, 0);27 {28 std::string str;29 raw_string_ostream os(str);30 LDGB_STREAM_LEVEL_AND_TYPE(os, "", 0) << "NoType";31 EXPECT_TRUE(StringRef(os.str()).starts_with('['));32 EXPECT_TRUE(StringRef(os.str()).ends_with("NoType\n"));33 }34 35 setCurrentDebugTypes(DT, 2);36 {37 std::string str;38 raw_string_ostream os(str);39 LDGB_STREAM_LEVEL_AND_TYPE(os, 0, "A") << "A";40 LDGB_STREAM_LEVEL_AND_TYPE(os, "B", 0) << "B";41 EXPECT_TRUE(StringRef(os.str()).starts_with('['));42 EXPECT_THAT(os.str(), AllOf(HasSubstr("A\n"), HasSubstr("B\n")));43 }44 45 setCurrentDebugType("A");46 {47 std::string str;48 raw_string_ostream os(str);49 // Just check that the macro doesn't result in dangling else.50 if (true)51 LDGB_STREAM_LEVEL_AND_TYPE(os, 0, "A") << "A";52 else53 LDGB_STREAM_LEVEL_AND_TYPE(os, 0, "A") << "B";54 LDGB_STREAM_LEVEL_AND_TYPE(os, 0, "B") << "B";55 EXPECT_THAT(os.str(), AllOf(HasSubstr("A\n"), Not(HasSubstr("B\n"))));56 57 int count = 0;58 auto inc = [&]() { return ++count; };59 EXPECT_THAT(count, Eq(0));60 LDGB_STREAM_LEVEL_AND_TYPE(os, 0, "A") << inc();61 EXPECT_THAT(count, Eq(1));62 LDGB_STREAM_LEVEL_AND_TYPE(os, 0, "B") << inc();63 EXPECT_THAT(count, Eq(1));64 }65}66 67TEST(DebugLogTest, BasicWithLevel) {68 llvm::DebugFlag = true;69 // We expect A to be always printed, B to be printed only when level is 1 or70 // below, and C to be printed only when level is 0 or below.71 static const char *DT[] = {"A", "B:1", "C:"};72 73 setCurrentDebugTypes(DT, sizeof(DT) / sizeof(DT[0]));74 std::string str;75 raw_string_ostream os(str);76 for (auto type : {"A", "B", "C", "D"})77 for (int level : llvm::seq<int>(0, 4))78 LDBG_STREAM_LEVEL_TYPE_FILE_AND_LINE(os, level, type, type, level)79 << level;80 EXPECT_EQ(os.str(), "[A:0 0] 0\n[A:1 1] 1\n[A:2 2] 2\n[A:3 3] 3\n[B:0 0] "81 "0\n[B:1 1] 1\n[C:0 0] 0\n");82}83 84TEST(DebugLogTest, NegativeLevel) {85 llvm::DebugFlag = true;86 // Test the special behavior when all the levels are 0.87 // In this case we expect all the debug types to be printed.88 static const char *DT[] = {"A:"};89 90 setCurrentDebugTypes(DT, sizeof(DT) / sizeof(DT[0]));91 std::string str;92 raw_string_ostream os(str);93 for (auto type : {"A", "B"})94 for (int level : llvm::seq<int>(0, 2))95 LDBG_STREAM_LEVEL_TYPE_FILE_AND_LINE(96 os, level, type, (std::string(type) + ".cpp").c_str(), level)97 << level;98 EXPECT_EQ(os.str(), "[A A.cpp:0 0] 0\n[B B.cpp:0 0] 0\n[B B.cpp:1 1] 1\n");99}100 101TEST(DebugLogTest, StreamPrefix) {102 llvm::DebugFlag = true;103 static const char *DT[] = {"A", "B"};104 setCurrentDebugTypes(DT, 2);105 106 std::string str;107 raw_string_ostream os(str);108 std::string expected = "PrefixA 1\nPrefixA 2\nPrefixA \nPrefixB "109 "3\nPrefixB 4\nPrefixA 5";110 {111 llvm::impl::raw_ldbg_ostream ldbg_osB("PrefixB ", os);112 llvm::impl::raw_ldbg_ostream ldbg_osA("PrefixA ", os);113 ldbg_osA << "1\n2";114 ldbg_osA << "\n\n";115 ldbg_osB << "3\n4\n";116 ldbg_osA << "5";117 EXPECT_EQ(os.str(), expected);118 }119 EXPECT_EQ(os.str(), expected);120}121 122TEST(DebugLogTest, DestructorPrefix) {123 llvm::DebugFlag = true;124 std::string str;125 raw_string_ostream os(str);126 {127 llvm::impl::raw_ldbg_ostream ldbg_osB("PrefixB ", os);128 }129 // After destructors, nothing should have been printed.130 EXPECT_EQ(os.str(), "");131}132 133TEST(DebugLogTest, LDBG_MACROS) {134 llvm::DebugFlag = true;135 static const char *DT[] = {"A:3", "B:2"};136 setCurrentDebugTypes(DT, sizeof(DT) / sizeof(DT[0]));137 std::string Str;138 raw_string_ostream DebugOs(Str);139 std::string StrExpected;140 raw_string_ostream ExpectedOs(StrExpected);141#undef LDBG_STREAM142#define LDBG_STREAM DebugOs143#define DEBUG_TYPE "A"144 LDBG() << "Hello, world!";145 ExpectedOs << "[A " << __LLVM_FILE_NAME__ << ":" << (__LINE__ - 1)146 << " 1] Hello, world!\n";147 EXPECT_EQ(DebugOs.str(), ExpectedOs.str());148 Str.clear();149 StrExpected.clear();150 151 // Test with a level, no type.152 LDBG(2) << "Hello, world!";153 ExpectedOs << "[A " << __LLVM_FILE_NAME__ << ":" << (__LINE__ - 1)154 << " 2] Hello, world!\n";155 EXPECT_EQ(DebugOs.str(), ExpectedOs.str());156 Str.clear();157 StrExpected.clear();158 159// Now check when we don't use DEBUG_TYPE, the file name is implicitly used160// instead.161#undef DEBUG_TYPE162 163 // Repeat the tests above, they won't match since the debug types defined164 // above don't match the file name.165 LDBG() << "Hello, world!";166 EXPECT_EQ(DebugOs.str(), "");167 Str.clear();168 StrExpected.clear();169 170 // Test with a level, no type.171 LDBG(2) << "Hello, world!";172 EXPECT_EQ(DebugOs.str(), "");173 Str.clear();174 StrExpected.clear();175 176 // Now enable the debug types that match the file name.177 auto fileNameAndLevel = std::string(__LLVM_FILE_NAME__) + ":3";178 static const char *DT2[] = {fileNameAndLevel.c_str(), "B:2"};179 setCurrentDebugTypes(DT2, sizeof(DT2) / sizeof(DT2[0]));180 181 // Repeat the tests above, they should match now.182 183 LDBG() << "Hello, world!";184 ExpectedOs << "[" << __LLVM_FILE_NAME__ << ":" << (__LINE__ - 1)185 << " 1] Hello, world!\n";186 EXPECT_EQ(DebugOs.str(), ExpectedOs.str());187 Str.clear();188 StrExpected.clear();189 190 // Test with a level, no type.191 LDBG(2) << "Hello, world!";192 ExpectedOs << "[" << __LLVM_FILE_NAME__ << ":" << (__LINE__ - 1)193 << " 2] Hello, world!\n";194 EXPECT_EQ(DebugOs.str(), ExpectedOs.str());195 Str.clear();196 StrExpected.clear();197 198 // Test with a type199 LDBG("B") << "Hello, world!";200 ExpectedOs << "[B " << __LLVM_FILE_NAME__ << ":" << (__LINE__ - 1)201 << " 1] Hello, world!\n";202 EXPECT_EQ(DebugOs.str(), ExpectedOs.str());203 Str.clear();204 StrExpected.clear();205 206 // Test with a type and a level207 LDBG("B", 2) << "Hello, world!";208 ExpectedOs << "[B " << __LLVM_FILE_NAME__ << ":" << (__LINE__ - 1)209 << " 2] Hello, world!\n";210 EXPECT_EQ(DebugOs.str(), ExpectedOs.str());211 Str.clear();212 StrExpected.clear();213 214 // Test with a type not enabled.215 LDBG("C", 1) << "Hello, world!";216 EXPECT_EQ(DebugOs.str(), "");217 218 // Test with a level not enabled.219 LDBG("B", 3) << "Hello, world!";220 EXPECT_EQ(DebugOs.str(), "");221 LDBG(__LLVM_FILE_NAME__, 4) << "Hello, world!";222 EXPECT_EQ(DebugOs.str(), "");223}224 225TEST(DebugLogTest, LDBG_OS_MACROS) {226 llvm::DebugFlag = true;227 static const char *DT[] = {"A:3", "B:2"};228 setCurrentDebugTypes(DT, sizeof(DT) / sizeof(DT[0]));229 std::string Str;230 raw_string_ostream DebugOs(Str);231 std::string StrExpected;232 raw_string_ostream ExpectedOs(StrExpected);233#undef LDBG_STREAM234#define LDBG_STREAM DebugOs235#define DEBUG_TYPE "A"236 LDBG_OS([](raw_ostream &Os) { Os << "Hello, world!"; });237 ExpectedOs << "[A " << __LLVM_FILE_NAME__ << ":" << (__LINE__ - 1)238 << " 1] Hello, world!\n";239 EXPECT_EQ(DebugOs.str(), ExpectedOs.str());240 Str.clear();241 StrExpected.clear();242 243 // Test with a level, no type.244 LDBG_OS(2, [](raw_ostream &Os) { Os << "Hello, world!"; });245 ExpectedOs << "[A " << __LLVM_FILE_NAME__ << ":" << (__LINE__ - 1)246 << " 2] Hello, world!\n";247 EXPECT_EQ(DebugOs.str(), ExpectedOs.str());248 Str.clear();249 StrExpected.clear();250 251// Now check when we don't use DEBUG_TYPE, the file name is implicitly used252// instead.253#undef DEBUG_TYPE254 255 // Repeat the tests above, they won't match since the debug types defined256 // above don't match the file name.257 LDBG_OS([](raw_ostream &Os) { Os << "Hello, world!"; });258 EXPECT_EQ(DebugOs.str(), "");259 Str.clear();260 StrExpected.clear();261 262 // Test with a level, no type.263 LDBG_OS(2, [](raw_ostream &Os) { Os << "Hello, world!"; });264 EXPECT_EQ(DebugOs.str(), "");265 Str.clear();266 StrExpected.clear();267 268 // Now enable the debug types that match the file name.269 auto fileNameAndLevel = std::string(__LLVM_FILE_NAME__) + ":3";270 static const char *DT2[] = {fileNameAndLevel.c_str(), "B:2"};271 setCurrentDebugTypes(DT2, sizeof(DT2) / sizeof(DT2[0]));272 273 // Repeat the tests above, they should match now.274 LDBG_OS([](raw_ostream &Os) { Os << "Hello, world!"; });275 ExpectedOs << "[" << __LLVM_FILE_NAME__ << ":" << (__LINE__ - 1)276 << " 1] Hello, world!\n";277 EXPECT_EQ(DebugOs.str(), ExpectedOs.str());278 Str.clear();279 StrExpected.clear();280 281 // Test with a level, no type.282 LDBG_OS(2, [](raw_ostream &Os) { Os << "Hello, world!"; });283 ExpectedOs << "[" << __LLVM_FILE_NAME__ << ":" << (__LINE__ - 1)284 << " 2] Hello, world!\n";285 EXPECT_EQ(DebugOs.str(), ExpectedOs.str());286 Str.clear();287 StrExpected.clear();288 289 // Test with a type.290 LDBG_OS("B", [](raw_ostream &Os) { Os << "Hello, world!"; });291 ExpectedOs << "[B " << __LLVM_FILE_NAME__ << ":" << (__LINE__ - 1)292 << " 1] Hello, world!\n";293 EXPECT_EQ(DebugOs.str(), ExpectedOs.str());294 Str.clear();295 StrExpected.clear();296 297 // Test with a type and a level298 LDBG_OS("B", 2, [](raw_ostream &Os) { Os << "Hello, world!"; });299 ExpectedOs << "[B " << __LLVM_FILE_NAME__ << ":" << (__LINE__ - 1)300 << " 2] Hello, world!\n";301 EXPECT_EQ(DebugOs.str(), ExpectedOs.str());302 Str.clear();303 StrExpected.clear();304 305 // Test with a type not enabled.306 LDBG_OS("C", 1, [](raw_ostream &Os) { Os << "Hello, world!"; });307 EXPECT_EQ(DebugOs.str(), "");308 309 // Test with a level not enabled.310 LDBG_OS("B", 3, [](raw_ostream &Os) { Os << "Hello, world!"; });311 EXPECT_EQ(DebugOs.str(), "");312}313 314#else315TEST(DebugLogTest, Basic) {316 // LDBG should be compiled out in NDEBUG, so just check it compiles and has317 // no effect.318 llvm::DebugFlag = true;319 static const char *DT[] = {"A"};320 setCurrentDebugTypes(DT, 0);321 int count = 0;322 auto inc = [&]() { return ++count; };323 EXPECT_THAT(count, Eq(0));324 LDBG() << inc();325 EXPECT_THAT(count, Eq(0));326}327#endif328