diff --git a/src/projections/irc/test.rs b/src/projections/irc/test.rs index 6e0e897..1b46065 100644 --- a/src/projections/irc/test.rs +++ b/src/projections/irc/test.rs @@ -22,6 +22,13 @@ impl<'a> TestScope<'a> { self.buffer.clear(); Ok(()) } + + async fn assert(&mut self, f: impl FnOnce(&str) -> Result<()>) -> Result<()> { + let len = self.reader.read_until(b'\n', &mut self.buffer).await?; + let res = f(std::str::from_utf8(&self.buffer[0..len])?); + self.buffer.clear(); + res + } } async fn init_client(stream: &mut TcpStream) -> Result { @@ -47,45 +54,28 @@ macro_rules! expect { }}; } +const SERVER_HOSTNAME: &'static str = "irc.localhost"; + +#[rustfmt::skip] async fn registration(scope: &mut TestScope<'_>, nickname: &str) -> Result<()> { expect!(scope, ":irc.localhost NOTICE * :Welcome to my server!\n"); send!(scope, "NICK {nickname}\n"); send!(scope, "USER UserName 0 * :Real Name\n"); - expect!( - scope, - ":irc.localhost 001 {nickname} :Welcome to Kek Server\n" - ); - expect!( - scope, - ":irc.localhost 002 {nickname} :Welcome to Kek Server\n" - ); - expect!( - scope, - ":irc.localhost 003 {nickname} :Welcome to Kek Server\n" - ); - expect!(scope, ":irc.localhost 004 {nickname} irc.localhost kek-0.1.alpha.3 DGMQRSZagiloswz CFILPQbcefgijklmnopqrstvz bkloveqjfI\n"); - expect!( - scope, - ":irc.localhost 005 {nickname} CHANTYPES=# :are supported by this server\n" - ); + expect!(scope, ":irc.localhost 001 {nickname} :Welcome to Kek Server\n"); + expect!(scope, ":irc.localhost 002 {nickname} :Welcome to Kek Server\n"); + expect!(scope, ":irc.localhost 003 {nickname} :Welcome to Kek Server\n"); + expect!(scope, ":irc.localhost 004 {nickname} irc.localhost kek-0.1.alpha.3 r CFILPQbcefgijklmnopqrstvz\n"); + expect!(scope, ":irc.localhost 005 {nickname} CHANTYPES=# :are supported by this server\n"); Ok(()) } -async fn join(scope: &mut TestScope<'_>, nickname: &str) -> Result<()> { - send!(scope, "JOIN #channol\n"); - expect!(scope, ":{nickname} JOIN #channol\n"); - expect!( - scope, - ":irc.localhost 332 {nickname} #channol :chan topic lol\n" - ); - expect!( - scope, - ":irc.localhost 353 {nickname} = #channol :{nickname}\n" - ); - expect!( - scope, - ":irc.localhost 366 {nickname} #channol :End of /NAMES list\n" - ); +#[rustfmt::skip] +async fn join(scope: &mut TestScope<'_>, nickname: &str, chan: &str) -> Result<()> { + send!(scope, "JOIN #{chan}\n"); + expect!(scope, ":{nickname} JOIN #{chan}\n"); + expect!(scope, ":irc.localhost 332 {nickname} #{chan} :New room\n"); + expect!(scope, ":irc.localhost 353 {nickname} = #{chan} :{nickname}\n"); + expect!(scope, ":irc.localhost 366 {nickname} #{chan} :End of /NAMES list\n"); Ok(()) } @@ -94,11 +84,12 @@ async fn test_registration() -> Result<()> { let mut stream = TcpStream::connect("127.0.0.1:6667").await?; let mut scope = init_client(&mut stream).await?; - registration(&mut scope, "NickName").await?; - join(&mut scope, "NickName").await?; + registration(&mut scope, "NickName1").await?; + join(&mut scope, "NickName1", "chan1").await?; Ok(()) } +#[rustfmt::skip] #[tokio::test] async fn test_two_connections_one_player() -> Result<()> { let mut stream1 = TcpStream::connect("127.0.0.1:6667").await?; @@ -106,21 +97,39 @@ async fn test_two_connections_one_player() -> Result<()> { let mut stream2 = TcpStream::connect("127.0.0.1:6667").await?; let mut scope2 = init_client(&mut stream2).await?; - registration(&mut scope1, "NickName").await?; - registration(&mut scope2, "NickName").await?; - join(&mut scope1, "NickName").await?; - join(&mut scope2, "NickName").await?; - send!(scope1, "PRIVMSG #channol :Chmoki vsem v etam chati!\n"); - expect!( - scope2, - ":NickName PRIVMSG #channol :Chmoki vsem v etam chati!\n" - ); - send!(scope2, "PRIVMSG #channol :I tebe privetiki\n"); - expect!(scope1, ":NickName PRIVMSG #channol :I tebe privetiki\n"); + let nickname = "NickName2"; + let chan = "chan2"; + + registration(&mut scope1, nickname).await?; + registration(&mut scope2, nickname).await?; + join(&mut scope1, nickname, chan).await?; + + // force join on second connection when the other one joins a room + expect!(scope2, ":{nickname} JOIN #{chan}\n"); + expect!(scope2, ":{SERVER_HOSTNAME} 332 {nickname} #{chan} :New room\n"); + expect!(scope2, ":{SERVER_HOSTNAME} 353 {nickname} = #{chan} :{nickname}\n"); + expect!(scope2, ":{SERVER_HOSTNAME} 366 {nickname} #{chan} :End of /NAMES list\n"); + + // force send PRIVMSG to other connections + send!(scope1, "PRIVMSG #{chan} :Chmoki vsem v etam chati!\n"); + expect!(scope2, ":{nickname} PRIVMSG #{chan} :Chmoki vsem v etam chati!\n"); + send!(scope2, "PRIVMSG #{chan} :I tebe privetiki\n"); + expect!(scope1, ":{nickname} PRIVMSG #{chan} :I tebe privetiki\n"); + + let mut stream3 = TcpStream::connect("127.0.0.1:6667").await?; + let mut scope3 = init_client(&mut stream3).await?; + registration(&mut scope3, nickname).await?; + + // force join on registration + expect!(scope3, ":{nickname} JOIN #{chan}\n"); + expect!(scope3, ":{SERVER_HOSTNAME} 332 {nickname} #{chan} :New room\n"); + expect!(scope3, ":{SERVER_HOSTNAME} 353 {nickname} = #{chan} :{nickname}\n"); + expect!(scope3, ":{SERVER_HOSTNAME} 366 {nickname} #{chan} :End of /NAMES list\n"); Ok(()) } +#[rustfmt::skip] #[tokio::test] async fn test_two_players() -> Result<()> { let mut stream1 = TcpStream::connect("127.0.0.1:6667").await?; @@ -128,17 +137,30 @@ async fn test_two_players() -> Result<()> { let mut stream2 = TcpStream::connect("127.0.0.1:6667").await?; let mut scope2 = init_client(&mut stream2).await?; - registration(&mut scope1, "NickName1").await?; - registration(&mut scope2, "NickName2").await?; - join(&mut scope1, "NickName1").await?; - join(&mut scope2, "NickName2").await?; - send!(scope1, "PRIVMSG #channol :Chmoki vsem v etam chati!\n"); - expect!( - scope2, - ":NickName1 PRIVMSG #channol :Chmoki vsem v etam chati!\n" - ); - send!(scope2, "PRIVMSG #channol :I tebe privetiki\n"); - expect!(scope1, ":NickName2 PRIVMSG #channol :I tebe privetiki\n"); + let nickname1 = "NickName3"; + let nickname2 = "NickName4"; + + let chan = "chan3"; + + registration(&mut scope1, "NickName3").await?; + registration(&mut scope2, "NickName4").await?; + join(&mut scope1, nickname1, "chan3").await?; + send!(scope2, "JOIN #{chan}\n"); + expect!(scope2, ":{nickname2} JOIN #{chan}\n"); + expect!(scope2, ":irc.localhost 332 {nickname2} #{chan} :New room\n"); + scope2.assert(|line| { + if line == format!(":irc.localhost 353 {nickname2} = #{chan} :{nickname1} {nickname2}\n") { return Ok(()) } + if line == format!(":irc.localhost 353 {nickname2} = #{chan} :{nickname2} {nickname1}\n") { return Ok(()) } + panic!("incorrect chan member list received: {line}"); + }).await?; + expect!(scope2, ":irc.localhost 366 {nickname2} #{chan} :End of /NAMES list\n"); + + expect!(scope1, ":{nickname2} JOIN #{chan}\n"); + + send!(scope1, "PRIVMSG #chan3 :Chmoki vsem v etam chati!\n"); + expect!(scope2, ":{nickname1} PRIVMSG #chan3 :Chmoki vsem v etam chati!\n"); + send!(scope2, "PRIVMSG #chan3 :I tebe privetiki\n"); + expect!(scope1, ":{nickname2} PRIVMSG #chan3 :I tebe privetiki\n"); Ok(()) } diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 0000000..397b4a7 --- /dev/null +++ b/test/.gitignore @@ -0,0 +1 @@ +*.log diff --git a/test/run.sh b/test/run.sh new file mode 100755 index 0000000..f1162e2 --- /dev/null +++ b/test/run.sh @@ -0,0 +1,5 @@ +#!/bin/sh +cargo build +./target/debug/lavina 1>test/lavina.stdout.log 2>test/lavina.stderr.log & +cargo test +kill %1