diff --git a/IrcStates/Channel.cs b/IrcStates/Channel.cs index 1850e51..b502f2a 100644 --- a/IrcStates/Channel.cs +++ b/IrcStates/Channel.cs @@ -8,7 +8,7 @@ namespace IrcStates { public string Name { get; set; } public string NameLower { get; set; } - public Dictionary Users { get; set; } + public Dictionary Users { get; set; } public string Topic { get; set; } public string TopicSetter { get; set; } public DateTime TopicTime { get; set; } @@ -23,7 +23,7 @@ namespace IrcStates public void SetName(string name, string nameLower) { - Name = name; + Name = name; NameLower = nameLower; } @@ -31,15 +31,9 @@ namespace IrcStates { if (listMode) { - if (!ListModes.ContainsKey(ch)) - { - ListModes[ch] = new List(); - } + if (!ListModes.ContainsKey(ch)) ListModes[ch] = new List(); - if (ListModes[ch].Contains(param)) - { - ListModes[ch].Add(param ?? string.Empty); - } + if (ListModes[ch].Contains(param)) ListModes[ch].Add(param ?? string.Empty); } else { @@ -54,10 +48,7 @@ namespace IrcStates if (ListModes[ch].Contains(param)) { ListModes[ch].Remove(param); - if (!ListModes[ch].Any()) - { - ListModes.Remove(ch); - } + if (!ListModes[ch].Any()) ListModes.Remove(ch); } } else if (Modes.ContainsKey(ch)) diff --git a/IrcStates/ChannelUser.cs b/IrcStates/ChannelUser.cs new file mode 100644 index 0000000..14f4280 --- /dev/null +++ b/IrcStates/ChannelUser.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace IrcStates +{ + public class ChannelUser + { + public List Modes { get; set; } + } +} diff --git a/IrcStates/Emit.cs b/IrcStates/Emit.cs index 9af7b62..3867a61 100644 --- a/IrcStates/Emit.cs +++ b/IrcStates/Emit.cs @@ -9,6 +9,7 @@ namespace IrcStates public string Text { get; set; } public List Tokens { get; set; } public bool Finished { get; set; } + public bool Self { get; set; } public bool SelfSource { get; set; } public bool SelfTarget { get; set; } public Tests.User User { get; set; } diff --git a/IrcStates/ISupport.cs b/IrcStates/ISupport.cs index 91e6d6d..bfee9ee 100644 --- a/IrcStates/ISupport.cs +++ b/IrcStates/ISupport.cs @@ -1,4 +1,5 @@ // ReSharper disable InconsistentNaming + namespace IrcStates { public class ISupport diff --git a/IrcStates/Numeric.cs b/IrcStates/Numeric.cs index 3cd63b3..8639c12 100644 --- a/IrcStates/Numeric.cs +++ b/IrcStates/Numeric.cs @@ -28,6 +28,8 @@ namespace IrcStates public const string RPL_QUIETLIST = "728"; public const string RPL_ENDOFQUIETLIST = "729"; + public const string RPL_LOGGEDIN = "900"; + public const string RPL_LOGGEDOUT = "901"; public const string RPL_SASLSUCCESS = "903"; public const string ERR_SASLFAIL = "904"; public const string ERR_SASLTOOLONG = "905"; diff --git a/IrcStates/ServerDisconnectedException.cs b/IrcStates/ServerDisconnectedException.cs index 636acec..c3e014f 100644 --- a/IrcStates/ServerDisconnectedException.cs +++ b/IrcStates/ServerDisconnectedException.cs @@ -4,6 +4,5 @@ namespace IrcStates { public class ServerDisconnectedException : Exception { - } } diff --git a/IrcStates/ServerException.cs b/IrcStates/ServerException.cs index 328b141..7164e76 100644 --- a/IrcStates/ServerException.cs +++ b/IrcStates/ServerException.cs @@ -4,6 +4,5 @@ namespace IrcStates { public class ServerException : Exception { - } } diff --git a/IrcStates/Tests/Channel.cs b/IrcStates/Tests/Channel.cs index 0de5f37..f6a6fbb 100644 --- a/IrcStates/Tests/Channel.cs +++ b/IrcStates/Tests/Channel.cs @@ -1,9 +1,180 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections.Generic; +using System.Linq; +using IrcTokens; +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace IrcStates.Tests { [TestClass] public class Channel { + private Server _server; + + [TestInitialize] + public void TestInitialize() + { + _server = new Server("test"); + _server.ParseTokens(new Line("001 nickname")); + _server.ParseTokens(new Line(":nickname JOIN #chan")); + } + + [TestMethod] + public void JoinSelf() + { + Assert.IsTrue(_server.Channels.ContainsKey("#chan")); + Assert.IsTrue(_server.Users.ContainsKey("nickname")); + Assert.AreEqual(1, _server.Channels.Count); + Assert.AreEqual(1, _server.Users.Count); + + var user = _server.Users["nickname"]; + var chan = _server.Channels["#chan"]; + Assert.IsTrue(chan.Users.ContainsKey(user.NickNameLower)); + var chanUser = chan.Users[user.NickNameLower]; + CollectionAssert.AreEqual(new List {chan.NameLower}, user.Channels.ToList()); + } + + [TestMethod] + public void JoinOther() + { + _server.ParseTokens(new Line(":other JOIN #chan")); + + Assert.AreEqual(2, _server.Users.Count); + Assert.IsTrue(_server.Users.ContainsKey("other")); + + var channel = _server.Channels["#chan"]; + Assert.AreEqual(2, channel.Users.Count); + + var user = _server.Users["other"]; + CollectionAssert.AreEqual(new List {channel.NameLower}, user.Channels.ToList()); + } + + [TestMethod] + public void PartSelf() + { + _server.ParseTokens(new Line(":nickname PART #chan")); + + Assert.AreEqual(0, _server.Users.Count); + Assert.AreEqual(0, _server.Channels.Count); + } + + [TestMethod] + public void PartOther() + { + _server.ParseTokens(new Line(":other JOIN #chan")); + _server.ParseTokens(new Line(":other PART #chan")); + + var user = _server.Users["nickname"]; + var channel = _server.Channels["#chan"]; + var chanUser = channel.Users[user.NickNameLower]; + + Assert.AreEqual(channel.NameLower, user.Channels.Single()); + CollectionAssert.AreEqual(new Dictionary {{"nickname", user}}, _server.Users); + CollectionAssert.AreEqual(new Dictionary {{"#chan", channel}}, _server.Channels); + CollectionAssert.AreEqual(new Dictionary {{"nickname", chanUser}}, channel.Users); + } + + [TestMethod] + public void KickSelf() + { + _server.ParseTokens(new Line(":nickname KICK #chan nickname")); + + Assert.AreEqual(0, _server.Users.Count); + Assert.AreEqual(0, _server.Channels.Count); + } + + [TestMethod] + public void KickOther() + { + _server.ParseTokens(new Line(":other JOIN #chan")); + _server.ParseTokens(new Line(":nickname KICK #chan other")); + + var user = _server.Users["nickname"]; + var channel = _server.Channels["#chan"]; + var chanUser = channel.Users[user.NickNameLower]; + + Assert.AreEqual(1, _server.Users.Count); + Assert.AreEqual(1, _server.Channels.Count); + Assert.AreEqual(channel.NameLower, user.Channels.Single()); + CollectionAssert.AreEqual(new Dictionary {{user.NickNameLower, chanUser}}, + channel.Users); + } + + [TestMethod] + public void TopicText() + { + _server.ParseTokens(new Line("332 * #chan :test")); + Assert.AreEqual("test", _server.Channels["#chan"].Topic); + } + + [TestMethod] + public void TopicSetByAt() + { + var dt = DateTimeOffset.FromUnixTimeSeconds(1584023277).DateTime; + _server.ParseTokens(new Line("333 * #chan other 1584023277")); + + var channel = _server.Channels["#chan"]; + + Assert.AreEqual("other", channel.TopicSetter); + Assert.AreEqual(dt, channel.TopicTime); + } + + [TestMethod] + public void TopicCommand() + { + _server.ParseTokens(new Line("TOPIC #chan :hello there")); + Assert.AreEqual("hello there", _server.Channels["#chan"].Topic); + } + + [TestMethod] + public void CreationDate() + { + _server.ParseTokens(new Line("329 * #chan 1584041889")); + Assert.AreEqual(DateTimeOffset.FromUnixTimeSeconds(1584041889).DateTime, _server.Channels["#chan"].Created); + } + + [TestMethod] + public void NamesCommand() + { + _server.ParseTokens(new Line("353 * * #chan :nickname @+other")); + Assert.IsTrue(_server.Users.ContainsKey("nickname")); + Assert.IsTrue(_server.Users.ContainsKey("other")); + + var user = _server.Users["other"]; + var channel = _server.Channels["#chan"]; + var chanUser1 = channel.Users[user.NickNameLower]; + var chanUser2 = channel.Users[_server.NickNameLower]; + + CollectionAssert.AreEqual( + new Dictionary + { + {user.NickNameLower, chanUser1}, {_server.NickNameLower, chanUser2} + }, channel.Users); + CollectionAssert.AreEqual(new List {"o", "v"}, chanUser1.Modes); + Assert.AreEqual(channel.NameLower, user.Channels.Single()); + } + + [TestMethod] + public void UserhostInNames() + { + _server.ParseTokens(new Line("353 * * #chan :nickname!user@host other@user2@host2")); + Assert.AreEqual("user", _server.UserName); + Assert.AreEqual("host", _server.HostName); + + var user = _server.Users["other"]; + Assert.AreEqual("user2", user.HostName); + Assert.AreEqual("host2", user.HostName); + } + + [TestMethod] + public void NickAfterJoin() + { + var user = _server.Users["nickname"]; + var channel = _server.Channels["#chan"]; + var chanUser = channel.Users[user.NickNameLower]; + _server.ParseTokens(new Line(":nickname NICK nickname2")); + CollectionAssert.AreEqual(new Dictionary {{user.NickNameLower, chanUser}}, + channel.Users); + } } } diff --git a/IrcStates/Tests/Emit.cs b/IrcStates/Tests/Emit.cs index f4495c5..b75e1dd 100644 --- a/IrcStates/Tests/Emit.cs +++ b/IrcStates/Tests/Emit.cs @@ -1,9 +1,117 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Collections.Generic; +using IrcTokens; +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace IrcStates.Tests { [TestClass] public class Emit { + private Server _server; + + [TestInitialize] + public void TestInitialize() + { + _server = new Server("test"); + _server.ParseTokens(new Line("001 nickname")); + } + + [TestMethod] + public void EmitJoin() + { + var emit = _server.ParseTokens(new Line(":nickname JOIN #chan")); + + Assert.AreEqual("JOIN", emit.Command); + Assert.IsTrue(emit.Self); + Assert.AreEqual(_server.Users["nickname"], emit.User); + Assert.AreEqual(_server.Channels["#chan"], emit.Channel); + + emit = _server.ParseTokens(new Line(":other JOIN #chan")); + Assert.IsNotNull(emit); + Assert.AreEqual("JOIN", emit.Command); + Assert.IsFalse(emit.Self); + Assert.AreEqual(_server.Users["other"], emit.User); + Assert.AreEqual(_server.Channels["#chan"], emit.Channel); + } + + [TestMethod] + public void EmitPrivmsg() + { + _server.ParseTokens(new Line(":nickname JOIN #chan")); + var emit = _server.ParseTokens(new Line(":nickname PRIVMSG #chan :hello")); + + Assert.IsNotNull(emit); + Assert.AreEqual("PRIVMSG", emit.Command); + Assert.AreEqual("hello", emit.Text); + Assert.IsTrue(emit.SelfSource); + Assert.AreEqual(_server.Users["nickname"], emit.User); + Assert.AreEqual(_server.Channels["#chan"], emit.Channel); + + _server.ParseTokens(new Line(":other JOIN #chan")); + emit = _server.ParseTokens(new Line(":other PRIVMSG #chan :hello2")); + + Assert.IsNotNull(emit); + Assert.AreEqual("PRIVMSG", emit.Command); + Assert.AreEqual("hello2", emit.Text); + Assert.IsFalse(emit.SelfSource); + Assert.AreEqual(_server.Users["other"], emit.User); + Assert.AreEqual(_server.Channels["#chan"], emit.Channel); + } + + [TestMethod] + public void EmitPrivmsgNoJoin() + { + _server.ParseTokens(new Line(":nickname JOIN #chan")); + var emit = _server.ParseTokens(new Line(":other PRIVMSG #chan :hello")); + + Assert.IsNotNull(emit); + Assert.AreEqual("PRIVMSG", emit.Command); + Assert.AreEqual("hello", emit.Text); + Assert.IsFalse(emit.SelfSource); + Assert.IsNotNull(emit.User); + + var channel = _server.Channels["#chan"]; + Assert.AreEqual(channel, emit.Channel); + } + + [TestMethod] + public void EmitKick() + { + _server.ParseTokens(new Line(":nickname JOIN #chan")); + + var user = _server.Users["nickname"]; + var channel = _server.Channels["#chan"]; + _server.ParseTokens(new Line(":other JOIN #chan")); + var userOther = _server.Users["other"]; + var emit = _server.ParseTokens(new Line(":nickname KICK #chan other :reason")); + + Assert.IsNotNull(emit); + Assert.AreEqual("KICK", emit.Command); + Assert.AreEqual("reason", emit.Text); + Assert.IsTrue(emit.SelfSource); + Assert.AreEqual(user, emit.UserSource); + Assert.AreEqual(userOther, emit.UserTarget); + Assert.AreEqual(channel, emit.Channel); + } + + [TestMethod] + public void EmitMode() + { + var emit = _server.ParseTokens(new Line("MODE nickname x+i-i+wi-wi")); + + Assert.IsNotNull(emit); + Assert.AreEqual("MODE", emit.Command); + Assert.IsTrue(emit.SelfTarget); + CollectionAssert.AreEqual(new List + { + "+x", + "+i", + "-i", + "+w", + "+i", + "-w", + "-i" + }, emit.Tokens); + } } } diff --git a/IrcStates/Tests/ISupport.cs b/IrcStates/Tests/ISupport.cs index aa6260a..f85f087 100644 --- a/IrcStates/Tests/ISupport.cs +++ b/IrcStates/Tests/ISupport.cs @@ -1,4 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; + // ReSharper disable InconsistentNaming namespace IrcStates.Tests diff --git a/IrcTokens/Line.cs b/IrcTokens/Line.cs index d1a8286..50f93ec 100644 --- a/IrcTokens/Line.cs +++ b/IrcTokens/Line.cs @@ -200,7 +200,7 @@ namespace IrcTokens if (Params != null && Params.Any()) { - var last = Params[^1]; + var last = Params[^1]; var withoutLast = Params.SkipLast(1).ToList(); foreach (var p in withoutLast) diff --git a/IrcTokens/StatefulEncoder.cs b/IrcTokens/StatefulEncoder.cs index 57f1b96..bec4e42 100644 --- a/IrcTokens/StatefulEncoder.cs +++ b/IrcTokens/StatefulEncoder.cs @@ -60,8 +60,8 @@ namespace IrcTokens { var sent = PendingBytes.Take(byteCount).Count(c => c == '\n'); - PendingBytes = PendingBytes.Skip(byteCount).ToArray(); - + PendingBytes = PendingBytes.Skip(byteCount).ToArray(); + var sentLines = _bufferedLines.Take(sent).ToList(); _bufferedLines = _bufferedLines.Skip(sent).ToList(); diff --git a/IrcTokens/Tests/Data/JoinModel.cs b/IrcTokens/Tests/Data/JoinModel.cs index b016fc3..2c08e58 100644 --- a/IrcTokens/Tests/Data/JoinModel.cs +++ b/IrcTokens/Tests/Data/JoinModel.cs @@ -9,8 +9,7 @@ namespace IrcTokens.Tests.Data public class Test { - [YamlMember(Alias = "desc")] - public string Description { get; set; } + [YamlMember(Alias = "desc")] public string Description { get; set; } public Atoms Atoms { get; set; }