-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: read CSV and map it to an strongly typed object (#43)
* feat: read CSV and map it to an strongly typed object * ci: include download of SDK 9.0
- Loading branch information
Showing
19 changed files
with
2,376 additions
and
240 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,75 +1,75 @@ | ||
<Project> | ||
<PropertyGroup> | ||
<!-- By default every projects are packable except Testing, Benchmark, Profiler projects--> | ||
<IsPackable>true</IsPackable> | ||
<IsPackable Condition="$(MSBuildProjectName.EndsWith('Testing'))">false</IsPackable> | ||
<IsPackable Condition="$(MSBuildProjectName.EndsWith('Benchmark'))">false</IsPackable> | ||
<IsPackable Condition="$(MSBuildProjectName.EndsWith('Profiler'))">false</IsPackable> | ||
<DebugType>portable</DebugType> | ||
</PropertyGroup> | ||
<PropertyGroup> | ||
<!-- By default every projects are packable except Testing, Benchmark, Profiler projects--> | ||
<IsPackable>true</IsPackable> | ||
<IsPackable Condition="$(MSBuildProjectName.EndsWith('Testing'))">false</IsPackable> | ||
<IsPackable Condition="$(MSBuildProjectName.EndsWith('Benchmark'))">false</IsPackable> | ||
<IsPackable Condition="$(MSBuildProjectName.EndsWith('Profiler'))">false</IsPackable> | ||
<DebugType>portable</DebugType> | ||
</PropertyGroup> | ||
|
||
<PropertyGroup> | ||
<TargetFrameworks>net6.0;net7.0;net8.0</TargetFrameworks> | ||
<Platform>AnyCPU</Platform> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
<LangVersion>12.0</LangVersion> | ||
</PropertyGroup> | ||
<PropertyGroup> | ||
<TargetFrameworks>net8.0;net9.0</TargetFrameworks> | ||
<Platform>AnyCPU</Platform> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
<LangVersion>13.0</LangVersion> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="DotNet.ReproducibleBuilds" Version="1.1.1"> | ||
<PrivateAssets>all</PrivateAssets> | ||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> | ||
</PackageReference> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<PackageReference Include="DotNet.ReproducibleBuilds" Version="1.1.1"> | ||
<PrivateAssets>all</PrivateAssets> | ||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> | ||
</PackageReference> | ||
</ItemGroup> | ||
|
||
|
||
<PropertyGroup> | ||
<RestoreProjectStyle>PackageReference</RestoreProjectStyle> | ||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> | ||
</PropertyGroup> | ||
|
||
<PropertyGroup> | ||
<Version>0.0.0</Version> | ||
<Authors>Cédric L. Charlier</Authors> | ||
<Owners>Seddryck</Owners> | ||
<Company>nbiguity</Company> | ||
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression> | ||
<PackageProjectUrl>https://github.com/Seddrycl/PocketCsvReader</PackageProjectUrl> | ||
<RepositoryType>git</RepositoryType> | ||
<RequireLicenseAcceptance>false</RequireLicenseAcceptance> | ||
<PackageIcon>icon\pocket-csv-reader.png</PackageIcon> | ||
<SymbolPackageFormat Condition=" '$(DebugType)' != 'embedded' ">snupkg</SymbolPackageFormat> | ||
<PackageReadmeFile>README.md</PackageReadmeFile> | ||
</PropertyGroup> | ||
<PropertyGroup> | ||
<Version>0.0.0</Version> | ||
<Authors>Cédric L. Charlier</Authors> | ||
<Owners>Seddryck</Owners> | ||
<Company>nbiguity</Company> | ||
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression> | ||
<PackageProjectUrl>https://github.com/Seddrycl/PocketCsvReader</PackageProjectUrl> | ||
<RepositoryType>git</RepositoryType> | ||
<RequireLicenseAcceptance>false</RequireLicenseAcceptance> | ||
<PackageIcon>icon\pocket-csv-reader.png</PackageIcon> | ||
<SymbolPackageFormat Condition=" '$(DebugType)' != 'embedded' ">snupkg</SymbolPackageFormat> | ||
<PackageReadmeFile>README.md</PackageReadmeFile> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<None Include="..\pocket-csv-reader.png" Pack="true" PackagePath="icon\" /> | ||
<None Include="..\README.md" Pack="true" PackagePath="\" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<None Include="..\pocket-csv-reader.png" Pack="true" PackagePath="icon\" /> | ||
<None Include="..\README.md" Pack="true" PackagePath="\" /> | ||
</ItemGroup> | ||
|
||
<PropertyGroup> | ||
<GenerateAssemblyInfo>true</GenerateAssemblyInfo> | ||
</PropertyGroup> | ||
|
||
<PropertyGroup> | ||
<!-- disable warning when XML comments are missing --> | ||
<NoWarn>$(NoWarn);CS1591</NoWarn> | ||
</PropertyGroup> | ||
|
||
<PropertyGroup Condition="'$(Configuration)'=='Release' AND $(IsPackable) == true"> | ||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> | ||
<Deterministic>true</Deterministic> | ||
</PropertyGroup> | ||
<PropertyGroup> | ||
<!-- disable warning when XML comments are missing --> | ||
<NoWarn>$(NoWarn);CS1591</NoWarn> | ||
</PropertyGroup> | ||
|
||
<PropertyGroup Condition="'$(Configuration)'=='Release' AND $(IsPackable) == true"> | ||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> | ||
<Deterministic>true</Deterministic> | ||
</PropertyGroup> | ||
|
||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net6.0|AnyCPU'"> | ||
<WarningLevel>5</WarningLevel> | ||
<LangVersion>preview</LangVersion> | ||
</PropertyGroup> | ||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net6.0|AnyCPU'"> | ||
<WarningLevel>5</WarningLevel> | ||
<LangVersion>preview</LangVersion> | ||
</PropertyGroup> | ||
|
||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net6.0|AnyCPU'"> | ||
<WarningLevel>5</WarningLevel> | ||
<LangVersion>preview</LangVersion> | ||
</PropertyGroup> | ||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net6.0|AnyCPU'"> | ||
<WarningLevel>5</WarningLevel> | ||
<LangVersion>preview</LangVersion> | ||
</PropertyGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
using PocketCsvReader; | ||
using NUnit.Framework; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Data; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Reflection; | ||
using System.Security.Cryptography; | ||
using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces; | ||
|
||
namespace PocketCsvReader.Testing; | ||
|
||
[TestFixture] | ||
public class CsvObjectReaderTest | ||
{ | ||
private static MemoryStream CreateStream(string content) | ||
{ | ||
byte[] byteArray = Encoding.UTF8.GetBytes(content); | ||
MemoryStream stream = new MemoryStream(byteArray); | ||
stream.Position = 0; | ||
return stream; | ||
} | ||
|
||
private record struct Human(string Name, bool IsAdult); | ||
[Test] | ||
public void GetString_SingleFieldAttemptForSecond_Throws() | ||
{ | ||
var spanMapper = new SpanMapper<Human>((span, fieldSpans) => | ||
{ | ||
return new Human( | ||
span.Slice(fieldSpans.First().Start, fieldSpans.First().Length).ToString(), | ||
int.Parse(span.Slice(fieldSpans.Last().Start, fieldSpans.Last().Length).ToString()) > 18); | ||
}); | ||
|
||
var profile = new CsvProfile(',', '\"', "\r\n", false); | ||
using var stream = CreateStream("foo,16\r\nbar,21"); | ||
using var dataReader = new CsvObjectReader<Human>(stream, profile, spanMapper); | ||
|
||
var humans = dataReader.Read().ToArray(); | ||
Assert.That(humans, Has.Length.EqualTo(2)); | ||
Assert.That(humans[0].Name, Is.EqualTo("foo")); | ||
Assert.That(humans[0].IsAdult, Is.False); | ||
Assert.That(humans[1].Name, Is.EqualTo("bar")); | ||
Assert.That(humans[1].IsAdult, Is.True); | ||
} | ||
|
||
private record struct Financial( | ||
int Year, int Month, int Day, DateTime DateTime, | ||
string ResolutionCode, string Status, string AreaCode, string AreaTypeCode, string AreaName, string MapCode, | ||
decimal Expenses, decimal Income, string Currency, DateTime UpdateTime); | ||
[Test] | ||
[TestCase("Ansi")] | ||
[TestCase("Utf16-BE")] | ||
[TestCase("Utf16-LE")] | ||
[TestCase("Utf8-BOM")] | ||
[TestCase("Utf8")] | ||
public void Read_FinancialWithCompleteParsers_CorrectRowsColumns(string filename) | ||
{ | ||
var profile = new CsvProfile('\t', '\"', "\r\n", true); | ||
|
||
using (var stream = | ||
Assembly.GetExecutingAssembly() | ||
.GetManifestResourceStream($"{Assembly.GetExecutingAssembly().GetName().Name}.Resources.{filename}.csv") | ||
?? throw new FileNotFoundException() | ||
) | ||
{ | ||
var spanMapper = new SpanMapper<Financial>((span, fieldSpans) => | ||
{ | ||
return new Financial( | ||
int.Parse(span.Slice(fieldSpans.ElementAt(0).Start, fieldSpans.ElementAt(0).Length)), | ||
int.Parse(span.Slice(fieldSpans.ElementAt(1).Start, fieldSpans.ElementAt(1).Length)), | ||
int.Parse(span.Slice(fieldSpans.ElementAt(2).Start, fieldSpans.ElementAt(2).Length)), | ||
DateTime.Parse(span.Slice(fieldSpans.ElementAt(3).Start, fieldSpans.ElementAt(3).Length)), | ||
span.Slice(fieldSpans.ElementAt(4).Start, fieldSpans.ElementAt(4).Length).ToString(), | ||
span.Slice(fieldSpans.ElementAt(5).Start, fieldSpans.ElementAt(5).Length).ToString(), | ||
span.Slice(fieldSpans.ElementAt(6).Start, fieldSpans.ElementAt(6).Length).ToString(), | ||
span.Slice(fieldSpans.ElementAt(7).Start, fieldSpans.ElementAt(7).Length).ToString(), | ||
span.Slice(fieldSpans.ElementAt(8).Start, fieldSpans.ElementAt(8).Length).ToString(), | ||
span.Slice(fieldSpans.ElementAt(9).Start, fieldSpans.ElementAt(9).Length).ToString(), | ||
decimal.Parse(span.Slice(fieldSpans.ElementAt(10).Start, fieldSpans.ElementAt(10).Length)), | ||
decimal.Parse(span.Slice(fieldSpans.ElementAt(11).Start, fieldSpans.ElementAt(11).Length)), | ||
span.Slice(fieldSpans.ElementAt(12).Start, fieldSpans.ElementAt(12).Length).ToString(), | ||
DateTime.Parse(span.Slice(fieldSpans.ElementAt(13).Start, fieldSpans.ElementAt(13).Length))); | ||
}); | ||
var rowCount = 0; | ||
using var dataReader = new CsvObjectReader<Financial>(stream, profile, spanMapper); | ||
foreach(var human in dataReader.Read()) | ||
{ Console.WriteLine($"{rowCount++}: {human.AreaCode}"); } | ||
Assert.That(rowCount, Is.EqualTo(21)); | ||
} | ||
} | ||
|
||
[Test] | ||
[TestCase("Ansi")] | ||
[TestCase("Utf16-BE")] | ||
[TestCase("Utf16-LE")] | ||
[TestCase("Utf8-BOM")] | ||
[TestCase("Utf8")] | ||
public void Read_FinancialWithSpanObjectBuilder_CorrectRowsColumns(string filename) | ||
{ | ||
var profile = new CsvProfile('\t', '\"', "\r\n", true); | ||
|
||
using (var stream = | ||
Assembly.GetExecutingAssembly() | ||
.GetManifestResourceStream($"{Assembly.GetExecutingAssembly().GetName().Name}.Resources.{filename}.csv") | ||
?? throw new FileNotFoundException() | ||
) | ||
{ | ||
var objBuilder = new SpanObjectBuilder<Financial>(); | ||
var spanMapper = new SpanMapper<Financial>(objBuilder.Instantiate); | ||
var rowCount = 0; | ||
using var dataReader = new CsvObjectReader<Financial>(stream, profile, spanMapper); | ||
foreach (var human in dataReader.Read()) | ||
{ rowCount++; } | ||
Assert.That(rowCount, Is.EqualTo(21)); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.