From 06e55af210ce1d33f0974b5de94316ec1f446de9 Mon Sep 17 00:00:00 2001 From: Matthew Hamilton Date: Mon, 6 Aug 2018 21:21:16 -0500 Subject: [PATCH 1/6] Fix spelling of 'builder'. --- src/FlatFile.Core/Base/FlatFileEngine.cs | 2 +- .../Base/{LineBulderBase.cs => LineBuilderBase.cs} | 4 ++-- src/FlatFile.Core/FlatFile.Core.csproj | 4 ++-- src/FlatFile.Core/{ILineBulder.cs => ILineBuilder.cs} | 2 +- src/FlatFile.Core/ILineBuilderFactory.cs | 2 +- src/FlatFile.Delimited/IDelimitedLineBuilder.cs | 2 +- .../Implementation/DelimetedFileMultiEngine.cs | 2 +- src/FlatFile.Delimited/Implementation/DelimitedFileEngine.cs | 2 +- src/FlatFile.Delimited/Implementation/DelimitedLineBuilder.cs | 2 +- src/FlatFile.FixedLength/IFixedLengthLineBuilder.cs | 2 +- .../Implementation/FixedLengthFileEngine.cs | 2 +- .../Implementation/FixedLengthFileMultiEngine.cs | 2 +- .../Implementation/FixedLengthLineBuilder.cs | 2 +- 13 files changed, 15 insertions(+), 15 deletions(-) rename src/FlatFile.Core/Base/{LineBulderBase.cs => LineBuilderBase.cs} (85%) rename src/FlatFile.Core/{ILineBulder.cs => ILineBuilder.cs} (69%) 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 85% rename from src/FlatFile.Core/Base/LineBulderBase.cs rename to src/FlatFile.Core/Base/LineBuilderBase.cs index 1bbfa2d..8a6797e 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; } diff --git a/src/FlatFile.Core/FlatFile.Core.csproj b/src/FlatFile.Core/FlatFile.Core.csproj index 08ab631..d20d4cf 100644 --- a/src/FlatFile.Core/FlatFile.Core.csproj +++ b/src/FlatFile.Core/FlatFile.Core.csproj @@ -100,7 +100,7 @@ - + @@ -117,7 +117,7 @@ - + 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.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/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/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) From 44df85ca5a3c6804c78be38b13ab67899c294d67 Mon Sep 17 00:00:00 2001 From: Matthew Hamilton Date: Mon, 6 Aug 2018 21:44:18 -0500 Subject: [PATCH 2/6] Add PropertyInfo to ITypeConverter members. --- .../Converters/CsvHelperTypeConverterForCustomType.cs | 4 ++-- .../Converters/FlatFileTypeConverterForCustomType.cs | 5 +++-- src/FlatFile.Core/Base/LineParserBase.cs | 7 ++++--- src/FlatFile.Core/ITypeConverter.cs | 5 +++-- .../Delimited/DelimitedAttributeMappingIntegrationTests.cs | 2 +- 5 files changed, 13 insertions(+), 10 deletions(-) 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/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/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.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); From b9563c471509d60d875c3a9ace0cf8188eeb8a1d Mon Sep 17 00:00:00 2001 From: Matthew Hamilton Date: Mon, 6 Aug 2018 21:44:52 -0500 Subject: [PATCH 3/6] Use type converter when building lines. --- src/FlatFile.Core/Base/LineBuilderBase.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/FlatFile.Core/Base/LineBuilderBase.cs b/src/FlatFile.Core/Base/LineBuilderBase.cs index 8a6797e..234b12e 100644 --- a/src/FlatFile.Core/Base/LineBuilderBase.cs +++ b/src/FlatFile.Core/Base/LineBuilderBase.cs @@ -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 From e858c039157a2605984d1af1a5186435f575c4e9 Mon Sep 17 00:00:00 2001 From: Matthew Hamilton Date: Tue, 7 Aug 2018 01:23:06 -0500 Subject: [PATCH 4/6] Implement field settings builder methods that take lambdas. Also add tests and the xunit Visual Studio runner. --- src/FlatFile.Core/Base/TypeConverterBase.cs | 36 ++++++++++ src/FlatFile.Core/DelegatingTypeConverter.cs | 37 ++++++++++ src/FlatFile.Core/FlatFile.Core.csproj | 2 + .../IFieldSettingsConstructor.cs | 3 + .../DelimitedFieldSettingsConstructor.cs | 27 ++++++++ .../FixedFieldSettingsConstructor.cs | 26 +++++++ .../Delimited/DelimitedLineBuilderTests.cs | 68 +++++++++++++++++++ .../Delimited/DelimitedLineParserTests.cs | 60 ++++++++++++++++ .../FixedLengthLineBuilderTests.cs | 68 +++++++++++++++++++ .../FixedLength/FixedLengthLineParserTests.cs | 43 ++++++++++++ src/FlatFile.Tests/FlatFile.Tests.csproj | 12 ++++ src/FlatFile.Tests/packages.config | 1 + 12 files changed, 383 insertions(+) create mode 100644 src/FlatFile.Core/Base/TypeConverterBase.cs create mode 100644 src/FlatFile.Core/DelegatingTypeConverter.cs create mode 100644 src/FlatFile.Tests/Delimited/DelimitedLineBuilderTests.cs create mode 100644 src/FlatFile.Tests/Delimited/DelimitedLineParserTests.cs create mode 100644 src/FlatFile.Tests/FixedLength/FixedLengthLineBuilderTests.cs 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 d20d4cf..052a837 100644 --- a/src/FlatFile.Core/FlatFile.Core.csproj +++ b/src/FlatFile.Core/FlatFile.Core.csproj @@ -102,6 +102,8 @@ + + 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.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.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.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}. + + +