Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SepWriter: Add async support (C# 13+ only) #224

Merged
merged 12 commits into from
Jan 21, 2025
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
Loading