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