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

feat(validation): support multiple delimiters, and return multiple validation errors, and return headers #95

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
9 changes: 4 additions & 5 deletions TinyCsvParser/TinyCsvParser.Benchmark/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TinyCsvParser.Benchmark.Mapper;
using TinyCsvParser.Benchmark.Model;

Expand All @@ -16,7 +14,7 @@ namespace TinyCsvParser.Benchmark
[MemoryDiagnoser]
public class TinyCsvParserBenchmarks
{


[GlobalSetup]
public void SetupBenchmarkData()
Expand All @@ -29,13 +27,13 @@ public void SetupBenchmarkData()

var testFilePath = GetTestFilePath();

using (var fileStream = File.Create(testFilePath))
using (var fileStream = File.Create(testFilePath))
{
using (var streamWriter = new StreamWriter(fileStream, Encoding.ASCII))
{
streamWriter.WriteLine(csvHeader);

for(int i = 0; i < numLinesToGenerate; i++)
for (int i = 0; i < numLinesToGenerate; i++)
{
streamWriter.WriteLine(csvLine);
}
Expand All @@ -52,6 +50,7 @@ public void LocalWeatherRead()
var csvParser = new CsvParser<LocalWeatherData>(csvParserOptions, csvMapper);

float result = csvParser.ReadFromFile(GetTestFilePath(), Encoding.ASCII)
.Items
.Where(x => x.IsValid)
.Select(x => x.Result)
.Average(x => x.DryBulbCelsius);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public CsvMeasurementMapping()
[Test]
public void FloatArraysTest()
{
CsvParserOptions csvParserOptions = new CsvParserOptions(false, ';' );
CsvParserOptions csvParserOptions = new CsvParserOptions(false, ';');
CsvReaderOptions csvReaderOptions = new CsvReaderOptions(new[] { Environment.NewLine });
CsvMeasurementMapping csvMapper = new CsvMeasurementMapping();
CsvParser<Measurement> csvParser = new CsvParser<Measurement>(csvParserOptions, csvMapper);
Expand All @@ -43,6 +43,7 @@ public void FloatArraysTest()

var result = csvParser
.ReadFromString(csvReaderOptions, stringBuilder.ToString())
.Items
.ToList();

Assert.AreEqual(2, result.Count);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public void ReadFromFileTest()

var result = csvParser
.ReadFromFile(filePath.ToString(), Encoding.UTF8)
.Items
.ToList();

Assert.AreEqual(2, result.Count);
Expand Down Expand Up @@ -116,6 +117,7 @@ public void ReadFromStreamTest()
{
var result = csvParser
.ReadFromStream(stream, Encoding.UTF8)
.Items
.ToList();

Assert.AreEqual(2, result.Count);
Expand Down
13 changes: 10 additions & 3 deletions TinyCsvParser/TinyCsvParser.Test/CsvParser/CsvParserTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public CsvPersonMapping()
[Test]
public void NullInputTest()
{
CsvParserOptions csvParserOptions = new CsvParserOptions(true, ';' );
CsvParserOptions csvParserOptions = new CsvParserOptions(true, ';');
CsvReaderOptions csvReaderOptions = new CsvReaderOptions(new[] { Environment.NewLine });
CsvPersonMapping csvMapper = new CsvPersonMapping();
CsvParser<Person> csvParser = new CsvParser<Person>(csvParserOptions, csvMapper);
Expand All @@ -46,7 +46,7 @@ public void NullInputTest()
[Test]
public void ToStringTest()
{
CsvParserOptions csvParserOptions = new CsvParserOptions(true, ';');
CsvParserOptions csvParserOptions = new CsvParserOptions(true, ';');
CsvReaderOptions csvReaderOptions = new CsvReaderOptions(new[] { Environment.NewLine });
CsvPersonMapping csvMapper = new CsvPersonMapping();
CsvParser<Person> csvParser = new CsvParser<Person>(csvParserOptions, csvMapper);
Expand All @@ -72,6 +72,7 @@ public void SkipHeaderTest()

var result = csvParser
.ReadFromString(csvReaderOptions, stringBuilder.ToString())
.Items
.ToList();

Assert.AreEqual(2, result.Count);
Expand Down Expand Up @@ -109,6 +110,7 @@ public void DoNotSkipHeaderTest()

var result = csvParser
.ReadFromString(csvReaderOptions, stringBuilder.ToString())
.Items
.ToList();

Assert.AreEqual(2, result.Count);
Expand Down Expand Up @@ -147,6 +149,7 @@ public void EmptyDataTest()

var result = csvParser
.ReadFromString(csvReaderOptions, stringBuilder.ToString())
.Items
.ToList();

Assert.AreEqual(0, result.Count);
Expand All @@ -167,6 +170,7 @@ public void TrimLineTest()

var result = csvParser
.ReadFromString(csvReaderOptions, stringBuilder.ToString())
.Items
.ToList();

Assert.AreEqual(2, result.Count);
Expand Down Expand Up @@ -203,6 +207,7 @@ public void ParallelLinqTest()

var result = csvParser
.ReadFromString(csvReaderOptions, stringBuilder.ToString())
.Items
.Where(x => x.IsValid)
.Where(x => x.Result.FirstName == "Philipp")
.ToList();
Expand All @@ -220,7 +225,7 @@ public void ParallelLinqTest()
[Test]
public void CommentLineTest()
{
CsvParserOptions csvParserOptions = new CsvParserOptions(true, "#", new StringSplitTokenizer(new [] {';'}, false));
CsvParserOptions csvParserOptions = new CsvParserOptions(true, "#", new StringSplitTokenizer(new[] { ';' }, false));
CsvReaderOptions csvReaderOptions = new CsvReaderOptions(new[] { Environment.NewLine });
CsvPersonMapping csvMapper = new CsvPersonMapping();
CsvParser<Person> csvParser = new CsvParser<Person>(csvParserOptions, csvMapper);
Expand All @@ -232,6 +237,7 @@ public void CommentLineTest()

var result = csvParser
.ReadFromString(csvReaderOptions, stringBuilder.ToString())
.Items
.Where(x => x.IsValid)
.ToList();

Expand Down Expand Up @@ -259,6 +265,7 @@ public void StringArrayMappingTest()

var result = csvParser
.ReadFromString(csvReaderOptions, stringBuilder.ToString())
.Items
.ToList();

Assert.AreEqual(2, result.Count);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public CsvPersonMappingWithCustomConverter()
[Test]
public void WeirdDateTimeTest_CustomConverterBased()
{
CsvParserOptions csvParserOptions = new CsvParserOptions(true, ';');
CsvParserOptions csvParserOptions = new CsvParserOptions(true, ';');
CsvReaderOptions csvReaderOptions = new CsvReaderOptions(new[] { Environment.NewLine });
CsvPersonMappingWithCustomConverter csvMapper = new CsvPersonMappingWithCustomConverter();
CsvParser<Person> csvParser = new CsvParser<Person>(csvParserOptions, csvMapper);
Expand All @@ -69,6 +69,7 @@ public void WeirdDateTimeTest_CustomConverterBased()

var result = csvParser
.ReadFromString(csvReaderOptions, stringBuilder.ToString())
.Items
.ToList();

Assert.AreEqual("Philipp", result[0].Result.FirstName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public void CustomEnumConverterTest()

var result = csvParser
.ReadFromString(csvReaderOptions, stringBuilder.ToString())
.Items
.ToList();

Assert.AreEqual(VehicleTypeEnum.Car, result[0].Result.VehicleType);
Expand Down
7 changes: 4 additions & 3 deletions TinyCsvParser/TinyCsvParser.Test/CsvParser/MapUsingTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public CsvMainClassMapping()
[Test]
public void MapUsingTest()
{
CsvParserOptions csvParserOptions = new CsvParserOptions(false, ';' );
CsvParserOptions csvParserOptions = new CsvParserOptions(false, ';');
CsvReaderOptions csvReaderOptions = new CsvReaderOptions(new[] { Environment.NewLine });
CsvMainClassMapping csvMapper = new CsvMainClassMapping();
CsvParser<MainClass> csvParser = new CsvParser<MainClass>(csvParserOptions, csvMapper);
Expand All @@ -65,15 +65,16 @@ public void MapUsingTest()

var result = csvParser
.ReadFromString(csvReaderOptions, stringBuilder.ToString())
.Items
.ToList();

Assert.AreEqual(2, result.Count);

Assert.IsFalse(result[0].IsValid);
Assert.IsTrue(result[1].IsValid);

Assert.AreEqual("A", result[1].Result.Property1);

Assert.IsNotNull(result[1].Result.SubClass);

Assert.AreEqual("B", result[1].Result.SubClass.Property2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public CsvEntityMapping()
[Test]
public void ParseWithNULLStringTest()
{
CsvParserOptions csvParserOptions = new CsvParserOptions(false, ';');
CsvParserOptions csvParserOptions = new CsvParserOptions(false, ';');
CsvReaderOptions csvReaderOptions = new CsvReaderOptions(new[] { Environment.NewLine });
CsvEntityMapping csvMapper = new CsvEntityMapping();
CsvParser<Entity> csvParser = new CsvParser<Entity>(csvParserOptions, csvMapper);
Expand All @@ -69,6 +69,7 @@ public void ParseWithNULLStringTest()

var result = csvParser
.ReadFromString(csvReaderOptions, stringBuilder.ToString())
.Items
.ToList();

Assert.AreEqual(null, result[0].Result.Property);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public CsvEntityMapping()
[Test]
public void ParseWithNULLStringTest()
{
CsvParserOptions csvParserOptions = new CsvParserOptions(false, ';');
CsvParserOptions csvParserOptions = new CsvParserOptions(false, ';');
CsvReaderOptions csvReaderOptions = new CsvReaderOptions(new[] { Environment.NewLine });
CsvEntityMapping csvMapper = new CsvEntityMapping();
CsvParser<Entity> csvParser = new CsvParser<Entity>(csvParserOptions, csvMapper);
Expand All @@ -39,6 +39,7 @@ public void ParseWithNULLStringTest()

var result = csvParser
.ReadFromString(csvReaderOptions, stringBuilder.ToString())
.Items
.ToList();

Assert.AreEqual(123.456, result[0].Result.Value);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using NUnit.Framework;
using System;
using System.Linq;
using System.Text;
using NUnit.Framework;
using TinyCsvParser.Mapping;
using TinyCsvParser.Model;

Expand All @@ -19,7 +19,7 @@ private class MyCsvRowEntity
public Shape Shape { get; set; }
}

private abstract class Shape {}
private abstract class Shape { }

private class Square : Shape
{
Expand Down Expand Up @@ -58,7 +58,7 @@ private bool ShapeMapper(MyCsvRowEntity inProgressEntity, TokenizedRow rowData)
// the process of building.
if (inProgressEntity.ShapeName == "square")
{
var subMap = squareMap.Map(rowData);
var subMap = squareMap.Map(rowData, 1);
if (subMap.IsValid)
{
inProgressEntity.Shape = subMap.Result;
Expand All @@ -69,15 +69,15 @@ private bool ShapeMapper(MyCsvRowEntity inProgressEntity, TokenizedRow rowData)

if (inProgressEntity.ShapeName == "triangle")
{
var subMap = triangleMap.Map(rowData);
var subMap = triangleMap.Map(rowData, 1);
if (subMap.IsValid)
{
inProgressEntity.Shape = subMap.Result;
}

return subMap.IsValid;
}

// NOTE: There are two possible strategies here. One, you can return true
// which will allow any *OTHER* Row Mappings to run and see if they can make
// sense of the data from this row. Maybe you have a whole separate mapper
Expand All @@ -89,7 +89,7 @@ private bool ShapeMapper(MyCsvRowEntity inProgressEntity, TokenizedRow rowData)
}
}


// NOTE: These "sub" maps aren't referenced directly by the CsvParser, but instead
// by the top-level map, which conditionally uses them based on the contents of a
// given row.
Expand Down Expand Up @@ -132,6 +132,7 @@ public void MapUsingPolymorphicTest()

var result = csvParser
.ReadFromString(csvReaderOptions, stringBuilder.ToString())
.Items
.ToList();

Assert.AreEqual(4, result.Count);
Expand All @@ -143,13 +144,13 @@ public void MapUsingPolymorphicTest()

Assert.AreEqual("square", result[0].Result.ShapeName);
Assert.AreEqual(typeof(Square), result[0].Result.Shape.GetType());
Assert.AreEqual(10, ((Square) result[0].Result.Shape).Width);
Assert.AreEqual(10, ((Square)result[0].Result.Shape).Width);

Assert.AreEqual("triangle", result[1].Result.ShapeName);
Assert.AreEqual(typeof(Triangle), result[1].Result.Shape.GetType());
Assert.AreEqual(3, ((Triangle) result[1].Result.Shape).Side1);
Assert.AreEqual(4, ((Triangle) result[1].Result.Shape).Side2);
Assert.AreEqual(5, ((Triangle) result[1].Result.Shape).Side3);
Assert.AreEqual(3, ((Triangle)result[1].Result.Shape).Side1);
Assert.AreEqual(4, ((Triangle)result[1].Result.Shape).Side2);
Assert.AreEqual(5, ((Triangle)result[1].Result.Shape).Side3);

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public void PersonMappingTest()

var result = csvParser
.ReadFromString(csvReaderOptions, stringBuilder.ToString())
.Items
.ToList();

Assert.AreEqual(2, result.Count);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TinyCsvParser.Mapping;
using TinyCsvParser.Tokenizer;
using TinyCsvParser.Tokenizer.RFC4180;
Expand Down Expand Up @@ -153,9 +151,10 @@ public void RunStringSplitTokenizerTest()
{
var cnt = parser
.ReadFromFile(filename, Encoding.UTF8)
.Items
.Where(x => x.IsValid)
.Count();

TestContext.WriteLine($"Parsed {cnt} valid lines ...");
},
timespanFormatter: x => $"{x.TotalMilliseconds} Milliseconds");
Expand All @@ -176,6 +175,7 @@ public void RunCustomTokenizerTest()
{
var cnt = parser
.ReadFromFile(filename, Encoding.UTF8)
.Items
.Where(x => x.IsValid)
.Count();

Expand All @@ -199,6 +199,7 @@ public void RunRfc4180TokenizerTest()
{
var cnt = parser
.ReadFromFile(filename, Encoding.UTF8)
.Items
.Where(x => x.IsValid)
.Count();

Expand Down
Loading