Logo ROOT  
Reference Guide
TestSupport.cxx
Go to the documentation of this file.
1/// \brief This file contains a specialised ROOT message handler to test for diagnostic in unit tests.
2///
3/// \author Stephan Hageboeck <stephan.hageboeck@cern.ch>
4
5/*************************************************************************
6 * Copyright (C) 1995-2021, Rene Brun and Fons Rademakers. *
7 * All rights reserved. *
8 * *
9 * For the licensing terms see $ROOTSYS/LICENSE. *
10 * For the list of contributors see $ROOTSYS/README/CREDITS. *
11 *************************************************************************/
12
13#include "ROOT/TestSupport.hxx"
14
15#include <algorithm>
16#include <cstring>
17#include <iostream>
18#include <iomanip>
19
20namespace ROOT {
21namespace TestSupport {
22
23/// Error handler for gtests that generates failures for every received diagnostic > kInfo when this file is linked to.
24static struct ForbidDiagnostics {
28 }
29
32 }
33
34 /// Diagnostic handler that's installed for all google tests.
35 /// It will generate a test failure when a diagnostic message is issued.
36 static void handler(int level, bool abort,
37 const char *location,
38 const char *msg) {
39 if (level <= gErrorIgnoreLevel) return;
40 if (level <= kInfo) {
41 std::cerr << "Diagnostic in '" << location << "': " << msg << std::endl;
42 return;
43 }
44
45 if (abort) {
46 std::cerr << "ROOT::TestSupport::ForbidDiagnostics::handler(): Forced to abort because of diagnostic with severity "
47 << level << " in '" << location << "' reading '" << msg << "'\n";
48 ::abort();
49 }
50
51 // FIXME: Windows has problem finding PCMs.
52 if (level == kError && strcmp(location, "TCling::LoadPCM") == 0 && strstr(msg, "file does not exist") != nullptr) {
53 std::cerr << "Error in " << location << " " << msg << std::endl;
54 return;
55 }
56
57 // FIXME: RNTuple warns that it's in beta stage.
58 if (level == kWarning
59 && strstr(msg, "The RNTuple file format will change. Do not store real data with this version of RNTuple!") != nullptr) {
60 std::cerr << "Warning in " << location << " " << msg << std::endl;
61 return;
62 }
63 if (level == kWarning
64 && strstr(msg, "Pre-release format version: RC ") != nullptr) {
65 std::cerr << "Warning in " << location << " " << msg << std::endl;
66 return;
67 }
68
69 // FIXME: DOAS backend is exprimental.
70 if (level == kWarning
71 && strstr(msg, "The DAOS backend is experimental and still under development") != nullptr) {
72 std::cerr << "Warning in " << location << " " << msg << std::endl;
73 return;
74 }
75
76 FAIL() << "Received unexpected diagnostic of severity "
77 << level
78 << " at '" << location << "' reading '" << msg << "'.\n"
79 << "Suppress those using ROOT/TestSupport.hxx";
80 }
81
84
85
86CheckDiagsRAII * CheckDiagsRAII::sActiveInstance = nullptr;
87
91 gInterpreter->ReportDiagnosticsToErrorHandler(/*enable=*/false);
92
93 if (!fUnexpectedDiags.empty()) ADD_FAILURE() << "ROOT::TestSupport::CheckDiagsRAII: Unexpected diagnostic messages received.";
94
95 const bool missingDiag = std::any_of(fExpectedDiags.begin(), fExpectedDiags.end(), [](const Diag_t & diag){ return !diag.optional && diag.receivedCount < 1; });
96 if (missingDiag) ADD_FAILURE() << "ROOT::TestSupport::CheckDiagsRAII: Diagnostic message missing.";
97
98 if (!fUnexpectedDiags.empty() || missingDiag) {
99 std::cout << "-------------------------\nPre-registered messages:\n";
101 std::cout << "Unexpected messages received:\n";
103 std::cout << "-------------------------" << std::endl;
104 }
105}
106
107/// Search list of expected diagnostics for given arguments, and increase the receivedCount.
108/// If no matching predefined diagnostic is found, this will trigger an unexpected diagnostic error on exit.
109void CheckDiagsRAII::checkDiag(int severity, const char * location, const char * msg) {
110 // Check that this received diagnostics was expected
111 const std::string message = msg;
112 const auto expectedMatch = std::find_if(fExpectedDiags.begin(), fExpectedDiags.end(), [=](const Diag_t& expectedDiag){
113 return expectedDiag.severity == severity
114 && strstr(location, expectedDiag.location.c_str()) != nullptr
115 && (expectedDiag.matchFullString ? expectedDiag.message == message : (message.find(expectedDiag.message) != std::string::npos));
116 });
117
118 if (expectedMatch != fExpectedDiags.end()) {
119 expectedMatch->receivedCount += 1;
120 } else if (severity <= kInfo) {
121 fOldErrorHandler(severity, false, location, msg);
122 } else {
123 fUnexpectedDiags.push_back({severity, location, std::move(message)});
124 }
125}
126
127void CheckDiagsRAII::printDiags(std::vector<Diag_t> const & diags) const {
128 std::map<int, std::string> dict = {
129 {kInfo, "kInfo"},
130 {kWarning, "kWarning"},
131 {kError, "kError"},
132 {kSysError, "kSysError"}
133 };
134
135 for (auto const & diag : diags) {
136 std::cout << std::setw(10) << dict[diag.severity] << "\t";
137 if (diag.receivedCount >= 0) {
138 std::cout << diag.receivedCount << "x received\t"
139 << "(" << (diag.optional ? "optional" : "required") << ", " << (diag.matchFullString ? "fullMatch" : "subMatch") << ")\t";
140 }
141 std::cout << "'" << diag.location << "' msg='" << diag.message << "'\n";
142 }
143}
144
145} } //ROOT::TestSupport
constexpr Int_t kError
Definition: TError.h:46
ErrorHandlerFunc_t GetErrorHandler()
Returns the current error handler function.
Definition: TError.cxx:102
constexpr Int_t kWarning
Definition: TError.h:45
void(* ErrorHandlerFunc_t)(int level, Bool_t abort, const char *location, const char *msg)
Definition: TError.h:70
constexpr Int_t kInfo
Definition: TError.h:44
Int_t gErrorIgnoreLevel
Definition: TError.cxx:34
constexpr Int_t kSysError
Definition: TError.h:48
ErrorHandlerFunc_t SetErrorHandler(ErrorHandlerFunc_t newhandler)
Set an errorhandler function. Returns the old handler.
Definition: TError.cxx:92
#define gInterpreter
Definition: TInterpreter.h:564
The file contains facilities allowing easier writing of in-tree unit tests.
void printDiags(std::vector< Diag_t > const &diags) const
Print the diags in diags to the terminal.
ErrorHandlerFunc_t const fOldErrorHandler
Last active handler in case handlers are nested.
static CheckDiagsRAII * sActiveInstance
Last active error handler function.
std::vector< Diag_t > fUnexpectedDiags
std::vector< Diag_t > fExpectedDiags
void checkDiag(int severity, const char *location, const char *msg)
Check all received diags against list of expected ones.
CheckDiagsRAII *const fOldInstance
static struct ROOT::TestSupport::ForbidDiagnostics noDiagCheckerInstance
This file contains a specialised ROOT message handler to test for diagnostic in unit tests.
Error handler for gtests that generates failures for every received diagnostic > kInfo when this file...
Definition: TestSupport.cxx:24
ErrorHandlerFunc_t const sOldErrorHandler
Definition: TestSupport.cxx:82
static void handler(int level, bool abort, const char *location, const char *msg)
Diagnostic handler that's installed for all google tests.
Definition: TestSupport.cxx:36