stateful in progress
This commit is contained in:
parent
616abc7030
commit
6a3bfd314d
|
@ -11,8 +11,18 @@
|
|||
|
||||
public override string ToString() => _source;
|
||||
|
||||
public override int GetHashCode() => _source.GetHashCode();
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null || GetType() != obj.GetType())
|
||||
return false;
|
||||
|
||||
return _source == ((Hostmask) obj)._source;
|
||||
}
|
||||
|
||||
private readonly string _source;
|
||||
|
||||
|
||||
public Hostmask(string source)
|
||||
{
|
||||
if (source == null) return;
|
||||
|
@ -30,7 +40,7 @@
|
|||
{
|
||||
NickName = source;
|
||||
}
|
||||
|
||||
|
||||
if (NickName.Contains('!'))
|
||||
{
|
||||
var userSplit = NickName.Split('!');
|
||||
|
@ -39,4 +49,4 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,10 +15,20 @@ namespace IrcTokens
|
|||
public List<string> Params { get; set; }
|
||||
|
||||
private Hostmask _hostmask;
|
||||
private string _rawLine;
|
||||
private readonly string _rawLine;
|
||||
|
||||
public override string ToString() =>
|
||||
$"Line(tags={string.Join(";", Tags.Select(kvp => $"{kvp.Key}={kvp.Value}"))}, params={string.Join(",", Params)})";
|
||||
public override string ToString() =>
|
||||
$"Line(source={Source}, command={Command}, tags={string.Join(";", Tags.Select(kvp => $"{kvp.Key}={kvp.Value}"))}, params={string.Join(",", Params)})";
|
||||
|
||||
public override int GetHashCode() => Format().GetHashCode();
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null || GetType() != obj.GetType())
|
||||
return false;
|
||||
|
||||
return Format() == ((Line) obj).Format();
|
||||
}
|
||||
|
||||
public Hostmask Hostmask =>
|
||||
_hostmask ??= new Hostmask(Source);
|
||||
|
@ -108,9 +118,7 @@ namespace IrcTokens
|
|||
}
|
||||
|
||||
if (Source != null)
|
||||
{
|
||||
outs.Add($":{Source}");
|
||||
}
|
||||
|
||||
outs.Add(Command);
|
||||
|
||||
|
@ -122,13 +130,13 @@ namespace IrcTokens
|
|||
foreach (var p in Params)
|
||||
{
|
||||
if (p.Contains(' '))
|
||||
throw new ArgumentException("non-last parameters cannot have spaces");
|
||||
throw new ArgumentException("non-last parameters cannot have spaces", p);
|
||||
if (p.StartsWith(':'))
|
||||
throw new ArgumentException("non-last parameters cannot start with colon");
|
||||
throw new ArgumentException("non-last parameters cannot start with colon", p);
|
||||
}
|
||||
outs.AddRange(Params);
|
||||
|
||||
if (last == null || string.IsNullOrWhiteSpace(last) || last.Contains(' ') || last.StartsWith(':'))
|
||||
if (string.IsNullOrWhiteSpace(last) || last.Contains(' ') || last.StartsWith(':'))
|
||||
last = $":{last}";
|
||||
outs.Add(last);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace IrcTokens
|
||||
{
|
||||
public class StatefulDecoder
|
||||
{
|
||||
private string _buffer;
|
||||
public EncodingInfo Encoding { get; set; }
|
||||
public EncodingInfo Fallback { get; set; }
|
||||
|
||||
public string Pending => _buffer;
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_buffer = "";
|
||||
}
|
||||
|
||||
public List<Line> Push(string data)
|
||||
{
|
||||
if (string.IsNullOrEmpty(data))
|
||||
return null;
|
||||
|
||||
_buffer += data;
|
||||
return _buffer
|
||||
.Split('\n')
|
||||
.Select(l => l.TrimEnd('\r'))
|
||||
.Select(l => new Line(l))
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace IrcTokens
|
||||
{
|
||||
public class StatefulEncoder
|
||||
{
|
||||
private string _buffer;
|
||||
public EncodingInfo Encoding { get; set; }
|
||||
private List<Line> _bufferedLines;
|
||||
|
||||
public string Pending => _buffer;
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_buffer = "";
|
||||
_bufferedLines.Clear();
|
||||
}
|
||||
|
||||
public void Push(Line line)
|
||||
{
|
||||
_buffer += $"{line.Format()}\r\n";
|
||||
_bufferedLines.Add(line);
|
||||
}
|
||||
|
||||
public List<Line> Pop(int byteCount)
|
||||
{
|
||||
var sent = _buffer.Substring(byteCount).Count(c => c == '\n');
|
||||
_buffer = _buffer.Substring(byteCount);
|
||||
_bufferedLines = _bufferedLines.Skip(sent).ToList();
|
||||
return _bufferedLines.Take(sent).ToList();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace IrcTokens.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class StatefulDecoderTests
|
||||
{
|
||||
private StatefulDecoder _decoder;
|
||||
|
||||
[TestInitialize]
|
||||
public void TestInitialize()
|
||||
{
|
||||
_decoder = new StatefulDecoder();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestPartial()
|
||||
{
|
||||
var lines = _decoder.Push("PRIVMSG ");
|
||||
Assert.AreEqual(new List<string>(), lines);
|
||||
|
||||
lines = _decoder.Push("#channel hello\r\n");
|
||||
Assert.AreEqual(1, lines.Count);
|
||||
|
||||
var line = new Line("PRIVMSG #channel hello");
|
||||
CollectionAssert.AreEqual(new List<Line> {line}, lines);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestMultiple()
|
||||
{
|
||||
_decoder.Push("PRIVMSG #channel1 hello\r\n");
|
||||
var lines = _decoder.Push("PRIVMSG #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.GetEncodings().Single(ei => ei.Name == "iso-8859-1");
|
||||
_decoder = new StatefulDecoder {Encoding = iso8859};
|
||||
var lines = _decoder.Push("PRIVMSG #channel :hello Č\r\n");
|
||||
var line = new Line("PRIVMSG #channel :hello Č");
|
||||
Assert.AreEqual(line, lines[0]);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestEncodingFallback()
|
||||
{
|
||||
var latin1 = Encoding.GetEncodings().Single(ei => ei.Name == "latin-1");
|
||||
_decoder = new StatefulDecoder {Fallback = latin1};
|
||||
var lines = _decoder.Push("PRIVMSG #channel hélló\r\n");
|
||||
Assert.AreEqual(1, lines.Count);
|
||||
Assert.AreEqual(new Line("PRIVMSG #channel hélló"), lines[0]);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestEmpty()
|
||||
{
|
||||
var lines = _decoder.Push(string.Empty);
|
||||
Assert.IsNull(lines);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestBufferUnfinished()
|
||||
{
|
||||
_decoder.Push("PRIVMSG #channel hello");
|
||||
var lines = _decoder.Push(string.Empty);
|
||||
Assert.IsNull(lines);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestClear()
|
||||
{
|
||||
_decoder.Push("PRIVMSG ");
|
||||
_decoder.Clear();
|
||||
Assert.AreEqual(string.Empty, _decoder.Pending);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestTagEncodingMismatch()
|
||||
{
|
||||
_decoder.Push("@asd=á ");
|
||||
var lines = _decoder.Push("PRIVMSG #chan :á\r\n");
|
||||
Assert.AreEqual("á", lines[0].Params[0]);
|
||||
Assert.AreEqual("á", lines[0].Tags["asd"]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace IrcTokens.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class StatefulEncoderTests
|
||||
{
|
||||
private StatefulEncoder _encoder;
|
||||
|
||||
[TestInitialize]
|
||||
public void TestInitialize()
|
||||
{
|
||||
_encoder = new 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 TestClear()
|
||||
{
|
||||
_encoder.Push(new Line("PRIVMSG #channel hello"));
|
||||
_encoder.Clear();
|
||||
Assert.AreEqual(string.Empty, _encoder.Pending);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestEncoding()
|
||||
{
|
||||
var iso88592 = Encoding.GetEncodings().Single(ei => ei.Name == "iso-8859-2");
|
||||
_encoder = new StatefulEncoder {Encoding = iso88592};
|
||||
_encoder.Push(new Line("PRIVMSG #channel :hello Č"));
|
||||
Assert.AreEqual("PRIVMSG #channel :hello Č\r\n", _encoder.Pending);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue