From 21f1e95fb8e935134a969bc3d729964d8d2aadfa Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Thu, 14 May 2020 23:06:10 -0400 Subject: rename Irc to IRC --- IrcTokens/Extensions.cs | 62 ------- IrcTokens/Hostmask.cs | 64 ------- IrcTokens/IrcTokens.csproj | 29 --- IrcTokens/Line.cs | 233 ------------------------ IrcTokens/README.md | 96 ---------- IrcTokens/StatefulDecoder.cs | 79 --------- IrcTokens/StatefulEncoder.cs | 71 -------- IrcTokens/Tests/Data/JoinModel.cs | 30 ---- IrcTokens/Tests/Data/SplitModel.cs | 15 -- IrcTokens/Tests/Data/msg-join.yaml | 221 ----------------------- IrcTokens/Tests/Data/msg-split.yaml | 343 ------------------------------------ IrcTokens/Tests/Format.cs | 105 ----------- IrcTokens/Tests/Hostmask.cs | 64 ------- IrcTokens/Tests/Parser.cs | 55 ------ IrcTokens/Tests/StatefulDecoder.cs | 88 --------- IrcTokens/Tests/StatefulEncoder.cs | 84 --------- IrcTokens/Tests/Tokenization.cs | 118 ------------- 17 files changed, 1757 deletions(-) delete mode 100644 IrcTokens/Extensions.cs delete mode 100644 IrcTokens/Hostmask.cs delete mode 100644 IrcTokens/IrcTokens.csproj delete mode 100644 IrcTokens/Line.cs delete mode 100644 IrcTokens/README.md delete mode 100644 IrcTokens/StatefulDecoder.cs delete mode 100644 IrcTokens/StatefulEncoder.cs delete mode 100644 IrcTokens/Tests/Data/JoinModel.cs delete mode 100644 IrcTokens/Tests/Data/SplitModel.cs delete mode 100644 IrcTokens/Tests/Data/msg-join.yaml delete mode 100644 IrcTokens/Tests/Data/msg-split.yaml delete mode 100644 IrcTokens/Tests/Format.cs delete mode 100644 IrcTokens/Tests/Hostmask.cs delete mode 100644 IrcTokens/Tests/Parser.cs delete mode 100644 IrcTokens/Tests/StatefulDecoder.cs delete mode 100644 IrcTokens/Tests/StatefulEncoder.cs delete mode 100644 IrcTokens/Tests/Tokenization.cs (limited to 'IrcTokens') diff --git a/IrcTokens/Extensions.cs b/IrcTokens/Extensions.cs deleted file mode 100644 index 4b23774..0000000 --- a/IrcTokens/Extensions.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace IrcTokens -{ - public static class Extensions - { - public static IEnumerable Split(this byte[] bytes, byte separator) - { - if (bytes == null || bytes.Length == 0) return new List(); - - var newLineIndices = bytes.Select((b, i) => b == separator ? i : -1).Where(i => i != -1).ToArray(); - var lines = new byte[newLineIndices.Length + 1][]; - var currentIndex = 0; - var arrIndex = 0; - - for (var i = 0; i < newLineIndices.Length && currentIndex < bytes.Length; ++i) - { - var n = new byte[newLineIndices[i] - currentIndex]; - Array.Copy(bytes, currentIndex, n, 0, newLineIndices[i] - currentIndex); - currentIndex = newLineIndices[i] + 1; - lines[arrIndex++] = n; - } - - // Handle the last string at the end of the array if there is one. - if (currentIndex < bytes.Length) - lines[arrIndex] = bytes.Skip(currentIndex).ToArray(); - else if (arrIndex == newLineIndices.Length) - // We had a separator character at the end of a string. Rather than just allowing - // a null character, we'll replace the last element in the array with an empty string. - lines[arrIndex] = Array.Empty(); - - return lines.ToArray(); - } - - public static byte[] Trim(this IEnumerable bytes, byte separator) - { - if (bytes == null) return Array.Empty(); - - var byteList = new List(bytes); - var i = 0; - - if (!byteList.Any()) return byteList.ToArray(); - - while (byteList[i] == separator) - { - byteList.RemoveAt(i); - i++; - } - - i = byteList.Count - 1; - while (byteList[i] == separator) - { - byteList.RemoveAt(i); - i--; - } - - return byteList.ToArray(); - } - } -} diff --git a/IrcTokens/Hostmask.cs b/IrcTokens/Hostmask.cs deleted file mode 100644 index 3c0b7f2..0000000 --- a/IrcTokens/Hostmask.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System; - -namespace IrcTokens -{ - /// - /// Represents the three parts of a hostmask. Parse with the constructor. - /// - public class Hostmask : IEquatable - { - private readonly string _source; - - public Hostmask(string source) - { - if (source == null) return; - - _source = source; - - if (source.Contains('@', StringComparison.Ordinal)) - { - var split = source.Split('@'); - - NickName = split[0]; - HostName = split[1]; - } - else - { - NickName = source; - } - - if (NickName.Contains('!', StringComparison.Ordinal)) - { - var userSplit = NickName.Split('!'); - NickName = userSplit[0]; - 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); - } - } -} diff --git a/IrcTokens/IrcTokens.csproj b/IrcTokens/IrcTokens.csproj deleted file mode 100644 index 2fe9300..0000000 --- a/IrcTokens/IrcTokens.csproj +++ /dev/null @@ -1,29 +0,0 @@ - - - - netcoreapp3.1 - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - - PreserveNewest - - - PreserveNewest - - - - diff --git a/IrcTokens/Line.cs b/IrcTokens/Line.cs deleted file mode 100644 index 36899bf..0000000 --- a/IrcTokens/Line.cs +++ /dev/null @@ -1,233 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; - -namespace IrcTokens -{ - /// - /// Tools to represent, parse, and format IRC lines - /// - public class Line : IEquatable - { - private static readonly string[] TagUnescaped = {"\\", " ", ";", "\r", "\n"}; - - private static readonly string[] TagEscaped = {"\\\\", "\\s", "\\:", "\\r", "\\n"}; - - private Hostmask _hostmask; - - public Line() - { - } - - public Line(string command, params string[] parameters) - { - Command = command; - Params = parameters.ToList(); - } - - /// - /// 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)); - - string[] split; - - if (line.StartsWith('@')) - { - Tags = new Dictionary(); - - split = line.Split(" ", 2); - var messageTags = split[0]; - line = split[1]; - - foreach (var part in messageTags.Substring(1).Split(';')) - if (part.Contains('=', StringComparison.Ordinal)) - { - 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]; - trailing = split[1]; - } - else - { - trailing = null; - } - - Params = line.Contains(' ', StringComparison.Ordinal) - ? line.Split(' ', StringSplitOptions.RemoveEmptyEntries).ToList() - : new List {line}; - - if (Params[0].StartsWith(':')) - { - Source = Params[0].Substring(1); - Params.RemoveAt(0); - } - - if (Params.Count > 0) - { - Command = Params[0].ToUpper(CultureInfo.InvariantCulture); - Params.RemoveAt(0); - } - - 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(); - } - - /// - /// Unescape ircv3 tag - /// - /// escaped string - /// unescaped string - private 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 - private 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() - { - var outs = new List(); - - if (Tags != null && Tags.Any()) - { - var tags = Tags.Keys - .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}"); - - outs.Add(Command); - - if (Params != null && Params.Any()) - { - var last = Params[^1]; - var withoutLast = Params.SkipLast(1).ToList(); - - foreach (var p in withoutLast) - { - 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(withoutLast); - - if (string.IsNullOrWhiteSpace(last) || last.Contains(' ', StringComparison.Ordinal) || - last.StartsWith(':')) - last = $":{last}"; - - outs.Add(last); - } - - return string.Join(" ", outs); - } - } -} diff --git a/IrcTokens/README.md b/IrcTokens/README.md deleted file mode 100644 index 3981654..0000000 --- a/IrcTokens/README.md +++ /dev/null @@ -1,96 +0,0 @@ -# irctokens - -this is a c\# port of jesopo's [irctokens]( -https://github.com/jesopo/irctokens) - -## usage - -### tokenization - - using IrcTokens; - - ... - - var line = new Line("@id=123 :ben!~ben@host.tld PRIVMSG #channel :hello there!"); - Console.WriteLine(line); - Console.WriteLine(line.Format()); - -### formatting - - var line = new Line {Command = "USER", Params = new List {"user", "0", "*", "real name"}}; - Console.WriteLine(line); - Console.WriteLine(line.Format()); - -### stateful - -see the full example in [TokensSample/Client.cs](../Examples/Tokens/Client.cs) - - public class Client - { - private readonly byte[] _bytes; - private readonly StatefulDecoder _decoder; - private readonly StatefulEncoder _encoder; - private readonly Socket _socket; - - public Client() - { - _decoder = new StatefulDecoder(); - _encoder = new StatefulEncoder(); - _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP); - _bytes = new byte[1024]; - } - - public void Start() - { - _socket.Connect("127.0.0.1", 6667); - while (!_socket.Connected) Thread.Sleep(1000); - - Send(new Line {Command = "NICK", Params = new List {"tokensbot"}}); - Send(new Line {Command = "USER", Params = new List {"tokensbot", "0", "*", "real name"}}); - - while (true) - { - var bytesReceived = _socket.Receive(_bytes); - - if (bytesReceived == 0) - { - Console.WriteLine("! disconnected"); - _socket.Shutdown(SocketShutdown.Both); - _socket.Close(); - break; - } - - var lines = _decoder.Push(_bytes, bytesReceived); - - foreach (var line in lines) - { - Console.WriteLine($"< {line.Format()}"); - - switch (line.Command) - { - case "PING": - Send(new Line {Command = "PONG", Params = line.Params}); - break; - case "001": - Send(new Line {Command = "JOIN", Params = new List {"#test"}}); - break; - case "PRIVMSG": - Send(new Line - { - Command = "PRIVMSG", Params = new List {line.Params[0], "hello there"} - }); - break; - } - } - } - } - - private void Send(Line line) - { - Console.WriteLine($"> {line.Format()}"); - _encoder.Push(line); - while (_encoder.PendingBytes.Length > 0) - _encoder.Pop(_socket.Send(_encoder.PendingBytes, SocketFlags.None)); - } - } - diff --git a/IrcTokens/StatefulDecoder.cs b/IrcTokens/StatefulDecoder.cs deleted file mode 100644 index 1f6636b..0000000 --- a/IrcTokens/StatefulDecoder.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace IrcTokens -{ - public class StatefulDecoder - { - private byte[] _buffer; - private Encoding _encoding; - private Encoding _fallback; - - public StatefulDecoder() - { - Clear(); - } - - public Encoding Encoding - { - get => _encoding ?? Encoding.GetEncoding(Encoding.UTF8.CodePage, EncoderFallback.ExceptionFallback, - DecoderFallback.ExceptionFallback); - set - { - if (value != null) - _encoding = Encoding.GetEncoding(value.CodePage, EncoderFallback.ExceptionFallback, - DecoderFallback.ReplacementFallback); - } - } - - public Encoding Fallback - { - get => _fallback ?? Encoding.GetEncoding(Encoding.GetEncoding("iso-8859-1").CodePage, - EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback); - set - { - if (value != null) - _fallback = Encoding.GetEncoding(value.CodePage, EncoderFallback.ReplacementFallback, - DecoderFallback.ReplacementFallback); - } - } - - public string Pending => Encoding.GetString(_buffer); - - public void Clear() - { - _buffer = Array.Empty(); - } - - public List Push(string data) - { - var bytes = Encoding.GetBytes(data); - return Push(bytes, bytes.Length); - } - - public List Push(byte[] data, int bytesReceived) - { - if (data == null) return null; - - _buffer = _buffer == null ? Array.Empty() : _buffer.Concat(data.Take(bytesReceived)).ToArray(); - - var listLines = _buffer.Split((byte) '\n').Select(l => l.Trim((byte) '\r')).ToList(); - _buffer = listLines.LastOrDefault() ?? Array.Empty(); - - var decodeLines = new List(); - foreach (var line in listLines.SkipLast(1).Select(l => l.ToArray())) - try - { - decodeLines.Add(new Line(Encoding.GetString(line))); - } - catch (DecoderFallbackException) - { - decodeLines.Add(new Line(Fallback.GetString(line))); - } - - return decodeLines; - } - } -} diff --git a/IrcTokens/StatefulEncoder.cs b/IrcTokens/StatefulEncoder.cs deleted file mode 100644 index bec4e42..0000000 --- a/IrcTokens/StatefulEncoder.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace IrcTokens -{ - public class StatefulEncoder - { - private List _bufferedLines; - private Encoding _encoding; - - public StatefulEncoder() - { - Clear(); - } - - public Encoding Encoding - { - get => _encoding ?? Encoding.GetEncoding(Encoding.UTF8.CodePage, EncoderFallback.ExceptionFallback, - DecoderFallback.ExceptionFallback); - set - { - if (value != null) - _encoding = Encoding.GetEncoding(value.CodePage, EncoderFallback.ExceptionFallback, - DecoderFallback.ExceptionFallback); - } - } - - public byte[] PendingBytes { get; private set; } - - public string Pending() - { - try - { - return Encoding.GetString(PendingBytes); - } - catch (DecoderFallbackException e) - { - Console.WriteLine(e); - throw; - } - } - - public void Clear() - { - PendingBytes = Array.Empty(); - _bufferedLines = new List(); - } - - public void Push(Line line) - { - if (line == null) throw new ArgumentNullException(nameof(line)); - - PendingBytes = PendingBytes.Concat(Encoding.GetBytes($"{line.Format()}\r\n")).ToArray(); - _bufferedLines.Add(line); - } - - public List Pop(int byteCount) - { - var sent = PendingBytes.Take(byteCount).Count(c => c == '\n'); - - PendingBytes = PendingBytes.Skip(byteCount).ToArray(); - - var sentLines = _bufferedLines.Take(sent).ToList(); - _bufferedLines = _bufferedLines.Skip(sent).ToList(); - - return sentLines; - } - } -} diff --git a/IrcTokens/Tests/Data/JoinModel.cs b/IrcTokens/Tests/Data/JoinModel.cs deleted file mode 100644 index 2c08e58..0000000 --- a/IrcTokens/Tests/Data/JoinModel.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Collections.Generic; -using YamlDotNet.Serialization; - -namespace IrcTokens.Tests.Data -{ - public class JoinModel - { - public List Tests { get; set; } - - public class Test - { - [YamlMember(Alias = "desc")] public string Description { get; set; } - - public Atoms Atoms { get; set; } - - public List Matches { get; set; } - } - - public class Atoms - { - public Dictionary Tags { get; set; } - - public string Source { get; set; } - - public string Verb { get; set; } - - public List Params { get; set; } - } - } -} diff --git a/IrcTokens/Tests/Data/SplitModel.cs b/IrcTokens/Tests/Data/SplitModel.cs deleted file mode 100644 index 65177a3..0000000 --- a/IrcTokens/Tests/Data/SplitModel.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Collections.Generic; - -namespace IrcTokens.Tests.Data -{ - public class SplitModel - { - public List Tests { get; set; } - - public class Test - { - public string Input { get; set; } - public JoinModel.Atoms Atoms { get; set; } - } - } -} diff --git a/IrcTokens/Tests/Data/msg-join.yaml b/IrcTokens/Tests/Data/msg-join.yaml deleted file mode 100644 index d1d7429..0000000 --- a/IrcTokens/Tests/Data/msg-join.yaml +++ /dev/null @@ -1,221 +0,0 @@ -# IRC parser tests -# joining atoms into sendable messages - -# Written in 2015 by Daniel Oaks -# -# To the extent possible under law, the author(s) have dedicated all copyright -# and related and neighboring rights to this software to the public domain -# worldwide. This software is distributed without any warranty. -# -# You should have received a copy of the CC0 Public Domain Dedication along -# with this software. If not, see -# . - -# some of the tests here originate from grawity's test vectors, which is WTFPL v2 licensed -# https://github.com/grawity/code/tree/master/lib/tests -# some of the tests here originate from Mozilla's test vectors, which is public domain -# https://dxr.mozilla.org/comm-central/source/chat/protocols/irc/test/test_ircMessage.js -# some of the tests here originate from SaberUK's test vectors, which he's indicated I am free to include here -# https://github.com/SaberUK/ircparser/tree/master/test - -tests: - # the desc string holds a description of the test, if it exists - - # the atoms dict has the keys: - # * tags: tags dict - # tags with no value are an empty string - # * source: source string, without single leading colon - # * verb: verb string - # * params: params split up as a list - # if the params key does not exist, assume it is empty - # if any other keys do no exist, assume they are null - # a key that is null does not exist or is not specified with the - # given input string - - # matches is a list of messages that match - - # simple tests - - desc: Simple test with verb and params. - atoms: - verb: "foo" - params: - - "bar" - - "baz" - - "asdf" - matches: - - "foo bar baz asdf" - - "foo bar baz :asdf" - - # with no regular params - - desc: Simple test with source and no params. - atoms: - source: "src" - verb: "AWAY" - matches: - - ":src AWAY" - - - desc: Simple test with source and empty trailing param. - atoms: - source: "src" - verb: "AWAY" - params: - - "" - matches: - - ":src AWAY :" - - # with source - - desc: Simple test with source. - atoms: - source: "coolguy" - verb: "foo" - params: - - "bar" - - "baz" - - "asdf" - matches: - - ":coolguy foo bar baz asdf" - - ":coolguy foo bar baz :asdf" - - # with trailing param - - desc: Simple test with trailing param. - atoms: - verb: "foo" - params: - - "bar" - - "baz" - - "asdf quux" - matches: - - "foo bar baz :asdf quux" - - - desc: Simple test with empty trailing param. - atoms: - verb: "foo" - params: - - "bar" - - "baz" - - "" - matches: - - "foo bar baz :" - - - desc: Simple test with trailing param containing colon. - atoms: - verb: "foo" - params: - - "bar" - - "baz" - - ":asdf" - matches: - - "foo bar baz ::asdf" - - # with source and trailing param - - desc: Test with source and trailing param. - atoms: - source: "coolguy" - verb: "foo" - params: - - "bar" - - "baz" - - "asdf quux" - matches: - - ":coolguy foo bar baz :asdf quux" - - - desc: Test with trailing containing beginning+end whitespace. - atoms: - source: "coolguy" - verb: "foo" - params: - - "bar" - - "baz" - - " asdf quux " - matches: - - ":coolguy foo bar baz : asdf quux " - - - desc: Test with trailing containing what looks like another trailing param. - atoms: - source: "coolguy" - verb: "PRIVMSG" - params: - - "bar" - - "lol :) " - matches: - - ":coolguy PRIVMSG bar :lol :) " - - - desc: Simple test with source and empty trailing. - atoms: - source: "coolguy" - verb: "foo" - params: - - "bar" - - "baz" - - "" - matches: - - ":coolguy foo bar baz :" - - - desc: Trailing contains only spaces. - atoms: - source: "coolguy" - verb: "foo" - params: - - "bar" - - "baz" - - " " - matches: - - ":coolguy foo bar baz : " - - - desc: Param containing tab (tab is not considered SPACE for message splitting). - atoms: - source: "coolguy" - verb: "foo" - params: - - "b\tar" - - "baz" - matches: - - ":coolguy foo b\tar baz" - - ":coolguy foo b\tar :baz" - - # with tags - - desc: Tag with no value and space-filled trailing. - atoms: - tags: - "asd": "" - source: "coolguy" - verb: "foo" - params: - - "bar" - - "baz" - - " " - matches: - - "@asd :coolguy foo bar baz : " - - - desc: Tags with escaped values. - atoms: - verb: "foo" - tags: - "a": "b\\and\nk" - "d": "gh;764" - matches: - - "@a=b\\\\and\\nk;d=gh\\:764 foo" - - "@d=gh\\:764;a=b\\\\and\\nk foo" - - - desc: Tags with escaped values and params. - atoms: - verb: "foo" - tags: - "a": "b\\and\nk" - "d": "gh;764" - params: - - "par1" - - "par2" - matches: - - "@a=b\\\\and\\nk;d=gh\\:764 foo par1 par2" - - "@a=b\\\\and\\nk;d=gh\\:764 foo par1 :par2" - - "@d=gh\\:764;a=b\\\\and\\nk foo par1 par2" - - "@d=gh\\:764;a=b\\\\and\\nk foo par1 :par2" - - - desc: Tag with long, strange values (including LF and newline). - atoms: - tags: - foo: "\\\\;\\s \r\n" - verb: "COMMAND" - matches: - - "@foo=\\\\\\\\\\:\\\\s\\s\\r\\n COMMAND" diff --git a/IrcTokens/Tests/Data/msg-split.yaml b/IrcTokens/Tests/Data/msg-split.yaml deleted file mode 100644 index fa3f4aa..0000000 --- a/IrcTokens/Tests/Data/msg-split.yaml +++ /dev/null @@ -1,343 +0,0 @@ -# IRC parser tests -# splitting messages into usable atoms - -# Written in 2015 by Daniel Oaks -# -# To the extent possible under law, the author(s) have dedicated all copyright -# and related and neighboring rights to this software to the public domain -# worldwide. This software is distributed without any warranty. -# -# You should have received a copy of the CC0 Public Domain Dedication along -# with this software. If not, see -# . - -# some of the tests here originate from grawity's test vectors, which is WTFPL v2 licensed -# https://github.com/grawity/code/tree/master/lib/tests -# some of the tests here originate from Mozilla's test vectors, which is public domain -# https://dxr.mozilla.org/comm-central/source/chat/protocols/irc/test/test_ircMessage.js -# some of the tests here originate from SaberUK's test vectors, which he's indicated I am free to include here -# https://github.com/SaberUK/ircparser/tree/master/test - -# we follow RFC1459 with regards to multiple ascii spaces splitting atoms: -# The prefix, command, and all parameters are -# separated by one (or more) ASCII space character(s) (0x20). -# because doing it as RFC2812 says (strictly as a single ascii space) isn't sane - -tests: - # input is the string coming directly from the server to parse - - # the atoms dict has the keys: - # * tags: tags dict - # tags with no value are an empty string - # * source: source string, without single leading colon - # * verb: verb string - # * params: params split up as a list - # if the params key does not exist, assume it is empty - # if any other keys do no exist, assume they are null - # a key that is null does not exist or is not specified with the - # given input string - - # simple - - input: "foo bar baz asdf" - atoms: - verb: "foo" - params: - - "bar" - - "baz" - - "asdf" - - # with source - - input: ":coolguy foo bar baz asdf" - atoms: - source: "coolguy" - verb: "foo" - params: - - "bar" - - "baz" - - "asdf" - - # with trailing param - - input: "foo bar baz :asdf quux" - atoms: - verb: "foo" - params: - - "bar" - - "baz" - - "asdf quux" - - - input: "foo bar baz :" - atoms: - verb: "foo" - params: - - "bar" - - "baz" - - "" - - - input: "foo bar baz ::asdf" - atoms: - verb: "foo" - params: - - "bar" - - "baz" - - ":asdf" - - # with source and trailing param - - input: ":coolguy foo bar baz :asdf quux" - atoms: - source: "coolguy" - verb: "foo" - params: - - "bar" - - "baz" - - "asdf quux" - - - input: ":coolguy foo bar baz : asdf quux " - atoms: - source: "coolguy" - verb: "foo" - params: - - "bar" - - "baz" - - " asdf quux " - - - input: ":coolguy PRIVMSG bar :lol :) " - atoms: - source: "coolguy" - verb: "PRIVMSG" - params: - - "bar" - - "lol :) " - - - input: ":coolguy foo bar baz :" - atoms: - source: "coolguy" - verb: "foo" - params: - - "bar" - - "baz" - - "" - - - input: ":coolguy foo bar baz : " - atoms: - source: "coolguy" - verb: "foo" - params: - - "bar" - - "baz" - - " " - - # with tags - - input: "@a=b;c=32;k;rt=ql7 foo" - atoms: - verb: "foo" - tags: - "a": "b" - "c": "32" - "k": "" - "rt": "ql7" - - # with escaped tags - - input: "@a=b\\\\and\\nk;c=72\\s45;d=gh\\:764 foo" - atoms: - verb: "foo" - tags: - "a": "b\\and\nk" - "c": "72 45" - "d": "gh;764" - - # with tags and source - - input: "@c;h=;a=b :quux ab cd" - atoms: - tags: - "c": "" - "h": "" - "a": "b" - source: "quux" - verb: "ab" - params: - - "cd" - - # different forms of last param - - input: ":src JOIN #chan" - atoms: - source: "src" - verb: "JOIN" - params: - - "#chan" - - - input: ":src JOIN :#chan" - atoms: - source: "src" - verb: "JOIN" - params: - - "#chan" - - # with and without last param - - input: ":src AWAY" - atoms: - source: "src" - verb: "AWAY" - - - input: ":src AWAY " - atoms: - source: "src" - verb: "AWAY" - - # tab is not considered - - input: ":cool\tguy foo bar baz" - atoms: - source: "cool\tguy" - verb: "foo" - params: - - "bar" - - "baz" - - # with weird control codes in the source - - input: ":coolguy!ag@net\x035w\x03ork.admin PRIVMSG foo :bar baz" - atoms: - source: "coolguy!ag@net\x035w\x03ork.admin" - verb: "PRIVMSG" - params: - - "foo" - - "bar baz" - - - input: ":coolguy!~ag@n\x02et\x0305w\x0fork.admin PRIVMSG foo :bar baz" - atoms: - source: "coolguy!~ag@n\x02et\x0305w\x0fork.admin" - verb: "PRIVMSG" - params: - - "foo" - - "bar baz" - - - input: "@tag1=value1;tag2;vendor1/tag3=value2;vendor2/tag4= :irc.example.com COMMAND param1 param2 :param3 param3" - atoms: - tags: - tag1: "value1" - tag2: "" - vendor1/tag3: "value2" - vendor2/tag4: "" - source: "irc.example.com" - verb: "COMMAND" - params: - - "param1" - - "param2" - - "param3 param3" - - - input: ":irc.example.com COMMAND param1 param2 :param3 param3" - atoms: - source: "irc.example.com" - verb: "COMMAND" - params: - - "param1" - - "param2" - - "param3 param3" - - - input: "@tag1=value1;tag2;vendor1/tag3=value2;vendor2/tag4 COMMAND param1 param2 :param3 param3" - atoms: - tags: - tag1: "value1" - tag2: "" - vendor1/tag3: "value2" - vendor2/tag4: "" - verb: "COMMAND" - params: - - "param1" - - "param2" - - "param3 param3" - - - input: "COMMAND" - atoms: - verb: "COMMAND" - - # yaml encoding + slashes is fun - - input: "@foo=\\\\\\\\\\:\\\\s\\s\\r\\n COMMAND" - atoms: - tags: - foo: "\\\\;\\s \r\n" - verb: "COMMAND" - - # broken messages from unreal - - input: ":gravel.mozilla.org 432 #momo :Erroneous Nickname: Illegal characters" - atoms: - source: "gravel.mozilla.org" - verb: "432" - params: - - "#momo" - - "Erroneous Nickname: Illegal characters" - - - input: ":gravel.mozilla.org MODE #tckk +n " - atoms: - source: "gravel.mozilla.org" - verb: "MODE" - params: - - "#tckk" - - "+n" - - - input: ":services.esper.net MODE #foo-bar +o foobar " - atoms: - source: "services.esper.net" - verb: "MODE" - params: - - "#foo-bar" - - "+o" - - "foobar" - - # tag values should be parsed char-at-a-time to prevent wayward replacements. - - input: "@tag1=value\\\\ntest COMMAND" - atoms: - tags: - tag1: "value\\ntest" - verb: "COMMAND" - - # If a tag value has a slash followed by a character which doesn't need - # to be escaped, the slash should be dropped. - - input: "@tag1=value\\1 COMMAND" - atoms: - tags: - tag1: "value1" - verb: "COMMAND" - - # A slash at the end of a tag value should be dropped - - input: "@tag1=value1\\ COMMAND" - atoms: - tags: - tag1: "value1" - verb: "COMMAND" - - # Duplicate tags: Parsers SHOULD disregard all but the final occurence - - input: "@tag1=1;tag2=3;tag3=4;tag1=5 COMMAND" - atoms: - tags: - tag1: "5" - tag2: "3" - tag3: "4" - verb: "COMMAND" - - # vendored tags can have the same name as a non-vendored tag - - input: "@tag1=1;tag2=3;tag3=4;tag1=5;vendor/tag2=8 COMMAND" - atoms: - tags: - tag1: "5" - tag2: "3" - tag3: "4" - vendor/tag2: "8" - verb: "COMMAND" - - # Some parsers handle /MODE in a special way, make sure they do it right - - input: ":SomeOp MODE #channel :+i" - atoms: - source: "SomeOp" - verb: "MODE" - params: - - "#channel" - - "+i" - - - input: ":SomeOp MODE #channel +oo SomeUser :AnotherUser" - atoms: - source: "SomeOp" - verb: "MODE" - params: - - "#channel" - - "+oo" - - "SomeUser" - - "AnotherUser" diff --git a/IrcTokens/Tests/Format.cs b/IrcTokens/Tests/Format.cs deleted file mode 100644 index 69a5682..0000000 --- a/IrcTokens/Tests/Format.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace IrcTokens.Tests -{ - [TestClass] - public class Format - { - [TestMethod] - public void TestTags() - { - var line = new Line("PRIVMSG", "#channel", "hello") - { - Tags = new Dictionary {{"id", "\\" + " " + ";" + "\r\n"}} - }.Format(); - - Assert.AreEqual("@id=\\\\\\s\\:\\r\\n PRIVMSG #channel hello", line); - } - - [TestMethod] - public void TestMissingTag() - { - var line = new Line("PRIVMSG", "#channel", "hello").Format(); - - Assert.AreEqual("PRIVMSG #channel hello", line); - } - - [TestMethod] - public void TestNullTag() - { - var line = new Line("PRIVMSG", "#channel", "hello") {Tags = new Dictionary {{"a", null}}} - .Format(); - - Assert.AreEqual("@a PRIVMSG #channel hello", line); - } - - [TestMethod] - public void TestEmptyTag() - { - var line = new Line("PRIVMSG", "#channel", "hello") {Tags = new Dictionary {{"a", ""}}} - .Format(); - - Assert.AreEqual("@a PRIVMSG #channel hello", line); - } - - [TestMethod] - public void TestSource() - { - var line = new Line("PRIVMSG", "#channel", "hello") {Source = "nick!user@host"}.Format(); - - Assert.AreEqual(":nick!user@host PRIVMSG #channel hello", line); - } - - [TestMethod] - public void TestCommandLowercase() - { - var line = new Line {Command = "privmsg"}.Format(); - Assert.AreEqual("privmsg", line); - } - - [TestMethod] - public void TestCommandUppercase() - { - var line = new Line {Command = "PRIVMSG"}.Format(); - Assert.AreEqual("PRIVMSG", line); - } - - [TestMethod] - public void TestTrailingSpace() - { - var line = new Line("PRIVMSG", "#channel", "hello world").Format(); - - Assert.AreEqual("PRIVMSG #channel :hello world", line); - } - - [TestMethod] - public void TestTrailingNoSpace() - { - var line = new Line("PRIVMSG", "#channel", "helloworld").Format(); - - Assert.AreEqual("PRIVMSG #channel helloworld", line); - } - - [TestMethod] - public void TestTrailingDoubleColon() - { - var line = new Line("PRIVMSG", "#channel", ":helloworld").Format(); - - Assert.AreEqual("PRIVMSG #channel ::helloworld", line); - } - - [TestMethod] - public void TestInvalidNonLastSpace() - { - Assert.ThrowsException(() => { new Line("USER", "user", "0 *", "real name").Format(); }); - } - - [TestMethod] - public void TestInvalidNonLastColon() - { - Assert.ThrowsException(() => { new Line("PRIVMSG", ":#channel", "hello").Format(); }); - } - } -} diff --git a/IrcTokens/Tests/Hostmask.cs b/IrcTokens/Tests/Hostmask.cs deleted file mode 100644 index 6a5cf65..0000000 --- a/IrcTokens/Tests/Hostmask.cs +++ /dev/null @@ -1,64 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace IrcTokens.Tests -{ - [TestClass] - public class Hostmask - { - [TestMethod] - public void TestHostmask() - { - var hostmask = new IrcTokens.Hostmask("nick!user@host"); - Assert.AreEqual("nick", hostmask.NickName); - Assert.AreEqual("user", hostmask.UserName); - Assert.AreEqual("host", hostmask.HostName); - } - - [TestMethod] - public void TestNoHostName() - { - var hostmask = new IrcTokens.Hostmask("nick!user"); - Assert.AreEqual("nick", hostmask.NickName); - Assert.AreEqual("user", hostmask.UserName); - Assert.IsNull(hostmask.HostName); - } - - [TestMethod] - public void TestNoUserName() - { - var hostmask = new IrcTokens.Hostmask("nick@host"); - Assert.AreEqual("nick", hostmask.NickName); - Assert.IsNull(hostmask.UserName); - Assert.AreEqual("host", hostmask.HostName); - } - - [TestMethod] - public void TestOnlyNickName() - { - var hostmask = new IrcTokens.Hostmask("nick"); - Assert.AreEqual("nick", hostmask.NickName); - Assert.IsNull(hostmask.UserName); - Assert.IsNull(hostmask.HostName); - } - - [TestMethod] - public void TestHostmaskFromLine() - { - 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); - Assert.AreEqual("user", line.Hostmask.UserName); - Assert.AreEqual("host", line.Hostmask.HostName); - } - - [TestMethod] - public void TestEmptyHostmaskFromLine() - { - var line = new Line("PRIVMSG #channel hello"); - Assert.IsNull(line.Hostmask.HostName); - Assert.IsNull(line.Hostmask.UserName); - Assert.IsNull(line.Hostmask.NickName); - } - } -} diff --git a/IrcTokens/Tests/Parser.cs b/IrcTokens/Tests/Parser.cs deleted file mode 100644 index ed4e406..0000000 --- a/IrcTokens/Tests/Parser.cs +++ /dev/null @@ -1,55 +0,0 @@ -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; - -namespace IrcTokens.Tests -{ - [TestClass] - public class Parser - { - private static T LoadYaml(string path) - { - var deserializer = new DeserializerBuilder() - .WithNamingConvention(CamelCaseNamingConvention.Instance) - .Build(); - - return deserializer.Deserialize(File.ReadAllText(path)); - } - - [TestMethod] - public void TestSplit() - { - foreach (var test in LoadYaml("Tests/Data/msg-split.yaml").Tests) - { - var tokens = new Line(test.Input); - 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}'"); - } - } - - [TestMethod] - public void TestJoin() - { - foreach (var test in LoadYaml("Tests/Data/msg-join.yaml").Tests) - { - var atoms = test.Atoms; - var line = new Line - { - 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 deleted file mode 100644 index 9d2b8b7..0000000 --- a/IrcTokens/Tests/StatefulDecoder.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System.Collections.Generic; -using System.Text; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace IrcTokens.Tests -{ - [TestClass] - public class StatefulDecoder - { - private IrcTokens.StatefulDecoder _decoder; - - [TestInitialize] - public void TestInitialize() - { - _decoder = new IrcTokens.StatefulDecoder(); - } - - [TestMethod] - public void TestPartial() - { - var lines = _decoder.Push("PRIVMSG "); - Assert.AreEqual(0, lines.Count); - - lines = _decoder.Push("#channel hello\r\n"); - Assert.AreEqual(1, lines.Count); - - var line = new Line("PRIVMSG #channel hello"); - CollectionAssert.AreEqual(new List {line}, lines); - } - - [TestMethod] - public void TestMultiple() - { - var lines = _decoder.Push("PRIVMSG #channel1 hello\r\nPRIVMSG #channel2 hello\r\n"); - Assert.AreEqual(2, lines.Count); - - var line1 = new Line("PRIVMSG #channel1 hello"); - var line2 = new Line("PRIVMSG #channel2 hello"); - Assert.AreEqual(line1, lines[0]); - Assert.AreEqual(line2, lines[1]); - } - - [TestMethod] - public void TestEncoding() - { - var iso8859 = Encoding.GetEncoding("iso-8859-1"); - _decoder = new IrcTokens.StatefulDecoder {Encoding = iso8859}; - var bytes = iso8859.GetBytes("PRIVMSG #channel :hello Ç\r\n"); - var lines = _decoder.Push(bytes, bytes.Length); - var line = new Line("PRIVMSG #channel :hello Ç"); - Assert.IsTrue(line.Equals(lines[0])); - } - - [TestMethod] - public void TestEncodingFallback() - { - var latin1 = Encoding.GetEncoding("iso-8859-1"); - _decoder = new IrcTokens.StatefulDecoder {Encoding = null, Fallback = latin1}; - var bytes = latin1.GetBytes("PRIVMSG #channel hélló\r\n"); - var lines = _decoder.Push(bytes, bytes.Length); - Assert.AreEqual(1, lines.Count); - Assert.IsTrue(new Line("PRIVMSG #channel hélló").Equals(lines[0])); - } - - [TestMethod] - public void TestEmpty() - { - var lines = _decoder.Push(string.Empty); - Assert.AreEqual(0, lines.Count); - } - - [TestMethod] - public void TestBufferUnfinished() - { - _decoder.Push("PRIVMSG #channel hello"); - var lines = _decoder.Push(string.Empty); - Assert.AreEqual(0, lines.Count); - } - - [TestMethod] - public void TestClear() - { - _decoder.Push("PRIVMSG "); - _decoder.Clear(); - Assert.AreEqual(string.Empty, _decoder.Pending); - } - } -} diff --git a/IrcTokens/Tests/StatefulEncoder.cs b/IrcTokens/Tests/StatefulEncoder.cs deleted file mode 100644 index f2cd6c4..0000000 --- a/IrcTokens/Tests/StatefulEncoder.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System.Text; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace IrcTokens.Tests -{ - [TestClass] - public class StatefulEncoder - { - private IrcTokens.StatefulEncoder _encoder; - - [TestInitialize] - public void TestInitialize() - { - _encoder = new IrcTokens.StatefulEncoder(); - } - - [TestMethod] - public void TestPush() - { - var line = new Line("PRIVMSG #channel hello"); - _encoder.Push(line); - Assert.AreEqual("PRIVMSG #channel hello\r\n", _encoder.Pending()); - } - - [TestMethod] - public void TestPopPartial() - { - var line = new Line("PRIVMSG #channel hello"); - _encoder.Push(line); - _encoder.Pop("PRIVMSG #channel hello".Length); - Assert.AreEqual("\r\n", _encoder.Pending()); - } - - [TestMethod] - public void TestPopReturned() - { - var line = new Line("PRIVMSG #channel hello"); - _encoder.Push(line); - _encoder.Push(line); - var lines = _encoder.Pop("PRIVMSG #channel hello\r\n".Length); - Assert.AreEqual(1, lines.Count); - Assert.AreEqual(line, lines[0]); - } - - [TestMethod] - public void TestPopNoneReturned() - { - var line = new Line("PRIVMSG #channel hello"); - _encoder.Push(line); - var lines = _encoder.Pop(1); - 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() - { - _encoder.Push(new Line("PRIVMSG #channel hello")); - _encoder.Clear(); - Assert.AreEqual(string.Empty, _encoder.Pending()); - } - - [TestMethod] - public void TestEncoding() - { - var iso8859 = Encoding.GetEncoding("iso-8859-1"); - _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 deleted file mode 100644 index 7e2139d..0000000 --- a/IrcTokens/Tests/Tokenization.cs +++ /dev/null @@ -1,118 +0,0 @@ -using System.Collections.Generic; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace IrcTokens.Tests -{ - [TestClass] - public class Tokenization - { - [TestMethod] - public void TestTagsMissing() - { - var line = new Line("PRIVMSG #channel"); - Assert.IsNull(line.Tags); - } - - [TestMethod] - public void TestTagsMissingValue() - { - var line = new Line("@id= PRIVMSG #channel"); - Assert.AreEqual(string.Empty, line.Tags["id"]); - } - - [TestMethod] - public void TestTagsMissingEqual() - { - var line = new Line("@id PRIVMSG #channel"); - Assert.AreEqual(string.Empty, line.Tags["id"]); - } - - [TestMethod] - public void TestTagsUnescape() - { - var line = new Line(@"@id=1\\\:\r\n\s2 PRIVMSG #channel"); - Assert.AreEqual("1\\;\r\n 2", line.Tags["id"]); - } - - [TestMethod] - public void TestTagsOverlap() - { - var line = new Line(@"@id=1\\\s\\s PRIVMSG #channel"); - Assert.AreEqual("1\\ \\s", line.Tags["id"]); - } - - [TestMethod] - public void TestTagsLoneEndSlash() - { - var line = new Line("@id=1\\ PRIVMSG #channel"); - Assert.AreEqual("1", line.Tags["id"]); - } - - [TestMethod] - public void TestSourceWithoutTags() - { - var line = new Line(":nick!user@host PRIVMSG #channel"); - Assert.AreEqual("nick!user@host", line.Source); - } - - [TestMethod] - public void TestSourceWithTags() - { - var line = new Line("@id=123 :nick!user@host PRIVMSG #channel"); - Assert.AreEqual("nick!user@host", line.Source); - } - - [TestMethod] - public void TestSourceMissingWithoutTags() - { - var line = new Line("PRIVMSG #channel"); - Assert.IsNull(line.Source); - } - - [TestMethod] - public void TestSourceMissingWithTags() - { - var line = new Line("@id=123 PRIVMSG #channel"); - Assert.IsNull(line.Source); - } - - [TestMethod] - public void TestCommand() - { - var line = new Line("privmsg #channel"); - Assert.AreEqual("PRIVMSG", line.Command); - } - - [TestMethod] - public void TestParamsTrailing() - { - var line = new Line("PRIVMSG #channel :hello world"); - 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); - } - - [TestMethod] - public void TestParamsMissing() - { - var line = new Line("PRIVMSG"); - Assert.AreEqual("PRIVMSG", line.Command); - CollectionAssert.AreEqual(new List(), line.Params); - } - - [TestMethod] - public void TestAllTokens() - { - var line = new Line("@id=123 :nick!user@host PRIVMSG #channel :hello world"); - 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); - } - } -} -- cgit 1.4.1