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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,5 @@ FileHelpers.userprefs
/FileHelpers.Analyzer/FileHelpers.Analyzer/FileHelpers.Analyzer.Vsix/bin
/FileHelpers.Analyzer/FileHelpers.Analyzer/FileHelpers.Analyzer.Vsix/obj
/FileHelpers.Examples/obj
/FileHelpers.Examples/Release
/FileHelpers.Examples/Release
/_ReSharper.Caches
3 changes: 3 additions & 0 deletions FileHelpers.Tests/Data/Good/NumberFormatFrench.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
10248|32,38|32,38|32,38
10249|1011,61|1011,61|1011,61
10250|1 165,83|1 165,83|1 165,83
2 changes: 2 additions & 0 deletions FileHelpers.Tests/FileHelpers.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@
<Compile Include="Tests\Common\HeaderText.cs" />
<Compile Include="Tests\Common\RealLineNumber.cs" />
<Compile Include="Tests\Converters\DateFormatCulture.cs" />
<Compile Include="Tests\Converters\DefaultCultureInfo.cs" />
<Compile Include="Tests\Dynamic\ClassBuilderTests.cs" />
<Compile Include="Tests\Common\ConditionalRecords.cs">
<SubType>Code</SubType>
Expand Down Expand Up @@ -509,6 +510,7 @@
<Content Include="Data\Good\DiscardFirstReport.txt" />
<Content Include="Data\Good\FieldNotEmpty1.txt" />
<Content Include="Data\Good\InNewLineAfterOptional1.txt" />
<Content Include="Data\Good\NumberFormatFrench.txt" />
<Content Include="Data\Good\OrdersSmallVerticalBar.txt" />
<Content Include="Data\Good\CustomersFixedWithout1AndHalfFields.txt" />
<Content Include="Data\Good\CustomersFixedWithout2Fields.txt" />
Expand Down
8 changes: 8 additions & 0 deletions FileHelpers.Tests/Tests/Converters/DecimalNumbers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,18 @@ public void Decimals1()
CheckDecimal((decimal) 81.91, res[9]);
}





private static void CheckDecimal(decimal dec, DecimalType res)
{
Assert.AreEqual((decimal) dec, res.DecimalField);
Assert.AreEqual((double) dec, res.DoubleField);
Assert.AreEqual((float) dec, res.FloatField);
}



[Test]
public void NegativeNumbers()
Expand Down Expand Up @@ -65,10 +70,13 @@ public class DecimalType
public decimal DecimalField;
}



