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

Added DelimitedFieldPaddingAttribute #373

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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: 3 additions & 0 deletions FileHelpers.FSharp.Tests/FileHelpers.FSharp.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@
<PackageReference Include="NUnit">
<Version>3.12.0</Version>
</PackageReference>
<PackageReference Include="NUnit3TestAdapter">
<Version>3.17.0</Version>
</PackageReference>
<PackageReference Include="System.Collections.Immutable">
<Version>1.5.0</Version>
</PackageReference>
Expand Down
4 changes: 4 additions & 0 deletions FileHelpers.Tests/FileHelpers.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@
<Compile Include="Tests\Common\ChineseSupport.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Tests\Common\DelimitedFieldPadding.cs" />
<Compile Include="Tests\Common\DynamicOptions.cs" />
<Compile Include="Tests\Common\FieldNotEmpty.cs" />
<Compile Include="Tests\Common\HeaderText.cs" />
Expand Down Expand Up @@ -658,6 +659,9 @@
<PackageReference Include="NUnit">
<Version>3.12.0</Version>
</PackageReference>
<PackageReference Include="NUnit3TestAdapter">
<Version>3.17.0</Version>
</PackageReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
Expand Down
193 changes: 193 additions & 0 deletions FileHelpers.Tests/Tests/Common/DelimitedFieldPadding.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
using System;
using System.Collections.Generic;
using NUnit.Framework;

namespace FileHelpers.Tests.CommonTests
{
[TestFixture]
public class DelimitedFieldPadding
{

[DelimitedRecord(",")]
private class AlignCenterSample
{
public AlignCenterSample()
{

}

public AlignCenterSample(string name, int amount, DateTime date )
{
this.Name = name;
this.Amount = amount;
this.Date = date;
}


[DelimitedFieldPadding(6, AlignMode.Center, '+')]
public string Name { get; set; }

[DelimitedFieldPadding(5, AlignMode.Center, '+')]
[FieldConverter(ConverterKind.Int32)]
public int Amount { get; set; }

[DelimitedFieldPadding(12, AlignMode.Center, '+')]
[FieldConverter(ConverterKind.Date, "yyyy-MM-dd")]
public DateTime Date { get; set; }
}


[Test]
public void TestPaddingCenterAlign()
{

List<AlignCenterSample> records = new List<AlignCenterSample>();
records.Add(new AlignCenterSample("AA", 100, new DateTime(2020, 1, 1)));


var engine = new FileHelperEngine<AlignCenterSample>();
string output = engine.WriteString(records).TrimEnd();

string expected = "++AA++,+100+,+2020-01-01+";
Copy link
Collaborator

Choose a reason for hiding this comment

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

Given the value would be "AAA" and the field length would be 4:

" AAA" or "AAA " ?


Assert.AreEqual(expected, output);
}


[DelimitedRecord(",")]
private class AlignLeftSample
{
public AlignLeftSample()
{

}

public AlignLeftSample(string name, int amount, DateTime date)
{
this.Name = name;
this.Amount = amount;
this.Date = date;
}


[DelimitedFieldPadding(6, AlignMode.Left, ' ')]
public string Name { get; set; }

[DelimitedFieldPadding(5, AlignMode.Left, ' ')]
[FieldConverter(ConverterKind.Int32)]
public int Amount { get; set; }

[DelimitedFieldPadding(12, AlignMode.Left, '*')]
[FieldConverter(ConverterKind.Date, "yyyy-MM-dd")]
public DateTime Date { get; set; }
}


[Test]
public void TestPaddingLeftAlign()
{

var records = new List<AlignLeftSample>();
records.Add(new AlignLeftSample("AA", 100, new DateTime(2020, 1, 1)));


var engine = new FileHelperEngine<AlignLeftSample>();
string output = engine.WriteString(records).TrimEnd();

string expected = "AA ,100 ,2020-01-01**";
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the expectation should be the other way round.

The .Net string behaves as follows
var text = "AA".PadLeft(6);
// text is now " AA"


Assert.AreEqual(expected, output);
}


[DelimitedRecord(",")]
private class AlignRightSample
{
public AlignRightSample()
{

}

public AlignRightSample(string name, int amount, DateTime date)
{
this.Name = name;
this.Amount = amount;
this.Date = date;
}


[DelimitedFieldPadding(6, AlignMode.Right, ' ')]
public string Name { get; set; }

[DelimitedFieldPadding(5, AlignMode.Right, '*')]
[FieldConverter(ConverterKind.Int32)]
public int Amount { get; set; }

[DelimitedFieldPadding(12, AlignMode.Right, '+')]
[FieldConverter(ConverterKind.Date, "yyyy-MM-dd")]
public DateTime Date { get; set; }
}




[Test]
public void TestPaddingRightAlign()
{

var records = new List<AlignRightSample>();
records.Add(new AlignRightSample("AA", 100, new DateTime(2020, 1, 1)));


var engine = new FileHelperEngine<AlignRightSample>();
string output = engine.WriteString(records).TrimEnd();

string expected = " AA,**100,++2020-01-01";
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same as left above: I think it should be the other way round.


Assert.AreEqual(expected, output);
}


[FixedLengthRecord]
private class FixedWithWithDelimitedFiledPaddingSample
{
public FixedWithWithDelimitedFiledPaddingSample()
{

}

public FixedWithWithDelimitedFiledPaddingSample(string name, string description)
{
this.Name = name;
this.Description = description;
}

[DelimitedFieldPadding(10, AlignMode.Left, ' ')]
[FieldFixedLength(10)]
public string Name { get; set; }

[DelimitedFieldPadding(50, AlignMode.Left, ' ')]
[FieldFixedLength(50)]
public string Description { get; set; }


}







[Test]
public void DelimitedFieldPaddingInvalidOnFixedWidthFile()
{

Assert.Throws<BadUsageException>(() =>
{
var engine = new FileHelperEngine<FixedWithWithDelimitedFiledPaddingSample>();
});

}
}
}
45 changes: 45 additions & 0 deletions FileHelpers/Attributes/DelimitedFieldPaddingAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System;


