rename to IrcSharp
continuous-integration/drone/push Build is passing Details

also tidy up formatting with vs tools
This commit is contained in:
Ben Harris 2020-04-22 16:28:51 -04:00
parent 338763fde7
commit 933a4f8560
35 changed files with 550 additions and 83 deletions

57
.editorconfig Normal file
View File

@ -0,0 +1,57 @@
[*.proto]
indent_style=tab
indent_size=tab
tab_width=4
[*.{asax,ascx,aspx,cs,cshtml,css,htm,html,js,jsx,master,razor,skin,ts,tsx,vb,xaml,xamlx,xoml}]
indent_style=space
indent_size=4
tab_width=4
[*.{appxmanifest,axml,build,config,csproj,dbml,discomap,dtd,json,jsproj,lsproj,njsproj,nuspec,proj,props,resjson,resw,resx,StyleCop,targets,tasks,vbproj,xml,xsd}]
indent_style=space
indent_size=2
tab_width=2
[*]
# Microsoft .NET properties
csharp_new_line_before_members_in_object_initializers=true
csharp_preferred_modifier_order=public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion
csharp_style_var_elsewhere=true:suggestion
csharp_style_var_for_built_in_types=true:suggestion
csharp_style_var_when_type_is_apparent=true:suggestion
dotnet_style_parentheses_in_arithmetic_binary_operators=never_if_unnecessary:none
dotnet_style_parentheses_in_other_binary_operators=never_if_unnecessary:none
dotnet_style_parentheses_in_relational_binary_operators=never_if_unnecessary:none
dotnet_style_predefined_type_for_locals_parameters_members=true:suggestion
dotnet_style_predefined_type_for_member_access=true:suggestion
dotnet_style_qualification_for_event=false:suggestion
dotnet_style_qualification_for_field=false:suggestion
dotnet_style_qualification_for_method=false:suggestion
dotnet_style_qualification_for_property=false:suggestion
dotnet_style_require_accessibility_modifiers=for_non_interface_members:suggestion
# ReSharper inspection severities
resharper_arrange_redundant_parentheses_highlighting=hint
resharper_arrange_this_qualifier_highlighting=hint
resharper_arrange_type_member_modifiers_highlighting=hint
resharper_arrange_type_modifiers_highlighting=hint
resharper_built_in_type_reference_style_for_member_access_highlighting=hint
resharper_built_in_type_reference_style_highlighting=hint
resharper_redundant_base_qualifier_highlighting=warning
resharper_suggest_var_or_type_built_in_types_highlighting=hint
resharper_suggest_var_or_type_elsewhere_highlighting=hint
resharper_suggest_var_or_type_simple_types_highlighting=hint
# ReSharper properties
resharper_csharp_insert_final_newline=true
resharper_int_align_assignments=true
resharper_int_align_switch_expressions=true
resharper_int_align_switch_sections=true
resharper_int_align_variables=true
resharper_keep_existing_embedded_arrangement=false
resharper_keep_existing_switch_expression_arrangement=false
resharper_place_simple_case_statement_on_same_line=if_owner_is_single_line
resharper_xmldoc_max_blank_lines_between_tags=1

View File

@ -5,7 +5,16 @@ VisualStudioVersion = 16.0.30011.22
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IrcTokens", "IrcTokens\IrcTokens.csproj", "{9E812F45-B2CD-42D2-8378-EBEBF8697905}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IrcTokens", "IrcTokens\IrcTokens.csproj", "{9E812F45-B2CD-42D2-8378-EBEBF8697905}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample", "Sample\Sample.csproj", "{A45DA39B-6B47-4713-8049-3B36E0235B67}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TokensSample", "Sample\TokensSample.csproj", "{A45DA39B-6B47-4713-8049-3B36E0235B67}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IrcStates", "IrcStates\IrcStates.csproj", "{233E3CB4-61F1-4368-9139-7E9F4A58ED2D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatesSample", "StatesSample\StatesSample.csproj", "{BC9F6696-9D83-4F7A-9E15-CE4D3626C1AF}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1A85EB22-D7B4-417F-AC3B-DAFD97DDEA08}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
EndProjectSection
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -21,6 +30,14 @@ Global
{A45DA39B-6B47-4713-8049-3B36E0235B67}.Debug|Any CPU.Build.0 = Debug|Any CPU {A45DA39B-6B47-4713-8049-3B36E0235B67}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A45DA39B-6B47-4713-8049-3B36E0235B67}.Release|Any CPU.ActiveCfg = Release|Any CPU {A45DA39B-6B47-4713-8049-3B36E0235B67}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A45DA39B-6B47-4713-8049-3B36E0235B67}.Release|Any CPU.Build.0 = Release|Any CPU {A45DA39B-6B47-4713-8049-3B36E0235B67}.Release|Any CPU.Build.0 = Release|Any CPU
{233E3CB4-61F1-4368-9139-7E9F4A58ED2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{233E3CB4-61F1-4368-9139-7E9F4A58ED2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{233E3CB4-61F1-4368-9139-7E9F4A58ED2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{233E3CB4-61F1-4368-9139-7E9F4A58ED2D}.Release|Any CPU.Build.0 = Release|Any CPU
{BC9F6696-9D83-4F7A-9E15-CE4D3626C1AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BC9F6696-9D83-4F7A-9E15-CE4D3626C1AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BC9F6696-9D83-4F7A-9E15-CE4D3626C1AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BC9F6696-9D83-4F7A-9E15-CE4D3626C1AF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

43
IrcStates/Casemap.cs Normal file
View File

@ -0,0 +1,43 @@
using System;
namespace IrcStates
{
public static class Casemap
{
public enum CaseMapping
{
Rfc1459,
Ascii
}
private const string AsciiUpperChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private const string AsciiLowerChars = "abcdefghijklmnopqrstuvwxyz";
private const string Rfc1459UpperChars = AsciiUpperChars + @"[]~\";
private const string Rfc1459LowerChars = AsciiLowerChars + @"{}^|";
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]);
}
return s;
}
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)
};
}
return string.Empty;
}
}
}

