ソースを参照

CTest: Add colored output on tests summary where supported

- Number of passed/failed tests is colored according to the whole outcome
- Individual listed tested are colored according to their completion status:
  * Disabled: blue
  * Failed: red
  * Not Run: yellow
Sylvain Joubert 7 年 前
コミット
ffdec37a19

+ 30 - 9
Source/CTest/cmCTestTestHandler.cxx

@@ -535,11 +535,21 @@ int cmCTestTestHandler::ProcessHandler()
       percent = 99;
     }
 
+    std::string passColorCode;
+    std::string failedColorCode;
+    if (failed.empty()) {
+      passColorCode = this->CTest->GetColorCode(cmCTest::Color::GREEN);
+    } else {
+      failedColorCode = this->CTest->GetColorCode(cmCTest::Color::RED);
+    }
     cmCTestLog(this->CTest, HANDLER_OUTPUT,
                std::endl
-                 << static_cast<int>(percent + .5f) << "% tests passed, "
-                 << failed.size() << " tests failed out of " << total
-                 << std::endl);
+                 << passColorCode << static_cast<int>(percent + .5f)
+                 << "% tests passed"
+                 << this->CTest->GetColorCode(cmCTest::Color::CLEAR_COLOR)
+                 << ", " << failedColorCode << failed.size() << " tests failed"
+                 << this->CTest->GetColorCode(cmCTest::Color::CLEAR_COLOR)
+                 << " out of " << total << std::endl);
     if ((!this->CTest->GetLabelsForSubprojects().empty() &&
          this->CTest->GetSubprojectSummary())) {
       this->PrintLabelOrSubprojectSummary(true);
@@ -562,6 +572,8 @@ int cmCTestTestHandler::ProcessHandler()
       this->StartLogFile("TestsDisabled", ofs);
 
       const char* disabled_reason;
+      cmCTestLog(this->CTest, HANDLER_OUTPUT,
+                 this->CTest->GetColorCode(cmCTest::Color::BLUE));
       for (cmCTestTestResult const& dt : disabledTests) {
         ofs << dt.TestCount << ":" << dt.Name << std::endl;
         if (dt.CompletionStatus == "Disabled") {
@@ -573,6 +585,8 @@ int cmCTestTestHandler::ProcessHandler()
                    "\t" << std::setw(3) << dt.TestCount << " - " << dt.Name
                         << " (" << disabled_reason << ")" << std::endl);
       }
+      cmCTestLog(this->CTest, HANDLER_OUTPUT,
+                 this->CTest->GetColorCode(cmCTest::Color::CLEAR_COLOR));
     }
 
     if (!failed.empty()) {
@@ -587,10 +601,17 @@ int cmCTestTestHandler::ProcessHandler()
             !cmHasLiteralPrefix(ft.CompletionStatus, "SKIP_RETURN_CODE=") &&
             ft.CompletionStatus != "Disabled") {
           ofs << ft.TestCount << ":" << ft.Name << std::endl;
-          cmCTestLog(this->CTest, HANDLER_OUTPUT,
-                     "\t" << std::setw(3) << ft.TestCount << " - " << ft.Name
-                          << " (" << this->GetTestStatus(ft) << ")"
-                          << std::endl);
+          auto testColor = cmCTest::Color::RED;
+          if (this->GetTestStatus(ft) == "Not Run") {
+            testColor = cmCTest::Color::YELLOW;
+          }
+          cmCTestLog(
+            this->CTest, HANDLER_OUTPUT,
+            "\t" << this->CTest->GetColorCode(testColor) << std::setw(3)
+                 << ft.TestCount << " - " << ft.Name << " ("
+                 << this->GetTestStatus(ft) << ")"
+                 << this->CTest->GetColorCode(cmCTest::Color::CLEAR_COLOR)
+                 << std::endl);
         }
       }
     }
@@ -1725,7 +1746,7 @@ void cmCTestTestHandler::UseExcludeRegExp()
   this->UseExcludeRegExpFirst = !this->UseIncludeRegExpFlag;
 }
 
-const char* cmCTestTestHandler::GetTestStatus(cmCTestTestResult const& result)
+std::string cmCTestTestHandler::GetTestStatus(cmCTestTestResult const& result)
 {
   static const char* statuses[] = { "Not Run",     "Timeout",   "SEGFAULT",
                                     "ILLEGAL",     "INTERRUPT", "NUMERICAL",
@@ -1737,7 +1758,7 @@ const char* cmCTestTestHandler::GetTestStatus(cmCTestTestResult const& result)
     return "No Status";
   }
   if (status == cmCTestTestHandler::OTHER_FAULT) {
-    return result.ExceptionStatus.c_str();
+    return result.ExceptionStatus;
   }
   return statuses[status];
 }

