in reply to How can I enable utf8 layer on Test::More diag output

I ran into the exact same problem while testing Perl6::Str, and I worked around it with the following sub, through which I piped all my output to diag(). It doesn't display the non-ASCII-Characters, but it does enable very detailed analysis even on non-utf-8 terminals:
use charnames (); sub escape_str { my $str = shift; $str =~ s{([^\0-\177])}{_N_escape($1)}eg; return $str; } sub _N_escape { return '\N{' . charnames::viacode(ord($_[0])) . '}'; }

However your post encouraged me to dig into Test::More source code, and in Test::Builder I found this code:

sub _print_diag { my $self = shift; local($\, $", $,) = (undef, ' ', ''); my $fh = $self->todo ? $self->todo_output : $self->failure_output; print $fh @_; }

So it seems you have to get hold of a test builder object, and then binmode todo_output or failure_output (or both):

$ perl -MTest::More -wle 'binmode Test::More->builder->failure_output, + ":utf8"; diag chr(228)' # ä
Not pretty, but it works.

Replies are listed 'Best First'.
Re^2: How can I enable utf8 layer on Test::More diag output
by mje (Curate) on Jul 22, 2008 at 15:03 UTC
    Yes, see my post below. You can set the failure_output and the todo_output but I don't see a place to obtain the handle from Test::Builder, just a way to set it. As a result this works:
    use Test::More; # both of the following are too late for Test::More # because it has already duplicated STDOUT, STDERR binmode(STDOUT, ":utf8"); binmode(STDERR, ":utf8"): my $tb = Test::More->builder; $tb->failure_output(\*STDERR); $tb->todo_output(\*STDERR); $tb->output(\*STDOUT);
    now we can diag utf8 data.
      Here's how you obtain the handles with the same methods you use for setting them:
      my $b = Test::More->builder; binmode STDOUT, $b->failure_output, ':utf8';
      # both of the following are too late for Test::More # because it has already duplicated STDOUT, STDERR

      That's not quite the cause. If it where, the following would work:

      BEGIN { binmode STDOUT, ':utf8'; binmode STDERR, ':utf8'; } use Test::More;
      however, it doesn't work for me.

      still for a general-purpose module I wouldn't assume that the terminal necessarily accepts UTF-8.

        Thank you, I had not realised failure_output without any args returns the file handle already in use.

        On the other issue, it is a combination of Test::More duplicating the handles on load AND the fact it does not copy the IO layers when it duplicates them. As a result, I would not expect setting binmode in BEGIN to help.