diff --git a/.gitignore b/.gitignore index 6feb516..b36df8f 100644 --- a/.gitignore +++ b/.gitignore @@ -157,3 +157,5 @@ $RECYCLE.BIN/ assets/FlatFile.Core.Compiled.nuspec assets/FlatFile.Delimited.Compiled.nuspec assets/FlatFile.FixedLength.Compiled.nuspec + +.vs/ \ No newline at end of file diff --git a/src/FlatFile.Benchmark/Converters/CsvHelperTypeConverterForCustomType.cs b/src/FlatFile.Benchmark/Converters/CsvHelperTypeConverterForCustomType.cs index 8f82fab..75ac847 100644 --- a/src/FlatFile.Benchmark/Converters/CsvHelperTypeConverterForCustomType.cs +++ b/src/FlatFile.Benchmark/Converters/CsvHelperTypeConverterForCustomType.cs @@ -14,12 +14,12 @@ public CsvHelperTypeConverterForCustomType() public string ConvertToString(CsvHelperTypeConversion.TypeConverterOptions options, object value) { - return converter.ConvertToString(value); + return converter.ConvertToString(value, null); } public object ConvertFromString(CsvHelperTypeConversion.TypeConverterOptions options, string text) { - return converter.ConvertFromString(text); + return converter.ConvertFromString(text, null); } public bool CanConvertFrom(Type type) diff --git a/src/FlatFile.Benchmark/Converters/FlatFileTypeConverterForCustomType.cs b/src/FlatFile.Benchmark/Converters/FlatFileTypeConverterForCustomType.cs index 148e297..3c6abcb 100644 --- a/src/FlatFile.Benchmark/Converters/FlatFileTypeConverterForCustomType.cs +++ b/src/FlatFile.Benchmark/Converters/FlatFileTypeConverterForCustomType.cs @@ -1,6 +1,7 @@ namespace FlatFile.Benchmark.Converters { using System; + using System.Reflection; using FlatFile.Benchmark.Entities; using FlatFile.Core; @@ -16,13 +17,13 @@ public bool CanConvertTo(Type type) return type == typeof (CustomType); } - public string ConvertToString(object source) + public string ConvertToString(object source, PropertyInfo sourceProperty) { var obj = (CustomType)source; return string.Format("{0}|{1}|{2}", obj.First, obj.Second, obj.Third); } - public object ConvertFromString(string source) + public object ConvertFromString(string source, PropertyInfo targetProperty) { var values = source.Split('|'); diff --git a/src/FlatFile.Core/Base/FlatFileEngine.cs b/src/FlatFile.Core/Base/FlatFileEngine.cs index 22d18a3..d87d3d5 100644 --- a/src/FlatFile.Core/Base/FlatFileEngine.cs +++ b/src/FlatFile.Core/Base/FlatFileEngine.cs @@ -24,7 +24,7 @@ public abstract class FlatFileEngine : IFlatF /// Gets the line builder. /// /// The line builder. - protected abstract ILineBulder LineBuilder { get; } + protected abstract ILineBuilder LineBuilder { get; } /// /// Gets the line parser. diff --git a/src/FlatFile.Core/Base/LineBulderBase.cs b/src/FlatFile.Core/Base/LineBuilderBase.cs similarity index 58% rename from src/FlatFile.Core/Base/LineBulderBase.cs rename to src/FlatFile.Core/Base/LineBuilderBase.cs index 1bbfa2d..234b12e 100644 --- a/src/FlatFile.Core/Base/LineBulderBase.cs +++ b/src/FlatFile.Core/Base/LineBuilderBase.cs @@ -1,12 +1,12 @@ namespace FlatFile.Core.Base { - public abstract class LineBulderBase : ILineBulder + public abstract class LineBuilderBase : ILineBuilder where TLayoutDescriptor : ILayoutDescriptor where TFieldSettings : IFieldSettingsContainer { private readonly TLayoutDescriptor _descriptor; - protected LineBulderBase(TLayoutDescriptor descriptor) + protected LineBuilderBase(TLayoutDescriptor descriptor) { this._descriptor = descriptor; } @@ -21,7 +21,7 @@ protected TLayoutDescriptor Descriptor protected virtual string GetStringValueFromField(TFieldSettings field, object fieldValue) { string lineValue = fieldValue != null - ? fieldValue.ToString() + ? ConvertToString(field, fieldValue) : field.NullValue ?? string.Empty; lineValue = TransformFieldValue(field, lineValue); @@ -33,5 +33,14 @@ protected virtual string TransformFieldValue(TFieldSettings field, string lineVa { return lineValue; } + + private static string ConvertToString(TFieldSettings field, object fieldValue) + { + var converter = field.TypeConverter; + if (converter != null && converter.CanConvertTo(typeof(string)) && converter.CanConvertFrom(field.PropertyInfo.PropertyType)) + return field.TypeConverter.ConvertToString(fieldValue, field.PropertyInfo); + + return fieldValue.ToString(); + } } } \ No newline at end of file diff --git a/src/FlatFile.Core/Base/LineParserBase.cs b/src/FlatFile.Core/Base/LineParserBase.cs index 9a802fc..78f2d16 100644 --- a/src/FlatFile.Core/Base/LineParserBase.cs +++ b/src/FlatFile.Core/Base/LineParserBase.cs @@ -1,6 +1,7 @@ namespace FlatFile.Core.Base { using System; + using System.Reflection; using FlatFile.Core.Extensions; public abstract class LineParserBase : ILineParser @@ -39,7 +40,7 @@ protected virtual object GetFieldValueFromString(TFieldSettings fieldSettings, s object obj; - if (!fieldSettings.TypeConverter.ConvertFromStringTo(memberValue, type, out obj)) + if (!fieldSettings.TypeConverter.ConvertFromStringTo(memberValue, type, fieldSettings.PropertyInfo, out obj)) { obj = memberValue.Convert(type); } @@ -56,11 +57,11 @@ protected virtual string TransformStringValue(TFieldSettings fieldSettingsBuilde public static class TypeConverterExtensions { - public static bool ConvertFromStringTo(this ITypeConverter converter, string source, Type targetType, out object obj) + public static bool ConvertFromStringTo(this ITypeConverter converter, string source, Type targetType, PropertyInfo targetProperty, out object obj) { if (converter != null && converter.CanConvertFrom(typeof(string)) && converter.CanConvertTo(targetType)) { - obj = converter.ConvertFromString(source); + obj = converter.ConvertFromString(source, targetProperty); return true; } diff --git a/src/FlatFile.Core/Base/TypeConverterBase.cs b/src/FlatFile.Core/Base/TypeConverterBase.cs new file mode 100644 index 0000000..9bf82bb --- /dev/null +++ b/src/FlatFile.Core/Base/TypeConverterBase.cs @@ -0,0 +1,36 @@ +using System; +using System.Reflection; + +namespace FlatFile.Core.Base +{ + /// + /// A generic base class for converting between strings and a given type. + /// + /// The type to convert to and from a string. + public abstract class TypeConverterBase : ITypeConverter + { + public virtual bool CanConvertFrom(Type type) + { + return type == typeof(string) || type == typeof(TValue); + } + + public virtual bool CanConvertTo(Type type) + { + return type == typeof(string) || type == typeof(TValue); + } + + public object ConvertFromString(string source, PropertyInfo targetProperty) + { + return ConvertFrom(source, targetProperty); + } + + protected abstract TValue ConvertFrom(string source, PropertyInfo targetProperty); + + public string ConvertToString(object source, PropertyInfo sourceProperty) + { + return ConvertTo((TValue)source, sourceProperty); + } + + protected abstract string ConvertTo(TValue source, PropertyInfo sourceProperty); + } +} diff --git a/src/FlatFile.Core/DelegatingTypeConverter.cs b/src/FlatFile.Core/DelegatingTypeConverter.cs new file mode 100644 index 0000000..f991a77 --- /dev/null +++ b/src/FlatFile.Core/DelegatingTypeConverter.cs @@ -0,0 +1,37 @@ +using System; +using System.Reflection; + +namespace FlatFile.Core +{ + /// + /// An implementation of that uses delegates for conversion. + /// + class DelegatingTypeConverter : ITypeConverter + { + internal Func ConversionFromString { get; set; } + + internal Func ConversionToString { get; set; } + + public bool CanConvertFrom(Type type) + { + return (type == typeof(string) && ConversionFromString != null) || + (type == typeof(TProperty) && ConversionToString != null); + } + + public bool CanConvertTo(Type type) + { + return (type == typeof(string) && ConversionToString != null) || + (type == typeof(TProperty) && ConversionFromString != null); + } + + public object ConvertFromString(string source, PropertyInfo targetProperty) + { + return ConversionFromString(source); + } + + public string ConvertToString(object source, PropertyInfo sourceProperty) + { + return ConversionToString((TProperty)source); + } + } +} diff --git a/src/FlatFile.Core/FlatFile.Core.csproj b/src/FlatFile.Core/FlatFile.Core.csproj index 08ab631..052a837 100644 --- a/src/FlatFile.Core/FlatFile.Core.csproj +++ b/src/FlatFile.Core/FlatFile.Core.csproj @@ -100,8 +100,10 @@ - + + + @@ -117,7 +119,7 @@ - + diff --git a/src/FlatFile.Core/IFieldSettingsConstructor.cs b/src/FlatFile.Core/IFieldSettingsConstructor.cs index 4acca7e..45e63c7 100644 --- a/src/FlatFile.Core/IFieldSettingsConstructor.cs +++ b/src/FlatFile.Core/IFieldSettingsConstructor.cs @@ -1,11 +1,14 @@ namespace FlatFile.Core { using FlatFile.Core.Base; + using System; public interface IFieldSettingsConstructor : IFieldSettingsContainer where TConstructor : IFieldSettingsConstructor { TConstructor AllowNull(string nullValue); TConstructor WithTypeConverter() where TConverter : ITypeConverter; + TConstructor WithConversionFromString(Func conversion); + TConstructor WithConversionToString(Func conversion); } } \ No newline at end of file diff --git a/src/FlatFile.Core/ILineBulder.cs b/src/FlatFile.Core/ILineBuilder.cs similarity index 69% rename from src/FlatFile.Core/ILineBulder.cs rename to src/FlatFile.Core/ILineBuilder.cs index 7d3e923..de3ca92 100644 --- a/src/FlatFile.Core/ILineBulder.cs +++ b/src/FlatFile.Core/ILineBuilder.cs @@ -1,6 +1,6 @@ namespace FlatFile.Core { - public interface ILineBulder + public interface ILineBuilder { string BuildLine(T entry); } diff --git a/src/FlatFile.Core/ILineBuilderFactory.cs b/src/FlatFile.Core/ILineBuilderFactory.cs index f2c561b..c649c0d 100644 --- a/src/FlatFile.Core/ILineBuilderFactory.cs +++ b/src/FlatFile.Core/ILineBuilderFactory.cs @@ -5,7 +5,7 @@ namespace FlatFile.Core public interface ILineBuilderFactory where TFieldSettings : IFieldSettings where TLayout : ILayoutDescriptor - where TBuilder : ILineBulder + where TBuilder : ILineBuilder { TBuilder GetBuilder(TLayout layout); } diff --git a/src/FlatFile.Core/ITypeConverter.cs b/src/FlatFile.Core/ITypeConverter.cs index f199ea8..06b7143 100644 --- a/src/FlatFile.Core/ITypeConverter.cs +++ b/src/FlatFile.Core/ITypeConverter.cs @@ -1,6 +1,7 @@ namespace FlatFile.Core { using System; + using System.Reflection; public interface ITypeConverter { @@ -8,8 +9,8 @@ public interface ITypeConverter bool CanConvertTo(Type type); - string ConvertToString(object source); + string ConvertToString(object source, PropertyInfo sourceProperty); - object ConvertFromString(string source); + object ConvertFromString(string source, PropertyInfo targetProperty); } } \ No newline at end of file diff --git a/src/FlatFile.Delimited/IDelimitedLineBuilder.cs b/src/FlatFile.Delimited/IDelimitedLineBuilder.cs index 3d2cf7f..3c822d9 100644 --- a/src/FlatFile.Delimited/IDelimitedLineBuilder.cs +++ b/src/FlatFile.Delimited/IDelimitedLineBuilder.cs @@ -2,7 +2,7 @@ { using FlatFile.Core; - public interface IDelimitedLineBuilder : ILineBulder + public interface IDelimitedLineBuilder : ILineBuilder { } } \ No newline at end of file diff --git a/src/FlatFile.Delimited/Implementation/DelimetedFileMultiEngine.cs b/src/FlatFile.Delimited/Implementation/DelimetedFileMultiEngine.cs index 215d974..bbf5f97 100644 --- a/src/FlatFile.Delimited/Implementation/DelimetedFileMultiEngine.cs +++ b/src/FlatFile.Delimited/Implementation/DelimetedFileMultiEngine.cs @@ -79,7 +79,7 @@ internal DelimitedFileMultiEngine( /// The line builder. /// The does not contain just a single line builder. /// - protected override ILineBulder LineBuilder { get { throw new NotImplementedException(); } } + protected override ILineBuilder LineBuilder { get { throw new NotImplementedException(); } } /// /// Gets the line parser. diff --git a/src/FlatFile.Delimited/Implementation/DelimitedFieldSettingsConstructor.cs b/src/FlatFile.Delimited/Implementation/DelimitedFieldSettingsConstructor.cs index 2124a0f..8f3cdbc 100644 --- a/src/FlatFile.Delimited/Implementation/DelimitedFieldSettingsConstructor.cs +++ b/src/FlatFile.Delimited/Implementation/DelimitedFieldSettingsConstructor.cs @@ -1,5 +1,6 @@ namespace FlatFile.Delimited.Implementation { + using System; using System.Reflection; using FlatFile.Core; using FlatFile.Core.Extensions; @@ -25,6 +26,32 @@ public IDelimitedFieldSettingsConstructor WithTypeConverter() where return this; } + public IDelimitedFieldSettingsConstructor WithConversionFromString(Func conversion) + { + if (TypeConverter == null) + TypeConverter = new DelegatingTypeConverter(); + + if (TypeConverter is DelegatingTypeConverter) + ((DelegatingTypeConverter)TypeConverter).ConversionFromString = conversion; + else + throw new InvalidOperationException("A type converter has already been explicitly set."); + + return this; + } + + public IDelimitedFieldSettingsConstructor WithConversionToString(Func conversion) + { + if (TypeConverter == null) + TypeConverter = new DelegatingTypeConverter(); + + if (TypeConverter is DelegatingTypeConverter) + ((DelegatingTypeConverter)TypeConverter).ConversionToString = conversion; + else + throw new InvalidOperationException("A type converter has already been explicitly set."); + + return this; + } + public IDelimitedFieldSettingsConstructor WithName(string name) { Name = name; diff --git a/src/FlatFile.Delimited/Implementation/DelimitedFileEngine.cs b/src/FlatFile.Delimited/Implementation/DelimitedFileEngine.cs index cccbd39..6ee7a6b 100644 --- a/src/FlatFile.Delimited/Implementation/DelimitedFileEngine.cs +++ b/src/FlatFile.Delimited/Implementation/DelimitedFileEngine.cs @@ -50,7 +50,7 @@ internal DelimitedFileEngine( /// Gets the line builder. /// /// The line builder. - protected override ILineBulder LineBuilder + protected override ILineBuilder LineBuilder { get { return _builderFactory.GetBuilder(LayoutDescriptor); } } diff --git a/src/FlatFile.Delimited/Implementation/DelimitedLineBuilder.cs b/src/FlatFile.Delimited/Implementation/DelimitedLineBuilder.cs index c7aaf02..e479c04 100644 --- a/src/FlatFile.Delimited/Implementation/DelimitedLineBuilder.cs +++ b/src/FlatFile.Delimited/Implementation/DelimitedLineBuilder.cs @@ -4,7 +4,7 @@ using FlatFile.Core.Base; public class DelimitedLineBuilder : - LineBulderBase, + LineBuilderBase, IDelimitedLineBuilder { public DelimitedLineBuilder(IDelimitedLayoutDescriptor descriptor) diff --git a/src/FlatFile.FixedLength/IFixedLengthLineBuilder.cs b/src/FlatFile.FixedLength/IFixedLengthLineBuilder.cs index 55927a3..d4e0fb4 100644 --- a/src/FlatFile.FixedLength/IFixedLengthLineBuilder.cs +++ b/src/FlatFile.FixedLength/IFixedLengthLineBuilder.cs @@ -2,7 +2,7 @@ namespace FlatFile.FixedLength { using FlatFile.Core; - public interface IFixedLengthLineBuilder : ILineBulder + public interface IFixedLengthLineBuilder : ILineBuilder { } } \ No newline at end of file diff --git a/src/FlatFile.FixedLength/Implementation/FixedFieldSettingsConstructor.cs b/src/FlatFile.FixedLength/Implementation/FixedFieldSettingsConstructor.cs index e8683be..4ea46fb 100644 --- a/src/FlatFile.FixedLength/Implementation/FixedFieldSettingsConstructor.cs +++ b/src/FlatFile.FixedLength/Implementation/FixedFieldSettingsConstructor.cs @@ -57,5 +57,31 @@ public IFixedFieldSettingsConstructor WithTypeConverter() where TCon this.TypeConverter = ReflectionHelper.CreateInstance(true); return this; } + + public IFixedFieldSettingsConstructor WithConversionFromString(Func conversion) + { + if (TypeConverter == null) + TypeConverter = new DelegatingTypeConverter(); + + if (TypeConverter is DelegatingTypeConverter) + ((DelegatingTypeConverter)TypeConverter).ConversionFromString = conversion; + else + throw new InvalidOperationException("A type converter has already been explicitly set."); + + return this; + } + + public IFixedFieldSettingsConstructor WithConversionToString(Func conversion) + { + if (TypeConverter == null) + TypeConverter = new DelegatingTypeConverter(); + + if (TypeConverter is DelegatingTypeConverter) + ((DelegatingTypeConverter)TypeConverter).ConversionToString = conversion; + else + throw new InvalidOperationException("A type converter has already been explicitly set."); + + return this; + } } } \ No newline at end of file diff --git a/src/FlatFile.FixedLength/Implementation/FixedLengthFileEngine.cs b/src/FlatFile.FixedLength/Implementation/FixedLengthFileEngine.cs index 22686c9..786a710 100644 --- a/src/FlatFile.FixedLength/Implementation/FixedLengthFileEngine.cs +++ b/src/FlatFile.FixedLength/Implementation/FixedLengthFileEngine.cs @@ -44,7 +44,7 @@ internal FixedLengthFileEngine( /// Gets the line builder. /// /// The line builder. - protected override ILineBulder LineBuilder + protected override ILineBuilder LineBuilder { get { return lineBuilderFactory.GetBuilder(LayoutDescriptor); } } diff --git a/src/FlatFile.FixedLength/Implementation/FixedLengthFileMultiEngine.cs b/src/FlatFile.FixedLength/Implementation/FixedLengthFileMultiEngine.cs index 9226d09..013c2b5 100644 --- a/src/FlatFile.FixedLength/Implementation/FixedLengthFileMultiEngine.cs +++ b/src/FlatFile.FixedLength/Implementation/FixedLengthFileMultiEngine.cs @@ -79,7 +79,7 @@ internal FixedLengthFileMultiEngine( /// The line builder. /// The does not contain just a single line builder. /// - protected override ILineBulder LineBuilder { get { throw new NotImplementedException(); } } + protected override ILineBuilder LineBuilder { get { throw new NotImplementedException(); } } /// /// Gets the line parser. diff --git a/src/FlatFile.FixedLength/Implementation/FixedLengthLineBuilder.cs b/src/FlatFile.FixedLength/Implementation/FixedLengthLineBuilder.cs index 088ccc6..e49466d 100644 --- a/src/FlatFile.FixedLength/Implementation/FixedLengthLineBuilder.cs +++ b/src/FlatFile.FixedLength/Implementation/FixedLengthLineBuilder.cs @@ -5,7 +5,7 @@ namespace FlatFile.FixedLength.Implementation using FlatFile.Core.Base; public class FixedLengthLineBuilder : - LineBulderBase, IFixedFieldSettingsContainer>, + LineBuilderBase, IFixedFieldSettingsContainer>, IFixedLengthLineBuilder { public FixedLengthLineBuilder(ILayoutDescriptor descriptor) diff --git a/src/FlatFile.Tests/Delimited/DelimitedAttributeMappingIntegrationTests.cs b/src/FlatFile.Tests/Delimited/DelimitedAttributeMappingIntegrationTests.cs index 03b2626..70376e9 100644 --- a/src/FlatFile.Tests/Delimited/DelimitedAttributeMappingIntegrationTests.cs +++ b/src/FlatFile.Tests/Delimited/DelimitedAttributeMappingIntegrationTests.cs @@ -36,7 +36,7 @@ public void EngineShouldCallTypeConverterWhenConverterAttributeIsPresent() { // a converter to convert "A" to "foo" var converter = A.Fake(); - A.CallTo(() => converter.ConvertFromString("A")).Returns("foo"); + A.CallTo(() => converter.ConvertFromString("A", A.Ignored)).Returns("foo"); A.CallTo(() => converter.CanConvertFrom(typeof(string))).Returns(true); A.CallTo(() => converter.CanConvertTo(typeof(string))).Returns(true); diff --git a/src/FlatFile.Tests/Delimited/DelimitedLineBuilderTests.cs b/src/FlatFile.Tests/Delimited/DelimitedLineBuilderTests.cs new file mode 100644 index 0000000..6e8ddc0 --- /dev/null +++ b/src/FlatFile.Tests/Delimited/DelimitedLineBuilderTests.cs @@ -0,0 +1,68 @@ +namespace FlatFile.Tests.Delimited +{ + using FlatFile.Core.Base; + using FlatFile.Delimited; + using FlatFile.Delimited.Implementation; + using FlatFile.Tests.Base.Entities; + using FluentAssertions; + using System; + using System.Globalization; + using System.Reflection; + using Xunit; + + public class DelimitedLineBuilderTests + { + private readonly DelimitedLineBuilder builder; + private readonly IDelimitedLayout layout; + + public DelimitedLineBuilderTests() + { + layout = new DelimitedLayout().WithDelimiter(","); + + builder = new DelimitedLineBuilder(layout); + } + + [Fact] + public void BuilderShouldUseTypeConverter() + { + layout.WithMember(o => o.Id, set => set.WithTypeConverter()); + + var entry = new TestObject + { + Id = 48879 + }; + + var line = builder.BuildLine(entry); + + line.Should().Be("BEEF"); + } + + [Fact] + public void BuilderShouldUseConversionFunction() + { + layout.WithMember(o => o.Id, set => set.WithConversionToString((int id) => id.ToString("X"))); + + var entry = new TestObject + { + Id = 48879 + }; + + var line = builder.BuildLine(entry); + + line.Should().Be("BEEF"); + } + + class IdHexConverter : TypeConverterBase + { + protected override int ConvertFrom(string source, PropertyInfo targetProperty) + { + return Int32.Parse(source, NumberStyles.AllowHexSpecifier); + } + + protected override string ConvertTo(int source, PropertyInfo sourceProperty) + { + return source.ToString("X"); + } + } + } +} diff --git a/src/FlatFile.Tests/Delimited/DelimitedLineParserTests.cs b/src/FlatFile.Tests/Delimited/DelimitedLineParserTests.cs new file mode 100644 index 0000000..04f7669 --- /dev/null +++ b/src/FlatFile.Tests/Delimited/DelimitedLineParserTests.cs @@ -0,0 +1,60 @@ +namespace FlatFile.Tests.Delimited +{ + using FlatFile.Core.Base; + using FlatFile.Delimited; + using FlatFile.Delimited.Implementation; + using FlatFile.Tests.Base.Entities; + using FluentAssertions; + using System; + using System.Globalization; + using System.Reflection; + using Xunit; + + public class DelimitedLineParserTests + { + private readonly DelimitedLineParser parser; + private readonly IDelimitedLayout layout; + + public DelimitedLineParserTests() + { + layout = new DelimitedLayout().WithDelimiter(","); + + parser = new DelimitedLineParser(layout); + } + + [Fact] + public void ParserShouldUseTypeConverter() + { + layout.WithMember(o => o.Id, set => set.WithTypeConverter()); + + var entry = new TestObject(); + var parsedEntity = parser.ParseLine("BEEF", entry); + + parsedEntity.Id.Should().Be(48879); + } + + [Fact] + public void ParserShouldUseConversionFunction() + { + layout.WithMember(o => o.Id, set => set.WithConversionFromString(s => Int32.Parse(s, NumberStyles.AllowHexSpecifier))); + + var entry = new TestObject(); + var parsedEntity = parser.ParseLine("BEEF", entry); + + parsedEntity.Id.Should().Be(48879); + } + + class IdHexConverter : TypeConverterBase + { + protected override int ConvertFrom(string source, PropertyInfo targetProperty) + { + return Int32.Parse(source, NumberStyles.AllowHexSpecifier); + } + + protected override string ConvertTo(int source, PropertyInfo sourceProperty) + { + return source.ToString("X"); + } + } + } +} diff --git a/src/FlatFile.Tests/FixedLength/FixedLengthLineBuilderTests.cs b/src/FlatFile.Tests/FixedLength/FixedLengthLineBuilderTests.cs new file mode 100644 index 0000000..6609035 --- /dev/null +++ b/src/FlatFile.Tests/FixedLength/FixedLengthLineBuilderTests.cs @@ -0,0 +1,68 @@ +namespace FlatFile.Tests.FixedLength +{ + using FlatFile.Core.Base; + using FlatFile.FixedLength; + using FlatFile.FixedLength.Implementation; + using FlatFile.Tests.Base.Entities; + using FluentAssertions; + using System; + using System.Globalization; + using System.Reflection; + using Xunit; + + public class FixedLengthLineBuilderTests + { + private readonly FixedLengthLineBuilder builder; + private readonly IFixedLayout layout; + + public FixedLengthLineBuilderTests() + { + layout = new FixedLayout(); + + builder = new FixedLengthLineBuilder(layout); + } + + [Fact] + public void BuilderShouldUseTypeConverter() + { + layout.WithMember(o => o.Id, set => set.WithLength(4).WithTypeConverter()); + + var entry = new TestObject + { + Id = 48879 + }; + + var line = builder.BuildLine(entry); + + line.Should().Be("BEEF"); + } + + [Fact] + public void BuilderShouldUseConversionFunction() + { + layout.WithMember(o => o.Id, set => set.WithLength(4).WithConversionToString((int id) => id.ToString("X"))); + + var entry = new TestObject + { + Id = 48879 + }; + + var line = builder.BuildLine(entry); + + line.Should().Be("BEEF"); + } + + class IdHexConverter : TypeConverterBase + { + protected override int ConvertFrom(string source, PropertyInfo targetProperty) + { + return Int32.Parse(source, NumberStyles.AllowHexSpecifier); + } + + protected override string ConvertTo(int source, PropertyInfo sourceProperty) + { + return source.ToString("X"); + } + } + } +} diff --git a/src/FlatFile.Tests/FixedLength/FixedLengthLineParserTests.cs b/src/FlatFile.Tests/FixedLength/FixedLengthLineParserTests.cs index a047bb7..bea64aa 100644 --- a/src/FlatFile.Tests/FixedLength/FixedLengthLineParserTests.cs +++ b/src/FlatFile.Tests/FixedLength/FixedLengthLineParserTests.cs @@ -2,10 +2,14 @@ namespace FlatFile.Tests.FixedLength { + using FlatFile.Core.Base; using FlatFile.FixedLength; using FlatFile.FixedLength.Implementation; using FlatFile.Tests.Base.Entities; using FluentAssertions; + using System; + using System.Globalization; + using System.Reflection; public class FixedLengthLineParserTests { @@ -50,5 +54,44 @@ public void ParserShouldSetValueNullValueIfStringIsToShort(string inputString, i parsedEntity.Description.Should().Be(description); parsedEntity.NullableInt.Should().Be(nullableInt); } + + [Fact] + public void ParserShouldUseTypeConverter() + { + layout.WithMember(o => o.Id, set => set.WithLength(4).WithTypeConverter()) + .WithMember(o => o.Description, set => set.WithLength(25).AllowNull(string.Empty)) + .WithMember(o => o.NullableInt, set => set.WithLength(5).AllowNull(string.Empty)); + + var entry = new TestObject(); + var parsedEntity = parser.ParseLine("BEEF", entry); + + parsedEntity.Id.Should().Be(48879); + } + + [Fact] + public void ParserShouldUseConversionFunction() + { + layout.WithMember(o => o.Id, set => set.WithLength(4).WithConversionFromString(s => Int32.Parse(s, NumberStyles.AllowHexSpecifier))) + .WithMember(o => o.Description, set => set.WithLength(25).AllowNull(string.Empty)) + .WithMember(o => o.NullableInt, set => set.WithLength(5).AllowNull(string.Empty)); + + var entry = new TestObject(); + var parsedEntity = parser.ParseLine("BEEF", entry); + + parsedEntity.Id.Should().Be(48879); + } + + class IdHexConverter : TypeConverterBase + { + protected override int ConvertFrom(string source, PropertyInfo targetProperty) + { + return Int32.Parse(source, NumberStyles.AllowHexSpecifier); + } + + protected override string ConvertTo(int source, PropertyInfo sourceProperty) + { + return source.ToString("X"); + } + } } } diff --git a/src/FlatFile.Tests/FlatFile.Tests.csproj b/src/FlatFile.Tests/FlatFile.Tests.csproj index 57f98f9..b4cc6c8 100644 --- a/src/FlatFile.Tests/FlatFile.Tests.csproj +++ b/src/FlatFile.Tests/FlatFile.Tests.csproj @@ -1,5 +1,6 @@  + Debug @@ -13,6 +14,8 @@ 512 ..\ true + + true @@ -79,11 +82,14 @@ + + + @@ -138,6 +144,12 @@ + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + +