Skip to content

Commit

Permalink
Merge pull request #30 from akankainen/Issue29
Browse files Browse the repository at this point in the history
Adds possibility to treat missing fields as null instead of throwing a MissingFieldException
  • Loading branch information
jefim authored Jun 29, 2023
2 parents 0d07f44 + 3dbbe2e commit 595a3b6
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 57 deletions.
104 changes: 73 additions & 31 deletions Frends.Csv.Tests/Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using Newtonsoft.Json.Linq;
using NUnit.Framework;


namespace Frends.Csv.Tests
{
[TestFixture]
Expand All @@ -18,18 +17,19 @@ public void TestParseSkipRowsWithAutomaticHeaders()
year;car;mark;price
1997;Ford;E350;2,34
2000;Mercury;Cougar;2,38";
var result = Csv.Parse(new ParseInput() {
var result = Csv.Parse(new ParseInput()
{
ColumnSpecifications = new ColumnSpecification[0],
Delimiter = ";",
Csv = csv
}, new ParseOption() {ContainsHeaderRow = true, SkipRowsFromTop = 2, SkipEmptyRows = false});
}, new ParseOption() { ContainsHeaderRow = true, SkipRowsFromTop = 2, SkipEmptyRows = false });

dynamic resultJArray = result.ToJson();
var resultXml = result.ToXml();
var resultData = result.Data;
Assert.That(resultData.Count, Is.EqualTo(2));
Assert.That(resultJArray.Count, Is.EqualTo(2));
Assert.That(resultXml,Does.Contain("<year>2000</year>"));
Assert.That(resultXml, Does.Contain("<year>2000</year>"));
Assert.That(resultJArray[0].price.ToString(), Is.EqualTo("2,34"));
}

Expand All @@ -41,20 +41,21 @@ public void TestParseWithColumnSpecAndMissingHeader()

var result = Csv.Parse(new ParseInput()
{
ColumnSpecifications = new[]
ColumnSpecifications = new[]
{
new ColumnSpecification() {Name = "Year", Type = ColumnType.Int},
new ColumnSpecification() {Name = "Car", Type = ColumnType.String},
new ColumnSpecification() {Name = "Mark", Type = ColumnType.String},
new ColumnSpecification() {Name = "Price", Type = ColumnType.Decimal}
},
Delimiter = ";", Csv = csv
}, new ParseOption() { ContainsHeaderRow = false, CultureInfo = "fi-FI"});
Delimiter = ";",
Csv = csv
}, new ParseOption() { ContainsHeaderRow = false, CultureInfo = "fi-FI" });
var resultJArray = result.ToJson() as JArray;
var resultXml = result.ToXml();
var resultData = result.Data;
Assert.That(resultData.Count, Is.EqualTo(2));
Assert.That(resultJArray.Count,Is.EqualTo(2));
Assert.That(resultJArray.Count, Is.EqualTo(2));
Assert.That(resultXml, Does.Contain("<Year>2000</Year>"));
Assert.That(resultJArray[0]["Price"].Value<decimal>(), Is.EqualTo(2.34));
}
Expand Down Expand Up @@ -105,14 +106,14 @@ public void TestParseWillAllKindOfDataTypes()
Delimiter = ";",
Csv = csv
}, new ParseOption() { ContainsHeaderRow = true, CultureInfo = "fi-FI" });
var resultJson = (JArray) result.ToJson();
var resultJson = (JArray)result.ToJson();
Assert.That(resultJson[0]["Long"].Value<long>(), Is.EqualTo(4294967296));
var resultXml = result.ToXml();
Assert.That(resultXml, Does.Contain("<DateTime2>1.5.2008 10.34.42</DateTime2>"));
var resultData = result.Data;
var itemArray = resultData[0];
Assert.That(itemArray[0].GetType(), Is.EqualTo(typeof(int)));
Assert.That(itemArray[0],Is.EqualTo(1997));
Assert.That(itemArray[0], Is.EqualTo(1997));

Assert.That(itemArray[1].GetType(), Is.EqualTo(typeof(string)));
Assert.That(itemArray[1], Is.EqualTo("Fo;rd"));
Expand All @@ -133,13 +134,67 @@ public void TestParseWillAllKindOfDataTypes()
Assert.That(itemArray[6], Is.EqualTo('f'));

Assert.That(itemArray[7].GetType(), Is.EqualTo(typeof(DateTime)));
Assert.That(itemArray[7], Is.EqualTo(new DateTime(2008,9,15)));
Assert.That(itemArray[7], Is.EqualTo(new DateTime(2008, 9, 15)));

