Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 12 additions & 13 deletions files-csharp/ReadFromCsv/ReadFromCsv/Person.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
using CsvHelper.Configuration.Attributes;
using CsvHelper.Configuration.Attributes;

namespace ReadFromCsv
namespace ReadFromCsv;

public class Person
{
public class Person
{
[Index(0)]
public int Id { get; set; }
[Index(1)]
public string? Name { get; set; }
[Index(2)]
public bool IsLiving { get; set; }
[Index(3)]
public DateTime DateOfBirth { get; set; }
}
[Index(0)]
public int Id { get; set; }
[Index(1)]
public string? Name { get; set; }
[Index(2)]
public bool IsLiving { get; set; }
[Index(3)]
public DateTime DateOfBirth { get; set; }
}
23 changes: 12 additions & 11 deletions files-csharp/ReadFromCsv/ReadFromCsv/PersonMap.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
using CsvHelper.Configuration;
using ReadFromCsv;
using CsvHelper.Configuration;

public class PersonMap : ClassMap<Person>
{
public PersonMap()
{
Map(p => p.Id).Index(0);
Map(p => p.Name).Index(1);
Map(p => p.IsLiving).Index(2);
}
}
namespace ReadFromCsv;

public class PersonMap : ClassMap<Person>
{
public PersonMap()
{
Map(p => p.Id).Index(0);
Map(p => p.Name).Index(1);
Map(p => p.IsLiving).Index(2);
}
}
7 changes: 5 additions & 2 deletions files-csharp/ReadFromCsv/ReadFromCsv/Program.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
using ReadFromCsv;
using ReadFromCsv;

ReadMethods.ReadPersons();
foreach (var person in ReadMethods.ReadPersons())
{
Console.WriteLine($"{person.Id} {person.Name} {person.IsLiving}");
}
10 changes: 8 additions & 2 deletions files-csharp/ReadFromCsv/ReadFromCsv/ReadFromCsv.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="CsvHelper" Version="27.2.1" />
<PackageReference Include="CsvHelper" Version="33.1.0" />
</ItemGroup>

<ItemGroup>
<None Update="filePersons.csv">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
32 changes: 15 additions & 17 deletions files-csharp/ReadFromCsv/ReadFromCsv/ReadMethods.cs
Original file line number Diff line number Diff line change
@@ -1,27 +1,25 @@
using CsvHelper;
using CsvHelper;
using CsvHelper.Configuration;
using System.Globalization;

namespace ReadFromCsv
namespace ReadFromCsv;

public static class ReadMethods
{
public static class ReadMethods
public static List<Person> ReadPersons()
{
public static void ReadPersons()
var configuration = new CsvConfiguration(CultureInfo.InvariantCulture)
{
var configuration = new CsvConfiguration(CultureInfo.InvariantCulture)
{
Delimiter = ",",
Comment = '#',
HasHeaderRecord = false
};
Delimiter = ",",
Comment = '#',
HasHeaderRecord = false
};

using var reader = new StreamReader("filePersons.csv");
using var csv = new CsvReader(reader, configuration);

using (var reader = new StreamReader("filePersons.csv"))
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
csv.Context.RegisterClassMap<PersonMap>();
var persons = csv.GetRecords<Person>();
}
csv.Context.RegisterClassMap<PersonMap>();

}
return csv.GetRecords<Person>().ToList();
}
}
3 changes: 3 additions & 0 deletions files-csharp/ReadFromCsv/ReadFromCsv/filePersons.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
1,John,True,03/05/2006
2,Steve,False,03/05/2006
3,James,True,03/05/2006
218 changes: 189 additions & 29 deletions files-csharp/ReadFromCsv/ReadFromCsvTests/ReadFromCsvTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using CsvHelper;
using CsvHelper.Configuration;
using CsvHelper.TypeConversion;
using Microsoft.VisualBasic.FileIO;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ReadFromCsv;
using System;
Expand All @@ -9,41 +11,199 @@
using System.Linq;
using System.Text;

namespace ReadFromCsvTests
namespace ReadFromCsvTests;

