| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
# You may distribute under the terms of either the GNU General Public License |
|
2
|
|
|
|
|
|
|
# or the Artistic License (the same terms as Perl itself) |
|
3
|
|
|
|
|
|
|
# |
|
4
|
|
|
|
|
|
|
# (C) Paul Evans, 2008-2011 -- leonerd@leonerd.org.uk |
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
package Test::HexString; |
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
our $VERSION = '0.03'; |
|
9
|
|
|
|
|
|
|
|
|
10
|
2
|
|
|
2
|
|
23423
|
use strict; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
78
|
|
|
11
|
2
|
|
|
2
|
|
16
|
use warnings; |
|
|
2
|
|
|
|
|
5
|
|
|
|
2
|
|
|
|
|
71
|
|
|
12
|
2
|
|
|
2
|
|
13
|
use base qw( Test::Builder::Module ); |
|
|
2
|
|
|
|
|
11
|
|
|
|
2
|
|
|
|
|
1952
|
|
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
our $CLASS = __PACKAGE__; |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
our @EXPORT = qw( |
|
17
|
|
|
|
|
|
|
is_hexstr |
|
18
|
|
|
|
|
|
|
); |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
our $BYTES_PER_BLOCK = 16; |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=head1 NAME |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
C - test binary strings with hex dump diagnostics |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
use Test::More tests => 1; |
|
29
|
|
|
|
|
|
|
use Test::HexString; |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
my $data = generate_some_output; |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
is_hexstr( $data, "\x01\x02\x03\x04", 'Generated output' ); |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
This testing module provides a single function, C, which asserts |
|
38
|
|
|
|
|
|
|
that the given string matches what was expected. When the strings match (i.e. |
|
39
|
|
|
|
|
|
|
compare equal using the C operator), the behaviour is identical to the |
|
40
|
|
|
|
|
|
|
usual C function provided by C. |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
When the strings are different, a hex dump is produced as diagnostic, rather |
|
43
|
|
|
|
|
|
|
than the string values being printed raw. This may be beneficial if the string |
|
44
|
|
|
|
|
|
|
contains largely binary data, such as may be produced by binary file or |
|
45
|
|
|
|
|
|
|
network protocol modules. |
|
46
|
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
To print the hex dump when it fails, each string is broken into 16 byte |
|
48
|
|
|
|
|
|
|
chunks. The first pair of chunks that fail to match are then printed, in both |
|
49
|
|
|
|
|
|
|
hexadecimal and character form, in a message in the following format: |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# Failed test at -e line 1. |
|
52
|
|
|
|
|
|
|
# at bytes 0-0xf (0-15) |
|
53
|
|
|
|
|
|
|
# got: | 61 20 6c 6f 6e 67 20 73 74 72 69 6e 67 20 68 65 |a long string he| |
|
54
|
|
|
|
|
|
|
# exp: | 61 20 6c 6f 6e 67 20 53 74 72 69 6e 67 20 68 65 |a long String he| |
|
55
|
|
|
|
|
|
|
# Looks like you failed 1 test of 1. |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
Only bytes in the range C<0x20-0x7e> are printed as literal characters. Any |
|
58
|
|
|
|
|
|
|
other byte is rendered as C<.>: |
|
59
|
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
# Failed test at -e line 1. |
|
61
|
|
|
|
|
|
|
# at bytes 0-0xf (0-15) |
|
62
|
|
|
|
|
|
|
# got: | 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f |................| |
|
63
|
|
|
|
|
|
|
# exp: | 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 |................| |
|
64
|
|
|
|
|
|
|
# Looks like you failed 1 test of 1. |
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
Only the first differing line is printed; because otherwise it may result in a |
|
67
|
|
|
|
|
|
|
long output because of misaligned bytes. |
|
68
|
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
If STDOUT is a terminal, then different bytes are printed in bold for |
|
70
|
|
|
|
|
|
|
visibility. |
|
71
|
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
=cut |
|
73
|
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
sub _bold |
|
75
|
|
|
|
|
|
|
{ |
|
76
|
104
|
|
|
104
|
|
131
|
my ( $str, $bold ) = @_; |
|
77
|
104
|
50
|
|
|
|
748
|
return $str unless -t STDOUT; |
|
78
|
0
|
0
|
|
|
|
0
|
return $bold ? "\e[1m$str\e[m" : $str; |
|
79
|
|
|
|
|
|
|
} |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
sub _hexline |
|
82
|
|
|
|
|
|
|
{ |
|
83
|
6
|
|
|
6
|
|
13
|
my ( $bytes, $boldmap ) = @_; |
|
84
|
|
|
|
|
|
|
|
|
85
|
6
|
|
|
|
|
46
|
my @b = split( m//, $bytes ); |
|
86
|
|
|
|
|
|
|
|
|
87
|
6
|
|
|
|
|
10
|
my $ret = "| "; |
|
88
|
6
|
|
|
|
|
34
|
$ret .= _bold(sprintf( "%02x ", ord $b[$_] ), $boldmap->[$_] ) for 0 .. $#b; |
|
89
|
6
|
|
|
|
|
17
|
$ret .= ".. " x ( $BYTES_PER_BLOCK - @b ); |
|
90
|
6
|
|
|
|
|
9
|
$ret .= "|"; |
|
91
|
6
|
100
|
|
|
|
31
|
$ret .= _bold($b[$_] =~ /[\x20-\x7e]/ ? $b[$_] : ".", $boldmap->[$_] ) for 0 .. $#b; |
|
92
|
6
|
|
|
|
|
14
|
$ret .= " " x ( $BYTES_PER_BLOCK - @b ); |
|
93
|
6
|
|
|
|
|
7
|
$ret .= "|"; |
|
94
|
|
|
|
|
|
|
|
|
95
|
6
|
|
|
|
|
34
|
return $ret; |
|
96
|
|
|
|
|
|
|
} |
|
97
|
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
=head1 FUNCTIONS |
|
99
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
=cut |
|
101
|
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
=head2 is_hexstr( $got, $expect, $name ) |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
Test that the string $got is what was expected by $expect. If the strings are |
|
105
|
|
|
|
|
|
|
not equal, a hex dump is printed showing the region where they first start to |
|
106
|
|
|
|
|
|
|
differ. |
|
107
|
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
=cut |
|
109
|
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
sub is_hexstr($$;$) |
|
111
|
|
|
|
|
|
|
{ |
|
112
|
5
|
|
|
5
|
1
|
3222
|
my ( $got, $expected, $name ) = @_; |
|
113
|
|
|
|
|
|
|
|
|
114
|
5
|
|
|
|
|
34
|
my $tb = $CLASS->builder; |
|
115
|
|
|
|
|
|
|
|
|
116
|
5
|
100
|
|
|
|
45
|
if( ref $got ) { |
|
117
|
1
|
|
|
|
|
4
|
my $ok = $tb->ok( 0, $name ); |
|
118
|
1
|
|
|
|
|
582
|
$tb->diag( " expected a plain string, was given a reference to " . ref($got) ); |
|
119
|
1
|
|
|
|
|
81
|
return $ok; |
|
120
|
|
|
|
|
|
|
} |
|
121
|
|
|
|
|
|
|
|
|
122
|
4
|
|
|
|
|
15
|
my $ok = $tb->ok( $got eq $expected, $name ); |
|
123
|
|
|
|
|
|
|
|
|
124
|
4
|
100
|
|
|
|
1859
|
unless( $ok ) { |
|
125
|
|
|
|
|
|
|
# Try to find where they differ |
|
126
|
3
|
|
|
|
|
14
|
for( my $offs = 0; $offs < length $got; $offs += $BYTES_PER_BLOCK ) { |
|
127
|
65
|
|
|
|
|
76
|
my $g = substr( $got, $offs, $BYTES_PER_BLOCK ); |
|
128
|
65
|
|
|
|
|
72
|
my $e = substr( $expected, $offs, $BYTES_PER_BLOCK ); |
|
129
|
65
|
100
|
|
|
|
195
|
next if $g eq $e; |
|
130
|
|
|
|
|
|
|
|
|
131
|
3
|
100
|
66
|
|
|
9
|
my @bold = map { $_ < length $g and $_ < length $e and substr( $g, $_, 1 ) ne substr( $e, $_, 1 ) } |
|
|
48
|
|
|
|
|
202
|
|
|
132
|
|
|
|
|
|
|
( 0 .. $BYTES_PER_BLOCK-1 ); |
|
133
|
|
|
|
|
|
|
|
|
134
|
3
|
|
|
|
|
29
|
$tb->diag( sprintf( " at bytes %#x-%#x (%d-%d)\n", |
|
135
|
|
|
|
|
|
|
$offs, $offs+$BYTES_PER_BLOCK-1, $offs, $offs+$BYTES_PER_BLOCK-1 ) . |
|
136
|
|
|
|
|
|
|
" got: " . _hexline( $g, \@bold ) . "\n" . |
|
137
|
|
|
|
|
|
|
" exp: " . _hexline( $e, \@bold ) |
|
138
|
|
|
|
|
|
|
); |
|
139
|
|
|
|
|
|
|
|
|
140
|
3
|
|
|
|
|
264
|
last; |
|
141
|
|
|
|
|
|
|
} |
|
142
|
|
|
|
|
|
|
} |
|
143
|
|
|
|
|
|
|
|
|
144
|
4
|
|
|
|
|
10
|
return $ok; |
|
145
|
|
|
|
|
|
|
} |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
=head1 AUTHOR |
|
148
|
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
Paul Evans |
|
150
|
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
=cut |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
0x55AA; |