Assert.That(itemArray[8].GetType(), Is.EqualTo(typeof(DateTime)));
Assert.That(itemArray[8], Is.EqualTo(new DateTime(2008,5,1,10,34,42)));
Assert.That(itemArray[8], Is.EqualTo(new DateTime(2008, 5, 1, 10, 34, 42)));
}

[Test]
public void TestParseTreatMissingFieldsAsNullSetToTrue()
{
var csv =
@"header1,header2,header3
value1,value2,value3
value1,value2,value3
value1,value2";

var result = Csv.Parse(new ParseInput()
{
ColumnSpecifications = new ColumnSpecification[0],
Delimiter = ",",
Csv = csv
}, new ParseOption() { ContainsHeaderRow = true, CultureInfo = "fi-FI", TreatMissingFieldsAsNulls = true });
var resultJson = (JArray)result.ToJson();
Assert.That(resultJson[2].Value<string>("header3"), Is.EqualTo(null));

var resultXml = result.ToXml();
Assert.That(resultXml, Does.Contain("<header3 />"));

var resultData = result.Data;
var nullItem = resultData[2][2];

Assert.That(nullItem, Is.EqualTo(null));
}

[Test]
public void TestParseTreatMissingFieldsAsNullSetToFalse()
{
Assert.Throws<CsvHelper.MissingFieldException>(
delegate
{
var csv =
@"header1,header2,header3
value1,value2,value3
value1,value2,value3
value1,value2";

var result = Csv.Parse(new ParseInput()
{
ColumnSpecifications = new ColumnSpecification[0],
Delimiter = ",",
Csv = csv
}, new ParseOption() { ContainsHeaderRow = true, CultureInfo = "fi-FI", TreatMissingFieldsAsNulls = false });
});
}

[Test]
public void TestParseTreatMissingFieldsAsNullDefaultValue()
{
var options = new ParseOption();

Assert.That(options.TreatMissingFieldsAsNulls, Is.EqualTo(false));
}

[Test]
public void TestWriteFromListTable()
Expand All @@ -161,7 +216,7 @@ public void TestWriteFromListTable()
new List<object>() {100, "Dilantin", "Melanie", date}
};

var result = Csv.Create(new CreateInput() { InputType = CreateInputType.List, Delimiter = ";", Data = data, Headers = headers}, new CreateOption() { CultureInfo = "fi-FI" });
var result = Csv.Create(new CreateInput() { InputType = CreateInputType.List, Delimiter = ";", Data = data, Headers = headers }, new CreateOption() { CultureInfo = "fi-FI" });
Assert.That(result.Csv,
Is.EqualTo(
@"Dosage;Drug;Patient;Date
Expand All @@ -173,12 +228,11 @@ public void TestWriteFromListTable()
"));
}


[Test]
public void TestWriteFromJson()
{
var json = @"[{""cool"":""nice"", ""what"": ""no""}, {""cool"":""not"", ""what"": ""yes""}, {""cool"":""maybe"", ""what"": ""never""}]";
var result = Csv.Create(new CreateInput() { InputType = CreateInputType.Json, Delimiter = ";", Json = json}, new CreateOption());
var result = Csv.Create(new CreateInput() { InputType = CreateInputType.Json, Delimiter = ";", Json = json }, new CreateOption());
Assert.That(result.Csv,
Is.EqualTo(@"cool;what
nice;no
Expand Down Expand Up @@ -211,19 +265,11 @@ public void TestNoQuotesOption()
"" Normally I would have quotes "";I would not
"));


var result1 = Csv.Create(new CreateInput() { InputType = CreateInputType.Json, Delimiter = ";", Json = json }, new CreateOption() { NeverAddQuotesAroundValues = true });
Assert.That(result1.Csv,
Is.EqualTo(@"foo;bar
Normally I would have quotes ;I would not
"));







}

[Test]
Expand Down Expand Up @@ -254,10 +300,11 @@ public void TestDecimalValues()
0.1;1.00;0.000000000000000000000000000000000000000000000000000000001
"));
}

[Test]
public void ParseAndWriteShouldUseSeparateCultures()
{
var csv =
var csv =
@"First; Second; Number; Date
Foo; bar; 100; 2000-01-01";

Expand All @@ -272,7 +319,7 @@ public void ParseAndWriteShouldUseSeparateCultures()
},
Delimiter = ";",
Csv = csv
}, new ParseOption() { ContainsHeaderRow = true, CultureInfo = "en-us"});
}, new ParseOption() { ContainsHeaderRow = true, CultureInfo = "en-us" });

