Skip to content

Commit

Permalink
Merge pull request #1259 from ioam/logging_unittests
Browse files Browse the repository at this point in the history
Added logging output support to unittests
  • Loading branch information
philippjfr authored Apr 10, 2017
2 parents 9fcf1ee + 1d7cf59 commit d75f3d5
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 3 deletions.
78 changes: 78 additions & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import os, sys
import param
import logging

from holoviews.element.comparison import ComparisonTestCase

try:
# Standardize backend due to random inconsistencies
Expand All @@ -9,3 +13,77 @@

cwd = os.path.abspath(os.path.split(__file__)[0])
sys.path.insert(0, os.path.join(cwd, '..'))


class MockLoggingHandler(logging.Handler):
"""
Mock logging handler to check for expected logs used by
LoggingComparisonTestCase.
Messages are available from an instance's ``messages`` dict, in
order, indexed by a lowercase log level string (e.g., 'debug',
'info', etc.)."""

def __init__(self, *args, **kwargs):
self.messages = {'DEBUG': [], 'INFO': [], 'WARNING': [],
'ERROR': [], 'CRITICAL': [], 'VERBOSE':[]}
super(MockLoggingHandler, self).__init__(*args, **kwargs)

def emit(self, record):
"Store a message to the instance's messages dictionary"
self.acquire()
try:
self.messages[record.levelname].append(record.getMessage())
finally:
self.release()

def reset(self):
self.acquire()
try:
for message_list in self.messages.values():
message_list = []
finally:
self.release()

def tail(self, level, n=1):
"Returns the last n lines captured at the given level"
return [str(el) for el in self.messages[level][-n:]]

def assertEndsWith(self, level, substring):
"""
Assert that the last line captured at the given level ends with
a particular substring.
"""
methods = {'WARNING':'param.warning()', 'INFO':'param.message()',
'VERBOSE':'param.verbose()', 'DEBUG':'param.debug()'}
msg='\n\n{method}: {last_line}\ndoes not end with:\n{substring}'
last_line = self.tail(level, n=1)
if len(last_line) == 0:
raise AssertionError('Missing {method} output: {repr(substring)}'.format(
method=methods[level], substring=repr(substring)))
if not last_line[0].endswith(substring):
raise AssertionError(msg.format(method=methods[level],
last_line=repr(last_line[0]),
substring=repr(substring)))



class LoggingComparisonTestCase(ComparisonTestCase):
"""
ComparisonTestCase with support for capturing param logging output.
Subclasses must call super setUp to make the
tests independent. Testing can then be done via the
self.log_handler.tail and self.log_handler.assertEndsWith methods.
"""

@classmethod
def setUpClass(cls):
super(LoggingComparisonTestCase, cls).setUpClass()
log = param.parameterized.get_logger()
cls.log_handler = MockLoggingHandler(level='DEBUG')
log.addHandler(cls.log_handler)

def setUp(self):
super(LoggingComparisonTestCase, self).setUp()
self.log_handler.reset()
9 changes: 7 additions & 2 deletions tests/testdimensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@
from unittest import SkipTest
from holoviews.core import Dimensioned, Dimension
from holoviews.element.comparison import ComparisonTestCase
from . import LoggingComparisonTestCase

import numpy as np
try:
import pandas as pd
except:
pd = None

class DimensionNameLabelTest(ComparisonTestCase):
class DimensionNameLabelTest(LoggingComparisonTestCase):

def setUp(self):
super(DimensionNameLabelTest, self).setUp()

def test_dimension_name(self):
dim = Dimension('test')
Expand All @@ -35,8 +39,9 @@ def test_dimension_label_kwarg(self):
self.assertEqual(dim.label, 'A test')

def test_dimension_label_kwarg_and_tuple(self):
# Should work but issue a warning
dim = Dimension(('test', 'A test'), label='Another test')
substr = "Using label as supplied by keyword ('Another test'), ignoring tuple value 'A test'"
self.log_handler.assertEndsWith('WARNING', substr)
self.assertEqual(dim.label, 'Another test')

def test_dimension_invalid_name(self):
Expand Down
2 changes: 1 addition & 1 deletion tests/testdynamic.py
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ def callback():
self.assertEqual(list(grid.keys()), [(i, j) for i in range(1, 3)
for j in range(1, 3)])
self.assertEqual(grid[(0, 1)][()], Image(np.array([[1, 1], [2, 3]])))

def test_dynamic_collate_grid_with_integer_stream_mapping(self):
def callback():
return GridSpace({(i, j): Image(np.array([[i, j], [2, 3]]))
Expand Down

0 comments on commit d75f3d5

Please sign in to comment.