69
IrcStates/Channel.cs Normal file
View File

@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace IrcStates
{
public class Channel
{
public string Name { get; set; }
public string NameLower { get; set; }
public Dictionary<string, User> Users { get; set; }
public string Topic { get; set; }
public string TopicSetter { get; set; }
public DateTime TopicTime { get; set; }
public DateTime Created { get; set; }
public Dictionary<string, List<string>> ListModes { get; set; }
public Dictionary<string, string> Modes { get; set; }
public override string ToString()
{
return $"Channel(name={Name})";
}
public void SetName(string name, string nameLower)
{
Name = name;
NameLower = nameLower;
}
public void AddMode(string ch, string param, bool listMode)
{
if (listMode)
{
if (!ListModes.ContainsKey(ch))
{
ListModes[ch] = new List<string>();
}
if (ListModes[ch].Contains(param))
{
ListModes[ch].Add(param ?? string.Empty);
}
}
else
{
Modes[ch] = param;
}
}
public void RemoveMode(string ch, string param)
{
if (ListModes.ContainsKey(ch))
{
if (ListModes[ch].Contains(param))
{
ListModes[ch].Remove(param);
if (!ListModes[ch].Any())
{
ListModes.Remove(ch);
}
}
}
else if (Modes.ContainsKey(ch))
{
Modes.Remove(ch);
}
}
}
}

6
IrcStates/Emit.cs Normal file
View File

@ -0,0 +1,6 @@
namespace IrcStates
{
public class Emit
{
}
}

7
IrcStates/ISupport.cs Normal file
View File

@ -0,0 +1,7 @@
// ReSharper disable InconsistentNaming
namespace IrcStates
{
public class ISupport
{
}
}

View File

@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.0" />
<PackageReference Include="MSTest.TestAdapter" Version="2.1.1" />
<PackageReference Include="MSTest.TestFramework" Version="2.1.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\IrcTokens\IrcTokens.csproj" />
</ItemGroup>
</Project>

49
IrcStates/Numeric.cs Normal file
View File

@ -0,0 +1,49 @@
// ReSharper disable InconsistentNaming
namespace IrcStates
{
public static class Numeric
{
public const string RPL_WELCOME = "001";
public const string RPL_ISUPPORT = "005";
public const string RPL_MOTD = "372";
public const string RPL_MOTDSTART = "375";
public const string RPL_UMODEIS = "221";
public const string RPL_VISIBLEHOST = "396";
public const string RPL_CHANNELMODEIS = "324";
public const string RPL_CREATIONTIME = "329";
public const string RPL_TOPIC = "332";
public const string RPL_TOPICWHOTIME = "333";
public const string RPL_WHOREPLY = "352";
public const string RPL_WHOSPCRPL = "354";
public const string RPL_ENDOFWHO = "315";
public const string RPL_NAMREPLY = "353";
public const string RPL_ENDOFNAMES = "366";
public const string RPL_BANLIST = "367";
public const string RPL_ENDOFBANLIST = "368";
public const string RPL_QUIETLIST = "728";
public const string RPL_ENDOFQUIETLIST = "729";
public const string RPL_SASLSUCCESS = "903";
public const string ERR_SASLFAIL = "904";
public const string ERR_SASLTOOLONG = "905";
public const string ERR_SASLABORTED = "906";
public const string ERR_SASLALREADY = "907";
public const string RPL_SASLMECHS = "908";
public const string RPL_WHOISUSER = "311";
public const string RPL_WHOISSERVER = "312";
public const string RPL_WHOISOPERATOR = "313";
public const string RPL_WHOISIDLE = "317";
public const string RPL_WHOISCHANNELS = "319";
public const string RPL_WHOISACCOUNT = "330";
public const string RPL_WHOISHOST = "378";
public const string RPL_WHOISMODES = "379";
public const string RPL_WHOISSECURE = "671";
public const string RPL_ENDOFWHOIS = "318";
public const string ERR_NOSUCHCHANNEL = "403";
}
}

