Skip to content

Commit

Permalink
feat: improve handling of custom types (#103)
Browse files Browse the repository at this point in the history
  • Loading branch information
Seddryck authored Feb 2, 2025
1 parent 0a4af2b commit f88a48a
Show file tree
Hide file tree
Showing 10 changed files with 193 additions and 424 deletions.
13 changes: 7 additions & 6 deletions PocketCsvReader.Testing/CsvDataReaderTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -653,18 +653,19 @@ public void Read_WithSchemaParsableTypes_CorrectParsing(string record)
.WithSchema(
(schema) => schema
.Named()
.WithCustomField<YearMonth>("foo", (f) => f.WithFormat(new DateTimeFormatInfo() { YearMonthPattern = "yyyy-MM" }))
.WithCustomField<YearQuarter>("bar", (f) => f.WithFormat(new YearQuarterFormatProvider() { YearQuarterPattern="Qq.yy" }))
.WithCustomField<Chrononuensis.YearMonth>("foo", (f) => f.WithFormat("yyyy-MM"))
.WithCustomField<Chrononuensis.YearQuarter>("bar", (f) => f.WithFormat("'Q'q.yy"))
);
using var dataReader = builder.Build().ToDataReader(buffer);
dataReader.Read();
Assert.That(dataReader.FieldCount, Is.EqualTo(2));
Assert.That(dataReader.GetName(0), Is.EqualTo("foo"));
Assert.That(dataReader.GetName(1), Is.EqualTo("bar"));
Assert.That(dataReader.GetFieldType(0), Is.EqualTo(typeof(YearMonth)));
Assert.That(dataReader.GetFieldType(1), Is.EqualTo(typeof(YearQuarter)));
Assert.That(dataReader.GetValue(0), Is.EqualTo(new YearMonth(2025,2)));
Assert.That(dataReader.GetValue(1), Is.EqualTo(new YearQuarter(2025, 1)));
Assert.That(dataReader.GetFieldType(0), Is.EqualTo(typeof(Chrononuensis.YearMonth)));
Assert.That(dataReader.GetFieldType(1), Is.EqualTo(typeof(Chrononuensis.YearQuarter)));
Assert.That(dataReader.GetValue(0), Is.EqualTo(new Chrononuensis.YearMonth(2025,2)));
Assert.That(dataReader.GetValue(1), Is.EqualTo(new Chrononuensis.YearQuarter(2025, 1)));

}


Expand Down
154 changes: 23 additions & 131 deletions PocketCsvReader.Testing/CsvDataRecordTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,45 +5,36 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Chrononuensis;
using Chrononuensis.Parsers;
using NUnit.Framework;
using PocketCsvReader.Configuration;

