def test_colorize(self): """ Passing ``colorize=True`` will colorize the output. """ fd = BytesIO() tree = Tree() tree.merge_tasks([action_task, action_task_end]) render_task_nodes( write=fd.write, nodes=tree.nodes(), field_limit=0, colorize=True) C = COLORS(colored) self.assertThat( fd.getvalue(), ExactlyEquals( u'\n'.join([ C.root(u'f3a32bb3-ea6b-457c-aa99-08a3d0491ab4'), u'\u2514\u2500\u2500 {}'.format( C.success(u'app:action@1/started')), u' \u251c\u2500\u2500 {}: {}'.format( C.prop(u'timestamp'), u'1425356800'), u' \u2514\u2500\u2500 {}'.format( C.success(u'app:action@2/succeeded')), u' \u2514\u2500\u2500 {}: {}'.format( C.prop('timestamp'), u'1425356802'), u'\n', ]).encode('utf-8')))
def test_multiple_lines(self): """ Truncate values that have more than a single line of text by only showing the first line. """ self.assertThat(format.truncate_value(10, u'abc\ndef'), ExactlyEquals(u'abc\u2026'))
def test_replace(self): """ Replace decoding errors with the Unicode replacement character. """ self.assertThat( format.binary('utf-32')(u'\N{SNOWMAN}'.encode('utf-8')), ExactlyEquals(u'\ufffd'))
def test_encoding(self): """ Binary values are decoded with the given encoding. """ self.assertThat( format.binary('utf-8')(u'\N{SNOWMAN}'.encode('utf-8')), ExactlyEquals(u'\u2603'))
def test_under(self): """ No truncation occurs if the length of the value is below the limit. """ self.assertThat( format.truncate_value(10, u'abcdefghijklmnopqrstuvwxyz'[:5]), ExactlyEquals(u'abcde'))
def test_over(self): """ Truncate values whose length is above the limit. """ self.assertThat( format.truncate_value(10, u'abcdefghijklmnopqrstuvwxyz'), ExactlyEquals(u'abcdefghij\u2026'))
def test_exact(self): """ No truncation occurs if the length of the value is exactly at the limit. """ self.assertThat( format.truncate_value(10, u'abcdefghijklmnopqrstuvwxyz'[:10]), ExactlyEquals(u'abcdefghij'))
def test_task(self): """ `Task`'s UUID is rendered. """ node = next(tasks_from_iterable([action_task])) self.assertThat( self.format_node(node), ExactlyEquals(node.root().task_uuid))
def test_tuple_other(self): """ Tuples can be a key and string, number, etc. rendered inline. """ node = (u'a\nb\x1bc', u'hello') self.assertThat( self.format_node(node, colors=colors), ExactlyEquals(u'{}: {}'.format( colors.prop(u'a\u240ab\u241bc'), u'hello'))) node = (u'a\nb\x1bc', 42) self.assertThat( self.format_node(node, colors=colors), ExactlyEquals(u'{}: {}'.format( colors.prop(u'a\u240ab\u241bc'), 42)))
def test_unicode(self): """ Pass ``unicode`` values straight through. """ format_value = _default_value_formatter(human_readable=False, field_limit=0) self.assertThat(format_value(u'\N{SNOWMAN}'), ExactlyEquals(u'\N{SNOWMAN}'))
def test_tuple_dict(self): """ Tuples whose value is a dict use the name in the first position of the tuple. """ get_name = get_name_factory(None) self.assertThat( get_name((u'key\x1bname', {})), ExactlyEquals(u'key\u241bname'))
def test_unicode_control_characters(self): """ Translate control characters to their Unicode "control picture" equivalent, instead of destroying a terminal. """ format_value = _default_value_formatter(human_readable=False, field_limit=0) self.assertThat(format_value(u'hello\001world'), ExactlyEquals(u'hello\u2401world'))
def test_tuple_unicode(self): """ Tuples whose value is unicode are a key/value pair. """ C = COLORS(colored) get_name = get_name_factory(C) self.assertThat( get_name((u'key\x1bname', u'hello')), ExactlyEquals(u'{}: hello'.format(C.prop(u'key\u241bname'))))
def test_local(self): """ Timestamps can be converted to local time. """ timestamp = 1433631432.0 utc = format.timestamp(utc_timestamps=True)(timestamp) local = format.timestamp(utc_timestamps=False)(timestamp + time.timezone) # Strip the "Z" off the end. self.assertThat(utc[:-1], ExactlyEquals(local))
def test_tuple_list(self): """ Tuples can be a key and list, in which case the value is not rendered here. """ node = (u'a\nb\x1bc', [u'x\n', u'y\x1b', u'z']) self.assertThat( self.format_node(node, colors=colors), ExactlyEquals(u'{}: '.format( colors.prop(u'a\u240ab\u241bc'))))
def test_mapping(self): """ Values for known field names are passed through their processor. """ fields = { u'a': format.binary('utf-8'), } self.assertThat( format.fields(fields)(u'\N{SNOWMAN}'.encode('utf-8'), u'a'), ExactlyEquals(u'\N{SNOWMAN}'))
def test_tuple_dict(self): """ Tuples can be a key and dict, in which case the value is not rendered here. """ node = (u'a\nb\x1bc', {u'x\n': u'y\x1b', u'z': u'zz'}) self.assertThat( self.format_node(node, colors=colors), ExactlyEquals(u'{}: {}'.format(colors.prop_key(u'a\u240ab\u241bc'), colors.prop_value(u''))))
def test_tuple_root(self): """ Tuples that are neither unicode nor a dict are assumed to be a root node. """ C = COLORS(colored) get_name = get_name_factory(C) self.assertThat( get_name((u'key\x1bname', None)), ExactlyEquals(C.root(u'key\u241bname')))
def test_dict_data(self): """ Task values that are ``dict``s are rendered as tree elements. """ self.assertThat( self.render_tasks([dict_action_task]), ExactlyEquals(u'f3a32bb3-ea6b-457c-aa99-08a3d0491ab4\n' u'\u2514\u2500\u2500 app:action/1 \u21d2 started ' u'1425356800\n' u' \u2514\u2500\u2500 some_data: \n' u' \u2514\u2500\u2500 a: 42\n\n'))
def test_anything(self): """ Pass unknown values to ``repr``. """ class _Thing(object): def __repr__(self): return 'Hello' format_value = _default_value_formatter(human_readable=False, field_limit=0) self.assertThat(format_value(_Thing()), ExactlyEquals(u'Hello'))
def test_ignored_keys(self): """ Task keys can be ignored. """ self.assertThat( self.render_tasks([action_task], ignored_fields={u'action_type'}), ExactlyEquals( u'f3a32bb3-ea6b-457c-aa99-08a3d0491ab4\n' u'\u2514\u2500\u2500 app:action/1 \u21d2 started ' u'1425356800\n' u' \u2514\u2500\u2500 action_status: started\n\n'))
def test_field_limit(self): """ Truncate task values that are longer than the field_limit if specified. """ self.assertThat( self.render_tasks([message_task], field_limit=5), ExactlyEquals(u'cdeb220d-7605-4d5f-8341-1a170222e308\n' u'\u2514\u2500\u2500 twisted:log/1 ' u'14253\u2026\n' u' \u251c\u2500\u2500 error: False\n' u' \u2514\u2500\u2500 message: Main \u2026\n\n'))
def test_timestamp_field_not_human(self): """ Do not format ``timestamp`` fields as human-readable if the feature was not requested. """ format_value = _default_value_formatter(human_readable=False, field_limit=0) # datetime(2015, 6, 6, 22, 57, 12) now = 1433631432 self.assertThat(format_value(now, u'timestamp'), ExactlyEquals(text_type(now)))
def test_nested(self): """ Render nested tasks in a way that visually represents that nesting. """ self.assertThat( self.render_tasks([action_task, nested_action_task]), ExactlyEquals( u'f3a32bb3-ea6b-457c-aa99-08a3d0491ab4\n' u'\u2514\u2500\u2500 app:action/1 \u21d2 started ' u'1425356800\n' u' \u2514\u2500\u2500 app:action:nest/1/1 \u21d2 started ' u'1425356900\n\n'))
def test_task_data(self): """ Task data is rendered as tree elements. """ self.assertThat( self.render_tasks([message_task]), ExactlyEquals( u'cdeb220d-7605-4d5f-8341-1a170222e308\n' u'\u2514\u2500\u2500 twisted:log/1 ' u'1425356700\n' u' \u251c\u2500\u2500 error: False\n' u' \u2514\u2500\u2500 message: Main loop terminated.\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. """ self.assertThat( self.render_tasks([multiline_action_task], field_limit=1000), ExactlyEquals( u'f3a32bb3-ea6b-457c-aa99-08a3d0491ab4\n' u'\u2514\u2500\u2500 app:action/1 \u21d2 started ' u'1425356800\n' u' \u2514\u2500\u2500 message: this is a\u2026\n\n'))
def test_node(self): """ Task nodes use their own name. """ tree = Tree() tree.merge_tasks([action_task]) node = tree.nodes()[0][1] C = COLORS(colored) get_name = get_name_factory(C) self.assertThat( get_name(node), ExactlyEquals(node.name))
def test_janky_message(self): """ Task names, UUIDs, keys and values in messages all have control characters escaped. """ self.assertThat( self.render_tasks([janky_message_task]), ExactlyEquals(u'cdeb220d-7605-4d5f-\u241b(08341-1a170222e308\n' u'\u2514\u2500\u2500 M\u241b(0/1 ' u'1425356700\n' u' \u251c\u2500\u2500 er\u241bror: False\n' u' \u2514\u2500\u2500 mes\u240asage: ' u'Main loop\u241b(0terminated.\n\n'))
def test_tasks(self): """ Render two tasks of sequential levels, by default most standard Eliot task keys are ignored. """ self.assertThat( self.render_tasks([action_task, action_task_end]), ExactlyEquals( u'f3a32bb3-ea6b-457c-aa99-08a3d0491ab4\n' u'\u2514\u2500\u2500 app:action/1 \u21d2 started ' u'1425356800 \u29d6 2\n' u' \u2514\u2500\u2500 app:action/2 \u21d2 succeeded ' u'1425356802\n\n'))
def test_node_failure(self): """ Task nodes indicating failure are colored. """ tree = Tree() tree.merge_tasks([action_task]) node = tree.nodes()[0][1].copy() node.success = False C = COLORS(colored) get_name = get_name_factory(C) self.assertThat( get_name(node), ExactlyEquals(C.failure(node.name)))