6
IrcStates/Server.cs Normal file
View File

@ -0,0 +1,6 @@
namespace IrcStates
{
public class Server
{
}
}

9
IrcStates/Tests/Cap.cs Normal file
View File

@ -0,0 +1,9 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace IrcStates.Tests
{
[TestClass]
public class Cap
{
}
}

View File

@ -0,0 +1,9 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace IrcStates.Tests
{
[TestClass]
public class Casemap
{
}
}

View File

@ -0,0 +1,9 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace IrcStates.Tests
{
[TestClass]
public class Channel
{
}
}

9
IrcStates/Tests/Emit.cs Normal file
View File

@ -0,0 +1,9 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace IrcStates.Tests
{
[TestClass]
public class Emit
{
}
}

View File

@ -0,0 +1,10 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
// ReSharper disable InconsistentNaming
namespace IrcStates.Tests
{
[TestClass]
public class ISupport
{
}
}

9
IrcStates/Tests/Mode.cs Normal file
View File

@ -0,0 +1,9 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace IrcStates.Tests
{
[TestClass]
public class Mode
{
}
}

9
IrcStates/Tests/Motd.cs Normal file
View File

@ -0,0 +1,9 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace IrcStates.Tests
{
[TestClass]
public class Motd
{
}
}

9
IrcStates/Tests/User.cs Normal file
View File

@ -0,0 +1,9 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace IrcStates.Tests
{
[TestClass]
public class User
{
}
}

9
IrcStates/Tests/Who.cs Normal file
View File

@ -0,0 +1,9 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace IrcStates.Tests
{
[TestClass]
public class Who
{
}
}

28
IrcStates/User.cs Normal file
View File

@ -0,0 +1,28 @@
using System.Collections.Generic;
namespace IrcStates
{
public class User
{
private string NickName;
private string NickNameLower;
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 HashSet<string> Channels { get; set; }
public override string ToString()
{
return $"User(nickname={NickName})";
}
public void SetNickName(string nick, string nickLower)
{
NickName = nick;
NickNameLower = nickLower;
}
}
}

View File