namespace PocketCsvReader.Testing;
public class CsvDataRecordTests
{
[Test]
[TestCase("yyyy-MM", "2025-01")]
[TestCase("yyyy-M", "2025-1")]
[TestCase("yyyy.MM", "2025.01")]
[TestCase("MM.yyyy", "01.2025")]
public void GetFieldValue_Parsable_Correct(string format, string input)
[TestCase("en-us", "2025-12-26")]
[TestCase("fr-fr", "26/12/2025")]
[TestCase("de-de", "26.12.2025")]
public void GetFieldValue_Parsable_Correct(string c, string input)
{
var culture = new CultureInfo("en-US");
culture.DateTimeFormat.YearMonthPattern = format;
var culture = new CultureInfo(c);

var record = new CsvDataRecord(new RecordMemory(input, [new FieldSpan(0, input.Length)]));
var value = record.GetFieldValue<YearMonth>(0, culture);
Assert.That(value, Is.EqualTo(new YearMonth(2025, 1)));
var value = record.GetFieldValue<DateTime>(0, culture);
Assert.That(value, Is.EqualTo(new DateTime(2025, 12, 26)));
}

[Test]
[TestCase("yyyy-MM", "2025-01")]
[TestCase("yyyy-M", "2025-1")]
[TestCase("yyyy.MM", "2025.01")]
[TestCase("MM.yyyy", "01.2025")]
public void GetFieldValue_NotParsable_Correct(string format, string input)
public void GetFieldValue_WithFormat_Correct(string format, string input)
{
var culture = new CultureInfo("en-US");
culture.DateTimeFormat.YearMonthPattern = format;

BaseYearMonth parse(string input)
{
(int year, int month) = new YearMonthParser().Parse(input, culture);
return new BaseYearMonth(year, month);
}

var record = new CsvDataRecord(new RecordMemory(input, [new FieldSpan(0, input.Length)]));
var value = record.GetFieldValue(0, parse);
var value = record.GetFieldValue<YearMonth>(0, format, CultureInfo.InvariantCulture);
Assert.That(value, Is.EqualTo(new YearMonth(2025, 1)));
}

Expand All @@ -52,23 +43,18 @@ BaseYearMonth parse(string input)
[TestCase("yyyy-M", "2025-1")]
[TestCase("yyyy.MM", "2025.01")]
[TestCase("MM.yyyy", "01.2025")]
public void GetValue_RegisteredGlobally_Parsable_Correct(string format, string input)
public void GetFieldValue_WithCustomFunction_Correct(string format, string input)
{
var profile = new CsvProfile(
new DialectDescriptorBuilder().Build()
, new SchemaDescriptorBuilder().Indexed().WithTemporalField<YearMonth>(f => f.WithFormat(format)).Build()
);
var culture = new CultureInfo("en-US");

IFormatProvider? getFormat(FieldDescriptor? field)
YearMonth parse(string input)
{
var customCulture = (CultureInfo)CultureInfo.InvariantCulture.Clone();
customCulture.DateTimeFormat.YearMonthPattern = format;
return customCulture;
};
(int year, int month) = new YearMonthParser().Parse(input, format, culture);
return new YearMonth(year, month);
}

var record = new CsvDataRecord(new RecordMemory(input, [new FieldSpan(0, input.Length)]), profile);
record.Register<YearMonth>(getFormat);
var value = record.GetValue(0);
var record = new CsvDataRecord(new RecordMemory(input, [new FieldSpan(0, input.Length)]));
var value = record.GetFieldValue(0, parse);
Assert.That(value, Is.EqualTo(new YearMonth(2025, 1)));
}

Expand All @@ -82,114 +68,20 @@ public void GetValue_RegisteredGlobally_NotParsable_Correct(string format, strin
var culture = new CultureInfo("en-US");
culture.DateTimeFormat.YearMonthPattern = format;

BaseYearMonth parse(string input)
YearMonth parse(string input)
{
(int year, int month) = new YearMonthParser().Parse(input, culture);
return new BaseYearMonth(year, month);
(int year, int month) = new YearMonthParser().Parse(input, format, culture);
return new YearMonth(year, month);
}

var profile = new CsvProfile(
new DialectDescriptorBuilder().Build()
, new SchemaDescriptorBuilder().Indexed().WithField<BaseYearMonth>().Build()
, new SchemaDescriptorBuilder().Indexed().WithField<YearMonth>().Build()
);

var record = new CsvDataRecord(new RecordMemory(input, [new FieldSpan(0, input.Length)]), profile);
record.Register(parse);
var value = record.GetValue(0);
Assert.That(value, Is.EqualTo(new YearMonth(2025, 1)));
}

[Test]
[TestCase("yyyy-Qq", "2025-Q1")]
[TestCase("yyyyQq", "2025Q1")]
[TestCase("Qqq.yy", "Q01.25")]
[TestCase("Qq'yy", "Q1'25")]
public void GetFieldValue_CustomFormatProviderParsable_Correct(string format, string input)
{
var provider = new YearQuarterFormatProvider();
provider.YearQuarterPattern = format;

var record = new CsvDataRecord(new RecordMemory(input, [new FieldSpan(0, input.Length)]));
var value = record.GetFieldValue<YearQuarter>(0, provider);
Assert.That(value, Is.EqualTo(new YearQuarter(2025, 1)));
}

