The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl

use strict;
use warnings;

use Test::More;
use IO::Async::Test;
use IO::Async::OS;
use IO::Async::Loop;
use IO::Async::Stream;

use Net::Async::IRC;

my $CRLF = "\x0d\x0a"; # because \r\n isn't portable

my $loop = IO::Async::Loop->new();
testing_loop( $loop );

my ( $S1, $S2 ) = IO::Async::OS->socketpair() or die "Cannot create socket pair - $!";

my $in_use = 0;
my $err_nick = 0;
my $irc = Net::Async::IRC->new(
   handle => $S1,

   user => "defaultuser",
   realname => "Default Real name",

   nick => "AlreadyUsedNick",

   on_message_ERR_NICKNAMEINUSE => sub { shift->change_nick( "1stNick" ); $in_use = 1; },
   on_message_ERR_ERRONEUSNICKNAME => sub { shift->change_nick( "FirstNickTOOLONG" ); $err_nick = 1; },
   on_message => sub { "IGNORE" },
);

$loop->add( $irc );

is( $irc->nick, "AlreadyUsedNick", 'Initial nick is set' );

ok( $irc->is_nick_me( "AlreadyUsedNick" ), 'Client recognises initial nick' );
ok( !$irc->is_nick_me( "SomeoneElse" ), 'Client does not recognise other nick' );

my $login_f = $irc->login;

my $serverstream = "";

wait_for_stream { $serverstream =~ m/$CRLF.*$CRLF/ } $S2 => $serverstream;

is( $serverstream, "USER defaultuser 0 * :Default Real name$CRLF" . 
                   "NICK AlreadyUsedNick$CRLF", 'Server stream after attempt to login with nick already in use' );

$S2->syswrite( ":irc.example.com 433 * AlreadyUsedNick :Nickname is already in use$CRLF" );

wait_for { $in_use };

ok( $in_use, 'Client recieves ERR_NICKNAMEINUSE error' );

$S2->syswrite( ":irc.example.com 432 * 1stNick :Erroneous nickname$CRLF" );

wait_for { $err_nick };

ok( $err_nick, 'Client recieves ERR_ERRONEUSNICK error' );

$S2->syswrite( ":irc.example.com 001 FirstNick :Welcome to IRC FirstNick!defaultuser\@your.host.here$CRLF" );

wait_for { $login_f->is_ready };
$login_f->get;

is( $irc->nick, "FirstNick", 'Nick was updated correctly even after multiple errors' );

$serverstream = "";

wait_for_stream { $serverstream =~ m/$CRLF/ } $S2 => $serverstream;

is( $serverstream, "NICK 1stNick$CRLF" .
                   "NICK FirstNickTOOLONG$CRLF", 'Server stream after login' );

$irc->change_nick( "SecondNick" );

is( $irc->nick, "FirstNick", 'Nick still old until server confirms' );

ok( $irc->is_nick_me( "FirstNick" ), 'Client recognises still old nick' );
ok( !$irc->is_nick_me( "SecondNick" ), 'Client does not recognise new nick' );

$serverstream = "";

wait_for_stream { $serverstream =~ m/$CRLF/ } $S2 => $serverstream;

is( $serverstream, "NICK SecondNick$CRLF", 'Server stream after NICK command' );

$S2->syswrite( ":FirstNick!defaultuser\@your.host.here NICK SecondNick$CRLF" );

wait_for { not $irc->is_nick_me( "FirstNick" ) };

is( $irc->nick, "SecondNick", 'Object now confirms new nick' );

ok( !$irc->is_nick_me( "FirstNick" ), 'Client no longer recognises old nick' );
ok( $irc->is_nick_me( "SecondNick" ), 'Client now recognises new nick' );

done_testing;