From 80afa2c0aec37b7f98cc22615417c36672e695da Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Tue, 28 Apr 2020 00:35:52 -0400 Subject: [PATCH] tidy up, work on stateful --- IrcStates/Casemap.cs | 11 +- IrcStates/Numeric.cs | 3 + IrcStates/Server.cs | 75 ++++++++- IrcStates/ServerDisconnectedException.cs | 9 ++ IrcStates/ServerException.cs | 9 ++ IrcStates/User.cs | 2 +- IrcTokens/Hostmask.cs | 64 ++++---- IrcTokens/Line.cs | 198 +++++++++++++---------- IrcTokens/Protocol.cs | 76 --------- IrcTokens/StatefulDecoder.cs | 25 +-- IrcTokens/StatefulEncoder.cs | 26 ++- IrcTokens/Tests/Format.cs | 60 ++----- IrcTokens/Tests/Hostmask.cs | 2 +- IrcTokens/Tests/Parser.cs | 16 +- IrcTokens/Tests/StatefulDecoder.cs | 12 +- IrcTokens/Tests/StatefulEncoder.cs | 19 ++- IrcTokens/Tests/Tokenization.cs | 12 +- 17 files changed, 314 insertions(+), 305 deletions(-) create mode 100644 IrcStates/ServerDisconnectedException.cs create mode 100644 IrcStates/ServerException.cs delete mode 100644 IrcTokens/Protocol.cs diff --git a/IrcStates/Casemap.cs b/IrcStates/Casemap.cs index 484c490..67867c5 100644 --- a/IrcStates/Casemap.cs +++ b/IrcStates/Casemap.cs @@ -17,10 +17,7 @@ namespace IrcStates private static string Replace(string s, string upper, string lower) { - for (var i = 0; i < upper.Length; ++i) - { - s = s.Replace(upper[i], lower[i]); - } + for (var i = 0; i < upper.Length; ++i) s = s.Replace(upper[i], lower[i]); return s; } @@ -28,14 +25,12 @@ namespace IrcStates public static string CaseFold(CaseMapping mapping, string s) { if (s != null) - { return mapping switch { CaseMapping.Rfc1459 => Replace(s, Rfc1459UpperChars, Rfc1459LowerChars), - CaseMapping.Ascii => Replace(s, AsciiUpperChars, AsciiLowerChars), - _ => throw new ArgumentOutOfRangeException(nameof(mapping), mapping, null) + CaseMapping.Ascii => Replace(s, AsciiUpperChars, AsciiLowerChars), + _ => throw new ArgumentOutOfRangeException(nameof(mapping), mapping, null) }; - } return string.Empty; } diff --git a/IrcStates/Numeric.cs b/IrcStates/Numeric.cs index f5525f6..3cd63b3 100644 --- a/IrcStates/Numeric.cs +++ b/IrcStates/Numeric.cs @@ -1,8 +1,10 @@ // ReSharper disable InconsistentNaming + namespace IrcStates { public static class Numeric { +#pragma warning disable CA1707 // Identifiers should not contain underscores public const string RPL_WELCOME = "001"; public const string RPL_ISUPPORT = "005"; public const string RPL_MOTD = "372"; @@ -45,5 +47,6 @@ namespace IrcStates public const string RPL_ENDOFWHOIS = "318"; public const string ERR_NOSUCHCHANNEL = "403"; +#pragma warning restore CA1707 // Identifiers should not contain underscores } } diff --git a/IrcStates/Server.cs b/IrcStates/Server.cs index 9f97f47..c20e041 100644 --- a/IrcStates/Server.cs +++ b/IrcStates/Server.cs @@ -1,6 +1,79 @@ -namespace IrcStates +using System; +using System.Collections.Generic; +using System.Linq; +using IrcTokens; + +namespace IrcStates { public class Server { + private readonly StatefulDecoder _decoder; + + public Dictionary>> LineHandlers; + + private Dictionary TempCaps; + + public Server(string name) + { + Name = name; + Registered = false; + Modes = new List(); + Motd = new List(); + _decoder = new StatefulDecoder(); + LineHandlers = new Dictionary>>(); + Users = new Dictionary(); + Channels = new Dictionary(); + ISupport = new ISupport(); + HasCap = false; + TempCaps = new Dictionary(); + AvailableCaps = new Dictionary(); + AgreedCaps = new List(); + } + + public string Name { get; set; } + public string NickName { get; set; } + public string NickNameLower { get; set; } + public string UserName { get; set; } + public string HostName { get; set; } + public string RealName { get; set; } + public string Account { get; set; } + public string Away { get; set; } + + public bool Registered { get; set; } + public List Modes { get; set; } + public List Motd { get; set; } + public Dictionary Users { get; set; } + public Dictionary Channels { get; set; } + public Dictionary AvailableCaps { get; set; } + public List AgreedCaps { get; set; } + + public ISupport ISupport { get; set; } + public bool HasCap { get; set; } + + public override string ToString() + { + return $"Server(name={Name})"; + } + + public List<(Line, Emit)> Recv(byte[] data) + { + var lines = _decoder.Push(data); + if (lines == null) throw new ServerDisconnectedException(); + + var emits = lines.Select(ParseTokens).ToList(); + return null; + } + + private Emit ParseTokens(Line line) + { + Emit ret; + if (LineHandlers.ContainsKey(line.Command)) + foreach (var callback in LineHandlers[line.Command]) + { + var emit = callback(line.Command, line); + } + + throw new NotImplementedException(); + } } } diff --git a/IrcStates/ServerDisconnectedException.cs b/IrcStates/ServerDisconnectedException.cs new file mode 100644 index 0000000..636acec --- /dev/null +++ b/IrcStates/ServerDisconnectedException.cs @@ -0,0 +1,9 @@ +using System; + +namespace IrcStates +{ + public class ServerDisconnectedException : Exception + { + + } +} diff --git a/IrcStates/ServerException.cs b/IrcStates/ServerException.cs new file mode 100644 index 0000000..328b141 --- /dev/null +++ b/IrcStates/ServerException.cs @@ -0,0 +1,9 @@ +using System; + +namespace IrcStates +{ + public class ServerException : Exception + { + + } +} diff --git a/IrcStates/User.cs b/IrcStates/User.cs index 9bc5ce8..3fea024 100644 --- a/IrcStates/User.cs +++ b/IrcStates/User.cs @@ -21,7 +21,7 @@ namespace IrcStates public void SetNickName(string nick, string nickLower) { - NickName = nick; + NickName = nick; NickNameLower = nickLower; } } diff --git a/IrcTokens/Hostmask.cs b/IrcTokens/Hostmask.cs index 01fe7d5..3c0b7f2 100644 --- a/IrcTokens/Hostmask.cs +++ b/IrcTokens/Hostmask.cs @@ -3,47 +3,15 @@ namespace IrcTokens { /// - /// Represents the three parts of a hostmask. Parse with the constructor. + /// Represents the three parts of a hostmask. Parse with the constructor. /// public class Hostmask : IEquatable { - public string NickName { get; set; } - public string UserName { get; set; } - public string HostName { get; set; } - - public override string ToString() - { - return _source; - } - - public override int GetHashCode() - { - return _source.GetHashCode(StringComparison.Ordinal); - } - - public bool Equals(Hostmask other) - { - if (other == null) - { - return false; - } - - return _source == other._source; - } - - public override bool Equals(object obj) - { - return Equals(obj as Hostmask); - } - private readonly string _source; public Hostmask(string source) { - if (source == null) - { - return; - } + if (source == null) return; _source = source; @@ -66,5 +34,31 @@ namespace IrcTokens UserName = userSplit[1]; } } + + public string NickName { get; set; } + public string UserName { get; set; } + public string HostName { get; set; } + + public bool Equals(Hostmask other) + { + if (other == null) return false; + + return _source == other._source; + } + + public override string ToString() + { + return _source; + } + + public override int GetHashCode() + { + return _source.GetHashCode(StringComparison.Ordinal); + } + + public override bool Equals(object obj) + { + return Equals(obj as Hostmask); + } } -} \ No newline at end of file +} diff --git a/IrcTokens/Line.cs b/IrcTokens/Line.cs index 24efe4a..2e6f696 100644 --- a/IrcTokens/Line.cs +++ b/IrcTokens/Line.cs @@ -2,83 +2,34 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Text; namespace IrcTokens { /// - /// Tools to represent, parse, and format IRC lines + /// Tools to represent, parse, and format IRC lines /// public class Line : IEquatable { - public Dictionary Tags { get; set; } - public string Source { get; set; } - public string Command { get; set; } - public List Params { get; set; } + private static readonly string[] TagUnescaped = {"\\", " ", ";", "\r", "\n"}; + + private static readonly string[] TagEscaped = {"\\\\", "\\s", "\\:", "\\r", "\\n"}; private Hostmask _hostmask; - public override string ToString() + public Line() { - var vars = new List(); - - if (Command != null) - { - vars.Add($"command={Command}"); - } - - if (Source != null) - { - vars.Add($"source={Source}"); - } - - if (Params != null && Params.Any()) - { - vars.Add($"params=[{string.Join(",", Params)}]"); - } - - if (Tags != null && Tags.Any()) - { - vars.Add($"tags=[{string.Join(";", Tags.Select(kvp => $"{kvp.Key}={kvp.Value}"))}]"); - } - - return $"Line({string.Join(", ", vars)})"; } - public override int GetHashCode() - { - return Format().GetHashCode(StringComparison.Ordinal); - } - - public bool Equals(Line other) - { - if (other == null) - { - return false; - } - - return Format() == other.Format(); - } - - public override bool Equals(object obj) - { - return Equals(obj as Line); - } - - public Hostmask Hostmask => - _hostmask ??= new Hostmask(Source); - - public Line() { } - /// - /// Build new object parsed from a string. Analogous to irctokens.tokenise() + /// Build new object parsed from + /// a string + /// . Analogous to irctokens.tokenise() /// /// irc line to parse public Line(string line) { - if (string.IsNullOrWhiteSpace(line)) - { - throw new ArgumentNullException(nameof(line)); - } + if (string.IsNullOrWhiteSpace(line)) throw new ArgumentNullException(nameof(line)); string[] split; @@ -91,24 +42,22 @@ namespace IrcTokens line = string.Join(" ", split.Skip(1)); foreach (var part in messageTags.Substring(1).Split(';')) - { if (part.Contains('=', StringComparison.Ordinal)) { - split = part.Split('=', 2); - Tags[split[0]] = Protocol.UnescapeTag(split[1]); + split = part.Split('=', 2); + Tags[split[0]] = UnescapeTag(split[1]); } else { Tags[part] = string.Empty; } - } } string trailing; if (line.Contains(" :", StringComparison.Ordinal)) { - split = line.Split(" :", 2); - line = split[0]; + split = line.Split(" :", 2); + line = split[0]; trailing = split[1]; } else @@ -118,7 +67,7 @@ namespace IrcTokens Params = line.Contains(' ', StringComparison.Ordinal) ? line.Split(' ', StringSplitOptions.RemoveEmptyEntries).ToList() - : new List { line }; + : new List {line}; if (Params[0].StartsWith(':')) { @@ -132,14 +81,102 @@ namespace IrcTokens Params.RemoveAt(0); } - if (trailing != null) - { - Params.Add(trailing); - } + if (trailing != null) Params.Add(trailing); + } + + public Dictionary Tags { get; set; } + public string Source { get; set; } + public string Command { get; set; } + public List Params { get; set; } + + public Hostmask Hostmask => + _hostmask ??= new Hostmask(Source); + + public bool Equals(Line other) + { + if (other == null) return false; + + return Format() == other.Format(); } /// - /// Format a as a standards-compliant IRC line + /// Unescape ircv3 tag + /// + /// escaped string + /// unescaped string + public static string UnescapeTag(string val) + { + var unescaped = new StringBuilder(); + + var graphemeIterator = StringInfo.GetTextElementEnumerator(val); + graphemeIterator.Reset(); + + while (graphemeIterator.MoveNext()) + { + var current = graphemeIterator.GetTextElement(); + + if (current == @"\") + try + { + graphemeIterator.MoveNext(); + var next = graphemeIterator.GetTextElement(); + var pair = current + next; + unescaped.Append(TagEscaped.Contains(pair) + ? TagUnescaped[Array.IndexOf(TagEscaped, pair)] + : next); + } + catch (InvalidOperationException) + { + // ignored + } + else + unescaped.Append(current); + } + + return unescaped.ToString(); + } + + /// + /// Escape strings for use in ircv3 tags + /// + /// string to escape + /// escaped string + public static string EscapeTag(string val) + { + for (var i = 0; i < TagUnescaped.Length; ++i) + val = val?.Replace(TagUnescaped[i], TagEscaped[i], StringComparison.Ordinal); + + return val; + } + + public override string ToString() + { + var vars = new List(); + + if (Command != null) vars.Add($"command={Command}"); + + if (Source != null) vars.Add($"source={Source}"); + + if (Params != null && Params.Any()) vars.Add($"params=[{string.Join(",", Params)}]"); + + if (Tags != null && Tags.Any()) + vars.Add($"tags=[{string.Join(";", Tags.Select(kvp => $"{kvp.Key}={kvp.Value}"))}]"); + + return $"Line({string.Join(", ", vars)})"; + } + + public override int GetHashCode() + { + return Format().GetHashCode(StringComparison.Ordinal); + } + + public override bool Equals(object obj) + { + return Equals(obj as Line); + } + + /// + /// Format a as a standards-compliant IRC line /// /// formatted irc line public string Format() @@ -149,16 +186,15 @@ namespace IrcTokens if (Tags != null && Tags.Any()) { var tags = Tags.Keys - .Select(key => string.IsNullOrWhiteSpace(Tags[key]) ? key : $"{key}={Protocol.EscapeTag(Tags[key])}") + .OrderBy(k => k) + .Select(key => + string.IsNullOrWhiteSpace(Tags[key]) ? key : $"{key}={EscapeTag(Tags[key])}") .ToList(); outs.Add($"@{string.Join(";", tags)}"); } - if (Source != null) - { - outs.Add($":{Source}"); - } + if (Source != null) outs.Add($":{Source}"); outs.Add(Command); @@ -170,21 +206,17 @@ namespace IrcTokens foreach (var p in Params) { if (p.Contains(' ', StringComparison.Ordinal)) - { throw new ArgumentException(@"non-last parameters cannot have spaces", p); - } if (p.StartsWith(':')) - { throw new ArgumentException(@"non-last parameters cannot start with colon", p); - } } + outs.AddRange(Params); - if (string.IsNullOrWhiteSpace(last) || last.Contains(' ', StringComparison.Ordinal) || last.StartsWith(':')) - { + if (string.IsNullOrWhiteSpace(last) || last.Contains(' ', StringComparison.Ordinal) || + last.StartsWith(':')) last = $":{last}"; - } outs.Add(last); } diff --git a/IrcTokens/Protocol.cs b/IrcTokens/Protocol.cs deleted file mode 100644 index 6ddb079..0000000 --- a/IrcTokens/Protocol.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System; -using System.Globalization; -using System.Linq; -using System.Text; - -namespace IrcTokens -{ - internal class Protocol - { - private static readonly string[] TagUnescaped = - { - "\\", " ", ";", "\r", "\n" - }; - - private static readonly string[] TagEscaped = - { - "\\\\", "\\s", "\\:", "\\r", "\\n" - }; - - /// - /// Unescape ircv3 tag - /// - /// escaped string - /// unescaped string - public static string UnescapeTag(string val) - { - var unescaped = new StringBuilder(); - - var graphemeIterator = StringInfo.GetTextElementEnumerator(val); - graphemeIterator.Reset(); - - while (graphemeIterator.MoveNext()) - { - var current = graphemeIterator.GetTextElement(); - - if (current == @"\") - { - try - { - graphemeIterator.MoveNext(); - var next = graphemeIterator.GetTextElement(); - var pair = current + next; - unescaped.Append(TagEscaped.Contains(pair) - ? TagUnescaped[Array.IndexOf(TagEscaped, pair)] - : next); - } - catch (InvalidOperationException) - { - // ignored - } - } - else - { - unescaped.Append(current); - } - } - - return unescaped.ToString(); - } - - /// - /// Escape strings for use in ircv3 tags - /// - /// string to escape - /// escaped string - public static string EscapeTag(string val) - { - for (var i = 0; i < TagUnescaped.Length; ++i) - { - val = val.Replace(TagUnescaped[i], TagEscaped[i], StringComparison.Ordinal); - } - - return val; - } - } -} diff --git a/IrcTokens/StatefulDecoder.cs b/IrcTokens/StatefulDecoder.cs index 47106d9..bdaf81d 100644 --- a/IrcTokens/StatefulDecoder.cs +++ b/IrcTokens/StatefulDecoder.cs @@ -11,17 +11,20 @@ namespace IrcTokens private Encoding _encoding; private Encoding _fallback; + public StatefulDecoder() + { + Clear(); + } + public Encoding Encoding { get => _encoding ?? Encoding.GetEncoding(Encoding.UTF8.CodePage, EncoderFallback.ExceptionFallback, - DecoderFallback.ExceptionFallback); + DecoderFallback.ExceptionFallback); set { if (value != null) - { _encoding = Encoding.GetEncoding(value.CodePage, EncoderFallback.ExceptionFallback, DecoderFallback.ReplacementFallback); - } } } @@ -32,20 +35,13 @@ namespace IrcTokens set { if (value != null) - { _fallback = Encoding.GetEncoding(value.CodePage, EncoderFallback.ReplacementFallback, DecoderFallback.ReplacementFallback); - } } } public string Pending => Encoding.GetString(_buffer); - public StatefulDecoder() - { - Clear(); - } - public void Clear() { _buffer = Array.Empty(); @@ -58,16 +54,13 @@ namespace IrcTokens public List Push(byte[] data) { - if (data == null || data.Length == 0) - { - return null; - } + if (data == null || data.Length == 0) return null; _buffer = _buffer.Concat(data).ToArray(); // simulate string.Split('\n') before decoding var newLineIndices = _buffer.Select((b, i) => b == '\n' ? i : -1).Where(i => i != -1).ToArray(); - var lines = new List(); + var lines = new List(); for (int i = 0, currentIndex = 0; i < newLineIndices.Length; ++i) { @@ -99,7 +92,6 @@ namespace IrcTokens var decodeLines = new List(); foreach (var line in listLines.Select(l => l.ToArray())) - { try { decodeLines.Add(Encoding.GetString(line)); @@ -108,7 +100,6 @@ namespace IrcTokens { decodeLines.Add(Fallback.GetString(line)); } - } return decodeLines .Select(l => new Line(l)) diff --git a/IrcTokens/StatefulEncoder.cs b/IrcTokens/StatefulEncoder.cs index c036400..b486736 100644 --- a/IrcTokens/StatefulEncoder.cs +++ b/IrcTokens/StatefulEncoder.cs @@ -7,8 +7,14 @@ namespace IrcTokens { public class StatefulEncoder { + private Queue _bufferedLines; private Encoding _encoding; + public StatefulEncoder() + { + Clear(); + } + public Encoding Encoding { get => _encoding ?? Encoding.GetEncoding(Encoding.UTF8.CodePage, EncoderFallback.ExceptionFallback, @@ -16,15 +22,11 @@ namespace IrcTokens set { if (value != null) - { _encoding = Encoding.GetEncoding(value.CodePage, EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback); - } } } - private Queue _bufferedLines; - public byte[] PendingBytes { get; private set; } public string Pending() @@ -40,23 +42,15 @@ namespace IrcTokens } } - public StatefulEncoder() - { - Clear(); - } - public void Clear() { - PendingBytes = Array.Empty(); + PendingBytes = Array.Empty(); _bufferedLines = new Queue(); } public void Push(Line line) { - if (line == null) - { - throw new ArgumentNullException(nameof(line)); - } + if (line == null) throw new ArgumentNullException(nameof(line)); PendingBytes = PendingBytes.Concat(Encoding.GetBytes($"{line.Format()}\r\n")).ToArray(); _bufferedLines.Enqueue(line); @@ -66,8 +60,8 @@ namespace IrcTokens { var sent = PendingBytes.Take(byteCount).Count(c => c == '\n'); - PendingBytes = PendingBytes.Skip(byteCount).ToArray(); - _bufferedLines = new Queue(_bufferedLines.Skip(sent)); + PendingBytes = PendingBytes.Skip(byteCount).ToArray(); + _bufferedLines = new Queue(_bufferedLines.Take(sent)); return Enumerable.Range(0, sent) .Select(_ => _bufferedLines.Dequeue()) diff --git a/IrcTokens/Tests/Format.cs b/IrcTokens/Tests/Format.cs index 64f974a..8ef5344 100644 --- a/IrcTokens/Tests/Format.cs +++ b/IrcTokens/Tests/Format.cs @@ -1,6 +1,6 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; +using System; using System.Collections.Generic; +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace IrcTokens.Tests { @@ -13,8 +13,8 @@ namespace IrcTokens.Tests var line = new Line { Command = "PRIVMSG", - Params = new List { "#channel", "hello" }, - Tags = new Dictionary { { "id", "\\" + " " + ";" + "\r\n" } } + Params = new List {"#channel", "hello"}, + Tags = new Dictionary {{"id", "\\" + " " + ";" + "\r\n"}} }.Format(); Assert.AreEqual("@id=\\\\\\s\\:\\r\\n PRIVMSG #channel hello", line); @@ -23,11 +23,7 @@ namespace IrcTokens.Tests [TestMethod] public void TestMissingTag() { - var line = new Line - { - Command = "PRIVMSG", - Params = new List { "#channel", "hello" } - }.Format(); + var line = new Line {Command = "PRIVMSG", Params = new List {"#channel", "hello"}}.Format(); Assert.AreEqual("PRIVMSG #channel hello", line); } @@ -38,8 +34,8 @@ namespace IrcTokens.Tests var line = new Line { Command = "PRIVMSG", - Params = new List { "#channel", "hello" }, - Tags = new Dictionary { { "a", null } } + Params = new List {"#channel", "hello"}, + Tags = new Dictionary {{"a", null}} }.Format(); Assert.AreEqual("@a PRIVMSG #channel hello", line); @@ -51,8 +47,8 @@ namespace IrcTokens.Tests var line = new Line { Command = "PRIVMSG", - Params = new List { "#channel", "hello" }, - Tags = new Dictionary { { "a", "" } } + Params = new List {"#channel", "hello"}, + Tags = new Dictionary {{"a", ""}} }.Format(); Assert.AreEqual("@a PRIVMSG #channel hello", line); @@ -63,9 +59,7 @@ namespace IrcTokens.Tests { var line = new Line { - Command = "PRIVMSG", - Params = new List { "#channel", "hello" }, - Source = "nick!user@host" + Command = "PRIVMSG", Params = new List {"#channel", "hello"}, Source = "nick!user@host" }.Format(); Assert.AreEqual(":nick!user@host PRIVMSG #channel hello", line); @@ -74,25 +68,21 @@ namespace IrcTokens.Tests [TestMethod] public void TestCommandLowercase() { - var line = new Line { Command = "privmsg" }.Format(); + var line = new Line {Command = "privmsg"}.Format(); Assert.AreEqual("privmsg", line); } [TestMethod] public void TestCommandUppercase() { - var line = new Line { Command = "PRIVMSG" }.Format(); + var line = new Line {Command = "PRIVMSG"}.Format(); Assert.AreEqual("PRIVMSG", line); } [TestMethod] public void TestTrailingSpace() { - var line = new Line - { - Command = "PRIVMSG", - Params = new List { "#channel", "hello world" } - }.Format(); + var line = new Line {Command = "PRIVMSG", Params = new List {"#channel", "hello world"}}.Format(); Assert.AreEqual("PRIVMSG #channel :hello world", line); } @@ -100,11 +90,7 @@ namespace IrcTokens.Tests [TestMethod] public void TestTrailingNoSpace() { - var line = new Line - { - Command = "PRIVMSG", - Params = new List { "#channel", "helloworld" } - }.Format(); + var line = new Line {Command = "PRIVMSG", Params = new List {"#channel", "helloworld"}}.Format(); Assert.AreEqual("PRIVMSG #channel helloworld", line); } @@ -112,11 +98,7 @@ namespace IrcTokens.Tests [TestMethod] public void TestTrailingDoubleColon() { - var line = new Line - { - Command = "PRIVMSG", - Params = new List { "#channel", ":helloworld" } - }.Format(); + var line = new Line {Command = "PRIVMSG", Params = new List {"#channel", ":helloworld"}}.Format(); Assert.AreEqual("PRIVMSG #channel ::helloworld", line); } @@ -126,11 +108,7 @@ namespace IrcTokens.Tests { Assert.ThrowsException(() => { - new Line - { - Command = "USER", - Params = new List { "user", "0 *", "real name" } - }.Format(); + new Line {Command = "USER", Params = new List {"user", "0 *", "real name"}}.Format(); }); } @@ -139,11 +117,7 @@ namespace IrcTokens.Tests { Assert.ThrowsException(() => { - new Line - { - Command = "PRIVMSG", - Params = new List { ":#channel", "hello" } - }.Format(); + new Line {Command = "PRIVMSG", Params = new List {":#channel", "hello"}}.Format(); }); } } diff --git a/IrcTokens/Tests/Hostmask.cs b/IrcTokens/Tests/Hostmask.cs index 51bc182..6a5cf65 100644 --- a/IrcTokens/Tests/Hostmask.cs +++ b/IrcTokens/Tests/Hostmask.cs @@ -44,7 +44,7 @@ namespace IrcTokens.Tests [TestMethod] public void TestHostmaskFromLine() { - var line = new Line(":nick!user@host PRIVMSG #channel hello"); + var line = new Line(":nick!user@host PRIVMSG #channel hello"); var hostmask = new IrcTokens.Hostmask("nick!user@host"); Assert.AreEqual(hostmask.ToString(), line.Hostmask.ToString()); Assert.AreEqual("nick", line.Hostmask.NickName); diff --git a/IrcTokens/Tests/Parser.cs b/IrcTokens/Tests/Parser.cs index df70b92..ed4e406 100644 --- a/IrcTokens/Tests/Parser.cs +++ b/IrcTokens/Tests/Parser.cs @@ -1,8 +1,8 @@ -using IrcTokens.Tests.Data; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System.Collections.Generic; +using System.Collections.Generic; using System.Globalization; using System.IO; +using IrcTokens.Tests.Data; +using Microsoft.VisualStudio.TestTools.UnitTesting; using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; @@ -26,13 +26,14 @@ namespace IrcTokens.Tests foreach (var test in LoadYaml("Tests/Data/msg-split.yaml").Tests) { var tokens = new Line(test.Input); - var atoms = test.Atoms; + var atoms = test.Atoms; Assert.AreEqual(atoms.Verb.ToUpper(CultureInfo.InvariantCulture), tokens.Command, $"command failed on: '{test.Input}'"); Assert.AreEqual(atoms.Source, tokens.Source, $"source failed on: '{test.Input}'"); CollectionAssert.AreEqual(atoms.Tags, tokens.Tags, $"tags failed on: '{test.Input}'"); - CollectionAssert.AreEqual(atoms.Params ?? new List(), tokens.Params, $"params failed on: '{test.Input}'"); + CollectionAssert.AreEqual(atoms.Params ?? new List(), tokens.Params, + $"params failed on: '{test.Input}'"); } } @@ -44,10 +45,7 @@ namespace IrcTokens.Tests var atoms = test.Atoms; var line = new Line { - Command = atoms.Verb, - Params = atoms.Params, - Source = atoms.Source, - Tags = atoms.Tags + Command = atoms.Verb, Params = atoms.Params, Source = atoms.Source, Tags = atoms.Tags }.Format(); Assert.IsTrue(test.Matches.Contains(line), test.Description); diff --git a/IrcTokens/Tests/StatefulDecoder.cs b/IrcTokens/Tests/StatefulDecoder.cs index 209a6cf..da4009e 100644 --- a/IrcTokens/Tests/StatefulDecoder.cs +++ b/IrcTokens/Tests/StatefulDecoder.cs @@ -1,6 +1,6 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System.Collections.Generic; +using System.Collections.Generic; using System.Text; +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace IrcTokens.Tests { @@ -25,7 +25,7 @@ namespace IrcTokens.Tests Assert.AreEqual(1, lines.Count); var line = new Line("PRIVMSG #channel hello"); - CollectionAssert.AreEqual(new List { line }, lines); + CollectionAssert.AreEqual(new List {line}, lines); } [TestMethod] @@ -44,9 +44,9 @@ namespace IrcTokens.Tests public void TestEncoding() { var iso8859 = Encoding.GetEncoding("iso-8859-1"); - _decoder = new IrcTokens.StatefulDecoder { Encoding = iso8859 }; + _decoder = new IrcTokens.StatefulDecoder {Encoding = iso8859}; var lines = _decoder.Push(iso8859.GetBytes("PRIVMSG #channel :hello Ç\r\n")); - var line = new Line("PRIVMSG #channel :hello Ç"); + var line = new Line("PRIVMSG #channel :hello Ç"); Assert.IsTrue(line.Equals(lines[0])); } @@ -54,7 +54,7 @@ namespace IrcTokens.Tests public void TestEncodingFallback() { var latin1 = Encoding.GetEncoding("iso-8859-1"); - _decoder = new IrcTokens.StatefulDecoder { Encoding = null, Fallback = latin1 }; + _decoder = new IrcTokens.StatefulDecoder {Encoding = null, Fallback = latin1}; var lines = _decoder.Push(latin1.GetBytes("PRIVMSG #channel hélló\r\n")); Assert.AreEqual(1, lines.Count); Assert.IsTrue(new Line("PRIVMSG #channel hélló").Equals(lines[0])); diff --git a/IrcTokens/Tests/StatefulEncoder.cs b/IrcTokens/Tests/StatefulEncoder.cs index e3ed70d..f2cd6c4 100644 --- a/IrcTokens/Tests/StatefulEncoder.cs +++ b/IrcTokens/Tests/StatefulEncoder.cs @@ -1,5 +1,5 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System.Text; +using System.Text; +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace IrcTokens.Tests { @@ -51,6 +51,19 @@ namespace IrcTokens.Tests Assert.AreEqual(0, lines.Count); } + [TestMethod] + public void TestPopMultipleLines() + { + var line1 = new Line("PRIVMSG #channel1 hello"); + _encoder.Push(line1); + var line2 = new Line("PRIVMSG #channel2 hello"); + _encoder.Push(line2); + + var lines = _encoder.Pop(_encoder.Pending().Length); + Assert.AreEqual(2, lines.Count); + Assert.AreEqual(string.Empty, _encoder.Pending()); + } + [TestMethod] public void TestClear() { @@ -63,7 +76,7 @@ namespace IrcTokens.Tests public void TestEncoding() { var iso8859 = Encoding.GetEncoding("iso-8859-1"); - _encoder = new IrcTokens.StatefulEncoder { Encoding = iso8859 }; + _encoder = new IrcTokens.StatefulEncoder {Encoding = iso8859}; _encoder.Push(new Line("PRIVMSG #channel :hello Ç")); CollectionAssert.AreEqual(iso8859.GetBytes("PRIVMSG #channel :hello Ç\r\n"), _encoder.PendingBytes); } diff --git a/IrcTokens/Tests/Tokenization.cs b/IrcTokens/Tests/Tokenization.cs index c4970ed..7e2139d 100644 --- a/IrcTokens/Tests/Tokenization.cs +++ b/IrcTokens/Tests/Tokenization.cs @@ -1,5 +1,5 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System.Collections.Generic; +using System.Collections.Generic; +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace IrcTokens.Tests { @@ -87,14 +87,14 @@ namespace IrcTokens.Tests public void TestParamsTrailing() { var line = new Line("PRIVMSG #channel :hello world"); - CollectionAssert.AreEqual(new List { "#channel", "hello world" }, line.Params); + CollectionAssert.AreEqual(new List {"#channel", "hello world"}, line.Params); } [TestMethod] public void TestParamsOnlyTrailing() { var line = new Line("PRIVMSG :hello world"); - CollectionAssert.AreEqual(new List { "hello world" }, line.Params); + CollectionAssert.AreEqual(new List {"hello world"}, line.Params); } [TestMethod] @@ -109,10 +109,10 @@ namespace IrcTokens.Tests public void TestAllTokens() { var line = new Line("@id=123 :nick!user@host PRIVMSG #channel :hello world"); - CollectionAssert.AreEqual(new Dictionary { { "id", "123" } }, line.Tags); + CollectionAssert.AreEqual(new Dictionary {{"id", "123"}}, line.Tags); Assert.AreEqual("nick!user@host", line.Source); Assert.AreEqual("PRIVMSG", line.Command); - CollectionAssert.AreEqual(new List { "#channel", "hello world" }, line.Params); + CollectionAssert.AreEqual(new List {"#channel", "hello world"}, line.Params); } } }