Skip to content

Commit

Permalink
SepWriter: Add async support (C# 13+ only) (#224)
Browse files Browse the repository at this point in the history
  • Loading branch information
nietras authored Jan 21, 2025
1 parent f92b65b commit e675124
Show file tree
Hide file tree
Showing 14 changed files with 1,058 additions and 407 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2105,19 +2105,21 @@ namespace nietras.SeparatedValues
AfterUnescape = 2,
All = 3,
}
public sealed class SepWriter : System.IDisposable
public sealed class SepWriter : System.IAsyncDisposable, System.IDisposable
{
public nietras.SeparatedValues.SepWriterHeader Header { get; }
public nietras.SeparatedValues.SepSpec Spec { get; }
public void Dispose() { }
public System.Threading.Tasks.ValueTask DisposeAsync() { }
public void Flush() { }
public System.Threading.Tasks.Task FlushAsync(System.Threading.CancellationToken cancellationToken = default) { }
public nietras.SeparatedValues.SepWriter.Row NewRow() { }
public override string ToString() { }
[System.Obsolete(("Types with embedded references are not supported in this version of your compiler" +
"."), true)]
[System.Runtime.CompilerServices.CompilerFeatureRequired("RefStructs")]
[System.Runtime.CompilerServices.IsByRefLike]
public struct Row : System.IDisposable
public struct Row : System.IAsyncDisposable, System.IDisposable
{
public nietras.SeparatedValues.SepWriter.Col this[int colIndex] { get; }
public nietras.SeparatedValues.SepWriter.Col this[string colName] { get; }
Expand All @@ -2126,6 +2128,7 @@ namespace nietras.SeparatedValues
public nietras.SeparatedValues.SepWriter.Cols this[System.Collections.Generic.IReadOnlyList<string> colNames] { get; }
public nietras.SeparatedValues.SepWriter.Cols this[string[] colNames] { get; }
public void Dispose() { }
public System.Threading.Tasks.ValueTask DisposeAsync() { }
}
[System.Obsolete(("Types with embedded references are not supported in this version of your compiler" +
"."), true)]
Expand Down Expand Up @@ -2210,6 +2213,7 @@ namespace nietras.SeparatedValues
public void Add(string colName) { }
public void Add(string[] colNames) { }
public void Write() { }
public System.Threading.Tasks.ValueTask WriteAsync(System.Threading.CancellationToken cancellationToken = default) { }
}
public readonly struct SepWriterOptions : System.IEquatable<nietras.SeparatedValues.SepWriterOptions>
{
Expand Down
140 changes: 87 additions & 53 deletions src/Sep.Test/SepWriterColTest.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Globalization;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace nietras.SeparatedValues.Test;
Expand All @@ -15,132 +16,132 @@ public class SepWriterColTest
static readonly string NL = Environment.NewLine;

[TestMethod]
public void SepWriterColTest_ColIndex()
public async ValueTask SepWriterColTest_ColIndex()
{
Run(col => Assert.AreEqual(0, col.ColIndex), null);
await Run(col => Assert.AreEqual(0, col.ColIndex), null);
}

[TestMethod]
public void SepWriterColTest_ColName()
public async ValueTask SepWriterColTest_ColName()
{
Run(col => Assert.AreEqual(ColName, col.ColName), null);
await Run(col => Assert.AreEqual(ColName, col.ColName), null);
}

[TestMethod]
public void SepWriterColTest_Set_String()
public async ValueTask SepWriterColTest_Set_String()
{
Run(col => col.Set(ColText));
await Run(col => col.Set(ColText));
}

[TestMethod]
public void SepWriterColTest_Set_String_Long()
public async ValueTask SepWriterColTest_Set_String_Long()
{
Run(col => col.Set(ColTextLong), ColTextLong);
await Run(col => col.Set(ColTextLong), ColTextLong);
}

[TestMethod]
public void SepWriterColTest_Set_Span()
public async ValueTask SepWriterColTest_Set_Span()
{
Run(col => col.Set(ColText.AsSpan()));
await Run(col => col.Set(ColText.AsSpan()));
}

[TestMethod]
public void SepWriterColTest_Set_Span_Long()
public async ValueTask SepWriterColTest_Set_Span_Long()
{
Run(col => col.Set(ColTextLong.AsSpan()), ColTextLong);
await Run(col => col.Set(ColTextLong.AsSpan()), ColTextLong);
}

[TestMethod]
public void SepWriterColTest_Set_InterpolatedString()
public async ValueTask SepWriterColTest_Set_InterpolatedString()
{
Run(col => col.Set($"{ColValue}"));
await Run(col => col.Set($"{ColValue}"));
}

[TestMethod]
public void SepWriterColTest_Set_InterpolatedString_F2()
public async ValueTask SepWriterColTest_Set_InterpolatedString_F2()
{
Run(col => col.Set($"{ColValue:F2}"), ColText + ".00");
await Run(col => col.Set($"{ColValue:F2}"), ColText + ".00");
}

[TestMethod]
public void SepWriterColTest_Set_InterpolatedString_F2_CultureInfoAsConfig()
public async ValueTask SepWriterColTest_Set_InterpolatedString_F2_CultureInfoAsConfig()
{
Run(col => col.Set($"{ColValue:F2}"), ColText + ",00", CultureInfo.GetCultureInfo("da-DK"));
await Run(col => col.Set($"{ColValue:F2}"), ColText + ",00", CultureInfo.GetCultureInfo("da-DK"));
}

[TestMethod]
public void SepWriterColTest_Set_InterpolatedString_F2_CultureInfoAsParam()
public async ValueTask SepWriterColTest_Set_InterpolatedString_F2_CultureInfoAsParam()
{
Run(col => col.Set(CultureInfo.GetCultureInfo("da-DK"), $"{ColValue:F2}"), ColText + ",00");
await Run(col => col.Set(CultureInfo.GetCultureInfo("da-DK"), $"{ColValue:F2}"), ColText + ",00");
}

[TestMethod]
public void SepWriterColTest_Set_InterpolatedString_F2_CultureInfoAsConfig_Null()
public async ValueTask SepWriterColTest_Set_InterpolatedString_F2_CultureInfoAsConfig_Null()
{
Run(col => col.Set($"{ColValue:F2}"), ColText + ".00", null);
await Run(col => col.Set($"{ColValue:F2}"), ColText + ".00", null);
}

[TestMethod]
public void SepWriterColTest_Set_InterpolatedString_F2_CultureInfoAsParam_Null()
public async ValueTask SepWriterColTest_Set_InterpolatedString_F2_CultureInfoAsParam_Null()
{
Run(col => col.Set(provider: null, $"{ColValue:F2}"), ColText + ".00");
await Run(col => col.Set(provider: null, $"{ColValue:F2}"), ColText + ".00");
}

[TestMethod]
public void SepWriterColTest_Set_InterpolatedString_AppendLiteral()
public async ValueTask SepWriterColTest_Set_InterpolatedString_AppendLiteral()
{
Run(col => col.Set($"{ColValue} {"Literal"}"), ColText + " Literal");
await Run(col => col.Set($"{ColValue} {"Literal"}"), ColText + " Literal");
}

[TestMethod]
public void SepWriterColTest_Set_InterpolatedString_AppendFormatted_Format_Alignment()
public async ValueTask SepWriterColTest_Set_InterpolatedString_AppendFormatted_Format_Alignment()
{
Run(col => col.Set($"{ColValue,16:F2}"), new string(' ', 16 - ColText.Length - 3) + ColText + ".00");
await Run(col => col.Set($"{ColValue,16:F2}"), new string(' ', 16 - ColText.Length - 3) + ColText + ".00");
}

[TestMethod]
public void SepWriterColTest_Set_InterpolatedString_AppendFormatted_Alignment()
public async ValueTask SepWriterColTest_Set_InterpolatedString_AppendFormatted_Alignment()
{
Run(col => col.Set($"{ColValue,16}"), new string(' ', 16 - ColText.Length) + ColText);
await Run(col => col.Set($"{ColValue,16}"), new string(' ', 16 - ColText.Length) + ColText);
}

[TestMethod]
public void SepWriterColTest_Set_InterpolatedString_AppendFormatted_Span()
public async ValueTask SepWriterColTest_Set_InterpolatedString_AppendFormatted_Span()
{
Run(col => col.Set($"{ColText.AsSpan()}"), ColText);
await Run(col => col.Set($"{ColText.AsSpan()}"), ColText);
}

[TestMethod]
public void SepWriterColTest_Set_InterpolatedString_AppendFormatted_Span_Alignment()
public async ValueTask SepWriterColTest_Set_InterpolatedString_AppendFormatted_Span_Alignment()
{
Run(col => col.Set($"{ColText.AsSpan(),16}"), new string(' ', 16 - ColText.Length) + ColText);
await Run(col => col.Set($"{ColText.AsSpan(),16}"), new string(' ', 16 - ColText.Length) + ColText);
}

[TestMethod]
public void SepWriterColTest_Set_InterpolatedString_AppendFormatted_String_Alignment()
public async ValueTask SepWriterColTest_Set_InterpolatedString_AppendFormatted_String_Alignment()
{
string? nullableString = ColText;
Run(col => col.Set($"{nullableString,16:s}"), new string(' ', 16 - ColText.Length) + ColText);
await Run(col => col.Set($"{nullableString,16:s}"), new string(' ', 16 - ColText.Length) + ColText);
}

[TestMethod]
public void SepWriterColTest_Set_InterpolatedString_AppendFormatted_Object_Alignment()
public async ValueTask SepWriterColTest_Set_InterpolatedString_AppendFormatted_Object_Alignment()
{
object? nullableObject = ColText;
Run(col => col.Set($"{nullableObject,16:s}"), new string(' ', 16 - ColText.Length) + ColText);
await Run(col => col.Set($"{nullableObject,16:s}"), new string(' ', 16 - ColText.Length) + ColText);
}

[TestMethod]
public void SepWriterColTest_Format()
public async ValueTask SepWriterColTest_Format()
{
Run(col => col.Format(ColValue));
await Run(col => col.Format(ColValue));
}

[TestMethod]
public void SepWriterColTest_Format_Long()
public async ValueTask SepWriterColTest_Format_Long()
{
var f = new LongSpanFormattable();
Run(col => col.Format(f), f.Text);
await Run(col => col.Format(f), f.Text);
}

public class LongSpanFormattable : ISpanFormattable
Expand Down Expand Up @@ -169,19 +170,35 @@ public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan
[DataRow("\r\n", "\"\r\n\"")]
[DataRow("a;b\rc\nd\"e", "\"a;b\rc\nd\"\"e\"")]
[DataTestMethod]
public void SepWriterColTest_Escape(string textCol, string expectedCol)
public async ValueTask SepWriterColTest_Escape(string textCol, string expectedCol)
{
using var writer = Sep.Writer(o => o with { Escape = true }).ToText();
{
using var row = writer.NewRow();
// Use both for col name and col value so both tested
row[textCol].Set(textCol);
using var writer = Sep.Writer(o => o with { Escape = true }).ToText();
{
using var row = writer.NewRow();
// Use both for col name and col value so both tested
row[textCol].Set(textCol);
}
Assert(expectedCol, writer);
}
{
await using var writer = Sep.Writer(o => o with { Escape = true }).ToText();
{
await using var row = writer.NewRow();
// Use both for col name and col value so both tested
row[textCol].Set(textCol);
}
Assert(expectedCol, writer);
}

static void Assert(string expectedCol, SepWriter writer)
{
var expected = $"{expectedCol}{NL}{expectedCol}{NL}";
Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AreEqual(expected, writer.ToString());
}
var expected = $"{expectedCol}{NL}{expectedCol}{NL}";
Assert.AreEqual(expected, writer.ToString());
}

static void Run(SepWriter.ColAction action, string? expectedColValue = ColText, CultureInfo? cultureInfo = null)
static async ValueTask Run(SepWriter.ColAction action, string? expectedColValue = ColText, CultureInfo? cultureInfo = null)
{
Func<SepWriter>[] createWriters =
[
Expand All @@ -191,11 +208,28 @@ static void Run(SepWriter.ColAction action, string? expectedColValue = ColText,
];
foreach (var createWriter in createWriters)
{
using var writer = createWriter();
// Sync
{
using var row = writer.NewRow();
action(row[ColName]);
using var writer = createWriter();
{
using var row = writer.NewRow();
action(row[ColName]);
}
AssertCol(expectedColValue, writer);
}
// Async
{
await using var writer = createWriter();
{
await using var row = writer.NewRow();
action(row[ColName]);
}
AssertCol(expectedColValue, writer);
}
}

static void AssertCol(string? expectedColValue, SepWriter writer)
{
if (expectedColValue is not null)
{
var expectedText = $"{ColName}{Environment.NewLine}{expectedColValue}{Environment.NewLine}";
Expand Down
Loading

0 comments on commit e675124

Please sign in to comment.