[TestClass]
public class ReadFromCsvTests
{
[TestClass]
public class ReadFromCsvTests
private static CsvReader CreateReader(string csvContent, CsvConfiguration configuration, out StreamReader reader)
{
var stream = new MemoryStream(Encoding.UTF8.GetBytes(csvContent));

reader = new StreamReader(stream);

return new CsvReader(reader, configuration);
}

[TestMethod]
public void GivenHeaderlessCsvFile_WhenReadingPersons_ThenEveryFieldIsMapped()
{
[TestMethod]
public void GivenCsvFile_WhenReadingPersonsFromCsv_ThenListOfPersonsIsPopulated()
var csvFile = "1,John,True,03/05/2006 00:00:00\n"
+ "2,Steve,False,03/05/2006 00:00:00\n"
+ "3,James,True,03/05/2006 00:00:00";

var expectedPersons = new List<Person>
{
string csvFile =
@"1, John, True, 03/05/2006 00:00:00
2, Steve, False, 03/05/2006 00:00:00
3, James, True, 03/05/2006 00:00:00";
new() { Id = 1, Name = "John", IsLiving = true, DateOfBirth = DateTime.Parse("03/05/2006", CultureInfo.InvariantCulture) },
new() { Id = 2, Name = "Steve", IsLiving = false, DateOfBirth = DateTime.Parse("03/05/2006", CultureInfo.InvariantCulture) },
new() { Id = 3, Name = "James", IsLiving = true, DateOfBirth = DateTime.Parse("03/05/2006", CultureInfo.InvariantCulture) }
};

var expectedPersons = new List<Person>()
{
new Person { Id = 1, IsLiving = true, Name = "John", DateOfBirth = Convert.ToDateTime("03/05/2006") },
new Person { Id = 2, IsLiving = true, Name = "Steve", DateOfBirth = Convert.ToDateTime("03/09/1998") },
new Person { Id = 3, IsLiving = true, Name = "James", DateOfBirth = Convert.ToDateTime("03/08/1994") }
};
var configuration = new CsvConfiguration(CultureInfo.InvariantCulture)
{
HasHeaderRecord = false
};

using (var test_Stream = new MemoryStream(Encoding.UTF8.GetBytes(csvFile)))
using var csv = CreateReader(csvFile, configuration, out var reader);
using (reader)
{
var persons = csv.GetRecords<Person>().ToList();

Assert.AreEqual(expectedPersons.Count, persons.Count);

for (var i = 0; i < expectedPersons.Count; i++)
{
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
HasHeaderRecord = false,
};

using (var reader = new StreamReader(test_Stream))
using (var csv = new CsvReader(reader, config))
{
var records = csv.GetRecords<Person>();

Assert.AreEqual(expectedPersons.Count, records.Count());
}
Assert.AreEqual(expectedPersons[i].Id, persons[i].Id);
Assert.AreEqual(expectedPersons[i].Name, persons[i].Name);
Assert.AreEqual(expectedPersons[i].IsLiving, persons[i].IsLiving);
Assert.AreEqual(expectedPersons[i].DateOfBirth, persons[i].DateOfBirth);
}
}
}
}

[TestMethod]
public void GivenHeaderlessCsvFile_WhenTheConfigurationIsNotPassedToTheReader_ThenTheFirstRowIsLost()
{
var csvFile = "1,John,True,03/05/2006 00:00:00\n2,Steve,False,03/05/2006 00:00:00";

var configuration = new CsvConfiguration(CultureInfo.InvariantCulture)
{
HasHeaderRecord = false
};

using (var csv = CreateReader(csvFile, configuration, out var withConfiguration))
using (withConfiguration)
{
Assert.AreEqual(2, csv.GetRecords<Person>().ToList().Count);
}

var cultureOnly = new CsvConfiguration(CultureInfo.InvariantCulture);

using (var csv = CreateReader(csvFile, cultureOnly, out var withCulture))
using (withCulture)
{
var persons = csv.GetRecords<Person>().ToList();

Assert.AreEqual(1, persons.Count);
Assert.AreEqual(2, persons[0].Id);
}
}