[Test]
[TestCase("yyyy-Qq", "2025-Q1")]
[TestCase("yyyyQq", "2025Q1")]
[TestCase("Qqq.yy", "Q01.25")]
[TestCase("Qq'yy", "Q1'25")]
public void GetFieldValue_CustomFormatProviderNotParsable_Correct(string format, string input)
{
var provider = new YearQuarterFormatProvider
{
YearQuarterPattern = format
};

BaseYearQuarter parse(string input)
{
(int year, int month) = new YearQuarterParser().Parse(input, provider);
return new BaseYearQuarter(year, month);
}

var record = new CsvDataRecord(new RecordMemory(input, [new FieldSpan(0, input.Length)]));
var value = record.GetFieldValue(0, parse);
Assert.That(value, Is.EqualTo(new YearQuarter(2025, 1)));
}

[Test]
[TestCase("yyyy-Qq", "2025-Q1")]
[TestCase("yyyyQq", "2025Q1")]
[TestCase("Qqq.yy", "Q01.25")]
[TestCase("Qq'yy", "Q1'25")]
public void GetValue_CustomFormatProviderRegisteredLocally_Parsable_Correct(string format, string input)
{
var profile = new CsvProfile(
new DialectDescriptorBuilder().Build()
, new SchemaDescriptorBuilder().Indexed().WithTemporalField<YearQuarter>(f => f.WithFormat(format)).Build()
);

IFormatProvider? getFormat(FieldDescriptor? field)
{
var provider = new YearQuarterFormatProvider
{
YearQuarterPattern = (field?.Format as TemporalFormatDescriptor)?.Pattern ?? "yyyy-Qq"
};
return provider;
};

var record = new CsvDataRecord(new RecordMemory(input, [new FieldSpan(0, input.Length)]), profile);
record.Register<YearQuarter>(getFormat);
var value = record.GetValue(0);
Assert.That(value, Is.EqualTo(new YearQuarter(2025, 1)));
}

[Test]
[TestCase("yyyy-Qq", "2025-Q1")]
[TestCase("yyyyQq", "2025Q1")]
[TestCase("Qqq.yy", "Q01.25")]
[TestCase("Qq'yy", "Q1'25")]
public void GetValue_CustomFormatProviderRegisteredGlobally_Parsable_Correct(string format, string input)
{
var provider = new YearQuarterFormatProvider
{
YearQuarterPattern = format
};

BaseYearQuarter parse(string input)
{
(int year, int quarter) = new YearQuarterParser().Parse(input, provider);
return new BaseYearQuarter(year, quarter);
}

var profile = new CsvProfile(
new DialectDescriptorBuilder().Build()
, new SchemaDescriptorBuilder().Indexed().WithField<BaseYearQuarter>().Build()
);

var record = new CsvDataRecord(new RecordMemory(input, [new FieldSpan(0, input.Length)]), profile);
record.Register(parse);
var value = record.GetValue(0);
Assert.That(value, Is.EqualTo(new YearQuarter(2025, 1)));
}
}
32 changes: 32 additions & 0 deletions PocketCsvReader.Testing/FieldParsing/TypeParserLocatorTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NUnit.Framework;
using PocketCsvReader.FieldParsing;

namespace PocketCsvReader.Testing.FieldParsing;
public class TypeParserLocatorTest
{
[Test]
[TestCase("Q1.25", "'Q'q.yy")]
public void Locate_YearQuarterTwoParameters_FindIt(string input, string format)
{
var locator = new TypeParserLocator<Chrononuensis.YearQuarter>();
var func = locator.Locate([format, CultureInfo.InvariantCulture]);
var value = func.Invoke(input);
Assert.That(value, Is.EqualTo(new Chrononuensis.YearQuarter(2025, 1)));
}

[Test]
[TestCase("2025-Q1")]
public void Locate_YearQuarterSingleParameter_FindIt(string input)
{
var locator = new TypeParserLocator<Chrononuensis.YearQuarter>();
var func = locator.Locate([CultureInfo.InvariantCulture]);
var value = func.Invoke(input);
Assert.That(value, Is.EqualTo(new Chrononuensis.YearQuarter(2025, 1)));
}
}
1 change: 1 addition & 0 deletions PocketCsvReader.Testing/PocketCsvReader.Testing.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<EmbeddedResource Include="Resources\Utf8.csv" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Chrononuensis" Version="0.13.0" />
<PackageReference Include="CommunityToolkit.HighPerformance" Version="8.4.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="NUnit" Version="4.3.2" />
Expand Down
Loading

0 comments on commit f88a48a

Please sign in to comment.