Skip to content

Commit

Permalink
Improve test coverage.
Browse files Browse the repository at this point in the history
  • Loading branch information
jonathanj committed Jun 6, 2015
1 parent 6b0c520 commit 8d33e4e
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 31 deletions.
14 changes: 7 additions & 7 deletions eliottree/render.py
Expand Up @@ -10,13 +10,13 @@ def _format_value(value, encoding):
Format a value for a task tree.
"""
if isinstance(value, datetime):
return value.isoformat(' ')
return value.isoformat(' ').encode(encoding)
elif isinstance(value, unicode):
return value.encode(encoding)
elif isinstance(value, dict):
return value
# XXX: This is probably wrong in a bunch of places.
return str(value)
elif isinstance(value, str):
# We guess bytes values are UTF-8.
return value.decode('utf-8', 'replace').encode(encoding)
return repr(value).decode('utf-8', 'replace').encode(encoding)


def _indented_write(write):
Expand Down Expand Up @@ -64,19 +64,19 @@ def _render_task(write, task, ignored_task_keys, field_limit, encoding):
for i, (key, value) in enumerate(sorted(task.items()), 1):
if key not in ignored_task_keys:
tree_char = '`' if i == num_items else '|'
_value = _format_value(value, encoding)
key = key.encode(encoding)
if isinstance(value, dict):
write(
'{tree_char}-- {key}:\n'.format(
tree_char=tree_char,
key=key))
_render_task(write=_write,
task=_value,
task=value,
ignored_task_keys={},
field_limit=field_limit,
encoding=encoding)
else:
_value = _format_value(value, encoding)
if field_limit:
first_line = _truncate_value(_value, field_limit)
else:
Expand Down
60 changes: 38 additions & 22 deletions eliottree/test/tasks.py
@@ -1,29 +1,45 @@
message_task = {
"task_uuid": "cdeb220d-7605-4d5f-8341-1a170222e308",
"error": False,
"timestamp": 1425356700,
"message": "Main loop terminated.",
"message_type": "twisted:log",
"action_type": "nope",
"task_level": [1]}
u"task_uuid": u"cdeb220d-7605-4d5f-8341-1a170222e308",
u"error": False,
u"timestamp": 1425356700,
u"message": u"Main loop terminated.",
u"message_type": u"twisted:log",
u"action_type": u"nope",
u"task_level": [1]}

action_task = {
"timestamp": 1425356800,
"action_status": "started",
"task_uuid": "f3a32bb3-ea6b-457c-aa99-08a3d0491ab4",
"action_type": "app:action",
"task_level": [1]}
u"timestamp": 1425356800,
u"action_status": u"started",
u"task_uuid": u"f3a32bb3-ea6b-457c-aa99-08a3d0491ab4",
u"action_type": u"app:action",
u"task_level": [1]}

nested_action_task = {
"timestamp": 1425356900,
"action_status": "started",
"task_uuid": "f3a32bb3-ea6b-457c-aa99-08a3d0491ab4",
"action_type": "app:action:nested",
"task_level": [1, 1]}
u"timestamp": 1425356900,
u"action_status": u"started",
u"task_uuid": u"f3a32bb3-ea6b-457c-aa99-08a3d0491ab4",
u"action_type": u"app:action:nested",
u"task_level": [1, 1]}

action_task_end = {
"timestamp": 1425356800,
"action_status": "succeeded",
"task_uuid": "f3a32bb3-ea6b-457c-aa99-08a3d0491ab4",
"action_type": "app:action",
"task_level": [2]}
u"timestamp": 1425356800,
u"action_status": u"succeeded",
u"task_uuid": u"f3a32bb3-ea6b-457c-aa99-08a3d0491ab4",
u"action_type": u"app:action",
u"task_level": [2]}

dict_action_task = {
u"timestamp": 1425356800,
u"action_status": u"started",
u"task_uuid": u"f3a32bb3-ea6b-457c-aa99-08a3d0491ab4",
u"action_type": u"app:action",
u"task_level": [1],
u"some_data": {u"a": 42}}

multiline_action_task = {
u"timestamp": 1425356800,
u"action_status": u"started",
u"task_uuid": u"f3a32bb3-ea6b-457c-aa99-08a3d0491ab4",
u"action_type": u"app:action",
u"task_level": [1],
u"message": u"this is a\nmany line message"}
127 changes: 125 additions & 2 deletions eliottree/test/test_render.py
@@ -1,11 +1,73 @@
from datetime import datetime
from StringIO import StringIO

from testtools import TestCase
from testtools.matchers import Equals

from eliottree import Tree, render_task_nodes
from eliottree.render import _format_value
from eliottree.test.tasks import (
action_task, action_task_end, message_task, nested_action_task)
action_task, action_task_end, dict_action_task, message_task,
multiline_action_task, nested_action_task)


class FormatValueTests(TestCase):
"""
Tests for ``eliottree.render._format_value``.
"""
def test_datetime(self):
"""
Format ``datetime`` values as ISO8601.
"""
now = datetime(2015, 6, 6, 22, 57, 12)
self.assertThat(
_format_value(now, 'utf-8'),
Equals('2015-06-06 22:57:12'))
self.assertThat(
_format_value(now, 'utf-16'),
Equals('\xff\xfe2\x000\x001\x005\x00-\x000\x006\x00-\x000\x006'
'\x00 \x002\x002\x00:\x005\x007\x00:\x001\x002\x00'))

def test_unicode(self):
"""
Encode ``unicode`` values as the specified encoding.
"""
self.assertThat(
_format_value(u'\N{SNOWMAN}', 'utf-8'),
Equals('\xe2\x98\x83'))
self.assertThat(
_format_value(u'\N{SNOWMAN}', 'utf-16'),
Equals('\xff\xfe\x03&'))

def test_str(self):
"""
Assume that ``str`` values are UTF-8.
"""
self.assertThat(
_format_value('foo', 'utf-8'),
Equals('foo'))
self.assertThat(
_format_value('\xe2\x98\x83', 'utf-8'),
Equals('\xe2\x98\x83'))
self.assertThat(
_format_value('\xff\xfe\x03&', 'utf-8'),
Equals('\xef\xbf\xbd\xef\xbf\xbd\x03&'))

def test_other(self):
"""
Pass unknown values to ``repr`` and encode as ``utf-8`` while replacing
encoding errors.
"""
self.assertThat(
_format_value(42, 'utf-8'),
Equals('42'))
self.assertThat(
_format_value({u'a': u'\N{SNOWMAN}'}, 'utf-8'),
Equals("{u'a': u'\\u2603'}"))
self.assertThat(
_format_value({u'a': u'\N{SNOWMAN}'}, 'utf-16'),
Equals("\xff\xfe{\x00u\x00'\x00a\x00'\x00:\x00 \x00u\x00'"
"\x00\\\x00u\x002\x006\x000\x003\x00'\x00}\x00"))


class RenderTaskNodesTests(TestCase):
Expand Down Expand Up @@ -33,6 +95,47 @@ def test_tasks(self):
' +-- app:action@2/succeeded\n'
' `-- timestamp: 1425356800\n\n'))

def test_multiline_field(self):
"""
When no field limit is specified for task values, multiple lines are
output for multiline tasks.
"""
fd = StringIO()
tree = Tree()
tree.merge_tasks([multiline_action_task])
render_task_nodes(
write=fd.write,
nodes=tree.nodes(),
field_limit=0)
self.assertThat(
fd.getvalue(),
Equals(
'f3a32bb3-ea6b-457c-aa99-08a3d0491ab4\n'
' +-- app:action@1/started\n'
' |-- message: this is a\n'
' many line message\n'
' `-- timestamp: 1425356800\n\n'))

def test_multiline_field_limit(self):
"""
When a field limit is specified for task values, only the first of
multiple lines is output.
"""
fd = StringIO()
tree = Tree()
tree.merge_tasks([multiline_action_task])
render_task_nodes(
write=fd.write,
nodes=tree.nodes(),
field_limit=1000)
self.assertThat(
fd.getvalue(),
Equals(
'f3a32bb3-ea6b-457c-aa99-08a3d0491ab4\n'
' +-- app:action@1/started\n'
' |-- message: this is a [...]\n'
' `-- timestamp: 1425356800\n\n'))

def test_field_limit(self):
"""
Truncate task values that are longer than the field_limit if specified.
Expand Down Expand Up @@ -78,7 +181,7 @@ def test_ignored_keys(self):

def test_task_data(self):
"""
Custom task data is rendered as tree elements.
Task data is rendered as tree elements.
"""
fd = StringIO()
tree = Tree()
Expand All @@ -97,6 +200,26 @@ def test_task_data(self):
' |-- message_type: twisted:log\n'
' `-- timestamp: 1425356700\n\n'))

def test_dict_data(self):
"""
Task values that are ``dict``s are rendered as tree elements.
"""
fd = StringIO()
tree = Tree()
tree.merge_tasks([dict_action_task])
render_task_nodes(
write=fd.write,
nodes=tree.nodes(),
field_limit=0)
self.assertThat(
fd.getvalue(),
Equals(
'f3a32bb3-ea6b-457c-aa99-08a3d0491ab4\n'
' +-- app:action@1/started\n'
' |-- some_data:\n'
' `-- a: 42\n'
' `-- timestamp: 1425356800\n\n'))

def test_nested(self):
"""
Render nested tasks in a way that visually represents that nesting.
Expand Down

0 comments on commit 8d33e4e

Please sign in to comment.