IRC parsing, tokenization, and state handling in C#
1using YamlDotNet.Serialization;
2using YamlDotNet.Serialization.NamingConventions;
3
4// ReSharper disable CollectionNeverUpdated.Global
5// ReSharper disable ClassNeverInstantiated.Global
6
7namespace IRCSharp.Tests.Tokenization;
8
9public class Parser
10{
11 [Test]
12 [YamlDataGenerator<TestCase>("Tokenization/Data/msg-split.yaml")]
13 [ArgumentDisplayFormatter<TestCase>]
14 public async Task Split(TestCase test)
15 {
16 var atoms = test.Atoms;
17 var line = new Line(test.Input);
18
19 await Assert.That(line.Command).IsEqualTo(atoms.Verb.ToUpperInvariant())
20 .Because($"command failed on: '{test.Input}'");
21
22 await Assert.That(line.Source).IsEqualTo(atoms.Source)
23 .Because($"source failed on: '{test.Input}'");
24
25 await Assert.That(line.Params).IsEquivalentTo(atoms.Params ?? [])
26 .Because($"params failed on: '{test.Input}'");
27
28 if (atoms.Tags is null)
29 {
30 await Assert.That(line.Tags).IsNull()
31 .Because("tags should be null");
32 }
33 else
34 {
35 await Assert.That(line.Tags).IsEquivalentTo(atoms.Tags)
36 .Because($"tags failed on: '{test.Input}'");
37 }
38 }
39
40 [Test]
41 [YamlDataGenerator<TestCase>("Tokenization/Data/msg-join.yaml")]
42 [ArgumentDisplayFormatter<TestCase>]
43 public async Task Join(TestCase test)
44 {
45 var atoms = test.Atoms;
46 var line = new Line { Command = atoms.Verb, Params = atoms.Params, Source = atoms.Source, Tags = atoms.Tags };
47
48 await Assert.That(test.Matches).Contains(line.Format()).Because(test.Description);
49 }
50}
51
52public class YamlDataGeneratorAttribute<T>(string yamlPath) : AsyncDataSourceGeneratorAttribute<T>
53 where T : class
54{
55 private readonly IDeserializer _deserializer = new DeserializerBuilder()
56 .WithNamingConvention(CamelCaseNamingConvention.Instance)
57 .Build();
58
59 protected override async IAsyncEnumerable<Func<Task<T>>> GenerateDataSourcesAsync(
60 DataGeneratorMetadata dataGeneratorMetadata)
61 {
62 foreach (var item in _deserializer.Deserialize<List<T>>(await File.ReadAllTextAsync(yamlPath)))
63 yield return () => Task.FromResult(item);
64 }
65}
66
67public class TestCase : ArgumentDisplayFormatter
68{
69 [YamlMember(Alias = "desc")]
70 public string Description { get; set; }
71 public Atoms Atoms { get; set; }
72 public List<string> Matches { get; set; }
73 public string Input { get; set; }
74 public override bool CanHandle(object value) => value is TestCase;
75 public override string FormatValue(object value)
76 {
77 var testCase = (TestCase)value!;
78 return testCase.Input ?? testCase.Description;
79 }
80}
81
82public class Atoms
83{
84 public Dictionary<string, string> Tags { get; set; }
85 public string Source { get; set; }
86 public string Verb { get; set; }
87 public List<string> Params { get; set; }
88}