Logo ROOT  
Reference Guide
 
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
Loading...
Searching...
No Matches
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 << "ROOT::TestSupport::ForbidDiagnostics::handler(): Diagnostic in '" << location << "':\n"
42 << msg << std::endl;
43 return;
44 }
45
46 if (abort) {
47 std::cerr << "ROOT::TestSupport::ForbidDiagnostics::handler(): Forced to abort because of diagnostic with severity "
48 << level << " in '" << location << "' reading '" << msg << "'\n";
49 ::abort();
50 }
51
52 // FIXME: Windows has problem finding PCMs.
53 if (level == kError && strcmp(location, "TCling::LoadPCM") == 0 && strstr(msg, "file does not exist") != nullptr) {
54 std::cerr << "Error in " << location << " " << msg << std::endl;
55 return;
56 }
57
58 // FIXME: RNTuple warns that it's in beta stage.
59 if (level == kWarning
60 && strstr(msg, "The RNTuple file format will change. Do not store real data with this version of RNTuple!") != nullptr) {
61 std::cerr << "Warning in " << location << " " << msg << std::endl;
62 return;
63 }
64 if (level == kWarning
65 && strstr(msg, "Pre-release format version: RC ") != nullptr) {
66 std::cerr << "Warning in " << location << " " << msg << std::endl;
67 return;
68 }
69
70 // FIXME: DOAS backend is exprimental.
71 if (level == kWarning
72 && strstr(msg, "The DAOS backend is experimental and still under development") != nullptr) {
73 std::cerr << "Warning in " << location << " " << msg << std::endl;
74 return;
75 }
76
77 FAIL() << "Received unexpected diagnostic of severity "
78 << level
79 << " at '" << location << "' reading '" << msg << "'.\n"
80 << "Suppress those using ROOT/TestSupport.hxx";
81 }
82
85
86
87CheckDiagsRAII * CheckDiagsRAII::sActiveInstance = nullptr;
88
92 gInterpreter->ReportDiagnosticsToErrorHandler(/*enable=*/false);
93
94 for (const auto &diag : fExpectedDiags) {
95 if (!diag.optional && diag.receivedCount < 1) {
96 ADD_FAILURE() << "ROOT::TestSupport::CheckDiagsRAII: Expected diagnostic message missing:\n" << diag;
97 }
98 }
99
100 for (const auto &diag : fUnexpectedDiags) {
101 ADD_FAILURE() << "ROOT::TestSupport::CheckDiagsRAII: Unexpected diagnostic message:\n" << diag;
102 }
103}
104
105/// Search list of expected diagnostics for given arguments, and increase the receivedCount.
106/// If no matching predefined diagnostic is found, this will trigger an unexpected diagnostic error on exit.
107void CheckDiagsRAII::checkDiag(int severity, const char * location, const char * msg) {
108 // Check that this received diagnostics was expected
109 const std::string message = msg;
110 const auto expectedMatch =
111 std::find_if(fExpectedDiags.begin(), fExpectedDiags.end(), [=](const Diag_t &expectedDiag) {
112 return expectedDiag.severity == severity
113 && strstr(location, expectedDiag.location.c_str()) != nullptr
114 && (expectedDiag.matchFullString ? expectedDiag.message == message : (message.find(expectedDiag.message) != std::string::npos));
115 });
116
117 if (expectedMatch != fExpectedDiags.end()) {
118 expectedMatch->receivedCount += 1;
119 } else if (severity <= kInfo) {
120 fOldErrorHandler(severity, false, location, msg);
121 } else {
122 fUnexpectedDiags.push_back({severity, location, std::move(message)});
123 }
124}
125
126std::ostream &operator<<(std::ostream &stream, CheckDiagsRAII::Diag_t const &diag)
127{
128 std::map<int, std::string> dict = {
129 {kInfo, "kInfo"}, {kWarning, "kWarning"}, {kError, "kError"}, {kSysError, "kSysError"}};
130
131 constexpr auto indent = 15;
132 stream << std::right << std::setw(indent) << "severity: " << dict[diag.severity];
133 if (diag.receivedCount >= 0) {
134 stream << "\n"
135 << std::setw(indent) << "received: " << diag.receivedCount << " times ("
136 << (diag.optional ? "optional" : "required") << ", " << (diag.matchFullString ? "fullMatch" : "subMatch")
137 << ")\t";
138 }
139 stream << "\n"
140 << std::setw(indent) << "origin: " << '"' << diag.location << "\""
141 << "\n"
142 << std::setw(indent) << "message: " << diag.message << "\n";
143
144 return stream;
145}
146} } //ROOT::TestSupport
TBuffer & operator<<(TBuffer &buf, const Tmpl *obj)
Definition TBuffer.h:399
static void indent(ostringstream &buf, int indent_level)
constexpr Int_t kError
Definition TError.h:46
ErrorHandlerFunc_t GetErrorHandler()
Returns the current error handler function.
Definition TError.cxx:100
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
Error handling routines.
Definition TError.cxx:31
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:90
#define gInterpreter
The file contains facilities allowing easier writing of in-tree unit tests.
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...
ErrorHandlerFunc_t const sOldErrorHandler
static void handler(int level, bool abort, const char *location, const char *msg)
Diagnostic handler that's installed for all google tests.