@ -5,29 +5,45 @@ namespace IrcTokens
/// <summary> /// <summary>
/// Represents the three parts of a hostmask. Parse with the constructor. /// Represents the three parts of a hostmask. Parse with the constructor.
/// </summary> /// </summary>
public class Hostmask public class Hostmask : IEquatable<Hostmask>
{ {
public string NickName { get; set; } public string NickName { get; set; }
public string UserName { get; set; } public string UserName { get; set; }
public string HostName { get; set; } public string HostName { get; set; }
public override string ToString() => _source; public override string ToString()
{
return _source;
}
public override int GetHashCode() => _source.GetHashCode(StringComparison.Ordinal); 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) public override bool Equals(object obj)
{ {
if (obj == null || GetType() != obj.GetType()) return Equals(obj as Hostmask);
return false;
return _source == ((Hostmask) obj)._source;
} }
private readonly string _source; private readonly string _source;
public Hostmask(string source) public Hostmask(string source)
{ {
if (source == null) return; if (source == null)
{
return;
}
_source = source; _source = source;

View File

@ -8,7 +8,7 @@ namespace IrcTokens
/// <summary> /// <summary>
/// Tools to represent, parse, and format IRC lines /// Tools to represent, parse, and format IRC lines
/// </summary> /// </summary>
public class Line public class Line : IEquatable<Line>
{ {
public Dictionary<string, string> Tags { get; set; } public Dictionary<string, string> Tags { get; set; }
public string Source { get; set; } public string Source { get; set; }
@ -16,32 +16,52 @@ namespace IrcTokens
public List<string> Params { get; set; } public List<string> Params { get; set; }
private Hostmask _hostmask; private Hostmask _hostmask;
private readonly string _rawLine;
public override string ToString() public override string ToString()
{ {
var vars = new List<string>(); var vars = new List<string>();
if (Command != null) if (Command != null)
{
vars.Add($"command={Command}"); vars.Add($"command={Command}");
}
if (Source != null) if (Source != null)
{
vars.Add($"source={Source}"); vars.Add($"source={Source}");
}
if (Params != null && Params.Any()) if (Params != null && Params.Any())
{
vars.Add($"params=[{string.Join(",", Params)}]"); vars.Add($"params=[{string.Join(",", Params)}]");
}
if (Tags != null && Tags.Any()) if (Tags != null && Tags.Any())
{
vars.Add($"tags=[{string.Join(";", Tags.Select(kvp => $"{kvp.Key}={kvp.Value}"))}]"); vars.Add($"tags=[{string.Join(";", Tags.Select(kvp => $"{kvp.Key}={kvp.Value}"))}]");
}
return $"Line({string.Join(", ", vars)})"; return $"Line({string.Join(", ", vars)})";
} }
public override int GetHashCode() => Format().GetHashCode(StringComparison.Ordinal); 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) public override bool Equals(object obj)
{ {
if (obj == null || GetType() != obj.GetType()) return Equals(obj as Line);
return false;
return Format() == ((Line) obj).Format();
} }
public Hostmask Hostmask => public Hostmask Hostmask =>
@ -56,9 +76,10 @@ namespace IrcTokens
public Line(string line) public Line(string line)
{ {
if (string.IsNullOrWhiteSpace(line)) if (string.IsNullOrWhiteSpace(line))
{
throw new ArgumentNullException(nameof(line)); throw new ArgumentNullException(nameof(line));
}
_rawLine = line;
string[] split; string[] split;
if (line.StartsWith('@')) if (line.StartsWith('@'))
@ -97,7 +118,7 @@ namespace IrcTokens
Params = line.Contains(' ', StringComparison.Ordinal) Params = line.Contains(' ', StringComparison.Ordinal)
? line.Split(' ', StringSplitOptions.RemoveEmptyEntries).ToList() ? line.Split(' ', StringSplitOptions.RemoveEmptyEntries).ToList()
: new List<string> {line}; : new List<string> { line };
if (Params[0].StartsWith(':')) if (Params[0].StartsWith(':'))
{ {
@ -135,7 +156,9 @@ namespace IrcTokens
} }
if (Source != null) if (Source != null)
{
outs.Add($":{Source}"); outs.Add($":{Source}");
}
outs.Add(Command); outs.Add(Command);
@ -147,14 +170,22 @@ namespace IrcTokens
foreach (var p in Params) foreach (var p in Params)
{ {
if (p.Contains(' ', StringComparison.Ordinal)) if (p.Contains(' ', StringComparison.Ordinal))
{
throw new ArgumentException(@"non-last parameters cannot have spaces", p); throw new ArgumentException(@"non-last parameters cannot have spaces", p);
}
if (p.StartsWith(':')) if (p.StartsWith(':'))
{
throw new ArgumentException(@"non-last parameters cannot start with colon", p); throw new ArgumentException(@"non-last parameters cannot start with colon", p);
}
} }
outs.AddRange(Params); 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}"; last = $":{last}";
}
outs.Add(last); outs.Add(last);
} }

View File

@ -50,7 +50,9 @@ namespace IrcTokens
} }
} }
else else
{
unescaped.Append(current); unescaped.Append(current);
}
} }
return unescaped.ToString(); return unescaped.ToString();

View File

