using AvParser.Core.Parsing.Samples; namespace AvParser.Core.Tests; public class KeyValueTextParserTests { private readonly KeyValueTextParser _parser = new(); [Theory] [InlineData("host = localhost")] [InlineData("host: localhost")] public async Task Accepts_both_separators(string input) { var (records, errors) = await _parser.CollectAsync(input); errors.ShouldBeEmpty(); var record = records.ShouldHaveSingleItem(); record.Field("Key").ShouldBe("host"); record.Field("Value").ShouldBe("localhost"); } [Fact] public async Task Splits_on_the_first_separator_only() { var (records, _) = await _parser.CollectAsync("url = https://example.com:8080/path"); records.ShouldHaveSingleItem().Field("Value").ShouldBe("https://example.com:8080/path"); } [Fact] public async Task Reports_lines_without_a_separator() { var (records, errors) = await _parser.CollectAsync("host = localhost\ngarbage\nport = 80"); records.Count.ShouldBe(2); errors.ShouldHaveSingleItem().LineNumber.ShouldBe(2); } [Fact] public async Task Reports_an_empty_key() { var (_, errors) = await _parser.CollectAsync("= orphan"); errors.ShouldHaveSingleItem().Message.ShouldContain("separator"); } [Fact] public async Task Skips_comments_and_blank_lines() { var (records, errors) = await _parser.CollectAsync("# comment\n\nhost = localhost\n"); errors.ShouldBeEmpty(); records.ShouldHaveSingleItem().Field("Key").ShouldBe("host"); } [Fact] public async Task Allows_an_empty_value() { var (records, errors) = await _parser.CollectAsync("host ="); errors.ShouldBeEmpty(); records.ShouldHaveSingleItem().Field("Value").ShouldBe(string.Empty); } }