var result = Csv.Create(new CreateInput() { InputType = CreateInputType.List, Delimiter = ";", Data = parseResult.Data, Headers = parseResult.Headers }, new CreateOption() { CultureInfo = "fi-FI" });

Expand Down Expand Up @@ -305,7 +352,6 @@ public void TestParseRowsWithAutomaticHeadersWhiteSpaceRemovalDefault()
Assert.That(resultJArray[0].price.ToString(), Is.EqualTo("2,34"));
}


[Test]
public void TestParseRowsWithAutomaticHeadersWhiteSpaceRemovalGiven()
{
Expand All @@ -328,9 +374,5 @@ public void TestParseRowsWithAutomaticHeadersWhiteSpaceRemovalGiven()
Assert.That(resultXml, Does.Contain("<year_of_the_z>"));
Assert.That(resultJArray[0].price.ToString(), Is.EqualTo("2,34"));
}



}
}

}
32 changes: 13 additions & 19 deletions Frends.Csv/Csv.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,28 @@ namespace Frends.Csv
{
public class Csv
{


/// <summary>
/// Parse string csv content to a object. See https://github.com/FrendsPlatform/Frends.Csv
/// </summary>
/// <returns>Object { List&lt;List&lt;object&gt;&gt; Data, List&lt;string&gt; Headers, JToken ToJson(), string ToXml() } </returns>
public static ParseResult Parse([PropertyTab] ParseInput input, [PropertyTab] ParseOption option)
{


var configuration = new CsvConfiguration(new CultureInfo(option.CultureInfo))
{
HasHeaderRecord = option.ContainsHeaderRow,
Delimiter = input.Delimiter,
TrimOptions = option.TrimOutput ? TrimOptions.None : TrimOptions.Trim,
TrimOptions = option.TrimOutput ? TrimOptions.None : TrimOptions.Trim,
IgnoreBlankLines = option.SkipEmptyRows
};


// Setting the MissingFieldFound -delegate property of configuration to null when
// option.TreatMissingFieldsAsNulls is set to true for returning null values for missing fields.
// Otherwise the default setting which throws a MissingFieldException is used

if (option.TreatMissingFieldsAsNulls)
{
configuration.MissingFieldFound = null;
}

using (TextReader sr = new StringReader(input.Csv))
{
Expand All @@ -45,12 +47,10 @@ public static ParseResult Parse([PropertyTab] ParseInput input, [PropertyTab] Pa

using (var csvReader = new CsvReader(sr, configuration))
{


if (option.ContainsHeaderRow)
{
csvReader.Read();
csvReader.ReadHeader();
{
csvReader.Read();
csvReader.ReadHeader();
}
var resultData = new List<List<object>>();
var headers = new List<string>();
Expand Down Expand Up @@ -87,8 +87,6 @@ public static ParseResult Parse([PropertyTab] ParseInput input, [PropertyTab] Pa
headers = csvReader.HeaderRecord.Select(x => x.Replace(" ", option.ReplaceHeaderWhitespaceWith)).ToList();
}



while (csvReader.Read())
{
var innerList = new List<object>();
Expand Down Expand Up @@ -122,7 +120,6 @@ public static ParseResult Parse([PropertyTab] ParseInput input, [PropertyTab] Pa
}

return new ParseResult(resultData, headers, configuration.CultureInfo);

}
}
}
Expand Down Expand Up @@ -153,17 +150,16 @@ public static CreateResult Create([PropertyTab] CreateInput input, [PropertyTab]
case CreateInputType.List:
csv = ListToCsvString(input.Data, input.Headers, config, option);
break;

case CreateInputType.Json:
csv = JsonToCsvString(input.Json, config, option);
break;
}
return new CreateResult(csv);

}

private static string ListToCsvString(List<List<object>> inputData, List<string> inputHeaders, CsvConfiguration config, CreateOption option)
{

using (var csvString = new StringWriter())
using (var csv = new CsvWriter(csvString, config))
{
Expand All @@ -189,7 +185,6 @@ private static string ListToCsvString(List<List<object>> inputData, List<string>
}
}


private static string JsonToCsvString(string json, CsvConfiguration config, CreateOption option)
{
List<Dictionary<string, string>> data = JsonConvert.DeserializeObject<List<Dictionary<string, string>>>(json);
Expand Down Expand Up @@ -218,6 +213,5 @@ private static string JsonToCsvString(string json, CsvConfiguration config, Crea
return csvString.ToString();
}
}

}
}
}
Loading

0 comments on commit 595a3b6

Please sign in to comment.