tidy up, work on stateful

This commit is contained in:
Ben Harris 2020-04-28 00:35:52 -04:00
parent 933a4f8560
commit 80afa2c0ae
17 changed files with 314 additions and 305 deletions

View File

@ -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;
}

View File

@ -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
}
}

View File

@ -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<string, List<Func<string, Line, Emit>>> LineHandlers;
private Dictionary<string, string> TempCaps;
public Server(string name)
{
Name = name;
Registered = false;
Modes = new List<string>();
Motd = new List<string>();
_decoder = new StatefulDecoder();
LineHandlers = new Dictionary<string, List<Func<string, Line, Emit>>>();
Users = new Dictionary<string, User>();
Channels = new Dictionary<string, Channel>();
ISupport = new ISupport();
HasCap = false;
TempCaps = new Dictionary<string, string>();
AvailableCaps = new Dictionary<string, string>();
AgreedCaps = new List<string>();
}
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<string> Modes { get; set; }
public List<string> Motd { get; set; }
public Dictionary<string, User> Users { get; set; }
public Dictionary<string, Channel> Channels { get; set; }
public Dictionary<string, string> AvailableCaps { get; set; }
public List<string> 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();
}
}
}

View File

@ -0,0 +1,9 @@
using System;
namespace IrcStates
{
public class ServerDisconnectedException : Exception
{
}
}

View File

@ -0,0 +1,9 @@
using System;
namespace IrcStates
{
public class ServerException : Exception
{
}
}

View File

@ -21,7 +21,7 @@ namespace IrcStates
public void SetNickName(string nick, string nickLower)
{
NickName = nick;
NickName = nick;
NickNameLower = nickLower;
}
}

View File

@ -3,47 +3,15 @@
namespace IrcTokens
{
/// <summary>
/// Represents the three parts of a hostmask. Parse with the constructor.
/// Represents the three parts of a hostmask. Parse with the constructor.
/// </summary>
public class Hostmask : IEquatable<Hostmask>
{
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);
}
}
}
}

View File

@ -2,83 +2,34 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
namespace IrcTokens
{
/// <summary>
/// Tools to represent, parse, and format IRC lines
/// Tools to represent, parse, and format IRC lines
/// </summary>
public class Line : IEquatable<Line>
{
public Dictionary<string, string> Tags { get; set; }
public string Source { get; set; }
public string Command { get; set; }
public List<string> 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<string>();
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() { }
/// <summary>
/// Build new <see cref="Line"/> object parsed from <param name="line">a string</param>. Analogous to irctokens.tokenise()
/// Build new <see cref="Line" /> object parsed from
/// <param name="line">a string</param>
/// . Analogous to irctokens.tokenise()
/// </summary>
/// <param name="line">irc line to parse</param>
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<string> { line };
: new List<string> {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<string, string> Tags { get; set; }
public string Source { get; set; }
public string Command { get; set; }
public List<string> Params { get; set; }
public Hostmask Hostmask =>
_hostmask ??= new Hostmask(Source);
public bool Equals(Line other)
{
if (other == null) return false;
return Format() == other.Format();
}
/// <summary>
/// Format a <see cref="Line"/> as a standards-compliant IRC line
/// Unescape ircv3 tag
/// </summary>
/// <param name="val">escaped string</param>
/// <returns>unescaped string</returns>
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();
}
/// <summary>
/// Escape strings for use in ircv3 tags
/// </summary>
/// <param name="val">string to escape</param>
/// <returns>escaped string</returns>
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<string>();
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);
}
/// <summary>
/// Format a <see cref="Line" /> as a standards-compliant IRC line
/// </summary>
/// <returns>formatted irc line</returns>
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);
}

View File

@ -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"
};
/// <summary>
/// Unescape ircv3 tag
/// </summary>
/// <param name="val">escaped string</param>
/// <returns>unescaped string</returns>
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();
}
/// <summary>
/// Escape strings for use in ircv3 tags
/// </summary>
/// <param name="val">string to escape</param>
/// <returns>escaped string</returns>
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;
}
}
}

View File