+ 1 - 1
Source/CTest/cmCTestTestHandler.h

@@ -274,7 +274,7 @@ private:
    */
   std::string FindTheExecutable(const char* exe);
 
-  const char* GetTestStatus(cmCTestTestResult const&);
+  std::string GetTestStatus(cmCTestTestResult const&);
   void ExpandTestsToRunInformation(size_t numPossibleTests);
   void ExpandTestsToRunInformationForRerunFailed();
 

+ 38 - 5
Source/cmCTest.cxx

@@ -296,6 +296,7 @@ cmCTest::cmCTest()
   this->DropSiteCDash = false;
   this->BuildID = "";
   this->OutputTestOutputOnTestFailure = false;
+  this->OutputColorCode = this->ColoredOutputSupportedByConsole();
   this->RepeatTests = 1; // default to run each test once
   this->RepeatUntilFail = false;
 
@@ -2075,7 +2076,18 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
   return true;
 }
 
-bool cmCTest::ProgressOutputSupportedByConsole() const
+#if !defined(_WIN32)
+bool cmCTest::ConsoleIsNotDumb()
+{
+  std::string term_env_variable;
+  if (cmSystemTools::GetEnv("TERM", term_env_variable)) {
+    return isatty(1) && term_env_variable != "dumb";
+  }
+  return false;
+}
+#endif
+
+bool cmCTest::ProgressOutputSupportedByConsole()
 {
 #if defined(_WIN32)
   // On Windows we need a console buffer.
@@ -2084,12 +2096,19 @@ bool cmCTest::ProgressOutputSupportedByConsole() const
   return GetConsoleScreenBufferInfo(console, &csbi);
 #else
   // On UNIX we need a non-dumb tty.
-  std::string term_env_variable;
-  if (cmSystemTools::GetEnv("TERM", term_env_variable)) {
-    return isatty(1) && term_env_variable != "dumb";
-  }
+  return ConsoleIsNotDumb();
 #endif
+}
+
+bool cmCTest::ColoredOutputSupportedByConsole()
+{
+#if defined(_WIN32)
+  // Not supported on Windows
   return false;
+#else
+  // On UNIX we need a non-dumb tty.
+  return ConsoleIsNotDumb();
+#endif
 }
 
 // handle the -S -SR and -SP arguments
@@ -2958,6 +2977,20 @@ void cmCTest::Log(int logType, const char* file, int line, const char* msg,
   }
 }
 
+std::string cmCTest::GetColorCode(Color color) const
+{
+  if (this->OutputColorCode) {
+#if defined(_WIN32)
+    // Not supported on Windows
+    static_cast<void>(color);
+#else
+    return "\033[0;" + std::to_string(static_cast<int>(color)) + "m";
+#endif
+  }
+
+  return "";
+}
+
 cmDuration cmCTest::GetRemainingTimeAllowed()
 {
   if (!this->GetHandler("script")) {

+ 23 - 1
Source/cmCTest.h

@@ -405,6 +405,19 @@ public:
   void Log(int logType, const char* file, int line, const char* msg,
            bool suppress = false);
 
+  /** Color values */
+  enum class Color
+  {
+    CLEAR_COLOR = 0,
+    RED = 31,
+    GREEN = 32,
+    YELLOW = 33,
+    BLUE = 34
+  };
+
+  /** Get color code characters for a specific color */
+  std::string GetColorCode(Color color) const;
+
   /** Get the version of dart server */
   int GetDartVersion() { return this->DartVersion; }
   int GetDropSiteCDash() { return this->DropSiteCDash; }
@@ -575,8 +588,16 @@ private:
   bool HandleCommandLineArguments(size_t& i, std::vector<std::string>& args,
                                   std::string& errormsg);
 
+#if !defined(_WIN32)
   /** returns true iff the console supports progress output */
-  bool ProgressOutputSupportedByConsole() const;
+  static bool ConsoleIsNotDumb();
+#endif
+
+  /** returns true iff the console supports progress output */
+  static bool ProgressOutputSupportedByConsole();
+
+  /** returns true iff the console supports colored output */
+  static bool ColoredOutputSupportedByConsole();
 
   /** handle the -S -SP and -SR arguments */
   void HandleScriptArguments(size_t& i, std::vector<std::string>& args,
@@ -625,6 +646,7 @@ private:
   int OutputLogFileLastTag;
 
   bool OutputTestOutputOnTestFailure;
+  bool OutputColorCode;
 
   std::map<std::string, std::string> Definitions;
 };