@ -18,8 +18,10 @@ namespace IrcTokens
set set
{ {
if (value != null) if (value != null)
{
_encoding = Encoding.GetEncoding(value.CodePage, EncoderFallback.ExceptionFallback, _encoding = Encoding.GetEncoding(value.CodePage, EncoderFallback.ExceptionFallback,
DecoderFallback.ReplacementFallback); DecoderFallback.ReplacementFallback);
}
} }
} }
@ -30,8 +32,10 @@ namespace IrcTokens
set set
{ {
if (value != null) if (value != null)
_encoding = Encoding.GetEncoding(value.CodePage, EncoderFallback.ReplacementFallback, {
_fallback = Encoding.GetEncoding(value.CodePage, EncoderFallback.ReplacementFallback,
DecoderFallback.ReplacementFallback); DecoderFallback.ReplacementFallback);
}
} }
} }
@ -55,7 +59,9 @@ namespace IrcTokens
public List<Line> Push(byte[] data) public List<Line> Push(byte[] data)
{ {
if (data == null || data.Length == 0) if (data == null || data.Length == 0)
{
return null; return null;
}
_buffer = _buffer.Concat(data).ToArray(); _buffer = _buffer.Concat(data).ToArray();

View File

@ -16,8 +16,10 @@ namespace IrcTokens
set set
{ {
if (value != null) if (value != null)
{
_encoding = Encoding.GetEncoding(value.CodePage, EncoderFallback.ExceptionFallback, _encoding = Encoding.GetEncoding(value.CodePage, EncoderFallback.ExceptionFallback,
DecoderFallback.ExceptionFallback); DecoderFallback.ExceptionFallback);
}
} }
} }
@ -52,7 +54,9 @@ namespace IrcTokens
public void Push(Line line) public void Push(Line line)
{ {
if (line == null) if (line == null)
{
throw new ArgumentNullException(nameof(line)); throw new ArgumentNullException(nameof(line));
}
PendingBytes = PendingBytes.Concat(Encoding.GetBytes($"{line.Format()}\r\n")).ToArray(); PendingBytes = PendingBytes.Concat(Encoding.GetBytes($"{line.Format()}\r\n")).ToArray();
_bufferedLines.Enqueue(line); _bufferedLines.Enqueue(line);

View File

@ -5,16 +5,16 @@ using System.Collections.Generic;
namespace IrcTokens.Tests namespace IrcTokens.Tests
{ {
[TestClass] [TestClass]
public class FormatTests public class Format
{ {
[TestMethod] [TestMethod]
public void TestTags() public void TestTags()
{ {
var line = new Line var line = new Line
{ {
Command = "PRIVMSG", Command = "PRIVMSG",
Params = new List<string> {"#channel", "hello"}, Params = new List<string> { "#channel", "hello" },
Tags = new Dictionary<string, string> {{"id", "\\" + " " + ";" + "\r\n"}} Tags = new Dictionary<string, string> { { "id", "\\" + " " + ";" + "\r\n" } }
}.Format(); }.Format();
Assert.AreEqual("@id=\\\\\\s\\:\\r\\n PRIVMSG #channel hello", line); Assert.AreEqual("@id=\\\\\\s\\:\\r\\n PRIVMSG #channel hello", line);
@ -25,8 +25,8 @@ namespace IrcTokens.Tests
{ {
var line = new Line var line = new Line
{ {
Command = "PRIVMSG", Command = "PRIVMSG",
Params = new List<string> {"#channel", "hello"} Params = new List<string> { "#channel", "hello" }
}.Format(); }.Format();
Assert.AreEqual("PRIVMSG #channel hello", line); Assert.AreEqual("PRIVMSG #channel hello", line);
@ -38,8 +38,8 @@ namespace IrcTokens.Tests
var line = new Line var line = new Line
{ {
Command = "PRIVMSG", Command = "PRIVMSG",
Params = new List<string> {"#channel", "hello"}, Params = new List<string> { "#channel", "hello" },
Tags = new Dictionary<string, string> {{"a", null}} Tags = new Dictionary<string, string> { { "a", null } }
}.Format(); }.Format();
Assert.AreEqual("@a PRIVMSG #channel hello", line); Assert.AreEqual("@a PRIVMSG #channel hello", line);
@ -51,8 +51,8 @@ namespace IrcTokens.Tests
var line = new Line var line = new Line
{ {
Command = "PRIVMSG", Command = "PRIVMSG",
Params = new List<string> {"#channel", "hello"}, Params = new List<string> { "#channel", "hello" },
Tags = new Dictionary<string, string> {{"a", ""}} Tags = new Dictionary<string, string> { { "a", "" } }
}.Format(); }.Format();
Assert.AreEqual("@a PRIVMSG #channel hello", line); Assert.AreEqual("@a PRIVMSG #channel hello", line);
@ -64,7 +64,7 @@ namespace IrcTokens.Tests
var line = new Line var line = new Line
{ {
Command = "PRIVMSG", Command = "PRIVMSG",
Params = new List<string> {"#channel", "hello"}, Params = new List<string> { "#channel", "hello" },
Source = "nick!user@host" Source = "nick!user@host"
}.Format(); }.Format();
@ -74,14 +74,14 @@ namespace IrcTokens.Tests
[TestMethod] [TestMethod]
public void TestCommandLowercase() public void TestCommandLowercase()
{ {
var line = new Line {Command = "privmsg"}.Format(); var line = new Line { Command = "privmsg" }.Format();
Assert.AreEqual("privmsg", line); Assert.AreEqual("privmsg", line);
} }
[TestMethod] [TestMethod]
public void TestCommandUppercase() public void TestCommandUppercase()
{ {
var line = new Line {Command = "PRIVMSG"}.Format(); var line = new Line { Command = "PRIVMSG" }.Format();
Assert.AreEqual("PRIVMSG", line); Assert.AreEqual("PRIVMSG", line);
} }
@ -91,7 +91,7 @@ namespace IrcTokens.Tests
var line = new Line var line = new Line
{ {
Command = "PRIVMSG", Command = "PRIVMSG",
Params = new List<string> {"#channel", "hello world"} Params = new List<string> { "#channel", "hello world" }
}.Format(); }.Format();
Assert.AreEqual("PRIVMSG #channel :hello world", line); Assert.AreEqual("PRIVMSG #channel :hello world", line);
@ -103,7 +103,7 @@ namespace IrcTokens.Tests
var line = new Line var line = new Line
{ {
Command = "PRIVMSG", Command = "PRIVMSG",
Params = new List<string> {"#channel", "helloworld"} Params = new List<string> { "#channel", "helloworld" }
}.Format(); }.Format();
Assert.AreEqual("PRIVMSG #channel helloworld", line); Assert.AreEqual("PRIVMSG #channel helloworld", line);
@ -115,7 +115,7 @@ namespace IrcTokens.Tests
var line = new Line var line = new Line
{ {
Command = "PRIVMSG", Command = "PRIVMSG",
Params = new List<string> {"#channel", ":helloworld"} Params = new List<string> { "#channel", ":helloworld" }
}.Format(); }.Format();
Assert.AreEqual("PRIVMSG #channel ::helloworld", line); Assert.AreEqual("PRIVMSG #channel ::helloworld", line);
@ -129,7 +129,7 @@ namespace IrcTokens.Tests
new Line new Line
{ {
Command = "USER", Command = "USER",
Params = new List<string> {"user", "0 *", "real name"} Params = new List<string> { "user", "0 *", "real name" }
}.Format(); }.Format();
}); });
} }
@ -142,7 +142,7 @@ namespace IrcTokens.Tests
new Line new Line
{ {
Command = "PRIVMSG", Command = "PRIVMSG",
Params = new List<string> {":#channel", "hello"} Params = new List<string> { ":#channel", "hello" }
}.Format(); }.Format();
}); });
} }