[TestMethod]
public void GivenAQuotedComma_WhenReadingTheRow_ThenTheFieldSurvivesIntact()
{
var csvFile = "Id,Name,IsLiving,DateOfBirth\n1,\"Close, Josh\",true,03/05/2006 00:00:00";

var configuration = new CsvConfiguration(CultureInfo.InvariantCulture);

using var csv = CreateReader(csvFile, configuration, out var reader);
using (reader)
{
var persons = csv.GetRecords<Person>().ToList();

Assert.AreEqual(1, persons.Count);
Assert.AreEqual("Close, Josh", persons[0].Name);
}
}

[TestMethod]
public void GivenACommentLine_WhenAllowCommentsIsFalse_ThenTheCommentIsReadAsData()
{
var csvFile = "1;John;True;03/05/2006 00:00:00\n% a comment line\n2;Steve;False;03/05/2006 00:00:00";

var configuration = new CsvConfiguration(CultureInfo.InvariantCulture)
{
HasHeaderRecord = false,
Delimiter = ";",
Comment = '%'
};

Assert.IsFalse(configuration.AllowComments);

using var csv = CreateReader(csvFile, configuration, out var reader);
using (reader)
{
Assert.ThrowsExactly<TypeConverterException>(() => csv.GetRecords<Person>().ToList());
}
}

[TestMethod]
public void GivenACommentLine_WhenAllowCommentsIsTrue_ThenTheCommentIsSkipped()
{
var csvFile = "1;John;True;03/05/2006 00:00:00\n% a comment line\n2;Steve;False;03/05/2006 00:00:00";

var configuration = new CsvConfiguration(CultureInfo.InvariantCulture)
{
HasHeaderRecord = false,
Delimiter = ";",
Comment = '%',
AllowComments = true
};

using var csv = CreateReader(csvFile, configuration, out var reader);
using (reader)
{
var persons = csv.GetRecords<Person>().ToList();

Assert.AreEqual(2, persons.Count);
Assert.AreEqual("Steve", persons[1].Name);
}
}

[TestMethod]
public void GivenAQuotedComma_WhenSplittingTheLine_ThenSplitBreaksItAndTextFieldParserDoesNot()
{
var row = "1,\"Close, Josh\",true,03/05/2006 00:00:00";

Assert.AreEqual(5, row.Split(',').Length);

using var stream = new MemoryStream(Encoding.UTF8.GetBytes(row));
using var parser = new TextFieldParser(stream)
{
TextFieldType = FieldType.Delimited,
HasFieldsEnclosedInQuotes = true
};

parser.SetDelimiters(",");

var fields = parser.ReadFields();

Assert.IsNotNull(fields);
Assert.AreEqual(4, fields.Length);
Assert.AreEqual("Close, Josh", fields[1]);
}

[TestMethod]
public void GivenAnUnconvertibleField_WhenReadingExceptionOccurredReturnsFalse_ThenTheBadRowIsSkipped()
{
var csvFile = "1,John,True,03/05/2006 00:00:00\n"
+ "2,Steve,notabool,03/05/2006 00:00:00\n"
+ "3,James,True,03/05/2006 00:00:00";

var strict = new CsvConfiguration(CultureInfo.InvariantCulture)
{
HasHeaderRecord = false
};

using (var csv = CreateReader(csvFile, strict, out var strictReader))
using (strictReader)
{
Assert.ThrowsExactly<TypeConverterException>(() => csv.GetRecords<Person>().ToList());
}

var tolerant = new CsvConfiguration(CultureInfo.InvariantCulture)
{
HasHeaderRecord = false,
ReadingExceptionOccurred = args => false
};

using (var csv = CreateReader(csvFile, tolerant, out var tolerantReader))
using (tolerantReader)
{
var persons = csv.GetRecords<Person>().ToList();

Assert.AreEqual(2, persons.Count);
Assert.AreEqual(3, persons[1].Id);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="CsvHelper" Version="27.2.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.7" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.7" />
<PackageReference Include="coverlet.collector" Version="3.1.0" />
<PackageReference Include="CsvHelper" Version="33.1.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.10.0" />
<PackageReference Include="MSTest.TestAdapter" Version="4.4.0" />
<PackageReference Include="MSTest.TestFramework" Version="4.4.0" />
<PackageReference Include="coverlet.collector" Version="10.0.1" />
</ItemGroup>

<ItemGroup>
Expand Down
Loading