1
- import collections
2
1
from contextlib import contextmanager
3
2
import functools
4
3
import sys
5
4
import traceback
6
5
import weakref
7
6
import datetime
8
7
8
+ from py ._code .code import TerminalRepr
9
+ from py ._code .code import ReprFileLocation
10
+
9
11
import pytest
10
12
11
13
from pytestqt .qt_compat import QtCore , QtTest , QApplication , QT_API , \
@@ -58,7 +60,6 @@ def result(*args, **kwargs):
58
60
59
61
@_inject_qtest_methods
60
62
class QtBot (object ):
61
-
62
63
"""
63
64
Instances of this class are responsible for sending events to `Qt` objects (usually widgets),
64
65
simulating user input.
@@ -206,10 +207,10 @@ def waitForWindowShown(self, widget):
206
207
.. note:: In Qt5, the actual method called is qWaitForWindowExposed,
207
208
but this name is kept for backward compatibility
208
209
"""
209
- if hasattr (QtTest .QTest , 'qWaitForWindowShown' ): # pragma: no cover
210
+ if hasattr (QtTest .QTest , 'qWaitForWindowShown' ): # pragma: no cover
210
211
# PyQt4 and PySide
211
212
QtTest .QTest .qWaitForWindowShown (widget )
212
- else : # pragma: no cover
213
+ else : # pragma: no cover
213
214
# PyQt5
214
215
QtTest .QTest .qWaitForWindowExposed (widget )
215
216
@@ -281,7 +282,6 @@ def waitSignal(self, signal=None, timeout=1000):
281
282
282
283
283
284
class SignalBlocker (object ):
284
-
285
285
"""
286
286
Returned by :meth:`QtBot.waitSignal` method.
287
287
@@ -417,6 +417,12 @@ def pytest_addoption(parser):
417
417
parser .addini ('qt_no_exception_capture' ,
418
418
'disable automatic exception capture' )
419
419
420
+ default_log_fail = QtLoggingPlugin .LOG_FAIL_OPTIONS [0 ]
421
+ parser .addini ('qt_log_level_fail' ,
422
+ 'log level in which tests can fail: {0} (default: "{1}")'
423
+ .format (QtLoggingPlugin .LOG_FAIL_OPTIONS , default_log_fail ),
424
+ default = default_log_fail )
425
+
420
426
parser .addoption ('--no-qt-log' , dest = 'qt_log' , action = 'store_false' ,
421
427
default = True )
422
428
parser .addoption ('--qt-log-format' , dest = 'qt_log_format' ,
@@ -452,6 +458,8 @@ class QtLoggingPlugin(object):
452
458
test and augment reporting if the test failed with the messages captured.
453
459
"""
454
460
461
+ LOG_FAIL_OPTIONS = ['NO' , 'CRITICAL' , 'WARNING' , 'DEBUG' ]
462
+
455
463
def __init__ (self , config ):
456
464
self .config = config
457
465
@@ -467,14 +475,25 @@ def pytest_runtest_makereport(self, item, call):
467
475
outcome = yield
468
476
report = outcome .result
469
477
478
+ log_format = self .config .getoption ('qt_log_format' )
479
+ log_fail_level = self .config .getini ('qt_log_level_fail' )
480
+
470
481
if call .when == 'call' :
471
482
483
+ if log_fail_level != 'NO' and report .outcome != 'failed' :
484
+ for rec in item .qt_log_capture .records :
485
+ if rec .matches_level (log_fail_level ):
486
+ report .outcome = 'failed'
487
+ if report .longrepr is None :
488
+ report .longrepr = \
489
+ _QtLogLevelErrorRepr (item , log_fail_level )
490
+ break
491
+
472
492
if not report .passed :
473
493
long_repr = getattr (report , 'longrepr' , None )
474
494
if hasattr (long_repr , 'addsection' ): # pragma: no cover
475
495
lines = []
476
496
for rec in item .qt_log_capture .records :
477
- log_format = self .config .getoption ('qt_log_format' )
478
497
lines .append (log_format .format (rec = rec ))
479
498
if lines :
480
499
long_repr .addsection ('Captured Qt messages' ,
@@ -568,3 +587,35 @@ def _get_log_type_name(cls, msg_type):
568
587
QtFatalMsg : 'FATAL' ,
569
588
}
570
589
return cls ._log_type_name_map [msg_type ]
590
+
591
+ def matches_level (self , level ):
592
+ if level == 'DEBUG' :
593
+ return self .log_type_name in {'DEBUG' , 'WARNING' , 'CRITICAL' }
594
+ elif level == 'WARNING' :
595
+ return self .log_type_name in {'WARNING' , 'CRITICAL' }
596
+ elif level == 'CRITICAL' :
597
+ return self .log_type_name in {'CRITICAL' }
598
+ else :
599
+ raise ValueError ('log_fail_level unknown: {0}' .format (level ))
600
+
601
+
602
+ class _QtLogLevelErrorRepr (TerminalRepr ):
603
+ """
604
+ TerminalRepr of a test which didn't fail by normal means, but emitted
605
+ messages at or above the allowed level.
606
+ """
607
+
608
+ def __init__ (self , item , level ):
609
+ msg = 'Failure: Qt messages with level {0} or above emitted'
610
+ path , line , _ = item .location
611
+ self .fileloc = ReprFileLocation (path , line , msg .format (level .upper ()))
612
+ self .sections = []
613
+
614
+ def addsection (self , name , content , sep = "-" ):
615
+ self .sections .append ((name , content , sep ))
616
+
617
+ def toterminal (self , out ):
618
+ self .fileloc .toterminal (out )
619
+ for name , content , sep in self .sections :
620
+ out .sep (sep , name )
621
+ out .line (content )
0 commit comments