namespace FileHelpers
{
/// <summary>
/// Supports padding when applied to a Delimited record field or property
/// </summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class DelimitedFieldPaddingAttribute : Attribute
{
/// <summary>
/// Total length of the fields in the output file.
/// </summary>
public int TotalLength { get; private set; }

/// <summary>
/// The position of the alignment.
/// </summary>
public AlignMode AlignMode { get; private set; }

/// <summary>
/// The character for padding.
/// </summary>
public char PaddingChar { get; private set; }


/// <summary>
/// Adds padding for a delimited file record field
/// </summary>
/// <param name="totalLength">Total length</param>
/// <param name="alignMode">Alignment position</param>
/// <param name="paddingChar">Character used for padding</param>
public DelimitedFieldPaddingAttribute(int totalLength, AlignMode alignMode, char paddingChar)
{

this.PaddingChar = paddingChar;

this.TotalLength = totalLength;

this.AlignMode = alignMode;

}
}
}
53 changes: 53 additions & 0 deletions FileHelpers/Fields/DelimitedField.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Globalization;
using System.Reflection;
using System.Text;
Expand Down Expand Up @@ -186,6 +187,10 @@ internal override void CreateFieldString(StringBuilder sb, object fieldValue, bo
{
string field = base.CreateFieldString(fieldValue);


if (this.DelimitedFieldPaddingChar.HasValue && this.DelimitedTotalLength > 0 && field != null && field.Length < this.DelimitedTotalLength)
field = this.applyDelimitedFieldPadding(field);

bool hasNewLine = mCompare.IndexOf(field, StringHelper.NewLine, CompareOptions.Ordinal) >= 0;

// If have a new line and this is not allowed. We throw an exception
Expand Down Expand Up @@ -214,6 +219,54 @@ internal override void CreateFieldString(StringBuilder sb, object fieldValue, bo
sb.Append(Separator);
}

private string applyDelimitedFieldPadding(string baseFieldValue)
{

string safeFieldValue = baseFieldValue ?? String.Empty;

string formattedOutput = null;



if (baseFieldValue != null && this.DelimitedTotalLength > 0 && baseFieldValue.Length < this.DelimitedTotalLength && this.DelimitedFieldPaddingChar.HasValue)
{
switch (this.DelimitedFieldAlignMode)
{
case AlignMode.Left:
formattedOutput = safeFieldValue.PadRight(this.DelimitedTotalLength, this.DelimitedFieldPaddingChar.Value);
break;

case AlignMode.Right:
formattedOutput = safeFieldValue.PadLeft(this.DelimitedTotalLength, this.DelimitedFieldPaddingChar.Value);
break;

case AlignMode.Center:
formattedOutput = this.padCenter(safeFieldValue);
break;


}

}
else
formattedOutput = baseFieldValue;


return formattedOutput;
}

private string padCenter(string baseFieldValue)
{
if (baseFieldValue == null)
throw new NullReferenceException("baseFieldValue");

int totalPaddingCount = this.DelimitedTotalLength - baseFieldValue.Length;

int padLeftCount = totalPaddingCount / 2 + baseFieldValue.Length;

return baseFieldValue.PadLeft(padLeftCount, this.DelimitedFieldPaddingChar.GetValueOrDefault()).PadRight(this.DelimitedTotalLength, this.DelimitedFieldPaddingChar.GetValueOrDefault());
}

/// <summary>
/// create a field base class and populate the delimited values
/// base class will add its own values
Expand Down
Loading