ok( $client->on_event(
        q[peer_read],
        sub {
            my ($self, $args) = @_;
            is($self, $client,
                q[Correct args passed to 'peer_read' [$_[0]]]);
            isa_ok($args->{q[Peer]}, q[Net::BitTorrent::Peer],
                   q[  ... [$_[1]->{'Peer'}]]);
            like($args->{q[Length]}, qr[^\d+$],
                 q[  ... [$_[1]->{'Length'}]]);
            my $peer = $args->{q[Peer]};
            delete $args->{q[Peer]};
            my $_len = $args->{q[Length]};
            delete $args->{q[Length]};
            is_deeply($args, {}, q[  ... No other keys in $_[1]]);
            warn(sprintf(q[Read %d bytes from '%s'],
                         $_len, $peer->as_string
                 )
            );
        }
    ),
    q[Installed 'peer_read' event handler]
);
ok( $client->on_event(
        q[peer_write],
        sub {
            my ($self, $args) = @_;
            is($self, $client,
                q[Correct args passed to 'peer_read' [$_[0]]]);
            isa_ok($args->{q[Peer]}, q[Net::BitTorrent::Peer],
                   q[  ... [$_[1]->{'Peer'}]]);
            like($args->{q[Length]}, qr[^\d+$],
                 q[  ... [$_[1]->{'Length'}]]);
            my $peer = $args->{q[Peer]};
            delete $args->{q[Peer]};
            my $_len = $args->{q[Length]};
            delete $args->{q[Length]};
            is_deeply($args, {}, q[  ... No other keys in $_[1]]);
            warn(sprintf(q[Wrote %d bytes from '%s'],
                         $_len, $peer->as_string
                 )
            );
        }
    ),
    q[Installed 'peer_write' event handler]
);
ok( $client->on_event(
        q[peer_disconnect],
        sub {
            my ($self, $args) = @_;
            is($self, $client,
                q[Correct args passed to 'peer_disconnect' [$_[0]]]);
            isa_ok($args->{q[Peer]}, q[Net::BitTorrent::Peer],
                   q[  ... [$_[1]->{'Peer'}]]);
            ok(defined($args->{q[Reason]}), q[  ... [$_[1]->{'Reason'}]]);
            my $peer = $args->{q[Peer]};
            delete $args->{q[Peer]};
            my $_why = $args->{q[Reason]};
            delete $args->{q[Reason]};
            is_deeply($args, {}, q[  ... No other keys in $_[1]]);
            warn(sprintf(q[Disconnected from '%s'%s],
                         $peer->as_string,
                         ($_why
                          ? (q[ (] . $_why . q[)])
                          : q[]
                         )
                 )
            );
        }
    ),
    q[Installed 'peer_disconnect' event handler]
);
ok( $client->on_event(
        q[peer_connect],
        sub {
            my ($self, $args) = @_;
            is($self, $client,
                q[Correct args passed to 'peer_connect' [$_[0]]]);
            isa_ok($args->{q[Peer]}, q[Net::BitTorrent::Peer],
                   q[  ... [$_[1]->{'Peer'}]]);
            my $peer = $args->{q[Peer]};
            delete $args->{q[Peer]};
            is_deeply($args, {}, q[  ... No other keys in $_[1]]);
            like($peer->_host . q[:] . $peer->_port,
                 qr[127.0.0.1:\d+],
                 sprintf q[%s connection %s '%s'],
                 ($peer->_incoming ? q[Incoming] : q[Outgoing]),
                 ($peer->_incoming ? q[from]     : q[to]),
                 $peer->as_string
            );
            return 1;
        }
    ),
    q[Installed 'peer_connect' event handler]
);
my @request_offsets = qw[0     16384 0     16384 16344 16354];
my @request_lengths = qw[16384 16384 16384 16384 16384 46384];
my @cancel_offsets  = reverse @request_offsets;
my @indexes         = (0 .. 10);                                 # have
ok( $client->on_event(
        q[incoming_packet],
        sub {
            my ($self, $args) = @_;
            my $type    = $args->{q[Type]};
            my $peer    = $args->{q[Peer]};
            my $payload = $args->{q[Payload]};
            if ($type eq KEEPALIVE) {
                warn q[TODO: keepalive];
            }
            elsif ($type == HANDSHAKE) {
                is($self, $client,
                    q[Correct args passed to 'packet_incoming_handshake' [$_[0]]]
                );
                isa_ok($args->{q[Peer]},
                       q[Net::BitTorrent::Peer],
                       q[  ... [$_[1]->{'Peer'}]]
                );
                is(scalar(keys %{$args->{'Payload'}}),
                    3, q[  ... scalar(keys %{$payload})]);
                is(length($args->{'Payload'}{q[Reserved]}),
                    8, q[  ... reserved conforms to spec]);
                is(length($args->{'Payload'}{q[Infohash]}),
                    20, q[  ... infohash conforms to spec]);
                is(length($args->{'Payload'}{q[PeerID]}),
                    20, q[  ... peerid conforms to spec]);
                delete $args->{q[Peer]};
                my $_len = $args->{q[Payload]};
                delete $args->{q[Payload]};
                is_deeply($args,
                          {Type => HANDSHAKE},
                          q[  ... No other keys in $_[1]]);

                if (   ($peer->peerid eq q[B] x 20)
                    or ($peer->peerid eq q[C] x 20)
                    or ($peer->peerid eq q[UNKNOWN-------------]))
                {   pass(sprintf q[PeerID is okay (%s)], $peer->peerid);
                }
                elsif ($peer->peerid eq $self->peerid) {
                    pass(sprintf q[Peerid match: %s eq %s],
                         $self->peerid, $peer->peerid);
                }
                else {
                    die(sprintf q[Unknown peerid: %s], $peer->peerid);
                }
            }
            elsif ($type == CHOKE) {
                my ($self, $args) = @_;
                is($self, $client,
                    q[Correct args passed to 'packet_incoming_choke' [$_[0]]]
                );
                isa_ok($args->{q[Peer]},
                       q[Net::BitTorrent::Peer],
                       q[  ... [$_[1]->{'Peer'}]]
                );
                delete $args->{q[Peer]};
                is_deeply($args,
                          {Payload => {}, Type => CHOKE},
                          q[  ... No other keys in $_[1]]);
                is($peer->peerid, q[C] x 20, q[Choked by 'CC..CC']);
            }
            elsif ($type == UNCHOKE) {
                my ($self, $args) = @_;
                is($self, $client,
                    q[Correct args passed to 'packet_incoming_unchoke' [$_[0]]]
                );
                isa_ok($args->{q[Peer]},
                       q[Net::BitTorrent::Peer],
                       q[  ... [$_[1]->{'Peer'}]]
                );
                delete $args->{q[Peer]};
                is_deeply($args,
                          {Payload => {}, Type => UNCHOKE},
                          q[  ... No other keys in $_[1]]);
                is($peer->peerid, q[C] x 20, q[Unchoked by 'CC..CC']);
            }
            elsif ($type == INTERESTED) {
                is($self, $client,
                    q[Correct args passed to 'packet_incoming_unchoke' [$_[0]]]
                );
                isa_ok($args->{q[Peer]},
                       q[Net::BitTorrent::Peer],
                       q[  ... [$_[1]->{'Peer'}]]
                );
                delete $args->{q[Peer]};
                is_deeply($args,
                          {Payload => {}, Type => INTERESTED},
                          q[  ... No other keys in $_[1]]);
                warn(
                    sprintf(q[%s is interested in me], $peer->as_string));
            }
            elsif ($type == NOT_INTERESTED) {
                is($self, $client,
                    q[Correct args passed to 'packet_incoming_unchoke' [$_[0]]]
                );
                isa_ok($args->{q[Peer]},
                       q[Net::BitTorrent::Peer],
                       q[  ... [$_[1]->{'Peer'}]]
                );
                delete $args->{q[Peer]};
                is_deeply($args,
                          {Payload => {}, Type => NOT_INTERESTED},
                          q[  ... No other keys in $_[1]]);
                warn(
                    sprintf(q[%s is interested in me], $peer->as_string));
            }
            elsif ($type == HAVE) {
                delete $_[1]->{q[Peer]};
                is_deeply(\@_,
                          [$client,
                           {Payload => {Index => shift(@indexes)},
                            Type    => HAVE
                           }
                          ],
                          q[Correct arguments passed to 'packet_incoming_have' event handler]
                );
                if ($peer->peerid eq q[C] x 20) {
                    if ($payload->{q[Index]} == 0) {
                        pass(q[Good peer has i:0]);
                    }
                    elsif ($payload->{q[Index]} == 1) {
                        pass(q[Good peer has i:1]);
                    }
                    else {
                        die(sprintf q[Peer claims to have %d],
                             $payload->{q[Index]});
                    }
                }
                else {
                    die(sprintf q[Unknown peer '%s' has %d],
                         $peer->peerid, $args->{q[Index]});
                }
            }
            elsif ($type == BITFIELD) {
                is($self, $client,
                    q[Correct args passed to 'packet_incoming_bitfield' [$_[0]]]
                );
                isa_ok($args->{q[Peer]},
                       q[Net::BitTorrent::Peer],
                       q[  ... [$_[1]->{'Peer'}]]
                );
                delete $args->{q[Peer]};
                is_deeply($args,
                          {Type    => BITFIELD,
                           Payload => {}
                          },
                          q[  ... No other keys in $_[1]]
                );
                if (   ($peer->peerid eq q[B] x 20)
                    or ($peer->peerid eq q[C] x 20))
                {   pass(sprintf q[PeerID is okay (%s)], $peer->peerid);
                }
                elsif ($peer->peerid eq $self->peerid) {
                    pass(sprintf q[Peerid match: %s eq %s],
                         $self->peerid, $peer->peerid);
                }
                else {
                    die(sprintf q[Unknown peerid: %s], $peer->peerid);
                }
                warn(sprintf(q[Bitfield from %s], $peer->as_string));
            }
            elsif ($type == REQUEST) {
                warn sprintf q[%s is requesting [I:%4d O:%6d L:%6d]],
                    $peer->as_string,
                    $payload->{q[Index]},
                    $payload->{q[Offset]},
                    $payload->{q[Length]};
            }
            elsif ($type == PIECE) {
                delete $_[1]->{q[Peer]};
                is_deeply(\@_,
                          [$client,
                           {Payload => {Index  => 0,
                                        Length => 16384,
                                        Offset => 0
                            },
                            Type => PIECE
                           }
                          ],
                          q[Correct args passed to 'packet_incoming_block' event handler]
                );
                is($peer->_torrent->downloaded,
                    16384, q[Torrent downloaded amount updated]);
                warn(
                    sprintf
                        q[%s sent us [I:%4d O:%6d L:%6d] I have now downloaded %d bytes],
                    $peer->as_string,      $payload->{q[Index]},
                    $payload->{q[Offset]}, $payload->{q[Length]},
                    $peer->_torrent->downloaded
                );
            }
            elsif ($type == CANCEL) {
                ok( 1,
                    sprintf q[%s has canceled [I:%4d O:%6d L:%6d]],
                    $peer->as_string,
                    $args->{q[Index]},
                    $args->{q[Offset]},
                    $args->{q[Length]}
                );
            }
            elsif ($type == HAVE_ALL) {
                ok(1, sprintf q[%s says they have everything],
                    $peer->as_string);
            }
            elsif ($type == HAVE_NONE) {
                ok(1, sprintf q[%s says they have nothing],
                    $peer->as_string);
            }
            else { die q[Unhandled packet: ] . $type }
        }
    ),
    q[Installed 'incoming_packet' event handler (TODO)]
);
ok( $client->on_event(
        q[outgoing_packet],
        sub {
            my ($self, $args) = @_;
            my $type    = $args->{q[Type]};
            my $peer    = $args->{q[Peer]};
            my $payload = $args->{q[Payload]};
            if ($type == HANDSHAKE) {
                is($self, $client,
                    q[Correct args passed for outgoing handshake [$_[0]]]
                );
                isa_ok($peer, q[Net::BitTorrent::Peer],
                       q[  ... [$_[1]->{'Peer'}]]);
                is(scalar(keys %{$payload}),
                    3, q[  ... scalar(@{$payload})]);
                is(length($payload->{q[Reserved]}), 8,
                    q[  ... [length($payload->{q[Reserved]}) ==  8] (reserved)]
                );
                is(length($payload->{q[Infohash]}), 20,
                    q[  ... [length($payload->{q[Infohash]}) == 20] (infohash)]
                );
                is(length($payload->{q[PeerID]}), 20,
                    q[  ... [length($payload->{q[PeerID]}) == 20] (peerid)]
                );
                delete $args->{q[Peer]};
                my $_len = $args->{q[Payload]};
                delete $args->{q[Payload]};
                is_deeply($args,
                          {Type => HANDSHAKE},
                          q[  ... No other keys in $_[1]]);

                if ($peer->_incoming) {
                    if (   ($peer->peerid eq q[B] x 20)
                        or ($peer->peerid eq q[C] x 20)
                        or ($peer->peerid eq q[UNKNOWN-------------]))
                    {   pass(sprintf q[PeerID is okay (%s)],
                             $peer->peerid);
                    }
                    elsif ($peer->peerid eq $self->peerid) {
                        pass(sprintf q[Peerid match: %s eq %s],
                             $self->peerid, $peer->peerid);
                    }
                    else {
                        die(sprintf q[Unknown peerid: %s],
                             $peer->peerid);
                    }
                }
            }
            elsif ($type == UNCHOKE) {
                my ($self, $args) = @_;
                is($self, $client,
                    q[Correct args passed to 'outgoing unchoke' [$_[0]]]);
                isa_ok($args->{q[Peer]},
                       q[Net::BitTorrent::Peer],
                       q[  ... [$_[1]->{'Peer'}]]
                );
                delete $args->{q[Peer]};
                is_deeply($args,
                          {Payload => {}, Type => UNCHOKE},
                          q[  ... No other keys in $_[1]]);
                warn(sprintf(q[Unchoking %s], $peer->as_string));
            }
            elsif ($type == REQUEST) {
                warn(sprintf q[Requesting [I:%4d O:%6d L:%6d] from %s],
                     $payload->{q[Index]},  $payload->{q[Offset]},
                     $payload->{q[Length]}, $peer->as_string
                );
                is($self, $client,
                    q[Correct args passed to 'outgoing request' [$_[0]]]);
                isa_ok($args->{q[Peer]},
                       q[Net::BitTorrent::Peer],
                       q[  ... [$_[1]->{'Peer'}]]
                );
                delete $args->{q[Peer]};
                like($args->{q[Payload]}{q[Index]},
                     qr[^\d+$], q[  ... [$_[1]->{'Payload'}{'Index'}]]);
                delete $args->{q[Payload]}{q[Index]};
                like($args->{q[Payload]}{q[Offset]},
                     qr[^\d+$], q[  ... [$_[1]->{'Payload'}{'Offset'}]]);
                delete $args->{q[Payload]}{q[Offset]};
                like($args->{q[Payload]}{q[Length]},
                     qr[^\d+$], q[  ... [$_[1]->{'Payload'}{'Length'}]]);
                delete $args->{q[Payload]}{q[Length]};
                is_deeply($args,
                          {Payload => {}, Type => REQUEST},
                          q[Correct args passed to 'outgoing request' event handler]
                );
            }
            elsif ($type == CANCEL) {
                is($self, $client,
                    q[Correct args passed to 'outgoing cancel' [$_[0]]]);
                isa_ok($args->{q[Peer]},
                       q[Net::BitTorrent::Peer],
                       q[  ... [$_[1]->{'Peer'}]]
                );
                delete $args->{q[Peer]};
                like($args->{q[Payload]}{q[Index]},
                     qr[^\d+$], q[  ... [$_[1]->{'Payload'}{'Index'}]]);
                delete $args->{q[Payload]}{q[Index]};
                like($args->{q[Payload]}{q[Offset]},
                     qr[^\d+$], q[  ... [$_[1]->{'Payload'}{'Offset'}]]);
                delete $args->{q[Payload]}{q[Offset]};
                like($args->{q[Payload]}{q[Length]},
                     qr[^\d+$], q[  ... [$_[1]->{'Payload'}{'Length'}]]);
                delete $args->{q[Payload]}{q[Length]};
                is_deeply($args,
                          {Payload => {}, Type => CANCEL},
                          q[Correct args passed to 'outgoing cancel' event handler]
                );
                warn(sprintf q[Canceling [I:%4d O:%6d L:%6d] from %s],
                     $payload->{q[Index]},  $payload->{q[Offset]},
                     $payload->{q[Length]}, $peer->as_string
                );
            }
            elsif ($type == PIECE) {
                warn sprintf
                    q[Sending [I:%4d O:%6d L:%6d] to %s. I have now uploaded %d bytes],
                    $payload->{q[Index]},
                    $payload->{q[Offset]},
                    $payload->{q[Length]},
                    $peer->as_string,
                    $peer->_torrent->uploaded;
            }
            elsif ($type == INTERESTED) {
                my ($self, $args) = @_;
                is($self, $client,
                    q[Correct args passed to 'outgoing interested' [$_[0]]]
                );
                isa_ok($args->{q[Peer]},
                       q[Net::BitTorrent::Peer],
                       q[  ... [$_[1]->{'Peer'}]]
                );
                delete $args->{q[Peer]};
                is_deeply($args,
                          {Type => INTERESTED, Payload => {}},
                          q[  ... No other keys in $_[1]]);
                warn(sprintf(q[I am interested in %s], $peer->as_string));
            }
            elsif ($type == CHOKE) {
                warn sprintf q[ ===> Choking %s], $peer->as_string;
            }
            elsif ($type == BITFIELD) {
                is($self, $client,
                    q[Correct args passed to 'outgoing bitfield' [$_[0]]]
                );
                isa_ok($args->{q[Peer]},
                       q[Net::BitTorrent::Peer],
                       q[  ... [$_[1]->{'Peer'}]]
                );
                delete $args->{q[Peer]};
                is_deeply($args,
                          {Type => BITFIELD},
                          q[  ... No other keys in $_[1]]);
                warn(sprintf(q[Sent bitfield to %s], $peer->as_string));
            }
            elsif ($type == HAVE_NONE) {
                is($self, $client,
                    q[Correct args passed to 'outgoing have none' [$_[0]]]
                );
                isa_ok($args->{q[Peer]},
                       q[Net::BitTorrent::Peer],
                       q[  ... [$_[1]->{'Peer'}]]
                );
                delete $args->{q[Peer]};
                is_deeply($args,
                          {Type => HAVE_NONE, Payload => {}},
                          q[  ... No other keys in $_[1]]);
            }
            elsif ($type == EXTPROTOCOL) {
                is($self, $client,
                    q[Correct args passed to 'outgoing extended protocol' [$_[0]]]
                );
                isa_ok($args->{q[Peer]},
                       q[Net::BitTorrent::Peer],
                       q[  ... [$_[1]->{'Peer'}]]
                );
                delete $args->{q[Peer]};
                delete $args->{q[Payload]};
                delete $args->{q[ID]};
                is_deeply($args,
                          {Type => EXTPROTOCOL},
                          q[  ... No other keys in $_[1]]);
            }
            else { warn q[****************** Unhandled packet: ] . $type }
        }
    ),
    q[Installed 'outgoing_packet' event handler]
);
ok( $client->on_event(
        q[ip_filter],
        sub {
            my ($self, $args) = @_;
            is($self, $client,
                q[Correct params passed to 'ip_filter' ($_[0])]);
        TODO: {
                local $TODO = q[Temporary DHT boot node breaks this test];
                like(
                    $args->{q[Address]},   # XXX - removed for DHT testing
                    qr[^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$],
                    q[  ... ($_[1]->{'Address'})]
                );
            }
            my $address = $args->{'Address'};
            delete $args->{'Address'};
            is_deeply(
                $args,
                {},
                q[Correct params passed to 'ip_filter' (  ... No other keys in $_[1])]
            );
            warn(sprintf(q[Check IP filter for %s], $address));
            return 1;
        }
    ),
    q[Installed 'ip_filter' event handler]
);
warn sprintf q[%d|%d], 7, $test_builder->{q[Curr_Test]};
warn(q[Net::BitTorrent::Peer->new() requires params...]);
is(Net::BitTorrent::Peer->new(),   undef, q[No params]);
is(Net::BitTorrent::Peer->new({}), undef, q[Empty hashref]);
is(Net::BitTorrent::Peer->new({Socket => undef}),
    undef, q[Socket => undef]);
