From 9c0e1fd4f1151f4780c1ff3db82322d8b28d2d8b Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Wed, 24 Jun 2020 18:31:28 -0600 Subject: [PATCH] add trace test; error formatting refinements --- src/libutil/error.cc | 86 ++++++++++++++++++++++++------------ src/libutil/error.hh | 2 + src/libutil/tests/logging.cc | 33 ++++++++++++-- 3 files changed, 89 insertions(+), 32 deletions(-) diff --git a/src/libutil/error.cc b/src/libutil/error.cc index b5edfa710..1185a0204 100644 --- a/src/libutil/error.cc +++ b/src/libutil/error.cc @@ -185,6 +185,31 @@ void printCodeLines(std::ostream &out, } } +void printAtPos(const string &prefix, const ErrPos &pos, std::ostream &out) +{ + { + switch (pos.origin) { + case foFile: { + out << prefix << ANSI_BLUE << "at: " << ANSI_YELLOW << showErrPos(pos) << + ANSI_BLUE << " in file: " << ANSI_NORMAL << pos.file; + break; + } + case foString: { + out << prefix << ANSI_BLUE << "at: " << ANSI_YELLOW << showErrPos(pos) << + ANSI_BLUE << " from command line argument" << ANSI_NORMAL; + break; + } + case foStdin: { + out << prefix << ANSI_BLUE << "at: " << ANSI_YELLOW << showErrPos(pos) << + ANSI_BLUE << " from stdin" << ANSI_NORMAL; + break; + } + default: + throw Error("invalid FileOrigin in errPos"); + } + } +} + std::ostream& operator<<(std::ostream &out, const ErrorInfo &einfo) { auto errwidth = std::max(getWindowSize().second, 20); @@ -240,8 +265,12 @@ std::ostream& operator<<(std::ostream &out, const ErrorInfo &einfo) } } - auto ndl = prefix.length() + levelString.length() + 3 + einfo.name.length() + einfo.programName.value_or("").length(); - auto dashwidth = ndl > (errwidth - 3) ? 3 : errwidth - ndl; + auto ndl = prefix.length() + + filterANSIEscapes(levelString, true).length() + + 7 + + einfo.name.length() + + einfo.programName.value_or("").length(); + auto dashwidth = std::max(errwidth - ndl, 3); std::string dashes(dashwidth, '-'); @@ -262,29 +291,8 @@ std::ostream& operator<<(std::ostream &out, const ErrorInfo &einfo) bool nl = false; // intersperse newline between sections. if (einfo.errPos.has_value()) { - switch (einfo.errPos->origin) { - case foFile: { - out << prefix << std::endl; - auto &pos = *einfo.errPos; - out << prefix << ANSI_BLUE << "at: " << ANSI_YELLOW << showErrPos(pos) << - ANSI_BLUE << " in file: " << ANSI_NORMAL << pos.file; - break; - } - case foString: { - out << prefix << std::endl; - out << prefix << ANSI_BLUE << "at: " << ANSI_YELLOW << showErrPos(*einfo.errPos) << - ANSI_BLUE << " from command line argument" << ANSI_NORMAL; - break; - } - case foStdin: { - out << prefix << std::endl; - out << prefix << ANSI_BLUE << "at: " << ANSI_YELLOW << showErrPos(*einfo.errPos) << - ANSI_BLUE << " from stdin" << ANSI_NORMAL; - break; - } - default: - throw Error("invalid FileOrigin in errPos"); - } + out << prefix << std::endl; + printAtPos(prefix, *einfo.errPos, out); nl = true; } @@ -320,13 +328,33 @@ std::ostream& operator<<(std::ostream &out, const ErrorInfo &einfo) for (auto iter = einfo.traces.rbegin(); iter != einfo.traces.rend(); ++iter) { try { - auto pos = *iter->pos; if (nl) out << std::endl << prefix; - out << std::endl << prefix; + + const string tracetitle(" show-trace output "); + + int fill = errwidth - tracetitle.length(); + int lw = 0; + int rw = 0; + const int min_dashes = 3; + if (fill > min_dashes * 2) { + if (fill % 2 != 0) { + lw = fill / 2; + rw = lw + 1; + } + else + { + lw = rw = fill / 2; + } + } + else + lw = rw = min_dashes; + + out << ANSI_BLUE << std::string(lw, '-') << tracetitle << std::string(rw, '-') << std::endl << prefix; out << iter->hint.str() << std::endl; - out << ANSI_BLUE << "at: " << ANSI_YELLOW << showErrPos(pos) << - ANSI_BLUE << " in file: " << ANSI_NORMAL << pos.file << std::endl; + + auto pos = *iter->pos; + printAtPos(prefix, pos, out); nl = true; auto loc = getCodeLines(pos); if (loc.has_value()) diff --git a/src/libutil/error.hh b/src/libutil/error.hh index 09fc57fee..d79ff8f8c 100644 --- a/src/libutil/error.hh +++ b/src/libutil/error.hh @@ -173,6 +173,8 @@ public: } BaseError & addTrace(std::optional e, hintformat hint); + + bool hasTrace() const { return !err.traces.empty(); } }; #define MakeError(newClass, superClass) \ diff --git a/src/libutil/tests/logging.cc b/src/libutil/tests/logging.cc index 0bbec482f..6d0431133 100644 --- a/src/libutil/tests/logging.cc +++ b/src/libutil/tests/logging.cc @@ -11,12 +11,12 @@ namespace nix { * logEI * --------------------------------------------------------------------------*/ - const char *test_file = + const char *test_file = "previous line of code\n" "this is the problem line of code\n" "next line of code\n"; - const char *one_liner = - "this is the problem line of code"; + const char *one_liner = + "this is the other problem line of code"; TEST(logEI, catpuresBasicProperties) { @@ -245,6 +245,33 @@ namespace nix { ASSERT_STREQ(str.c_str(), "\x1B[33;1mwarning:\x1B[0m\x1B[34;1m --- warning name --- error-unit-test\x1B[0m\n\x1B[34;1mat: \x1B[33;1m(2:13)\x1B[34;1m from stdin\x1B[0m\n\nwarning description\n\n 1| previous line of code\n 2| this is the problem line of code\n | \x1B[31;1m^\x1B[0m\n 3| next line of code\n\nthis hint has \x1B[33;1myellow\x1B[0m templated \x1B[33;1mvalues\x1B[0m!!\n"); } + /* ---------------------------------------------------------------------------- + * traces + * --------------------------------------------------------------------------*/ + + TEST(addTrace, showTracesWithShowTrace) { + SymbolTable testTable; + auto problem_file = testTable.create(test_file); + + auto oneliner_file = testTable.create(one_liner); + + auto e = AssertionError(ErrorInfo { + .name = "wat", + .description = "a well-known problem occurred", + .hint = hintfmt("it has been %1% days since our last error", "zero"), + .errPos = Pos(foString, problem_file, 2, 13), + }); + + e.addTrace(Pos(foStdin, oneliner_file, 1, 19), "while trying to compute %1%", 42); + + testing::internal::CaptureStderr(); + + logError(e.info()); + + auto str = testing::internal::GetCapturedStderr(); + ASSERT_STREQ(str.c_str(), "\x1B[31;1merror:\x1B[0m\x1B[34;1m --- AssertionError --- error-unit-test\x1B[0m\n\x1B[34;1mat: \x1B[33;1m(2:13)\x1B[34;1m from command line argument\x1B[0m\n\na well-known problem occurred\n\n 1| previous line of code\n 2| this is the problem line of code\n | \x1B[31;1m^\x1B[0m\n 3| next line of code\n\nit has been \x1B[33;1mzero\x1B[0m days since our last error\n\x1B[34;1m--- show-trace output ---\nwhile trying to compute \x1B[33;1m42\x1B[0m\n\x1B[34;1mat: \x1B[33;1m(1:19)\x1B[34;1m from stdin\x1B[0m\n 1| this is the other problem line of code\n | \x1B[31;1m^\x1B[0m\n"); + } + /* ---------------------------------------------------------------------------- * hintfmt * --------------------------------------------------------------------------*/