1use Test::More;
2
3use Bencode qw( bdecode );
4
5my @test = (
6	'0:0:'                     => \[ qr/\Atrailing garbage at 2\b/, 'data past end of first correct bencoded string' ],
7	'i'                        => \[ qr/\Aunexpected end of data at 1\b/, 'aborted integer' ],
8	'i0'                       => \[ qr/\Amalformed integer data at 1\b/, 'unterminated integer' ],
9	'ie'                       => \[ qr/\Amalformed integer data at 1\b/, 'empty integer' ],
10	'i341foo382e'              => \[ qr/\Amalformed integer data at 1\b/, 'malformed integer' ],
11	'i4e'                      => 4,
12	'i0e'                      => 0,
13	'i123456789e'              => 123456789,
14	'i-10e'                    => -10,
15	'i-0e'                     => \[ qr/\Amalformed integer data at 1\b/, 'negative zero integer' ],
16	'i123'                     => \[ qr/\Amalformed integer data at 1\b/, 'unterminated integer' ],
17	''                         => \[ qr/\Aunexpected end of data at 0/, 'empty data' ],
18	'1:'                       => \[ qr/\Aunexpected end of string data starting at 2\b/, 'string longer than data' ],
19	'i6easd'                   => \[ qr/\Atrailing garbage at 3\b/, 'integer with trailing garbage' ],
20	'35208734823ljdahflajhdf'  => \[ qr/\Agarbage at 0/, 'garbage looking vaguely like a string, with large count' ],
21	'2:abfdjslhfld'            => \[ qr/\Atrailing garbage at 4\b/, 'string with trailing garbage' ],
22	'0:'                       => '',
23	'3:abc'                    => 'abc',
24	'10:1234567890'            => '1234567890',
25	'02:xy'                    => \[ qr/\Amalformed string length at 0\b/, 'string with extra leading zero in count' ],
26	'l'                        => \[ qr/\Aunexpected end of data at 1\b/, 'unclosed empty list' ],
27	'le'                       => [],
28	'leanfdldjfh'              => \[ qr/\Atrailing garbage at 2\b/, 'empty list with trailing garbage' ],
29	'l0:0:0:e'                 => [ '', '', '' ],
30	'relwjhrlewjh'             => \[ qr/\Agarbage at 0/, 'complete garbage' ],
31	'li1ei2ei3ee'              => [ 1, 2, 3 ],
32	'l3:asd2:xye'              => [ 'asd', 'xy' ],
33	'll5:Alice3:Bobeli2ei3eee' => [ [ 'Alice', 'Bob' ], [ 2, 3 ] ],
34	'd'                        => \[ qr/\Aunexpected end of data at 1\b/, 'unclosed empty dict' ],
35	'defoobar'                 => \[ qr/\Atrailing garbage at 2\b/, 'empty dict with trailing garbage' ],
36	'de'                       => {},
37	'd3:agei25e4:eyes4:bluee'  => { 'age' => 25, 'eyes' => 'blue' },
38	'd8:spam.mp3d6:author5:Alice6:lengthi100000eee' => { 'spam.mp3' => { 'author' => 'Alice', 'length' => 100000 } },
39	'd3:fooe'                  => \[ qr/\Adict key is missing value at 7\b/, 'dict with odd number of elements' ],
40	'di1e0:e'                  => \[ qr/\Adict key is not a string at 1/, 'dict with integer key' ],
41	'd1:b0:1:a0:e'             => \[ qr/\Adict key not in sort order at 9/, 'missorted keys' ],
42	'd1:a0:1:a0:e'             => \[ qr/\Aduplicate dict key at 9/, 'duplicate keys' ],
43	'i03e'                     => \[ qr/\Amalformed integer data at 1/, 'integer with leading zero' ],
44	'l01:ae'                   => \[ qr/\Amalformed string length at 1/, 'list with string with leading zero in count' ],
45	'9999:x'                   => \[ qr/\Aunexpected end of string data starting at 5/, 'string shorter than count' ],
46	'l0:'                      => \[ qr/\Aunexpected end of data at 3/, 'unclosed list with content' ],
47	'd0:0:'                    => \[ qr/\Aunexpected end of data at 5/, 'unclosed dict with content' ],
48	'd0:'                      => \[ qr/\Aunexpected end of data at 3/, 'unclosed dict with odd number of elements' ],
49	'00:'                      => \[ qr/\Amalformed string length at 0/, 'zero-length string with extra leading zero in count' ],
50	'l-3:e'                    => \[ qr/\Amalformed string length at 1/, 'list with negative-length string' ],
51	'i-03e'                    => \[ qr/\Amalformed integer data at 1/, 'negative integer with leading zero' ],
52	"2:\x0A\x0D"               => "\x0A\x0D",
53	['d1:a0:e', 0, 1]          => { a => '' }, # Accept single dict when max_depth is 1
54	['d1:a0:e', 0, 0]          => \[ qr/\Anesting depth exceeded at 1/, 'single dict when max_depth is 0' ],
55	['d1:ad1:a0:ee', 0, 2]     => { a => { a => '' } }, # Accept a nested dict when max_depth is 2
56	['d1:ad1:a0:ee', 0, 1]     => \[ qr/\Anesting depth exceeded at 5/, 'nested dict when max_depth is 1' ],
57	['l0:e', 0, 1]             => [ '' ], # Accept single list when max_depth is 1
58	['l0:e', 0, 0]             => \[ qr/\Anesting depth exceeded at 1/, 'single list when max_depth is 0' ],
59	['ll0:ee', 0, 2]           => [ [ '' ] ], # Accept a nested list when max_depth is 2
60	['ll0:ee', 0, 1]           => \[ qr/\Anesting depth exceeded at 2/, 'nested list when max_depth is 1' ],
61	['d1:al0:ee', 0, 2]        => { a => [ '' ] }, # Accept dict containing list when max_depth is 2
62	['d1:al0:ee', 0, 1]        => \[ qr/\Anesting depth exceeded at 5/, 'list in dict when max_depth is 1' ],
63	['ld1:a0:ee', 0, 2]        => [ { 'a'  => '' } ], # Accept list containing dict when max_depth is 2
64	['ld1:a0:ee', 0, 1]        => \[ qr/\Anesting depth exceeded at 2/, 'dict in list when max_depth is 1' ],
65	['d1:a0:1:bl0:ee', 0, 2]   => { a => '', b => [ '' ] }, # Accept dict containing list when max_depth is 2
66	['d1:a0:1:bl0:ee', 0, 1]   => \[ qr/\Anesting depth exceeded at 10/, 'list in dict when max_depth is 1' ],
67);
68
69plan tests => 1 + @test / 2;
70
71while ( my ( $frozen, $thawed ) = splice @test, 0, 2 ) {
72	my $result;
73	my $testname;
74	my $lived = eval {
75		if ( ref $frozen eq 'ARRAY' ) {
76			local $, = ', ';
77			$testname = "decode [@$frozen]";
78			$result = bdecode( @$frozen );
79		}
80		else {
81			$testname = "decode '$frozen'";
82			$result = bdecode( $frozen );
83		}
84		1
85	};
86
87	if ( ref $thawed ne 'REF' ) {
88		is_deeply( $result, $thawed, $testname );
89	}
90	else {
91		my ( $error_rx, $kind_of_brokenness ) = @$$thawed;
92		like( $@, $error_rx, "reject $kind_of_brokenness" );
93	}
94}
95
96is_deeply(
97	bdecode( 'd1:b0:1:a0:e', 1 ),
98	{ a => '', b => '', },
99	'accept missorted keys when decoding leniently',
100);
101
102# vim: set ft=perl:
103