[Test]
public void DecimalsWithExponents()
{
var engine = new FileHelperEngine<DecimalType>();


DecimalType[] res;
res = TestCommon.ReadTest<DecimalType>(engine, "Good", "NumberFormat2.txt");
Expand Down
158 changes: 158 additions & 0 deletions FileHelpers.Tests/Tests/Converters/DefaultCultureInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
using NUnit.Framework;

namespace FileHelpers.Tests.Converters
{
[TestFixture]
public class DefaultCultureInfo
{
[DelimitedRecord("|")]
public class RecordWithoutSpecifiedCulture
{
public decimal DecimalField;
}

[DelimitedRecord("|", "fr-FR")]
public class RecordWithDefaultCulture
{
public decimal DecimalFieldWithoutCulture;


[FieldConverter(ConverterKind.Decimal, "en-US")]
public decimal DecimalFieldWithEnglishCulture;
}

[DelimitedRecord("|")]
public class RecordWithFieldCulture
{
[FieldConverter(ConverterKind.Decimal, "fr-FR")]
public decimal DecimalFieldWithFrenchCulture;

public decimal DecimalFieldWithoutCulture;
}


[Test]
public void RecordWithoutCultureHasDefaultSeparator()
{
var engine = new FileHelperEngine<RecordWithoutSpecifiedCulture>();
Assert.AreEqual(1, engine.Options.Fields.Count);
var decimalConverter = engine.Options.Fields[0].Converter;
AssertCanConvertEnglishNumbers(decimalConverter);
}

[Test]
public void RecordWithSpecifiedCultureInRecordAttributeUsesThatCultureByDefault()
{
var engine = new FileHelperEngine<RecordWithDefaultCulture>();
Assert.AreEqual(2, engine.Options.Fields.Count);
var decimalConverterWithoutCulture = engine.Options.Fields[0].Converter;
AssertCanConvertFrenchNumbers(decimalConverterWithoutCulture);

var decimalConverterWithEnglishCulture = engine.Options.Fields[1].Converter;
AssertCanConvertEnglishNumbers(decimalConverterWithEnglishCulture);
}

[Test]
public void FieldWithSpecifiedCultureInFieldConverterAttributeUsesThatCulture()
{
var engine = new FileHelperEngine<RecordWithFieldCulture>();
Assert.AreEqual(2, engine.Options.Fields.Count);
var decimalConverterWithFrenchCulture = engine.Options.Fields[0].Converter;
AssertCanConvertFrenchNumbers(decimalConverterWithFrenchCulture);

var decimalConverterWithoutCulture = engine.Options.Fields[1].Converter;
AssertCanConvertEnglishNumbers(decimalConverterWithoutCulture);
}

#region Helpers
private static void AssertCanConvertEnglishNumbers(ConverterBase decimalConverter)
{
Assert.AreEqual(123.12,
decimalConverter.StringToField("123.12"),
"If no culture is specified, the decimal separator should be a dot");
Assert.AreEqual(1234.12,
decimalConverter.StringToField("1,234.12"),
"If no culture is specified, the group separator should be a comma");
}

private static void AssertCanConvertFrenchNumbers(ConverterBase decimalConverterWithoutCulture)
{
Assert.AreEqual(1.23, decimalConverterWithoutCulture.StringToField("1,23"), "If a culture is specified, the decimal separator should be the specified culture decimal separator");
Assert.AreEqual(1234.12, decimalConverterWithoutCulture.StringToField("1 234,12"), "If a culture is specified, the group separator should be the specified culture group separator");
Assert.Catch(() => { decimalConverterWithoutCulture.StringToField("1.23"); }, "The dot is not a valid french separator");
}
#endregion

[DelimitedRecord("|", defaultCultureName: "fr-FR")]
public class DecimalTypeWithFrenchConversionAsAWhole
{
public int IntField;
public float FloatField;
public double DoubleField;
public decimal DecimalField;
}

[DelimitedRecord("|")]
public class DecimalTypeWithFrenchConversion
{
[FieldConverter(ConverterKind.Int32, "fr-FR")]
public int IntField;
[FieldConverter(ConverterKind.Single, "fr-FR")]
public float FloatField;
[FieldConverter(ConverterKind.Double, "fr-FR")]
public double DoubleField;
[FieldConverter(ConverterKind.Decimal, "fr-FR")]
public decimal DecimalField;
}

[Test]
public void DecimalsWithFrenchCulture()
{
var engine = new FileHelperEngine<DecimalTypeWithFrenchConversion>();
var res = TestCommon.ReadTest<DecimalTypeWithFrenchConversion>(engine, "Good", "NumberFormatFrench.txt");

Assert.AreEqual(3, res.Length);

Assert.AreEqual(10248, res[0].IntField);
CheckDecimal((decimal)32.38, res[0]);

Assert.AreEqual(10249, res[1].IntField);
CheckDecimal((decimal)1011.61, res[1]);

Assert.AreEqual(10250, res[2].IntField);
CheckDecimal((decimal)1165.83, res[2]);
}

[Test]
public void DecimalsWithFrenchCulture2()
{
var engine = new FileHelperEngine<DecimalTypeWithFrenchConversionAsAWhole>();
var res = TestCommon.ReadTest<DecimalTypeWithFrenchConversionAsAWhole>(engine, "Good", "NumberFormatFrench.txt");

Assert.AreEqual(3, res.Length);

Assert.AreEqual(10248, res[0].IntField);
CheckDecimal((decimal)32.38, res[0]);

Assert.AreEqual(10249, res[1].IntField);
CheckDecimal((decimal)1011.61, res[1]);

Assert.AreEqual(10250, res[2].IntField);
CheckDecimal((decimal)1165.83, res[2]);
}

private static void CheckDecimal(decimal dec, DecimalTypeWithFrenchConversion res)
{
Assert.AreEqual((decimal)dec, res.DecimalField);
Assert.AreEqual((double)dec, res.DoubleField);
Assert.AreEqual((float)dec, res.FloatField);
}

private static void CheckDecimal(decimal dec, DecimalTypeWithFrenchConversionAsAWhole res)
{
Assert.AreEqual((decimal)dec, res.DecimalField);
Assert.AreEqual((double)dec, res.DoubleField);
Assert.AreEqual((float)dec, res.FloatField);
}
}
}
3 changes: 2 additions & 1 deletion FileHelpers/Attributes/DelimitedRecordAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ public sealed class DelimitedRecordAttribute : TypedRecordAttribute

/// <summary>Indicates that this class represents a delimited record. </summary>
/// <param name="delimiter">The separator string used to split the fields of the record.</param>
public DelimitedRecordAttribute(string delimiter)
/// <param name="defaultCultureName">Default culture name used for each properties if no converter is specified otherwise. If null, the default decimal separator (".") will be used.</param>
public DelimitedRecordAttribute(string delimiter, string defaultCultureName = null) : base(defaultCultureName: defaultCultureName)
{
if (Separator != String.Empty)
this.Separator = delimiter;
Expand Down
3 changes: 2 additions & 1 deletion FileHelpers/Attributes/FixedLengthRecordAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ public FixedLengthRecordAttribute()
/// specified variable length record behavior.
/// </summary>
/// <param name="fixedMode">The <see cref="FileHelpers.FixedMode"/> used for variable length records. By Default is FixedMode.ExactLength</param>
public FixedLengthRecordAttribute(FixedMode fixedMode)
/// <param name="defaultCultureName">Default culture name used for each properties if no converter is specified otherwise. If null, the default decimal separator (".") will be used.</param>
public FixedLengthRecordAttribute(FixedMode fixedMode, string defaultCultureName = null) : base(defaultCultureName: defaultCultureName)
{
FixedMode = fixedMode;
}
Expand Down
11 changes: 10 additions & 1 deletion FileHelpers/Attributes/TypedRecordAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,19 @@ namespace FileHelpers
public abstract class TypedRecordAttribute
: Attribute
{
/// <summary>
/// Default culture name used for each properties if no converter is specified otherwise. If null, the default decimal separator (".") will be used.
/// </summary>
public string DefaultCultureName { get; private set; }

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Auto propety can be get only.


#region " Constructors "

/// <summary>Abstract class, see inheritors.</summary>
protected TypedRecordAttribute() {}
protected TypedRecordAttribute(string defaultCultureName)
{
this.DefaultCultureName = defaultCultureName;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"this" qualifier is not necessary

}

#endregion
}
Expand Down
Loading