1 /*=========================================================================
2 
3   Library:   CTK
4 
5   Copyright (c) Kitware Inc.
6 
7   Licensed under the Apache License, Version 2.0 (the "License");
8   you may not use this file except in compliance with the License.
9   You may obtain a copy of the License at
10 
11       http://www.apache.org/licenses/LICENSE-2.0.txt
12 
13   Unless required by applicable law or agreed to in writing, software
14   distributed under the License is distributed on an "AS IS" BASIS,
15   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   See the License for the specific language governing permissions and
17   limitations under the License.
18 
19 =========================================================================*/
20 
21 // Qt includes
22 #include <QCoreApplication>
23 #include <QDebug>
24 #include <QSignalSpy>
25 
26 // CTK includes
27 #include "ctkErrorLogFDMessageHandler.h"
28 #include "ctkErrorLogQtMessageHandler.h"
29 #include "ctkErrorLogStreamMessageHandler.h"
30 #include "ctkModelTester.h"
31 
32 // STL includes
33 #include <cstdlib>
34 #include <iostream>
35 
36 // Helper functions
37 #include "Testing/Cpp/ctkErrorLogModelTestHelper.cpp"
38 
39 //-----------------------------------------------------------------------------
ctkErrorLogModelTest1(int argc,char * argv[])40 int ctkErrorLogModelTest1(int argc, char * argv [])
41 {
42   QCoreApplication app(argc, argv);
43   Q_UNUSED(app);
44   ctkErrorLogModel model;
45   ctkModelTester modelTester;
46   modelTester.setVerbose(false);
47   QString errorMsg;
48 
49   QStringList enabledMessageHandlers = model.msgHandlerEnabled();
50   int currentEnabledMessageHandlersCount = enabledMessageHandlers.count();
51   errorMsg = checkInteger(__LINE__, "EnabledMessageHandlersCount", currentEnabledMessageHandlersCount, 0);
52   if (!errorMsg.isEmpty())
53     {
54     model.disableAllMsgHandler();
55     printErrorMessage(errorMsg);
56     return EXIT_FAILURE;
57     }
58 
59   try
60     {
61     modelTester.setModel(&model);
62 
63     // --------------------------------------------------------------------------
64     // Monitor Qt messages
65       {
66       model.registerMsgHandler(new ctkErrorLogQtMessageHandler);
67       model.setMsgHandlerEnabled(ctkErrorLogQtMessageHandler::HandlerName, true);
68 
69       QSignalSpy entryAddedSpy(&model, SIGNAL(entryAdded(ctkErrorLogLevel::LogLevel)));
70 
71       errorMsg = checkRowCount(__LINE__, model.logEntryCount(), /* expected = */ 0);
72       if (!errorMsg.isEmpty())
73         {
74         model.disableAllMsgHandler();
75         printErrorMessage(errorMsg);
76         printTextMessages(model);
77         return EXIT_FAILURE;
78         }
79 
80       errorMsg = checkSpyCount(__LINE__, entryAddedSpy.count(), /* expected = */ 0);
81       if (!errorMsg.isEmpty())
82         {
83         model.disableAllMsgHandler();
84         printErrorMessage(errorMsg);
85         printTextMessages(model);
86         return EXIT_FAILURE;
87         }
88 
89       QString qtMessage0("This is a qDebug message");
90       qDebug().nospace() << qPrintable(qtMessage0);
91 
92       QString qtMessage1("This is a qWarning message");
93       qWarning().nospace() << qPrintable(qtMessage1);
94 
95       QString qtMessage2("This is a qCritical message");
96       qCritical().nospace() << qPrintable(qtMessage2);
97 
98       // Give enough time to the ErrorLogModel to consider the queued messages.
99       processEvents(1000);
100 
101       QStringList expectedQtMessages;
102       expectedQtMessages << qtMessage0 << qtMessage1 << qtMessage2;
103 
104       errorMsg = checkRowCount(__LINE__, model.logEntryCount(), /* expected = */ expectedQtMessages.count());
105       if (!errorMsg.isEmpty())
106         {
107         model.disableAllMsgHandler();
108         printErrorMessage(errorMsg);
109         printTextMessages(model);
110         return EXIT_FAILURE;
111         }
112 
113       errorMsg = checkSpyCount(__LINE__, entryAddedSpy.count(), /* expected = */ expectedQtMessages.count());
114       if (!errorMsg.isEmpty())
115         {
116         model.disableAllMsgHandler();
117         printErrorMessage(errorMsg);
118         printTextMessages(model);
119         return EXIT_FAILURE;
120         }
121 
122       errorMsg = checkTextMessages(__LINE__, model, expectedQtMessages);
123       if (!errorMsg.isEmpty())
124         {
125         model.disableAllMsgHandler();
126         printErrorMessage(errorMsg);
127         printTextMessages(model);
128         return EXIT_FAILURE;
129         }
130 
131       // Check if msgHandlerEnabled() works as expected
132       enabledMessageHandlers = model.msgHandlerEnabled();
133       currentEnabledMessageHandlersCount = enabledMessageHandlers.count();
134       errorMsg = checkInteger(__LINE__, "EnabledMessageHandlersCount", currentEnabledMessageHandlersCount, 1);
135       if (!errorMsg.isEmpty())
136         {
137         model.disableAllMsgHandler();
138         printErrorMessage(errorMsg);
139         printTextMessages(model);
140         return EXIT_FAILURE;
141         }
142 
143       // Check if handler can be enabled / disabled multiple times in a row
144       for (int idx = 0; idx < 3; ++idx)
145         {
146         model.setMsgHandlerEnabled(ctkErrorLogQtMessageHandler::HandlerName, false);
147         model.setMsgHandlerEnabled(ctkErrorLogQtMessageHandler::HandlerName, true);
148         }
149 
150       // Clear
151       model.clear();
152       entryAddedSpy.clear();
153 
154       // Disable Qt messages monitoring
155       model.setMsgHandlerEnabled(ctkErrorLogQtMessageHandler::HandlerName, false);
156 
157       qDebug() << "This qDebug message should appear in the console";
158       qWarning() << "This qWarning message should appear in the console";
159       qCritical() << "This qCritical message should appear in the console";
160 
161       errorMsg = checkRowCount(__LINE__, model.logEntryCount(), /* expected = */ 0);
162       if (!errorMsg.isEmpty())
163         {
164         model.disableAllMsgHandler();
165         printErrorMessage(errorMsg);
166         printTextMessages(model);
167         return EXIT_FAILURE;
168         }
169 
170       errorMsg = checkSpyCount(__LINE__, entryAddedSpy.count(), /* expected = */ 0);
171       if (!errorMsg.isEmpty())
172         {
173         model.disableAllMsgHandler();
174         printErrorMessage(errorMsg);
175         printTextMessages(model);
176         return EXIT_FAILURE;
177         }
178       }
179 
180     // --------------------------------------------------------------------------
181     // Monitor Stream messages
182       {
183       model.registerMsgHandler(new ctkErrorLogStreamMessageHandler);
184       model.setMsgHandlerEnabled(ctkErrorLogStreamMessageHandler::HandlerName, true);
185 
186       QSignalSpy entryAddedSpy(&model, SIGNAL(entryAdded(ctkErrorLogLevel::LogLevel)));
187 
188       // Make sure Qt message handler is still disabled
189       if (model.msgHandlerEnabled(ctkErrorLogQtMessageHandler::HandlerName))
190         {
191         model.disableAllMsgHandler();
192         errorMsg = QLatin1String("Line %1 - Qt message handler should be disabled");
193         printErrorMessage(errorMsg.arg(__LINE__));
194         printTextMessages(model);
195         return EXIT_FAILURE;
196         }
197 
198       errorMsg = checkRowCount(__LINE__, model.logEntryCount(), /* expected = */ 0);
199       if (!errorMsg.isEmpty())
200         {
201         model.disableAllMsgHandler();
202         printErrorMessage(errorMsg);
203         printTextMessages(model);
204         return EXIT_FAILURE;
205         }
206 
207       errorMsg = checkSpyCount(__LINE__, entryAddedSpy.count(), /* expected = */ 0);
208       if (!errorMsg.isEmpty())
209         {
210         model.disableAllMsgHandler();
211         printErrorMessage(errorMsg);
212         printTextMessages(model);
213         return EXIT_FAILURE;
214         }
215 
216       QString streamMessage0("This is a Cout message");
217       std::cout << qPrintable(streamMessage0) << std::endl;
218 
219       QString streamMessage1("This is a Cerr message");
220       std::cerr << qPrintable(streamMessage1) << std::endl;
221 
222       // Give enough time to the ErrorLogModel to consider the queued messages.
223       processEvents(1000);
224 
225       QStringList expectedStreamMessages;
226       expectedStreamMessages << streamMessage0 << streamMessage1;
227 
228       errorMsg = checkRowCount(__LINE__, model.logEntryCount(), /* expected = */ expectedStreamMessages.count());
229       if (!errorMsg.isEmpty())
230         {
231         model.disableAllMsgHandler();
232         printErrorMessage(errorMsg);
233         printTextMessages(model);
234         return EXIT_FAILURE;
235         }
236 
237       errorMsg = checkSpyCount(__LINE__, entryAddedSpy.count(), /* expected = */ expectedStreamMessages.count());
238       if (!errorMsg.isEmpty())
239         {
240         model.disableAllMsgHandler();
241         printErrorMessage(errorMsg);
242         printTextMessages(model);
243         return EXIT_FAILURE;
244         }
245 
246       errorMsg = checkTextMessages(__LINE__, model, expectedStreamMessages);
247       if (!errorMsg.isEmpty())
248         {
249         model.disableAllMsgHandler();
250         printErrorMessage(errorMsg);
251         printTextMessages(model);
252         return EXIT_FAILURE;
253         }
254 
255       // Check if handler can be enabled / disabled multiple times in a row
256       for (int idx = 0; idx < 3; ++idx)
257         {
258         model.setMsgHandlerEnabled(ctkErrorLogStreamMessageHandler::HandlerName, false);
259         model.setMsgHandlerEnabled(ctkErrorLogStreamMessageHandler::HandlerName, true);
260         }
261 
262       // Clear
263       model.clear();
264       entryAddedSpy.clear();
265 
266       // Disable Stream messages monitoring
267       model.setMsgHandlerEnabled(ctkErrorLogStreamMessageHandler::HandlerName, false);
268 
269       std::cout << "This std::cout message should appear in the console" << std::endl;
270       std::cerr << "This std::cerr message should appear in the console" << std::endl;
271 
272       errorMsg = checkRowCount(__LINE__, model.logEntryCount(), /* expected = */ 0);
273       if (!errorMsg.isEmpty())
274         {
275         model.disableAllMsgHandler();
276         printErrorMessage(errorMsg);
277         printTextMessages(model);
278         return EXIT_FAILURE;
279         }
280 
281       errorMsg = checkSpyCount(__LINE__, entryAddedSpy.count(), /* expected = */ 0);
282       if (!errorMsg.isEmpty())
283         {
284         model.disableAllMsgHandler();
285         printErrorMessage(errorMsg);
286         printTextMessages(model);
287         return EXIT_FAILURE;
288         }
289       }
290 
291     // --------------------------------------------------------------------------
292     // Monitor FD messages
293       {
294       model.registerMsgHandler(new ctkErrorLogFDMessageHandler);
295       model.setMsgHandlerEnabled(ctkErrorLogFDMessageHandler::HandlerName, true);
296 
297       QSignalSpy entryAddedSpy(&model, SIGNAL(entryAdded(ctkErrorLogLevel::LogLevel)));
298 
299       errorMsg = checkRowCount(__LINE__, model.logEntryCount(), /* expected = */ 0);
300       if (!errorMsg.isEmpty())
301         {
302         model.disableAllMsgHandler();
303         printErrorMessage(errorMsg);
304         printTextMessages(model);
305         return EXIT_FAILURE;
306         }
307 
308       errorMsg = checkSpyCount(__LINE__, entryAddedSpy.count(), /* expected = */ 0);
309       if (!errorMsg.isEmpty())
310         {
311         model.disableAllMsgHandler();
312         printErrorMessage(errorMsg);
313         printTextMessages(model);
314         return EXIT_FAILURE;
315         }
316 
317       QString fdMessage0("This is a stdout");
318       fprintf(stdout, "%s", qPrintable(fdMessage0));
319       QString fdMessage0b(" message");
320       fprintf(stdout, "%s\n", qPrintable(fdMessage0b));
321       fdMessage0.append(fdMessage0b);
322       fflush(stdout);
323 
324       QString fdMessage1("This is a 2nd stdout message");
325       fprintf(stdout, "%s\n", qPrintable(fdMessage1));
326       fflush(stdout);
327 
328       QString fdMessage2("This is a stderr");
329       fprintf(stderr, "%s", qPrintable(fdMessage2));
330       QString fdMessage2b(" message");
331       fprintf(stderr, "%s\n", qPrintable(fdMessage2b));
332       fdMessage2.append(fdMessage2b);
333       fflush(stderr);
334 
335       QString fdMessage3("This is a 2nd stderr message");
336       fprintf(stderr, "%s\n", qPrintable(fdMessage3));
337       fflush(stderr);
338 
339       QStringList expectedFDMessages;
340       expectedFDMessages << fdMessage0 << fdMessage1 << fdMessage2 << fdMessage3;
341 
342       // Give enough time to the ErrorLogModel to consider the queued messages.
343       // and also to the QFileSystemWatcher used internally by ctkErrorLogFDMessageHandler
344       // to consider the updated files.
345       processEvents(1500);
346 
347       errorMsg = checkRowCount(__LINE__, model.logEntryCount(), /* expected = */ expectedFDMessages.count());
348       if (!errorMsg.isEmpty())
349         {
350         model.disableAllMsgHandler();
351         printErrorMessage(errorMsg);
352         printTextMessages(model);
353         return EXIT_FAILURE;
354         }
355 
356       errorMsg = checkSpyCount(__LINE__, entryAddedSpy.count(), /* expected = */ expectedFDMessages.count());
357       if (!errorMsg.isEmpty())
358         {
359         model.disableAllMsgHandler();
360         printErrorMessage(errorMsg);
361         printTextMessages(model);
362         return EXIT_FAILURE;
363         }
364 
365       errorMsg = checkTextMessages(__LINE__, model, expectedFDMessages);
366       if (!errorMsg.isEmpty())
367         {
368         model.disableAllMsgHandler();
369         printErrorMessage(errorMsg);
370         printTextMessages(model);
371         return EXIT_FAILURE;
372         }
373 
374       // Check if handler can be enabled / disabled multiple times in a row
375       for (int idx = 0; idx < 3; ++idx)
376         {
377         model.setMsgHandlerEnabled(ctkErrorLogFDMessageHandler::HandlerName, false);
378         model.setMsgHandlerEnabled(ctkErrorLogFDMessageHandler::HandlerName, true);
379         }
380 
381       // Clear
382       model.clear();
383       entryAddedSpy.clear();
384 
385       // Disable FD messages monitoring
386       model.setMsgHandlerEnabled(ctkErrorLogFDMessageHandler::HandlerName, false);
387 
388       fprintf(stdout, "%s", "This stdout message should appear in the console\n");
389       fprintf(stderr, "%s", "This stderr message should appear in the console\n");
390       fflush(stderr);
391 
392       errorMsg = checkRowCount(__LINE__, model.logEntryCount(), /* expected = */ 0);
393       if (!errorMsg.isEmpty())
394         {
395         model.disableAllMsgHandler();
396         printErrorMessage(errorMsg);
397         printTextMessages(model);
398         return EXIT_FAILURE;
399         }
400 
401       errorMsg = checkSpyCount(__LINE__, entryAddedSpy.count(), /* expected = */ 0);
402       if (!errorMsg.isEmpty())
403         {
404         model.disableAllMsgHandler();
405         printErrorMessage(errorMsg);
406         printTextMessages(model);
407         return EXIT_FAILURE;
408         }
409       }
410 
411     }
412   catch (const char* error)
413     {
414     model.disableAllMsgHandler();
415     std::cerr << error << std::endl;
416     return EXIT_FAILURE;
417     }
418 
419   return EXIT_SUCCESS;
420 }
421