View File

@ -3,12 +3,12 @@
namespace IrcTokens.Tests namespace IrcTokens.Tests
{ {
[TestClass] [TestClass]
public class HostmaskTests public class Hostmask
{ {
[TestMethod] [TestMethod]
public void TestHostmask() public void TestHostmask()
{ {
var hostmask = new Hostmask("nick!user@host"); var hostmask = new IrcTokens.Hostmask("nick!user@host");
Assert.AreEqual("nick", hostmask.NickName); Assert.AreEqual("nick", hostmask.NickName);
Assert.AreEqual("user", hostmask.UserName); Assert.AreEqual("user", hostmask.UserName);
Assert.AreEqual("host", hostmask.HostName); Assert.AreEqual("host", hostmask.HostName);
@ -17,7 +17,7 @@ namespace IrcTokens.Tests
[TestMethod] [TestMethod]
public void TestNoHostName() public void TestNoHostName()
{ {
var hostmask = new Hostmask("nick!user"); var hostmask = new IrcTokens.Hostmask("nick!user");
Assert.AreEqual("nick", hostmask.NickName); Assert.AreEqual("nick", hostmask.NickName);
Assert.AreEqual("user", hostmask.UserName); Assert.AreEqual("user", hostmask.UserName);
Assert.IsNull(hostmask.HostName); Assert.IsNull(hostmask.HostName);
@ -26,7 +26,7 @@ namespace IrcTokens.Tests
[TestMethod] [TestMethod]
public void TestNoUserName() public void TestNoUserName()
{ {
var hostmask = new Hostmask("nick@host"); var hostmask = new IrcTokens.Hostmask("nick@host");
Assert.AreEqual("nick", hostmask.NickName); Assert.AreEqual("nick", hostmask.NickName);
Assert.IsNull(hostmask.UserName); Assert.IsNull(hostmask.UserName);
Assert.AreEqual("host", hostmask.HostName); Assert.AreEqual("host", hostmask.HostName);
@ -35,7 +35,7 @@ namespace IrcTokens.Tests
[TestMethod] [TestMethod]
public void TestOnlyNickName() public void TestOnlyNickName()
{ {
var hostmask = new Hostmask("nick"); var hostmask = new IrcTokens.Hostmask("nick");
Assert.AreEqual("nick", hostmask.NickName); Assert.AreEqual("nick", hostmask.NickName);
Assert.IsNull(hostmask.UserName); Assert.IsNull(hostmask.UserName);
Assert.IsNull(hostmask.HostName); Assert.IsNull(hostmask.HostName);
@ -45,7 +45,7 @@ namespace IrcTokens.Tests
public void TestHostmaskFromLine() 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 Hostmask("nick!user@host"); var hostmask = new IrcTokens.Hostmask("nick!user@host");
Assert.AreEqual(hostmask.ToString(), line.Hostmask.ToString()); Assert.AreEqual(hostmask.ToString(), line.Hostmask.ToString());
Assert.AreEqual("nick", line.Hostmask.NickName); Assert.AreEqual("nick", line.Hostmask.NickName);
Assert.AreEqual("user", line.Hostmask.UserName); Assert.AreEqual("user", line.Hostmask.UserName);

View File

@ -1,15 +1,15 @@
using System.Collections.Generic; using IrcTokens.Tests.Data;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using IrcTokens.Tests.Data;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using YamlDotNet.Serialization; using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions; using YamlDotNet.Serialization.NamingConventions;
namespace IrcTokens.Tests namespace IrcTokens.Tests
{ {
[TestClass] [TestClass]
public class ParserTests public class Parser
{ {
private static T LoadYaml<T>(string path) private static T LoadYaml<T>(string path)
{ {
@ -46,7 +46,7 @@ namespace IrcTokens.Tests
{ {
Command = atoms.Verb, Command = atoms.Verb,
Params = atoms.Params, Params = atoms.Params,
Source = atoms.Source ?? null, Source = atoms.Source,
Tags = atoms.Tags Tags = atoms.Tags
}.Format(); }.Format();

View File

@ -1,19 +1,18 @@
using System.Collections.Generic; using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq; using System.Collections.Generic;
using System.Text; using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace IrcTokens.Tests namespace IrcTokens.Tests
{ {
[TestClass] [TestClass]
public class StatefulDecoderTests public class StatefulDecoder
{ {
private StatefulDecoder _decoder; private IrcTokens.StatefulDecoder _decoder;
[TestInitialize] [TestInitialize]
public void TestInitialize() public void TestInitialize()
{ {
_decoder = new StatefulDecoder(); _decoder = new IrcTokens.StatefulDecoder();
} }
[TestMethod] [TestMethod]
@ -26,7 +25,7 @@ namespace IrcTokens.Tests
Assert.AreEqual(1, lines.Count); Assert.AreEqual(1, lines.Count);
var line = new Line("PRIVMSG #channel hello"); var line = new Line("PRIVMSG #channel hello");
CollectionAssert.AreEqual(new List<Line> {line}, lines); CollectionAssert.AreEqual(new List<Line> { line }, lines);
} }
[TestMethod] [TestMethod]
@ -45,7 +44,7 @@ namespace IrcTokens.Tests
public void TestEncoding() public void TestEncoding()
{ {
var iso8859 = Encoding.GetEncoding("iso-8859-1"); var iso8859 = Encoding.GetEncoding("iso-8859-1");
_decoder = new StatefulDecoder {Encoding = iso8859}; _decoder = new IrcTokens.StatefulDecoder { Encoding = iso8859 };
var lines = _decoder.Push(iso8859.GetBytes("PRIVMSG #channel :hello Ç\r\n")); 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])); Assert.IsTrue(line.Equals(lines[0]));
@ -55,7 +54,7 @@ namespace IrcTokens.Tests
public void TestEncodingFallback() public void TestEncodingFallback()
{ {
var latin1 = Encoding.GetEncoding("iso-8859-1"); var latin1 = Encoding.GetEncoding("iso-8859-1");
_decoder = new 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")); var lines = _decoder.Push(latin1.GetBytes("PRIVMSG #channel hélló\r\n"));
Assert.AreEqual(1, lines.Count); Assert.AreEqual(1, lines.Count);
Assert.IsTrue(new Line("PRIVMSG #channel hélló").Equals(lines[0])); Assert.IsTrue(new Line("PRIVMSG #channel hélló").Equals(lines[0]));

View File

@ -1,18 +1,17 @@
using System.Linq; using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Text; using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace IrcTokens.Tests namespace IrcTokens.Tests
{ {
[TestClass] [TestClass]
public class StatefulEncoderTests public class StatefulEncoder
{ {
private StatefulEncoder _encoder; private IrcTokens.StatefulEncoder _encoder;
[TestInitialize] [TestInitialize]
public void TestInitialize() public void TestInitialize()
{ {
_encoder = new StatefulEncoder(); _encoder = new IrcTokens.StatefulEncoder();
} }
[TestMethod] [TestMethod]
@ -64,7 +63,7 @@ namespace IrcTokens.Tests
public void TestEncoding() public void TestEncoding()
{ {
var iso8859 = Encoding.GetEncoding("iso-8859-1"); var iso8859 = Encoding.GetEncoding("iso-8859-1");
_encoder = new StatefulEncoder {Encoding = iso8859}; _encoder = new IrcTokens.StatefulEncoder { Encoding = iso8859 };
_encoder.Push(new Line("PRIVMSG #channel :hello Ç")); _encoder.Push(new Line("PRIVMSG #channel :hello Ç"));
CollectionAssert.AreEqual(iso8859.GetBytes("PRIVMSG #channel :hello Ç\r\n"), _encoder.PendingBytes); CollectionAssert.AreEqual(iso8859.GetBytes("PRIVMSG #channel :hello Ç\r\n"), _encoder.PendingBytes);
} }

View File

@ -1,10 +1,10 @@
using System.Collections.Generic; using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Collections.Generic;
namespace IrcTokens.Tests namespace IrcTokens.Tests
{ {
[TestClass] [TestClass]
public class TokenizationTests public class Tokenization
{ {
[TestMethod] [TestMethod]
public void TestTagsMissing() public void TestTagsMissing()
@ -87,14 +87,14 @@ namespace IrcTokens.Tests
public void TestParamsTrailing() public void TestParamsTrailing()
{ {
var line = new Line("PRIVMSG #channel :hello world"); 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] [TestMethod]
public void TestParamsOnlyTrailing() public void TestParamsOnlyTrailing()
{ {
var line = new Line("PRIVMSG :hello world"); 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] [TestMethod]
@ -109,10 +109,10 @@ namespace IrcTokens.Tests
public void TestAllTokens() public void TestAllTokens()
{ {
var line = new Line("@id=123 :nick!user@host PRIVMSG #channel :hello world"); 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("nick!user@host", line.Source);
Assert.AreEqual("PRIVMSG", line.Command); 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);
} }
} }
} }

View File

@ -1,10 +1,9 @@
using System; using IrcTokens;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text;
using IrcTokens;
namespace Sample namespace TokensSample
{ {
public class Client public class Client
{ {
@ -25,15 +24,15 @@ namespace Sample
{ {
_socket.Connect("127.0.0.1", 6667); _socket.Connect("127.0.0.1", 6667);
Send(new Line {Command = "USER", Params = new List<string> {"username", "0", "*", "real name"}}); Send(new Line { Command = "USER", Params = new List<string> { "username", "0", "*", "real name" } });
Send(new Line {Command = "NICK", Params = new List<string> {"statefulbot"}}); Send(new Line { Command = "NICK", Params = new List<string> { "tokensbot" } });
while (true) while (true)
{ {
var bytesReceived = _socket.Receive(_bytes); var bytesReceived = _socket.Receive(_bytes);
var lines = _decoder.Push(_bytes); var lines = _decoder.Push(_bytes);
if (lines.Count == 0) if (bytesReceived == 0)
{ {
Console.WriteLine("! disconnected"); Console.WriteLine("! disconnected");
_socket.Shutdown(SocketShutdown.Both); _socket.Shutdown(SocketShutdown.Both);
@ -47,10 +46,10 @@ namespace Sample
switch (line.Command) switch (line.Command)
{ {
case "PING": case "PING":
Send(new Line {Command = "PONG", Params = line.Params}); Send(new Line { Command = "PONG", Params = line.Params });
break; break;
case "001": case "001":
Send(new Line {Command = "JOIN", Params = new List<string> {"#channel"}}); Send(new Line { Command = "JOIN", Params = new List<string> { "#channel" } });
break; break;
} }
} }
@ -62,7 +61,9 @@ namespace Sample
Console.WriteLine($"> {line.Format()}"); Console.WriteLine($"> {line.Format()}");
_encoder.Push(line); _encoder.Push(line);
while (_encoder.PendingBytes.Length > 0) while (_encoder.PendingBytes.Length > 0)
{
_encoder.Pop(_socket.Send(_encoder.PendingBytes)); _encoder.Pop(_socket.Send(_encoder.PendingBytes));
}
} }
} }
} }

View File

@ -1,8 +1,8 @@
using System; using IrcTokens;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using IrcTokens;
namespace Sample namespace TokensSample
{ {
public class Program public class Program
{ {
@ -17,7 +17,7 @@ namespace Sample
var line2 = new Line var line2 = new Line
{ {
Command = "USER", Command = "USER",
Params = new List<string> {"user", "0", "*", "real name"} Params = new List<string> { "user", "0", "*", "real name" }
}; };
Console.WriteLine(line2); Console.WriteLine(line2);
Console.WriteLine(line2.Format()); Console.WriteLine(line2.Format());

12
StatesSample/Program.cs Normal file
View File

@ -0,0 +1,12 @@
using System;
namespace StatesSample
{
public static class Program
{
private static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}

View File

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\IrcStates\IrcStates.csproj" />
</ItemGroup>
</Project>