tangled
alpha
login
or
join now
benharri.org
/
ircsharp
1
fork
atom
IRC parsing, tokenization, and state handling in C#
1
fork
atom
overview
issues
pulls
pipelines
rename to IrcSharp
also tidy up formatting with vs tools
benharri.org
5 years ago
933a4f85
338763fd
+578
-111
36 changed files
expand all
collapse all
unified
split
.editorconfig
IrcSharp.sln
IrcStates
Casemap.cs
Channel.cs
Emit.cs
ISupport.cs
IrcStates.csproj
Numeric.cs
Server.cs
Tests
Cap.cs
Casemap.cs
Channel.cs
Emit.cs
ISupport.cs
Mode.cs
Motd.cs
User.cs
Who.cs
User.cs
IrcTokens
Hostmask.cs
Line.cs
Protocol.cs
StatefulDecoder.cs
StatefulEncoder.cs
Tests
Format.cs
Hostmask.cs
Parser.cs
StatefulDecoder.cs
StatefulEncoder.cs
Tokenization.cs
IrcTokens.sln
Sample
Client.cs
Program.cs
TokensSample.csproj
StatesSample
Program.cs
StatesSample.csproj
+57
.editorconfig
···
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
···
1
+
2
+
[*.proto]
3
+
indent_style=tab
4
+
indent_size=tab
5
+
tab_width=4
6
+
7
+
[*.{asax,ascx,aspx,cs,cshtml,css,htm,html,js,jsx,master,razor,skin,ts,tsx,vb,xaml,xamlx,xoml}]
8
+
indent_style=space
9
+
indent_size=4
10
+
tab_width=4
11
+
12
+
[*.{appxmanifest,axml,build,config,csproj,dbml,discomap,dtd,json,jsproj,lsproj,njsproj,nuspec,proj,props,resjson,resw,resx,StyleCop,targets,tasks,vbproj,xml,xsd}]
13
+
indent_style=space
14
+
indent_size=2
15
+
tab_width=2
16
+
17
+
[*]
18
+
19
+
# Microsoft .NET properties
20
+
csharp_new_line_before_members_in_object_initializers=true
21
+
csharp_preferred_modifier_order=public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion
22
+
csharp_style_var_elsewhere=true:suggestion
23
+
csharp_style_var_for_built_in_types=true:suggestion
24
+
csharp_style_var_when_type_is_apparent=true:suggestion
25
+
dotnet_style_parentheses_in_arithmetic_binary_operators=never_if_unnecessary:none
26
+
dotnet_style_parentheses_in_other_binary_operators=never_if_unnecessary:none
27
+
dotnet_style_parentheses_in_relational_binary_operators=never_if_unnecessary:none
28
+
dotnet_style_predefined_type_for_locals_parameters_members=true:suggestion
29
+
dotnet_style_predefined_type_for_member_access=true:suggestion
30
+
dotnet_style_qualification_for_event=false:suggestion
31
+
dotnet_style_qualification_for_field=false:suggestion
32
+
dotnet_style_qualification_for_method=false:suggestion
33
+
dotnet_style_qualification_for_property=false:suggestion
34
+
dotnet_style_require_accessibility_modifiers=for_non_interface_members:suggestion
35
+
36
+
# ReSharper inspection severities
37
+
resharper_arrange_redundant_parentheses_highlighting=hint
38
+
resharper_arrange_this_qualifier_highlighting=hint
39
+
resharper_arrange_type_member_modifiers_highlighting=hint
40
+
resharper_arrange_type_modifiers_highlighting=hint
41
+
resharper_built_in_type_reference_style_for_member_access_highlighting=hint
42
+
resharper_built_in_type_reference_style_highlighting=hint
43
+
resharper_redundant_base_qualifier_highlighting=warning
44
+
resharper_suggest_var_or_type_built_in_types_highlighting=hint
45
+
resharper_suggest_var_or_type_elsewhere_highlighting=hint
46
+
resharper_suggest_var_or_type_simple_types_highlighting=hint
47
+
48
+
# ReSharper properties
49
+
resharper_csharp_insert_final_newline=true
50
+
resharper_int_align_assignments=true
51
+
resharper_int_align_switch_expressions=true
52
+
resharper_int_align_switch_sections=true
53
+
resharper_int_align_variables=true
54
+
resharper_keep_existing_embedded_arrangement=false
55
+
resharper_keep_existing_switch_expression_arrangement=false
56
+
resharper_place_simple_case_statement_on_same_line=if_owner_is_single_line
57
+
resharper_xmldoc_max_blank_lines_between_tags=1
+48
IrcSharp.sln
···
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
···
1
+
2
+
Microsoft Visual Studio Solution File, Format Version 12.00
3
+
# Visual Studio Version 16
4
+
VisualStudioVersion = 16.0.30011.22
5
+
MinimumVisualStudioVersion = 10.0.40219.1
6
+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IrcTokens", "IrcTokens\IrcTokens.csproj", "{9E812F45-B2CD-42D2-8378-EBEBF8697905}"
7
+
EndProject
8
+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TokensSample", "Sample\TokensSample.csproj", "{A45DA39B-6B47-4713-8049-3B36E0235B67}"
9
+
EndProject
10
+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IrcStates", "IrcStates\IrcStates.csproj", "{233E3CB4-61F1-4368-9139-7E9F4A58ED2D}"
11
+
EndProject
12
+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatesSample", "StatesSample\StatesSample.csproj", "{BC9F6696-9D83-4F7A-9E15-CE4D3626C1AF}"
13
+
EndProject
14
+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1A85EB22-D7B4-417F-AC3B-DAFD97DDEA08}"
15
+
ProjectSection(SolutionItems) = preProject
16
+
.editorconfig = .editorconfig
17
+
EndProjectSection
18
+
EndProject
19
+
Global
20
+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
21
+
Debug|Any CPU = Debug|Any CPU
22
+
Release|Any CPU = Release|Any CPU
23
+
EndGlobalSection
24
+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
25
+
{9E812F45-B2CD-42D2-8378-EBEBF8697905}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
26
+
{9E812F45-B2CD-42D2-8378-EBEBF8697905}.Debug|Any CPU.Build.0 = Debug|Any CPU
27
+
{9E812F45-B2CD-42D2-8378-EBEBF8697905}.Release|Any CPU.ActiveCfg = Release|Any CPU
28
+
{9E812F45-B2CD-42D2-8378-EBEBF8697905}.Release|Any CPU.Build.0 = Release|Any CPU
29
+
{A45DA39B-6B47-4713-8049-3B36E0235B67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
30
+
{A45DA39B-6B47-4713-8049-3B36E0235B67}.Debug|Any CPU.Build.0 = Debug|Any CPU
31
+
{A45DA39B-6B47-4713-8049-3B36E0235B67}.Release|Any CPU.ActiveCfg = Release|Any CPU
32
+
{A45DA39B-6B47-4713-8049-3B36E0235B67}.Release|Any CPU.Build.0 = Release|Any CPU
33
+
{233E3CB4-61F1-4368-9139-7E9F4A58ED2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
34
+
{233E3CB4-61F1-4368-9139-7E9F4A58ED2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
35
+
{233E3CB4-61F1-4368-9139-7E9F4A58ED2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
36
+
{233E3CB4-61F1-4368-9139-7E9F4A58ED2D}.Release|Any CPU.Build.0 = Release|Any CPU
37
+
{BC9F6696-9D83-4F7A-9E15-CE4D3626C1AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
38
+
{BC9F6696-9D83-4F7A-9E15-CE4D3626C1AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
39
+
{BC9F6696-9D83-4F7A-9E15-CE4D3626C1AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
40
+
{BC9F6696-9D83-4F7A-9E15-CE4D3626C1AF}.Release|Any CPU.Build.0 = Release|Any CPU
41
+
EndGlobalSection
42
+
GlobalSection(SolutionProperties) = preSolution
43
+
HideSolutionNode = FALSE
44
+
EndGlobalSection
45
+
GlobalSection(ExtensibilityGlobals) = postSolution
46
+
SolutionGuid = {0B91F0EA-8564-4318-8EEC-ED0640475141}
47
+
EndGlobalSection
48
+
EndGlobal
+43
IrcStates/Casemap.cs
···
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
···
1
+
using System;
2
+
3
+
namespace IrcStates
4
+
{
5
+
public static class Casemap
6
+
{
7
+
public enum CaseMapping
8
+
{
9
+
Rfc1459,
10
+
Ascii
11
+
}
12
+
13
+
private const string AsciiUpperChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
14
+
private const string AsciiLowerChars = "abcdefghijklmnopqrstuvwxyz";
15
+
private const string Rfc1459UpperChars = AsciiUpperChars + @"[]~\";
16
+
private const string Rfc1459LowerChars = AsciiLowerChars + @"{}^|";
17
+
18
+
private static string Replace(string s, string upper, string lower)
19
+
{
20
+
for (var i = 0; i < upper.Length; ++i)
21
+
{
22
+
s = s.Replace(upper[i], lower[i]);
23
+
}
24
+
25
+
return s;
26
+
}
27
+
28
+
public static string CaseFold(CaseMapping mapping, string s)
29
+
{
30
+
if (s != null)
31
+
{
32
+
return mapping switch
33
+
{
34
+
CaseMapping.Rfc1459 => Replace(s, Rfc1459UpperChars, Rfc1459LowerChars),
35
+
CaseMapping.Ascii => Replace(s, AsciiUpperChars, AsciiLowerChars),
36
+
_ => throw new ArgumentOutOfRangeException(nameof(mapping), mapping, null)
37
+
};
38
+
}
39
+
40
+
return string.Empty;
41
+
}
42
+
}
43
+
}
+69
IrcStates/Channel.cs
···
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
···
1
+
using System;
2
+
using System.Collections.Generic;
3
+
using System.Linq;
4
+
5
+
namespace IrcStates
6
+
{
7
+
public class Channel
8
+
{
9
+
public string Name { get; set; }
10
+
public string NameLower { get; set; }
11
+
public Dictionary<string, User> Users { get; set; }
12
+
public string Topic { get; set; }
13
+
public string TopicSetter { get; set; }
14
+
public DateTime TopicTime { get; set; }
15
+
public DateTime Created { get; set; }
16
+
public Dictionary<string, List<string>> ListModes { get; set; }
17
+
public Dictionary<string, string> Modes { get; set; }
18
+
19
+
public override string ToString()
20
+
{
21
+
return $"Channel(name={Name})";
22
+
}
23
+
24
+
public void SetName(string name, string nameLower)
25
+
{
26
+
Name = name;
27
+
NameLower = nameLower;
28
+
}
29
+
30
+
public void AddMode(string ch, string param, bool listMode)
31
+
{
32
+
if (listMode)
33
+
{
34
+
if (!ListModes.ContainsKey(ch))
35
+
{
36
+
ListModes[ch] = new List<string>();
37
+
}
38
+
39
+
if (ListModes[ch].Contains(param))
40
+
{
41
+
ListModes[ch].Add(param ?? string.Empty);
42
+
}
43
+
}
44
+
else
45
+
{
46
+
Modes[ch] = param;
47
+
}
48
+
}
49
+
50
+
public void RemoveMode(string ch, string param)
51
+
{
52
+
if (ListModes.ContainsKey(ch))
53
+
{
54
+
if (ListModes[ch].Contains(param))
55
+
{
56
+
ListModes[ch].Remove(param);
57
+
if (!ListModes[ch].Any())
58
+
{
59
+
ListModes.Remove(ch);
60
+
}
61
+
}
62
+
}
63
+
else if (Modes.ContainsKey(ch))
64
+
{
65
+
Modes.Remove(ch);
66
+
}
67
+
}
68
+
}
69
+
}
+6
IrcStates/Emit.cs
···
0
0
0
0
0
0
···
1
+
namespace IrcStates
2
+
{
3
+
public class Emit
4
+
{
5
+
}
6
+
}
+7
IrcStates/ISupport.cs
···
0
0
0
0
0
0
0
···
1
+
// ReSharper disable InconsistentNaming
2
+
namespace IrcStates
3
+
{
4
+
public class ISupport
5
+
{
6
+
}
7
+
}
+21
IrcStates/IrcStates.csproj
···
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
···
1
+
<Project Sdk="Microsoft.NET.Sdk">
2
+
3
+
<PropertyGroup>
4
+
<TargetFramework>netcoreapp3.1</TargetFramework>
5
+
</PropertyGroup>
6
+
7
+
<ItemGroup>
8
+
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8">
9
+
<PrivateAssets>all</PrivateAssets>
10
+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
11
+
</PackageReference>
12
+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.0" />
13
+
<PackageReference Include="MSTest.TestAdapter" Version="2.1.1" />
14
+
<PackageReference Include="MSTest.TestFramework" Version="2.1.1" />
15
+
</ItemGroup>
16
+
17
+
<ItemGroup>
18
+
<ProjectReference Include="..\IrcTokens\IrcTokens.csproj" />
19
+
</ItemGroup>
20
+
21
+
</Project>
+49
IrcStates/Numeric.cs
···
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
···
1
+
// ReSharper disable InconsistentNaming
2
+
namespace IrcStates
3
+
{
4
+
public static class Numeric
5
+
{
6
+
public const string RPL_WELCOME = "001";
7
+
public const string RPL_ISUPPORT = "005";
8
+
public const string RPL_MOTD = "372";
9
+
public const string RPL_MOTDSTART = "375";
10
+
public const string RPL_UMODEIS = "221";
11
+
public const string RPL_VISIBLEHOST = "396";
12
+
13
+
public const string RPL_CHANNELMODEIS = "324";
14
+
public const string RPL_CREATIONTIME = "329";
15
+
public const string RPL_TOPIC = "332";
16
+
public const string RPL_TOPICWHOTIME = "333";
17
+
18
+
public const string RPL_WHOREPLY = "352";
19
+
public const string RPL_WHOSPCRPL = "354";
20
+
public const string RPL_ENDOFWHO = "315";
21
+
public const string RPL_NAMREPLY = "353";
22
+
public const string RPL_ENDOFNAMES = "366";
23
+
24
+
public const string RPL_BANLIST = "367";
25
+
public const string RPL_ENDOFBANLIST = "368";
26
+
public const string RPL_QUIETLIST = "728";
27
+
public const string RPL_ENDOFQUIETLIST = "729";
28
+
29
+
public const string RPL_SASLSUCCESS = "903";
30
+
public const string ERR_SASLFAIL = "904";
31
+
public const string ERR_SASLTOOLONG = "905";
32
+
public const string ERR_SASLABORTED = "906";
33
+
public const string ERR_SASLALREADY = "907";
34
+
public const string RPL_SASLMECHS = "908";
35
+
36
+
public const string RPL_WHOISUSER = "311";
37
+
public const string RPL_WHOISSERVER = "312";
38
+
public const string RPL_WHOISOPERATOR = "313";
39
+
public const string RPL_WHOISIDLE = "317";
40
+
public const string RPL_WHOISCHANNELS = "319";
41
+
public const string RPL_WHOISACCOUNT = "330";
42
+
public const string RPL_WHOISHOST = "378";
43
+
public const string RPL_WHOISMODES = "379";
44
+
public const string RPL_WHOISSECURE = "671";
45
+
public const string RPL_ENDOFWHOIS = "318";
46
+
47
+
public const string ERR_NOSUCHCHANNEL = "403";
48
+
}
49
+
}
+6
IrcStates/Server.cs
···
0
0
0
0
0
0
···
1
+
namespace IrcStates
2
+
{
3
+
public class Server
4
+
{
5
+
}
6
+
}
+9
IrcStates/Tests/Cap.cs
···
0
0
0
0
0
0
0
0
0
···
1
+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2
+
3
+
namespace IrcStates.Tests
4
+
{
5
+
[TestClass]
6
+
public class Cap
7
+
{
8
+
}
9
+
}
+9
IrcStates/Tests/Casemap.cs
···
0
0
0
0
0
0
0
0
0
···
1
+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2
+
3
+
namespace IrcStates.Tests
4
+
{
5
+
[TestClass]
6
+
public class Casemap
7
+
{
8
+
}
9
+
}
+9
IrcStates/Tests/Channel.cs
···
0
0
0
0
0
0
0
0
0
···
1
+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2
+
3
+
namespace IrcStates.Tests
4
+
{
5
+
[TestClass]
6
+
public class Channel
7
+
{
8
+
}
9
+
}
+9
IrcStates/Tests/Emit.cs
···
0
0
0
0
0
0
0
0
0
···
1
+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2
+
3
+
namespace IrcStates.Tests
4
+
{
5
+
[TestClass]
6
+
public class Emit
7
+
{
8
+
}
9
+
}
+10
IrcStates/Tests/ISupport.cs
···
0
0
0
0
0
0
0
0
0
0
···
1
+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2
+
// ReSharper disable InconsistentNaming
3
+
4
+
namespace IrcStates.Tests
5
+
{
6
+
[TestClass]
7
+
public class ISupport
8
+
{
9
+
}
10
+
}
+9
IrcStates/Tests/Mode.cs
···
0
0
0
0
0
0
0
0
0
···
1
+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2
+
3
+
namespace IrcStates.Tests
4
+
{
5
+
[TestClass]
6
+
public class Mode
7
+
{
8
+
}
9
+
}
+9
IrcStates/Tests/Motd.cs
···
0
0
0
0
0
0
0
0
0
···
1
+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2
+
3
+
namespace IrcStates.Tests
4
+
{
5
+
[TestClass]
6
+
public class Motd
7
+
{
8
+
}
9
+
}
+9
IrcStates/Tests/User.cs
···
0
0
0
0
0
0
0
0
0
···
1
+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2
+
3
+
namespace IrcStates.Tests
4
+
{
5
+
[TestClass]
6
+
public class User
7
+
{
8
+
}
9
+
}
+9
IrcStates/Tests/Who.cs
···
0
0
0
0
0
0
0
0
0
···
1
+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2
+
3
+
namespace IrcStates.Tests
4
+
{
5
+
[TestClass]
6
+
public class Who
7
+
{
8
+
}
9
+
}
+28
IrcStates/User.cs
···
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
···
1
+
using System.Collections.Generic;
2
+
3
+
namespace IrcStates
4
+
{
5
+
public class User
6
+
{
7
+
private string NickName;
8
+
private string NickNameLower;
9
+
10
+
public string UserName { get; set; }
11
+
public string HostName { get; set; }
12
+
public string RealName { get; set; }
13
+
public string Account { get; set; }
14
+
public string Away { get; set; }
15
+
public HashSet<string> Channels { get; set; }
16
+
17
+
public override string ToString()
18
+
{
19
+
return $"User(nickname={NickName})";
20
+
}
21
+
22
+
public void SetNickName(string nick, string nickLower)
23
+
{
24
+
NickName = nick;
25
+
NickNameLower = nickLower;
26
+
}
27
+
}
28
+
}
-31
IrcTokens.sln
···
1
-
2
-
Microsoft Visual Studio Solution File, Format Version 12.00
3
-
# Visual Studio Version 16
4
-
VisualStudioVersion = 16.0.30011.22
5
-
MinimumVisualStudioVersion = 10.0.40219.1
6
-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IrcTokens", "IrcTokens\IrcTokens.csproj", "{9E812F45-B2CD-42D2-8378-EBEBF8697905}"
7
-
EndProject
8
-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample", "Sample\Sample.csproj", "{A45DA39B-6B47-4713-8049-3B36E0235B67}"
9
-
EndProject
10
-
Global
11
-
GlobalSection(SolutionConfigurationPlatforms) = preSolution
12
-
Debug|Any CPU = Debug|Any CPU
13
-
Release|Any CPU = Release|Any CPU
14
-
EndGlobalSection
15
-
GlobalSection(ProjectConfigurationPlatforms) = postSolution
16
-
{9E812F45-B2CD-42D2-8378-EBEBF8697905}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17
-
{9E812F45-B2CD-42D2-8378-EBEBF8697905}.Debug|Any CPU.Build.0 = Debug|Any CPU
18
-
{9E812F45-B2CD-42D2-8378-EBEBF8697905}.Release|Any CPU.ActiveCfg = Release|Any CPU
19
-
{9E812F45-B2CD-42D2-8378-EBEBF8697905}.Release|Any CPU.Build.0 = Release|Any CPU
20
-
{A45DA39B-6B47-4713-8049-3B36E0235B67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21
-
{A45DA39B-6B47-4713-8049-3B36E0235B67}.Debug|Any CPU.Build.0 = Debug|Any CPU
22
-
{A45DA39B-6B47-4713-8049-3B36E0235B67}.Release|Any CPU.ActiveCfg = Release|Any CPU
23
-
{A45DA39B-6B47-4713-8049-3B36E0235B67}.Release|Any CPU.Build.0 = Release|Any CPU
24
-
EndGlobalSection
25
-
GlobalSection(SolutionProperties) = preSolution
26
-
HideSolutionNode = FALSE
27
-
EndGlobalSection
28
-
GlobalSection(ExtensibilityGlobals) = postSolution
29
-
SolutionGuid = {0B91F0EA-8564-4318-8EEC-ED0640475141}
30
-
EndGlobalSection
31
-
EndGlobal
···
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
+23
-7
IrcTokens/Hostmask.cs
···
5
/// <summary>
6
/// Represents the three parts of a hostmask. Parse with the constructor.
7
/// </summary>
8
-
public class Hostmask
9
{
10
public string NickName { get; set; }
11
public string UserName { get; set; }
12
public string HostName { get; set; }
13
14
-
public override string ToString() => _source;
0
0
0
15
16
-
public override int GetHashCode() => _source.GetHashCode(StringComparison.Ordinal);
0
0
0
17
18
-
public override bool Equals(object obj)
19
{
20
-
if (obj == null || GetType() != obj.GetType())
0
21
return false;
0
22
23
-
return _source == ((Hostmask) obj)._source;
0
0
0
0
0
24
}
25
26
private readonly string _source;
27
28
public Hostmask(string source)
29
{
30
-
if (source == null) return;
0
0
0
31
32
_source = source;
33
···
5
/// <summary>
6
/// Represents the three parts of a hostmask. Parse with the constructor.
7
/// </summary>
8
+
public class Hostmask : IEquatable<Hostmask>
9
{
10
public string NickName { get; set; }
11
public string UserName { get; set; }
12
public string HostName { get; set; }
13
14
+
public override string ToString()
15
+
{
16
+
return _source;
17
+
}
18
19
+
public override int GetHashCode()
20
+
{
21
+
return _source.GetHashCode(StringComparison.Ordinal);
22
+
}
23
24
+
public bool Equals(Hostmask other)
25
{
26
+
if (other == null)
27
+
{
28
return false;
29
+
}
30
31
+
return _source == other._source;
32
+
}
33
+
34
+
public override bool Equals(object obj)
35
+
{
36
+
return Equals(obj as Hostmask);
37
}
38
39
private readonly string _source;
40
41
public Hostmask(string source)
42
{
43
+
if (source == null)
44
+
{
45
+
return;
46
+
}
47
48
_source = source;
49
+39
-8
IrcTokens/Line.cs
···
8
/// <summary>
9
/// Tools to represent, parse, and format IRC lines
10
/// </summary>
11
-
public class Line
12
{
13
public Dictionary<string, string> Tags { get; set; }
14
public string Source { get; set; }
···
16
public List<string> Params { get; set; }
17
18
private Hostmask _hostmask;
19
-
private readonly string _rawLine;
20
21
public override string ToString()
22
{
23
var vars = new List<string>();
24
25
if (Command != null)
0
26
vars.Add($"command={Command}");
0
0
27
if (Source != null)
0
28
vars.Add($"source={Source}");
0
0
29
if (Params != null && Params.Any())
0
30
vars.Add($"params=[{string.Join(",", Params)}]");
0
0
31
if (Tags != null && Tags.Any())
0
32
vars.Add($"tags=[{string.Join(";", Tags.Select(kvp => $"{kvp.Key}={kvp.Value}"))}]");
0
33
34
return $"Line({string.Join(", ", vars)})";
35
}
36
37
-
public override int GetHashCode() => Format().GetHashCode(StringComparison.Ordinal);
0
0
0
38
39
-
public override bool Equals(object obj)
40
{
41
-
if (obj == null || GetType() != obj.GetType())
0
42
return false;
0
43
44
-
return Format() == ((Line) obj).Format();
0
0
0
0
0
45
}
46
47
public Hostmask Hostmask =>
···
56
public Line(string line)
57
{
58
if (string.IsNullOrWhiteSpace(line))
0
59
throw new ArgumentNullException(nameof(line));
0
60
61
-
_rawLine = line;
62
string[] split;
63
64
if (line.StartsWith('@'))
···
97
98
Params = line.Contains(' ', StringComparison.Ordinal)
99
? line.Split(' ', StringSplitOptions.RemoveEmptyEntries).ToList()
100
-
: new List<string> {line};
101
102
if (Params[0].StartsWith(':'))
103
{
···
135
}
136
137
if (Source != null)
0
138
outs.Add($":{Source}");
0
139
140
outs.Add(Command);
141
···
147
foreach (var p in Params)
148
{
149
if (p.Contains(' ', StringComparison.Ordinal))
0
150
throw new ArgumentException(@"non-last parameters cannot have spaces", p);
0
0
151
if (p.StartsWith(':'))
0
152
throw new ArgumentException(@"non-last parameters cannot start with colon", p);
0
153
}
154
outs.AddRange(Params);
155
156
if (string.IsNullOrWhiteSpace(last) || last.Contains(' ', StringComparison.Ordinal) || last.StartsWith(':'))
0
157
last = $":{last}";
0
0
158
outs.Add(last);
159
}
160
···
8
/// <summary>
9
/// Tools to represent, parse, and format IRC lines
10
/// </summary>
11
+
public class Line : IEquatable<Line>
12
{
13
public Dictionary<string, string> Tags { get; set; }
14
public string Source { get; set; }
···
16
public List<string> Params { get; set; }
17
18
private Hostmask _hostmask;
0
19
20
public override string ToString()
21
{
22
var vars = new List<string>();
23
24
if (Command != null)
25
+
{
26
vars.Add($"command={Command}");
27
+
}
28
+
29
if (Source != null)
30
+
{
31
vars.Add($"source={Source}");
32
+
}
33
+
34
if (Params != null && Params.Any())
35
+
{
36
vars.Add($"params=[{string.Join(",", Params)}]");
37
+
}
38
+
39
if (Tags != null && Tags.Any())
40
+
{
41
vars.Add($"tags=[{string.Join(";", Tags.Select(kvp => $"{kvp.Key}={kvp.Value}"))}]");
42
+
}
43
44
return $"Line({string.Join(", ", vars)})";
45
}
46
47
+
public override int GetHashCode()
48
+
{
49
+
return Format().GetHashCode(StringComparison.Ordinal);
50
+
}
51
52
+
public bool Equals(Line other)
53
{
54
+
if (other == null)
55
+
{
56
return false;
57
+
}
58
59
+
return Format() == other.Format();
60
+
}
61
+
62
+
public override bool Equals(object obj)
63
+
{
64
+
return Equals(obj as Line);
65
}
66
67
public Hostmask Hostmask =>
···
76
public Line(string line)
77
{
78
if (string.IsNullOrWhiteSpace(line))
79
+
{
80
throw new ArgumentNullException(nameof(line));
81
+
}
82
0
83
string[] split;
84
85
if (line.StartsWith('@'))
···
118
119
Params = line.Contains(' ', StringComparison.Ordinal)
120
? line.Split(' ', StringSplitOptions.RemoveEmptyEntries).ToList()
121
+
: new List<string> { line };
122
123
if (Params[0].StartsWith(':'))
124
{
···
156
}
157
158
if (Source != null)
159
+
{
160
outs.Add($":{Source}");
161
+
}
162
163
outs.Add(Command);
164
···
170
foreach (var p in Params)
171
{
172
if (p.Contains(' ', StringComparison.Ordinal))
173
+
{
174
throw new ArgumentException(@"non-last parameters cannot have spaces", p);
175
+
}
176
+
177
if (p.StartsWith(':'))
178
+
{
179
throw new ArgumentException(@"non-last parameters cannot start with colon", p);
180
+
}
181
}
182
outs.AddRange(Params);
183
184
if (string.IsNullOrWhiteSpace(last) || last.Contains(' ', StringComparison.Ordinal) || last.StartsWith(':'))
185
+
{
186
last = $":{last}";
187
+
}
188
+
189
outs.Add(last);
190
}
191
+2
IrcTokens/Protocol.cs
···
50
}
51
}
52
else
0
53
unescaped.Append(current);
0
54
}
55
56
return unescaped.ToString();
···
50
}
51
}
52
else
53
+
{
54
unescaped.Append(current);
55
+
}
56
}
57
58
return unescaped.ToString();
+7
-1
IrcTokens/StatefulDecoder.cs
···
18
set
19
{
20
if (value != null)
0
21
_encoding = Encoding.GetEncoding(value.CodePage, EncoderFallback.ExceptionFallback,
22
DecoderFallback.ReplacementFallback);
0
23
}
24
}
25
···
30
set
31
{
32
if (value != null)
33
-
_encoding = Encoding.GetEncoding(value.CodePage, EncoderFallback.ReplacementFallback,
0
34
DecoderFallback.ReplacementFallback);
0
35
}
36
}
37
···
55
public List<Line> Push(byte[] data)
56
{
57
if (data == null || data.Length == 0)
0
58
return null;
0
59
60
_buffer = _buffer.Concat(data).ToArray();
61
···
18
set
19
{
20
if (value != null)
21
+
{
22
_encoding = Encoding.GetEncoding(value.CodePage, EncoderFallback.ExceptionFallback,
23
DecoderFallback.ReplacementFallback);
24
+
}
25
}
26
}
27
···
32
set
33
{
34
if (value != null)
35
+
{
36
+
_fallback = Encoding.GetEncoding(value.CodePage, EncoderFallback.ReplacementFallback,
37
DecoderFallback.ReplacementFallback);
38
+
}
39
}
40
}
41
···
59
public List<Line> Push(byte[] data)
60
{
61
if (data == null || data.Length == 0)
62
+
{
63
return null;
64
+
}
65
66
_buffer = _buffer.Concat(data).ToArray();
67
+4
IrcTokens/StatefulEncoder.cs
···
16
set
17
{
18
if (value != null)
0
19
_encoding = Encoding.GetEncoding(value.CodePage, EncoderFallback.ExceptionFallback,
20
DecoderFallback.ExceptionFallback);
0
21
}
22
}
23
···
52
public void Push(Line line)
53
{
54
if (line == null)
0
55
throw new ArgumentNullException(nameof(line));
0
56
57
PendingBytes = PendingBytes.Concat(Encoding.GetBytes($"{line.Format()}\r\n")).ToArray();
58
_bufferedLines.Enqueue(line);
···
16
set
17
{
18
if (value != null)
19
+
{
20
_encoding = Encoding.GetEncoding(value.CodePage, EncoderFallback.ExceptionFallback,
21
DecoderFallback.ExceptionFallback);
22
+
}
23
}
24
}
25
···
54
public void Push(Line line)
55
{
56
if (line == null)
57
+
{
58
throw new ArgumentNullException(nameof(line));
59
+
}
60
61
PendingBytes = PendingBytes.Concat(Encoding.GetBytes($"{line.Format()}\r\n")).ToArray();
62
_bufferedLines.Enqueue(line);
+18
-18
IrcTokens/Tests/FormatTests.cs
IrcTokens/Tests/Format.cs
···
5
namespace IrcTokens.Tests
6
{
7
[TestClass]
8
-
public class FormatTests
9
{
10
[TestMethod]
11
public void TestTags()
12
{
13
var line = new Line
14
{
15
-
Command = "PRIVMSG",
16
-
Params = new List<string> {"#channel", "hello"},
17
-
Tags = new Dictionary<string, string> {{"id", "\\" + " " + ";" + "\r\n"}}
18
}.Format();
19
20
Assert.AreEqual("@id=\\\\\\s\\:\\r\\n PRIVMSG #channel hello", line);
···
25
{
26
var line = new Line
27
{
28
-
Command = "PRIVMSG",
29
-
Params = new List<string> {"#channel", "hello"}
30
}.Format();
31
32
Assert.AreEqual("PRIVMSG #channel hello", line);
···
38
var line = new Line
39
{
40
Command = "PRIVMSG",
41
-
Params = new List<string> {"#channel", "hello"},
42
-
Tags = new Dictionary<string, string> {{"a", null}}
43
}.Format();
44
45
Assert.AreEqual("@a PRIVMSG #channel hello", line);
···
51
var line = new Line
52
{
53
Command = "PRIVMSG",
54
-
Params = new List<string> {"#channel", "hello"},
55
-
Tags = new Dictionary<string, string> {{"a", ""}}
56
}.Format();
57
58
Assert.AreEqual("@a PRIVMSG #channel hello", line);
···
64
var line = new Line
65
{
66
Command = "PRIVMSG",
67
-
Params = new List<string> {"#channel", "hello"},
68
Source = "nick!user@host"
69
}.Format();
70
···
74
[TestMethod]
75
public void TestCommandLowercase()
76
{
77
-
var line = new Line {Command = "privmsg"}.Format();
78
Assert.AreEqual("privmsg", line);
79
}
80
81
[TestMethod]
82
public void TestCommandUppercase()
83
{
84
-
var line = new Line {Command = "PRIVMSG"}.Format();
85
Assert.AreEqual("PRIVMSG", line);
86
}
87
···
91
var line = new Line
92
{
93
Command = "PRIVMSG",
94
-
Params = new List<string> {"#channel", "hello world"}
95
}.Format();
96
97
Assert.AreEqual("PRIVMSG #channel :hello world", line);
···
103
var line = new Line
104
{
105
Command = "PRIVMSG",
106
-
Params = new List<string> {"#channel", "helloworld"}
107
}.Format();
108
109
Assert.AreEqual("PRIVMSG #channel helloworld", line);
···
115
var line = new Line
116
{
117
Command = "PRIVMSG",
118
-
Params = new List<string> {"#channel", ":helloworld"}
119
}.Format();
120
121
Assert.AreEqual("PRIVMSG #channel ::helloworld", line);
···
129
new Line
130
{
131
Command = "USER",
132
-
Params = new List<string> {"user", "0 *", "real name"}
133
}.Format();
134
});
135
}
···
142
new Line
143
{
144
Command = "PRIVMSG",
145
-
Params = new List<string> {":#channel", "hello"}
146
}.Format();
147
});
148
}
···
5
namespace IrcTokens.Tests
6
{
7
[TestClass]
8
+
public class Format
9
{
10
[TestMethod]
11
public void TestTags()
12
{
13
var line = new Line
14
{
15
+
Command = "PRIVMSG",
16
+
Params = new List<string> { "#channel", "hello" },
17
+
Tags = new Dictionary<string, string> { { "id", "\\" + " " + ";" + "\r\n" } }
18
}.Format();
19
20
Assert.AreEqual("@id=\\\\\\s\\:\\r\\n PRIVMSG #channel hello", line);
···
25
{
26
var line = new Line
27
{
28
+
Command = "PRIVMSG",
29
+
Params = new List<string> { "#channel", "hello" }
30
}.Format();
31
32
Assert.AreEqual("PRIVMSG #channel hello", line);
···
38
var line = new Line
39
{
40
Command = "PRIVMSG",
41
+
Params = new List<string> { "#channel", "hello" },
42
+
Tags = new Dictionary<string, string> { { "a", null } }
43
}.Format();
44
45
Assert.AreEqual("@a PRIVMSG #channel hello", line);
···
51
var line = new Line
52
{
53
Command = "PRIVMSG",
54
+
Params = new List<string> { "#channel", "hello" },
55
+
Tags = new Dictionary<string, string> { { "a", "" } }
56
}.Format();
57
58
Assert.AreEqual("@a PRIVMSG #channel hello", line);
···
64
var line = new Line
65
{
66
Command = "PRIVMSG",
67
+
Params = new List<string> { "#channel", "hello" },
68
Source = "nick!user@host"
69
}.Format();
70
···
74
[TestMethod]
75
public void TestCommandLowercase()
76
{
77
+
var line = new Line { Command = "privmsg" }.Format();
78
Assert.AreEqual("privmsg", line);
79
}
80
81
[TestMethod]
82
public void TestCommandUppercase()
83
{
84
+
var line = new Line { Command = "PRIVMSG" }.Format();
85
Assert.AreEqual("PRIVMSG", line);
86
}
87
···
91
var line = new Line
92
{
93
Command = "PRIVMSG",
94
+
Params = new List<string> { "#channel", "hello world" }
95
}.Format();
96
97
Assert.AreEqual("PRIVMSG #channel :hello world", line);
···
103
var line = new Line
104
{
105
Command = "PRIVMSG",
106
+
Params = new List<string> { "#channel", "helloworld" }
107
}.Format();
108
109
Assert.AreEqual("PRIVMSG #channel helloworld", line);
···
115
var line = new Line
116
{
117
Command = "PRIVMSG",
118
+
Params = new List<string> { "#channel", ":helloworld" }
119
}.Format();
120
121
Assert.AreEqual("PRIVMSG #channel ::helloworld", line);
···
129
new Line
130
{
131
Command = "USER",
132
+
Params = new List<string> { "user", "0 *", "real name" }
133
}.Format();
134
});
135
}
···
142
new Line
143
{
144
Command = "PRIVMSG",
145
+
Params = new List<string> { ":#channel", "hello" }
146
}.Format();
147
});
148
}
+6
-6
IrcTokens/Tests/HostmaskTests.cs
IrcTokens/Tests/Hostmask.cs
···
3
namespace IrcTokens.Tests
4
{
5
[TestClass]
6
-
public class HostmaskTests
7
{
8
[TestMethod]
9
public void TestHostmask()
10
{
11
-
var hostmask = new Hostmask("nick!user@host");
12
Assert.AreEqual("nick", hostmask.NickName);
13
Assert.AreEqual("user", hostmask.UserName);
14
Assert.AreEqual("host", hostmask.HostName);
···
17
[TestMethod]
18
public void TestNoHostName()
19
{
20
-
var hostmask = new Hostmask("nick!user");
21
Assert.AreEqual("nick", hostmask.NickName);
22
Assert.AreEqual("user", hostmask.UserName);
23
Assert.IsNull(hostmask.HostName);
···
26
[TestMethod]
27
public void TestNoUserName()
28
{
29
-
var hostmask = new Hostmask("nick@host");
30
Assert.AreEqual("nick", hostmask.NickName);
31
Assert.IsNull(hostmask.UserName);
32
Assert.AreEqual("host", hostmask.HostName);
···
35
[TestMethod]
36
public void TestOnlyNickName()
37
{
38
-
var hostmask = new Hostmask("nick");
39
Assert.AreEqual("nick", hostmask.NickName);
40
Assert.IsNull(hostmask.UserName);
41
Assert.IsNull(hostmask.HostName);
···
45
public void TestHostmaskFromLine()
46
{
47
var line = new Line(":nick!user@host PRIVMSG #channel hello");
48
-
var hostmask = new Hostmask("nick!user@host");
49
Assert.AreEqual(hostmask.ToString(), line.Hostmask.ToString());
50
Assert.AreEqual("nick", line.Hostmask.NickName);
51
Assert.AreEqual("user", line.Hostmask.UserName);
···
3
namespace IrcTokens.Tests
4
{
5
[TestClass]
6
+
public class Hostmask
7
{
8
[TestMethod]
9
public void TestHostmask()
10
{
11
+
var hostmask = new IrcTokens.Hostmask("nick!user@host");
12
Assert.AreEqual("nick", hostmask.NickName);
13
Assert.AreEqual("user", hostmask.UserName);
14
Assert.AreEqual("host", hostmask.HostName);
···
17
[TestMethod]
18
public void TestNoHostName()
19
{
20
+
var hostmask = new IrcTokens.Hostmask("nick!user");
21
Assert.AreEqual("nick", hostmask.NickName);
22
Assert.AreEqual("user", hostmask.UserName);
23
Assert.IsNull(hostmask.HostName);
···
26
[TestMethod]
27
public void TestNoUserName()
28
{
29
+
var hostmask = new IrcTokens.Hostmask("nick@host");
30
Assert.AreEqual("nick", hostmask.NickName);
31
Assert.IsNull(hostmask.UserName);
32
Assert.AreEqual("host", hostmask.HostName);
···
35
[TestMethod]
36
public void TestOnlyNickName()
37
{
38
+
var hostmask = new IrcTokens.Hostmask("nick");
39
Assert.AreEqual("nick", hostmask.NickName);
40
Assert.IsNull(hostmask.UserName);
41
Assert.IsNull(hostmask.HostName);
···
45
public void TestHostmaskFromLine()
46
{
47
var line = new Line(":nick!user@host PRIVMSG #channel hello");
48
+
var hostmask = new IrcTokens.Hostmask("nick!user@host");
49
Assert.AreEqual(hostmask.ToString(), line.Hostmask.ToString());
50
Assert.AreEqual("nick", line.Hostmask.NickName);
51
Assert.AreEqual("user", line.Hostmask.UserName);
+5
-5
IrcTokens/Tests/ParserTests.cs
IrcTokens/Tests/Parser.cs
···
1
-
using System.Collections.Generic;
0
0
2
using System.Globalization;
3
using System.IO;
4
-
using IrcTokens.Tests.Data;
5
-
using Microsoft.VisualStudio.TestTools.UnitTesting;
6
using YamlDotNet.Serialization;
7
using YamlDotNet.Serialization.NamingConventions;
8
9
namespace IrcTokens.Tests
10
{
11
[TestClass]
12
-
public class ParserTests
13
{
14
private static T LoadYaml<T>(string path)
15
{
···
46
{
47
Command = atoms.Verb,
48
Params = atoms.Params,
49
-
Source = atoms.Source ?? null,
50
Tags = atoms.Tags
51
}.Format();
52
···
1
+
using IrcTokens.Tests.Data;
2
+
using Microsoft.VisualStudio.TestTools.UnitTesting;
3
+
using System.Collections.Generic;
4
using System.Globalization;
5
using System.IO;
0
0
6
using YamlDotNet.Serialization;
7
using YamlDotNet.Serialization.NamingConventions;
8
9
namespace IrcTokens.Tests
10
{
11
[TestClass]
12
+
public class Parser
13
{
14
private static T LoadYaml<T>(string path)
15
{
···
46
{
47
Command = atoms.Verb,
48
Params = atoms.Params,
49
+
Source = atoms.Source,
50
Tags = atoms.Tags
51
}.Format();
52
+8
-9
IrcTokens/Tests/StatefulDecoderTests.cs
IrcTokens/Tests/StatefulDecoder.cs
···
1
-
using System.Collections.Generic;
2
-
using System.Linq;
3
using System.Text;
4
-
using Microsoft.VisualStudio.TestTools.UnitTesting;
5
6
namespace IrcTokens.Tests
7
{
8
[TestClass]
9
-
public class StatefulDecoderTests
10
{
11
-
private StatefulDecoder _decoder;
12
13
[TestInitialize]
14
public void TestInitialize()
15
{
16
-
_decoder = new StatefulDecoder();
17
}
18
19
[TestMethod]
···
26
Assert.AreEqual(1, lines.Count);
27
28
var line = new Line("PRIVMSG #channel hello");
29
-
CollectionAssert.AreEqual(new List<Line> {line}, lines);
30
}
31
32
[TestMethod]
···
45
public void TestEncoding()
46
{
47
var iso8859 = Encoding.GetEncoding("iso-8859-1");
48
-
_decoder = new StatefulDecoder {Encoding = iso8859};
49
var lines = _decoder.Push(iso8859.GetBytes("PRIVMSG #channel :hello Ç\r\n"));
50
var line = new Line("PRIVMSG #channel :hello Ç");
51
Assert.IsTrue(line.Equals(lines[0]));
···
55
public void TestEncodingFallback()
56
{
57
var latin1 = Encoding.GetEncoding("iso-8859-1");
58
-
_decoder = new StatefulDecoder {Encoding = null, Fallback = latin1};
59
var lines = _decoder.Push(latin1.GetBytes("PRIVMSG #channel hélló\r\n"));
60
Assert.AreEqual(1, lines.Count);
61
Assert.IsTrue(new Line("PRIVMSG #channel hélló").Equals(lines[0]));
···
1
+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2
+
using System.Collections.Generic;
3
using System.Text;
0
4
5
namespace IrcTokens.Tests
6
{
7
[TestClass]
8
+
public class StatefulDecoder
9
{
10
+
private IrcTokens.StatefulDecoder _decoder;
11
12
[TestInitialize]
13
public void TestInitialize()
14
{
15
+
_decoder = new IrcTokens.StatefulDecoder();
16
}
17
18
[TestMethod]
···
25
Assert.AreEqual(1, lines.Count);
26
27
var line = new Line("PRIVMSG #channel hello");
28
+
CollectionAssert.AreEqual(new List<Line> { line }, lines);
29
}
30
31
[TestMethod]
···
44
public void TestEncoding()
45
{
46
var iso8859 = Encoding.GetEncoding("iso-8859-1");
47
+
_decoder = new IrcTokens.StatefulDecoder { Encoding = iso8859 };
48
var lines = _decoder.Push(iso8859.GetBytes("PRIVMSG #channel :hello Ç\r\n"));
49
var line = new Line("PRIVMSG #channel :hello Ç");
50
Assert.IsTrue(line.Equals(lines[0]));
···
54
public void TestEncodingFallback()
55
{
56
var latin1 = Encoding.GetEncoding("iso-8859-1");
57
+
_decoder = new IrcTokens.StatefulDecoder { Encoding = null, Fallback = latin1 };
58
var lines = _decoder.Push(latin1.GetBytes("PRIVMSG #channel hélló\r\n"));
59
Assert.AreEqual(1, lines.Count);
60
Assert.IsTrue(new Line("PRIVMSG #channel hélló").Equals(lines[0]));
+5
-6
IrcTokens/Tests/StatefulEncoderTests.cs
IrcTokens/Tests/StatefulEncoder.cs
···
1
-
using System.Linq;
2
using System.Text;
3
-
using Microsoft.VisualStudio.TestTools.UnitTesting;
4
5
namespace IrcTokens.Tests
6
{
7
[TestClass]
8
-
public class StatefulEncoderTests
9
{
10
-
private StatefulEncoder _encoder;
11
12
[TestInitialize]
13
public void TestInitialize()
14
{
15
-
_encoder = new StatefulEncoder();
16
}
17
18
[TestMethod]
···
64
public void TestEncoding()
65
{
66
var iso8859 = Encoding.GetEncoding("iso-8859-1");
67
-
_encoder = new StatefulEncoder {Encoding = iso8859};
68
_encoder.Push(new Line("PRIVMSG #channel :hello Ç"));
69
CollectionAssert.AreEqual(iso8859.GetBytes("PRIVMSG #channel :hello Ç\r\n"), _encoder.PendingBytes);
70
}
···
1
+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2
using System.Text;
0
3
4
namespace IrcTokens.Tests
5
{
6
[TestClass]
7
+
public class StatefulEncoder
8
{
9
+
private IrcTokens.StatefulEncoder _encoder;
10
11
[TestInitialize]
12
public void TestInitialize()
13
{
14
+
_encoder = new IrcTokens.StatefulEncoder();
15
}
16
17
[TestMethod]
···
63
public void TestEncoding()
64
{
65
var iso8859 = Encoding.GetEncoding("iso-8859-1");
66
+
_encoder = new IrcTokens.StatefulEncoder { Encoding = iso8859 };
67
_encoder.Push(new Line("PRIVMSG #channel :hello Ç"));
68
CollectionAssert.AreEqual(iso8859.GetBytes("PRIVMSG #channel :hello Ç\r\n"), _encoder.PendingBytes);
69
}
+7
-7
IrcTokens/Tests/TokenizationTests.cs
IrcTokens/Tests/Tokenization.cs
···
1
-
using System.Collections.Generic;
2
-
using Microsoft.VisualStudio.TestTools.UnitTesting;
3
4
namespace IrcTokens.Tests
5
{
6
[TestClass]
7
-
public class TokenizationTests
8
{
9
[TestMethod]
10
public void TestTagsMissing()
···
87
public void TestParamsTrailing()
88
{
89
var line = new Line("PRIVMSG #channel :hello world");
90
-
CollectionAssert.AreEqual(new List<string> {"#channel", "hello world"}, line.Params);
91
}
92
93
[TestMethod]
94
public void TestParamsOnlyTrailing()
95
{
96
var line = new Line("PRIVMSG :hello world");
97
-
CollectionAssert.AreEqual(new List<string> {"hello world"}, line.Params);
98
}
99
100
[TestMethod]
···
109
public void TestAllTokens()
110
{
111
var line = new Line("@id=123 :nick!user@host PRIVMSG #channel :hello world");
112
-
CollectionAssert.AreEqual(new Dictionary<string, string> {{"id", "123"}}, line.Tags);
113
Assert.AreEqual("nick!user@host", line.Source);
114
Assert.AreEqual("PRIVMSG", line.Command);
115
-
CollectionAssert.AreEqual(new List<string> {"#channel", "hello world"}, line.Params);
116
}
117
}
118
}
···
1
+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2
+
using System.Collections.Generic;
3
4
namespace IrcTokens.Tests
5
{
6
[TestClass]
7
+
public class Tokenization
8
{
9
[TestMethod]
10
public void TestTagsMissing()
···
87
public void TestParamsTrailing()
88
{
89
var line = new Line("PRIVMSG #channel :hello world");
90
+
CollectionAssert.AreEqual(new List<string> { "#channel", "hello world" }, line.Params);
91
}
92
93
[TestMethod]
94
public void TestParamsOnlyTrailing()
95
{
96
var line = new Line("PRIVMSG :hello world");
97
+
CollectionAssert.AreEqual(new List<string> { "hello world" }, line.Params);
98
}
99
100
[TestMethod]
···
109
public void TestAllTokens()
110
{
111
var line = new Line("@id=123 :nick!user@host PRIVMSG #channel :hello world");
112
+
CollectionAssert.AreEqual(new Dictionary<string, string> { { "id", "123" } }, line.Tags);
113
Assert.AreEqual("nick!user@host", line.Source);
114
Assert.AreEqual("PRIVMSG", line.Command);
115
+
CollectionAssert.AreEqual(new List<string> { "#channel", "hello world" }, line.Params);
116
}
117
}
118
}
+10
-9
Sample/Client.cs
···
1
-
using System;
0
2
using System.Collections.Generic;
3
using System.Net.Sockets;
4
-
using System.Text;
5
-
using IrcTokens;
6
7
-
namespace Sample
8
{
9
public class Client
10
{
···
25
{
26
_socket.Connect("127.0.0.1", 6667);
27
28
-
Send(new Line {Command = "USER", Params = new List<string> {"username", "0", "*", "real name"}});
29
-
Send(new Line {Command = "NICK", Params = new List<string> {"statefulbot"}});
30
31
while (true)
32
{
33
var bytesReceived = _socket.Receive(_bytes);
34
var lines = _decoder.Push(_bytes);
35
36
-
if (lines.Count == 0)
37
{
38
Console.WriteLine("! disconnected");
39
_socket.Shutdown(SocketShutdown.Both);
···
47
switch (line.Command)
48
{
49
case "PING":
50
-
Send(new Line {Command = "PONG", Params = line.Params});
51
break;
52
case "001":
53
-
Send(new Line {Command = "JOIN", Params = new List<string> {"#channel"}});
54
break;
55
}
56
}
···
62
Console.WriteLine($"> {line.Format()}");
63
_encoder.Push(line);
64
while (_encoder.PendingBytes.Length > 0)
0
65
_encoder.Pop(_socket.Send(_encoder.PendingBytes));
0
66
}
67
}
68
}
···
1
+
using IrcTokens;
2
+
using System;
3
using System.Collections.Generic;
4
using System.Net.Sockets;
0
0
5
6
+
namespace TokensSample
7
{
8
public class Client
9
{
···
24
{
25
_socket.Connect("127.0.0.1", 6667);
26
27
+
Send(new Line { Command = "USER", Params = new List<string> { "username", "0", "*", "real name" } });
28
+
Send(new Line { Command = "NICK", Params = new List<string> { "tokensbot" } });
29
30
while (true)
31
{
32
var bytesReceived = _socket.Receive(_bytes);
33
var lines = _decoder.Push(_bytes);
34
35
+
if (bytesReceived == 0)
36
{
37
Console.WriteLine("! disconnected");
38
_socket.Shutdown(SocketShutdown.Both);
···
46
switch (line.Command)
47
{
48
case "PING":
49
+
Send(new Line { Command = "PONG", Params = line.Params });
50
break;
51
case "001":
52
+
Send(new Line { Command = "JOIN", Params = new List<string> { "#channel" } });
53
break;
54
}
55
}
···
61
Console.WriteLine($"> {line.Format()}");
62
_encoder.Push(line);
63
while (_encoder.PendingBytes.Length > 0)
64
+
{
65
_encoder.Pop(_socket.Send(_encoder.PendingBytes));
66
+
}
67
}
68
}
69
}
+4
-4
Sample/Program.cs
···
1
-
using System;
0
2
using System.Collections.Generic;
3
-
using IrcTokens;
4
5
-
namespace Sample
6
{
7
public class Program
8
{
···
17
var line2 = new Line
18
{
19
Command = "USER",
20
-
Params = new List<string> {"user", "0", "*", "real name"}
21
};
22
Console.WriteLine(line2);
23
Console.WriteLine(line2.Format());
···
1
+
using IrcTokens;
2
+
using System;
3
using System.Collections.Generic;
0
4
5
+
namespace TokensSample
6
{
7
public class Program
8
{
···
17
var line2 = new Line
18
{
19
Command = "USER",
20
+
Params = new List<string> { "user", "0", "*", "real name" }
21
};
22
Console.WriteLine(line2);
23
Console.WriteLine(line2.Format());
Sample/Sample.csproj
Sample/TokensSample.csproj
+12
StatesSample/Program.cs
···
0
0
0
0
0
0
0
0
0
0
0
0
···
1
+
using System;
2
+
3
+
namespace StatesSample
4
+
{
5
+
public static class Program
6
+
{
7
+
private static void Main(string[] args)
8
+
{
9
+
Console.WriteLine("Hello World!");
10
+
}
11
+
}
12
+
}
+12
StatesSample/StatesSample.csproj
···
0
0
0
0
0
0
0
0
0
0
0
0
···
1
+
<Project Sdk="Microsoft.NET.Sdk">
2
+
3
+
<PropertyGroup>
4
+
<OutputType>Exe</OutputType>
5
+
<TargetFramework>netcoreapp3.1</TargetFramework>
6
+
</PropertyGroup>
7
+
8
+
<ItemGroup>
9
+
<ProjectReference Include="..\IrcStates\IrcStates.csproj" />
10
+
</ItemGroup>
11
+
12
+
</Project>