is(Net::BitTorrent::Peer->new({Socket => 0}), undef, q[Socket => 0]);
is(Net::BitTorrent::Peer->new({Socket => bless {}, q[GLOB]}),
    undef, q[Missing Client]);
is( Net::BitTorrent::Peer->new({Socket => bless({}, q[GLOB]), Client => 0}
    ),
    undef,
    q[Client => 0]
);
is( Net::BitTorrent::Peer->new({Socket => bless(\{}, q[GLOB]),
                                Client => bless(\{}, q[junk])
                               }
    ),
    undef,
    q[Client => bless \{}, 'junk']
);
warn sprintf q[%d|%d], 14, $test_builder->{q[Curr_Test]};
warn(q[For this next bit, we're testing outgoing peers...]);
is( Net::BitTorrent::Peer->new({Client  => $client,
                                Torrent => $torrent,
                                Address => q[junk]
                               }
    ),
    undef,
    q[Address => 'junk']
);
is( Net::BitTorrent::Peer->new({Client  => $client,
                                Torrent => $torrent,
                                Address => undef
                               }
    ),
    undef,
    q[Address => undef]
);
is( Net::BitTorrent::Peer->new({Client  => $client,
                                Address => q[127.0.0.1:0]
                               }
    ),
    undef,
    q[Missing Torrent]
);
is( Net::BitTorrent::Peer->new({Client  => $client,
                                Torrent => undef,
                                Address => q[127.0.0.1:0]
                               }
    ),
    undef,
    q[Torrent => undef]
);
is( Net::BitTorrent::Peer->new({Client  => $client,
                                Torrent => 0,
                                Address => q[127.0.0.1:0]
                               }
    ),
    undef,
    q[Torrent => 0]
);
is( Net::BitTorrent::Peer->new({Client  => $client,
                                Torrent => 'junk',
                                Address => q[127.0.0.1:0]
                               }
    ),
    undef,
    q[Torrent => 'junk']
);
is( Net::BitTorrent::Peer->new({Client  => $client,
                                Torrent => bless(\{}, 'junk'),
                                Address => q[127.0.0.1:0]
                               }
    ),
    undef,
    q[Torrent => bless(\{}, 'junk')]
);
is( Net::BitTorrent::Peer->new({Client  => $client,
                                Torrent => $torrent,
                                Address => q[127.0.0.1:0]
                               }
    ),
    undef,
    q[No Source]
);
is( Net::BitTorrent::Peer->new({Client  => $client,
                                Torrent => $torrent,
                                Address => q[127.0.0.1:0],
                                Source  => undef
                               }
    ),
    undef,
    q[Source => undef]
);
warn sprintf q[%d|%d], 21, $test_builder->{q[Curr_Test]};
warn(q[Test incoming peers]);
{
    $peers{q[A]} =
        Net::BitTorrent::Peer->new({Client  => $client,
                                    Torrent => $torrent,
                                    Address => q[127.0.0.1:0],
                                    Source  => q[User]
                                   }
        );
    isa_ok($peers{q[A]}, q[Net::BitTorrent::Peer], q[new()]);
    weaken $peers{q[A]};
    ok(isweak($peers{q[A]}),    q[  ...make $peers{q[A]} a weak ref]);
    ok($peers{q[A]}->as_string, q[as_string]);
    is($peers{q[A]}->as_string,
        $peers{q[A]}->as_string(0),
        q[as_string() vs as_string(0)]);
    isn't($peers{q[A]}->as_string,
          $peers{q[A]}->as_string(1),
          q[as_string() vs as_string(1)]);
    sub TIEHANDLE { pass(q[Tied STDERR]); bless \{}, shift; }

    sub PRINT {
        is((caller(0))[0],
            q[Net::BitTorrent::Peer], q[String written to STDERR]);
    }
    sub UNTIE { pass(q[Untied STDERR]); }
    tie(*STDERR, __PACKAGE__);
    $peers{q[A]}->as_string;
    $peers{q[A]}->as_string(1);
    untie *STDERR;
    isa_ok($peers{q[A]}->_socket, q[GLOB], q[_socket]);
    isa_ok($peers{q[A]}->_torrent,
           q[Net::BitTorrent::Torrent], q[_torrent]);
    is($peers{q[A]}->_bitfield,     "\0", q[_bitfield]);
    is($peers{q[A]}->_peer_choking, 1,    q[Default peer_choking status]);
    is($peers{q[A]}->_am_choking,   1,    q[Default am_choking status]);
    is($peers{q[A]}->_peer_interested,
        0, q[Default peer_interested status]);
    is($peers{q[A]}->_am_interested, 0, q[Default am_interested status]);
    is($peers{q[A]}->_incoming,      0, q[Direction status is correct.]);
    warn sprintf q[%d|%d], 39, $test_builder->{q[Curr_Test]};
}
{
    my $newsock_A = newsock($client);
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    warn sprintf q[%d|%d], 44, $test_builder->{q[Curr_Test]};
    is( syswrite($newsock_A,
                 build_handshake(chr(0) x 8, q[A] x 20, q[B] x 20)
        ),
        68,
        q[Sent handshake to client]
    );
    my $with_peer = scalar keys %{$client->_connections};
    is(syswrite($newsock_A, build_bitfield(chr(1))),
        6, q[Sent bitfield to client]);
    is(syswrite($newsock_A, build_bitfield(chr(0))),
        6, q[Sent bitfield to client]);
    is(syswrite($newsock_A, build_bitfield(chr(0))),
        6, q[Sent bitfield to client]);
    is(syswrite($newsock_A, build_bitfield(chr(0))),
        6, q[Sent bitfield to client]);
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    ok(($with_peer > scalar keys %{$client->_connections}),
        q[Peer removed from list of connections]);
    warn sprintf q[%d|%d], 71, $test_builder->{q[Curr_Test]};
}
{
    my $newsock_B = newsock($client);
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    is( syswrite($newsock_B,
                 build_handshake(chr(0) x 8,
                                 pack(q[H40], $torrent->infohash),
                                 $client->peerid
                 )
        ),
        68,
        q[Sent handshake to client]
    );
    my $with_peer = scalar keys %{$client->_connections};
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    ok(($with_peer > scalar keys %{$client->_connections}),
        q[Peer removed from list of connections]);
    warn sprintf q[%d|%d], 99, $test_builder->{q[Curr_Test]};
}
{
    my $newsock_C = newsock($client);
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    is( syswrite($newsock_C,
                 build_handshake(chr(0) x 8,
                                 pack(q[H40], $torrent->infohash),
                                 q[C] x 20
                 )
        ),
        68,
        q[Sent handshake to client]
    );
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    ($peers{q[C]}) = map {
        (    $_->{q[Object]}->isa(q[Net::BitTorrent::Peer])
         and defined $_->{q[Object]}->peerid
         and ($_->{q[Object]}->peerid eq q[C] x 20))
            ? $_->{q[Object]}
            : ()
    } values %{$client->_connections};
    weaken $peers{q[C]};
    ok(isweak($peers{q[C]}), q[  ...make $peers{q[C]} a weak ref]);
    warn sprintf q[%d|%d], 131, $test_builder->{q[Curr_Test]};
    like(${$peers{q[C]}}, qr[127.0.0.1:\d+],
         q[Address properly resolved]);
    is($peers{q[C]}->_host, q[127.0.0.1], q[_host]);
    like($peers{q[C]}->_port, qr[^\d+$], q[_port]);
    is($peers{q[C]}->peerid, q[C] x 20, q[PeerID check]);
    isa_ok($peers{q[C]}->_socket, q[GLOB], q[Socket stored properly]);
    warn sprintf q[%d|%d], 136, $test_builder->{q[Curr_Test]};
    is($peers{q[C]}->_am_choking,      1, q[Initial outgoing choke]);
    is($peers{q[C]}->_peer_choking,    1, q[Initial incoming choke]);
    is($peers{q[C]}->_am_interested,   0, q[Initial outgoing interest]);
    is($peers{q[C]}->_peer_interested, 0, q[Initial incoming interest]);

    ok(syswrite($newsock_C, build_interested), q[Incoming interested]);
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    is($peers{q[C]}->_peer_interested, 1, q[Peer is interested]);

    ok(syswrite($newsock_C, build_unchoke), q[Incoming unchoke]);
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    is($peers{q[C]}->_peer_choking, 0, q[Peer has unchoked us]);
    warn sprintf q[%d|%d], 172, $test_builder->{q[Curr_Test]};

    ok(syswrite($newsock_C, build_choke), q[Incoming choke]);
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    is($peers{q[C]}->_peer_choking,
        1, q[Post-choke incoming choke status]);
    is($peers{q[C]}->_am_interested,
        0, q[Post-choke outgoing interest status]);
    warn sprintf q[%d|%d], 184, $test_builder->{q[Curr_Test]};
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    is($peers{q[C]}->_am_choking,
        0, q[Post-interested outgoing choke status]);
    warn sprintf q[%d|%d], 186, $test_builder->{q[Curr_Test]};
    is($peers{q[C]}->_peer_choking,
        1, q[Post-interested incoming choke status]);
    is($peers{q[C]}->_am_interested,
        0, q[Post-interested outgoing interest status]);
    $client->do_one_loop(0);
    is($peers{q[C]}->_peer_interested,
        1, q[Post-interested incoming interest status]);
    warn sprintf q[%d|%d], 189, $test_builder->{q[Curr_Test]};
    ok(shutdown($newsock_C, 2),
        q[Peer closes socket. Leaving us hanging.]);
    my $with_peer = scalar keys %{$client->_connections};
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    ok(($with_peer > scalar keys %{$client->_connections}),
        q[Peer removed from list of connections]);
    warn sprintf q[%d|%d], 196, $test_builder->{q[Curr_Test]};
}
{
    my $newsock_D = newsock($client);
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    is( syswrite($newsock_D,
                 build_handshake(qq[\0\0\0\0\0\20\0\4],
                                 pack(q[H40], $torrent->infohash),
                                 q[C] x 20
                 )
        ),
        68,
        q[Sent handshake to client]
    );
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    my $data = q[];

    #ok(sysread($newsock_D, $data, 68), q[Read handshake reply]);
    warn sprintf q[%d|%d], 233, $test_builder->{q[Curr_Test]};
    is(syswrite($newsock_D, build_keepalive()),
        4, q[Sent keepalive to client]);
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    is(syswrite($newsock_D, build_unchoke()),
        5, q[Sent unchoke to client]);
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    warn sprintf q[%d|%d], 253, $test_builder->{q[Curr_Test]};
    is(syswrite($newsock_D, build_choke()), 5, q[Sent choke to client]);
    is(syswrite($newsock_D, build_not_interested()),
        5, q[Sent not interested to client]);
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    is(syswrite($newsock_D, build_have(0)), 9, q[Sent have to client]);
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    ok(sysread($newsock_D, $data, 1024, length $data), q[Read]);
    warn sprintf q[%d|%d], 279, $test_builder->{q[Curr_Test]};
    is(syswrite($newsock_D, build_unchoke()),
        5, q[Sent unchoke to client]);
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    ok(sysread($newsock_D, $data, 1024, length $data), q[Read]);
    my $fake_piece = q[A] x 16384;
    is(syswrite($newsock_D, build_piece(0, 0, \$fake_piece)),
        16397, q[Sent piece i:0 o:0 l:16384 to client]);
    warn sprintf q[%d|%d], 307, $test_builder->{q[Curr_Test]};
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    is(syswrite($newsock_D, build_choke()), 5, q[Sent choke to client]);
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    is(syswrite($newsock_D, build_unchoke()),
        5, q[Sent choke to client to read second unchoke]);
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    warn sprintf q[%d|%d], 344, $test_builder->{q[Curr_Test]};
    $flux_capacitor = 0.5;
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    warn sprintf q[%d|%d], 349, $test_builder->{q[Curr_Test]};
    $flux_capacitor = 1;
    ok($client->do_one_loop(3), q[    do_one_loop(3)]);
    ok(sysread($newsock_D, $data, 1024, length $data), q[Read]);
    warn sprintf q[%d|%d], 351, $test_builder->{q[Curr_Test]};
    ok(syswrite($newsock_D, build_keepalive()), q[Write keepalive]);
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    is(syswrite($newsock_D, build_interested()),
        5, q[Sent interested to client]);
    $flux_capacitor = 2.5;
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);

    #is(sysread($newsock_D, my ($in), 1024),
    #    undef, q[Fail to read data because socket was closed.]);
    #ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    warn q[TODO: Test multithreaded stuff...];
}
{
    my $newsock_E = newsock($client);
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    is( syswrite($newsock_E,
                 build_handshake(qq[\0\0\0\0\0\0\0\4],
                                 pack(q[H40], $torrent->infohash),
                                 q[UNKNOWN-------------]
                 )
        ),
        68,
        q[Sent handshake to client]
    );
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    is(syswrite($newsock_E, build_have_all()),
        5, q[Sent HAVEALL to client]);
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    warn sprintf q[%d|%d], 425, $test_builder->{q[Curr_Test]};
}
{
    my $newsock_F = newsock($client);
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    is( syswrite($newsock_F,
                 build_handshake(qq[\0\0\0\0\0\0\0\4],
                                 pack(q[H40], $torrent->infohash),
                                 q[UNKNOWN-------------]
                 )
        ),
        68,
        q[Sent handshake to client]
    );
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    is(syswrite($newsock_F, build_have_none()),
        5, q[Sent HAVEALL to client]);
    ok($client->do_one_loop(1), q[    do_one_loop(1)]);
    warn sprintf q[%d|%d], 474, $test_builder->{q[Curr_Test]};
}

1 POD Error

The following errors were encountered while parsing the POD:

Around line 709:

Unknown directive: =old