@ -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<byte>();
@ -58,16 +54,13 @@ namespace IrcTokens
public List<Line> 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<byte[]>();
var lines = new List<byte[]>();
for (int i = 0, currentIndex = 0; i < newLineIndices.Length; ++i)
{
@ -99,7 +92,6 @@ namespace IrcTokens
var decodeLines = new List<string>();
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))

View File

@ -7,8 +7,14 @@ namespace IrcTokens
{
public class StatefulEncoder
{
private Queue<Line> _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<Line> _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<byte>();
PendingBytes = Array.Empty<byte>();
_bufferedLines = new Queue<Line>();
}
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<Line>(_bufferedLines.Skip(sent));
PendingBytes = PendingBytes.Skip(byteCount).ToArray();
_bufferedLines = new Queue<Line>(_bufferedLines.Take(sent));
return Enumerable.Range(0, sent)
.Select(_ => _bufferedLines.Dequeue())

View File

@ -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<string> { "#channel", "hello" },
Tags = new Dictionary<string, string> { { "id", "\\" + " " + ";" + "\r\n" } }
Params = new List<string> {"#channel", "hello"},
Tags = new Dictionary<string, string> {{"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<string> { "#channel", "hello" }
}.Format();
var line = new Line {Command = "PRIVMSG", Params = new List<string> {"#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<string> { "#channel", "hello" },
Tags = new Dictionary<string, string> { { "a", null } }
Params = new List<string> {"#channel", "hello"},
Tags = new Dictionary<string, string> {{"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<string> { "#channel", "hello" },
Tags = new Dictionary<string, string> { { "a", "" } }
Params = new List<string> {"#channel", "hello"},
Tags = new Dictionary<string, string> {{"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<string> { "#channel", "hello" },
Source = "nick!user@host"
Command = "PRIVMSG", Params = new List<string> {"#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<string> { "#channel", "hello world" }
}.Format();
var line = new Line {Command = "PRIVMSG", Params = new List<string> {"#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<string> { "#channel", "helloworld" }
}.Format();
var line = new Line {Command = "PRIVMSG", Params = new List<string> {"#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<string> { "#channel", ":helloworld" }
}.Format();
var line = new Line {Command = "PRIVMSG", Params = new List<string> {"#channel", ":helloworld"}}.Format();
Assert.AreEqual("PRIVMSG #channel ::helloworld", line);
}
@ -126,11 +108,7 @@ namespace IrcTokens.Tests
{
Assert.ThrowsException<ArgumentException>(() =>
{
new Line
{
Command = "USER",
Params = new List<string> { "user", "0 *", "real name" }
}.Format();
new Line {Command = "USER", Params = new List<string> {"user", "0 *", "real name"}}.Format();
});
}
@ -139,11 +117,7 @@ namespace IrcTokens.Tests
{
Assert.ThrowsException<ArgumentException>(() =>
{
new Line
{
Command = "PRIVMSG",
Params = new List<string> { ":#channel", "hello" }
}.Format();
new Line {Command = "PRIVMSG", Params = new List<string> {":#channel", "hello"}}.Format();
});
}
}

View File

@ -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);

View File

@ -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<SplitModel>("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<string>(), tokens.Params, $"params failed on: '{test.Input}'");
CollectionAssert.AreEqual(atoms.Params ?? new List<string>(), 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);

View File

@ -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> { line }, lines);
CollectionAssert.AreEqual(new List<Line> {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]));

View File

@ -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);
}

View File

@ -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<string> { "#channel", "hello world" }, line.Params);
CollectionAssert.AreEqual(new List<string> {"#channel", "hello world"}, line.Params);
}
[TestMethod]
public void TestParamsOnlyTrailing()
{
var line = new Line("PRIVMSG :hello world");
CollectionAssert.AreEqual(new List<string> { "hello world" }, line.Params);
CollectionAssert.AreEqual(new List<string> {"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<string, string> { { "id", "123" } }, line.Tags);
CollectionAssert.AreEqual(new Dictionary<string, string> {{"id", "123"}}, line.Tags);
Assert.AreEqual("nick!user@host", line.Source);
Assert.AreEqual("PRIVMSG", line.Command);
CollectionAssert.AreEqual(new List<string> { "#channel", "hello world" }, line.Params);
CollectionAssert.AreEqual(new List<string> {"#channel", "hello world"}, line.Params);
}
}
}