// Copyright (C) Stichting Deltares 2024. All rights reserved.
//
// This file is part of the application DAM - UI.
//
// DAM - UI is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
// All names, logos, and references to "Deltares" are registered trademarks of
// Stichting Deltares and remain full property of Stichting Deltares at all times.
// All rights reserved.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Deltares.Dam.Data;
using NUnit.Framework;
namespace Deltares.Dam.Tests;
[TestFixture]
public class CsvParserTest
{
private string testFile;
[SetUp]
public void FixtureSetup()
{
testFile = "test.csv";
using StreamWriter writer = File.CreateText(testFile);
writer.WriteLine("name;age");
writer.WriteLine("Anouar;31");
writer.WriteLine("Barry;39");
writer.WriteLine("Tom;48");
writer.WriteLine("Remko;39");
}
[TearDown]
public void FixtureTearDown()
{
if (File.Exists(testFile))
{
File.Delete(testFile);
}
}
[Test]
public void ThrowsArgumentExceptionWhenHeaderStringIsNullByCallingParseHeader()
{
const string expectedMessage = "The header in the import file is not valid";
Assert.That(() => CsvParser.ParseHeader(null, new Regex("")), Throws.InstanceOf().With.Message.EqualTo(expectedMessage));
}
[Test]
public void ThrowsArgumentExceptionSplitterIsNull()
{
string expectedMessage = "The given pattern to split the data values of the CSV files is not valid (Parameter 'splitter')";
Assert.That(() => CsvParser.ParseHeader("test;test", null), Throws.InstanceOf().With.Message.EqualTo(expectedMessage));
}
[Test]
public void ThrowsExceptionWhenSplitPatternIsEmpty()
{
const string expectedMessage = "The given pattern to split the data values of the CSV files is not valid";
Assert.That(() => CsvParser.ParseHeader("test", new Regex("")), Throws.InstanceOf().With.Message.EqualTo(expectedMessage));
}
[Test]
public void ThrowsExceptionWhenNoHeaderItemsAreParsed()
{
Assert.That(() => CsvParser.ParseHeader("test", new Regex("")), Throws.InstanceOf());
}
[Test]
public void CanParseHeaderWithSemicolonSeparatedItems()
{
string[] items = CsvParser.ParseHeader("header1;header 2", new Regex(CsvParser.CsvSplitPatternSemicolonOnly));
Assert.That(items.Length, Is.EqualTo(2));
Assert.That(items[0], Is.EqualTo("header1"));
Assert.That(items[1], Is.EqualTo("header 2"));
}
[Test]
public void CannotParseHeaderWithCommaSeparatedItems()
{
string[] items = CsvParser.ParseHeader("header1,header 2", new Regex(CsvParser.CsvSplitPatternSemicolonOnly));
Assert.That(items.Length, Is.EqualTo(1));
Assert.That(items[0], Is.EqualTo("header1,header 2"));
}
[Test]
public void ThrowsExceptionWhenObjectMaterializerNull()
{
Assert.That(() => CsvParser.LoadFromCsvFile(null, testFile).ToList(), Throws.ArgumentNullException);
}
[Test]
public void ThrowsExceptionWhenObjectMaterializerNotValid()
{
var loader = new ObjectMaterializer();
Assert.That(() => loader.LoadFromCsvFile(testFile).ToList(), Throws.InstanceOf());
}
[Test]
public void ThrowsExceptionWhenFileNameNull()
{
var loader = new ObjectMaterializer();
Assert.That(() => loader.LoadFromCsvFile(null).ToList(), Throws.ArgumentException);
}
[Test]
public void ThrowsExceptionWhenFileNameEmpty()
{
var loader = new ObjectMaterializer();
Assert.That(() => loader.LoadFromCsvFile("").ToList(), Throws.ArgumentException);
}
[Test]
public void ThrowsExceptionWhenFileNameContainsOnlySpaces()
{
var loader = new ObjectMaterializer();
Assert.That(() => loader.LoadFromCsvFile(" ").ToList(), Throws.ArgumentException);
}
[Test]
public void ThrowsExceptionWhenNumberOfItemsDoesntMatchWithHeader()
{
using (StreamWriter writer = File.CreateText(testFile))
{
writer.WriteLine("name;age"); //<- header contains name and age
writer.WriteLine("Barry;39;20");
}
var loader = new ObjectMaterializer();
loader.Add("name", (entity, value) => entity.Name = value);
loader.Add("age", (entity, value) => entity.Age = int.Parse(value));
Assert.That(() => loader.LoadFromCsvFile(testFile).Count(), Throws.InstanceOf()); // <- use count() to force the parser to run because it uses defered execution
}
[Test]
public void ThrowsExceptionWhenMappedKeyDoesntExistInCsvHeader()
{
using (StreamWriter writer = File.CreateText(testFile))
{
writer.WriteLine("name;age");
writer.WriteLine("Barry;39;");
}
var loader = new ObjectMaterializer();
loader.Add("name", (entity, value) => entity.Name = value);
loader.Add("ages", (entity, value) => entity.Age = int.Parse(value));
Assert.That(() => loader.LoadFromCsvFile(testFile).Count(), Throws.InstanceOf()); // <- use count() to force the parser to run because it uses defered execution
}
[Test]
public void CanParseTestFile()
{
using (StreamWriter writer = File.CreateText(testFile))
{
writer.WriteLine("name;age");
writer.WriteLine("Anouar;31");
writer.WriteLine("Barry;39");
writer.WriteLine("Tom;48");
writer.WriteLine("Remko;39");
}
var loader = new ObjectMaterializer();
loader.Add("name", (entity, value) => entity.Name = value);
loader.Add("age", (entity, value) => entity.Age = int.Parse(value));
List items = loader.LoadFromCsvFile(testFile).ToList();
Assert.That(items.Count, Is.EqualTo(4));
Assert.That(items.ElementAt(2).Name, Is.EqualTo("Tom"));
Assert.That(items.ElementAt(2).Age, Is.EqualTo(48));
}
private class Foo
{
public string Name { get; set; }
public int Age { get; set; }
}
}