Skip to content

Commit

Permalink
Fix #26: Type conversion now uses invariant culture.
Browse files Browse the repository at this point in the history
  • Loading branch information
tillig committed Jan 30, 2020
1 parent 94f35ac commit 1635b86
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 110 deletions.
6 changes: 3 additions & 3 deletions src/Autofac.Configuration/Util/TypeManipulation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,22 +129,22 @@ public static object ChangeToCompatibleType(object value, Type destinationType,
converter = GetTypeConverterFromName(converterAttribute.ConverterTypeName);
if (converter.CanConvertFrom(value.GetType()))
{
return converter.ConvertFrom(value);
return converter.ConvertFrom(null, CultureInfo.InvariantCulture, value);
}
}

// If there's not a custom converter specified via attribute, try for a default.
converter = TypeDescriptor.GetConverter(value.GetType());
if (converter.CanConvertTo(destinationType))
{
return converter.ConvertTo(value, destinationType);
return converter.ConvertTo(null, CultureInfo.InvariantCulture, value, destinationType);
}

// Try explicit opposite conversion.
converter = TypeDescriptor.GetConverter(destinationType);
if (converter.CanConvertFrom(value.GetType()))
{
return converter.ConvertFrom(value);
return converter.ConvertFrom(null, CultureInfo.InvariantCulture, value);
}

// Try a TryParse method.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Xunit;

Expand Down Expand Up @@ -37,8 +38,8 @@ public void ConvertsTypeInList()
var poco = container.Resolve<B>();

Assert.True(poco.List.Count == 2);
Assert.Equal(1, poco.List[0]);
Assert.Equal(2, poco.List[1]);
Assert.Equal(1.234, poco.List[0]);
Assert.Equal(2.345, poco.List[1]);
}

public class C
Expand All @@ -54,8 +55,8 @@ public void FillsNonGenericListWithString()
var poco = container.Resolve<C>();

Assert.True(poco.List.Count == 2);
Assert.Equal("1", poco.List[0]);
Assert.Equal("2", poco.List[1]);
Assert.Equal("1.234", poco.List[0]);
Assert.Equal("2.345", poco.List[1]);
}

public class D
Expand All @@ -70,7 +71,7 @@ public void InjectsSingleValueWithConversion()

var poco = container.Resolve<D>();

Assert.True(poco.Num == 123);
Assert.Equal(123.456, poco.Num);
}

public class E
Expand All @@ -91,8 +92,28 @@ public void InjectsConstructorParameter()
var poco = container.Resolve<E>();

Assert.True(poco.List.Count == 2);
Assert.Equal(1, poco.List[0]);
Assert.Equal(2, poco.List[1]);
Assert.Equal(1.234, poco.List[0]);
Assert.Equal(2.345, poco.List[1]);
}

[Theory]
[MemberData(nameof(ParsingCultures))]
public void TypeConversionsAreCaseInvariant(CultureInfo culture)
{
// Issue #26 - parsing needs to be InvariantCulture or config fails
// when it's moved from machine to machine.
TestCulture.With(
culture,
() =>
{
var container = EmbeddedConfiguration.ConfigureContainerWithXml("ConfigurationExtensions_EnumerableParameters.xml").Build();

var poco = container.Resolve<E>();

Assert.True(poco.List.Count == 2);
Assert.Equal(1.234, poco.List[0]);
Assert.Equal(2.345, poco.List[1]);
});
}

public class G
Expand Down Expand Up @@ -129,8 +150,8 @@ public void InjectsGenericIEnumerable()
Assert.NotNull(poco.Enumerable);
var enumerable = poco.Enumerable.ToList();
Assert.True(enumerable.Count == 2);
Assert.Equal(1, enumerable[0]);
Assert.Equal(2, enumerable[1]);
Assert.Equal(1.234, enumerable[0]);
Assert.Equal(2.345, enumerable[1]);
}

public class I
Expand All @@ -147,8 +168,8 @@ public void InjectsGenericCollection()

Assert.NotNull(poco.Collection);
Assert.True(poco.Collection.Count == 2);
Assert.Equal(1, poco.Collection.First());
Assert.Equal(2, poco.Collection.Last());
Assert.Equal(1.234, poco.Collection.First());
Assert.Equal(2.345, poco.Collection.Last());
}

public class J
Expand Down Expand Up @@ -243,5 +264,13 @@ public void ParameterStringListInjectionSecondElementHasNoName()
// Val2 is dropped from the configuration when it's parsed.
Assert.Collection(poco.List, v => Assert.Equal("Val1", v));
}

public static IEnumerable<object[]> ParsingCultures()
{
yield return new object[] { new CultureInfo("en-US") };
yield return new object[] { new CultureInfo("es-MX") };
yield return new object[] { new CultureInfo("it-IT") };
yield return new object[] { CultureInfo.InvariantCulture };
}
}
}
Original file line number Diff line number Diff line change
@@ -1,96 +1,96 @@
<?xml version="1.0" encoding="utf-8" ?>
<autofac defaultAssembly="Autofac.Configuration.Test">
<components name="0">
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+A</type>
<properties>
<List name="0">Val1</List>
<List name="1">Val2</List>
</properties>
</components>
<components name="1">
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+B</type>
<properties>
<List name="0">1</List>
<List name="1">2</List>
</properties>
</components>
<components name="2">
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+C</type>
<properties>
<List name="0">1</List>
<List name="1">2</List>
</properties>
</components>
<components name="3">
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+D</type>
<properties>
<Num>123</Num>
</properties>
</components>
<components name="4">
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+E</type>
<parameters>
<List name="0">1</List>
<List name="1">2</List>
</parameters>
</components>
<!--
Microsoft.Extensions.Configuration ignores empty elements so you
don't know the difference between null and empty.
<components name="5">
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+F</type>
<properties>
<List />
</properties>
</components>
-->
<components name="6">
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+G</type>
<properties>
<Enumerable name="0">Val1</Enumerable>
<Enumerable name="1">Val2</Enumerable>
</properties>
</components>
<components name="7">
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+H</type>
<properties>
<Enumerable name="0">1</Enumerable>
<Enumerable name="1">2</Enumerable>
</properties>
</components>
<components name="8">
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+I</type>
<properties>
<Collection name="0">1</Collection>
<Collection name="1">2</Collection>
</properties>
</components>
<components name="9">
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+J</type>
<parameters>
<list name="0">Val1</list>
<list name="1">Val2</list>
</parameters>
</components>
<components name="10">
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+K</type>
<parameters>
<list name="0">Val1</list>
<list name="1">Val2</list>
</parameters>
</components>
<components name="11">
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+L</type>
<parameters>
<list name="0">Val1</list>
<list name="1">Val2</list>
</parameters>
</components>
<components name="12">
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+M</type>
<parameters>
<list name="0">Val1</list>
<list>Val2</list> <!-- no name -->
</parameters>
</components>
</autofac>
<?xml version="1.0" encoding="utf-8" ?>
<autofac defaultAssembly="Autofac.Configuration.Test">
<components name="0">
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+A</type>
<properties>
<List name="0">Val1</List>
<List name="1">Val2</List>
</properties>
</components>
<components name="1">
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+B</type>
<properties>
<List name="0">1.234</List>
<List name="1">2.345</List>
</properties>
</components>
<components name="2">
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+C</type>
<properties>
<List name="0">1.234</List>
<List name="1">2.345</List>
</properties>
</components>
<components name="3">
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+D</type>
<properties>
<Num>123.456</Num>
</properties>
</components>
<components name="4">
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+E</type>
<parameters>
<List name="0">1.234</List>
<List name="1">2.345</List>
</parameters>
</components>
<!--
Microsoft.Extensions.Configuration ignores empty elements so you
don't know the difference between null and empty.
<components name="5">
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+F</type>
<properties>
<List />
</properties>
</components>
-->
<components name="6">
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+G</type>
<properties>
<Enumerable name="0">Val1</Enumerable>
<Enumerable name="1">Val2</Enumerable>
</properties>
</components>
<components name="7">
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+H</type>
<properties>
<Enumerable name="0">1.234</Enumerable>
<Enumerable name="1">2.345</Enumerable>
</properties>
</components>
<components name="8">
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+I</type>
<properties>
<Collection name="0">1.234</Collection>
<Collection name="1">2.345</Collection>
</properties>
</components>
<components name="9">
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+J</type>
<parameters>
<list name="0">Val1</list>
<list name="1">Val2</list>
</parameters>
</components>
<components name="10">
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+K</type>
<parameters>
<list name="0">Val1</list>
<list name="1">Val2</list>
</parameters>
</components>
<components name="11">
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+L</type>
<parameters>
<list name="0">Val1</list>
<list name="1">Val2</list>
</parameters>
</components>
<components name="12">
<type>Autofac.Configuration.Test.Core.ConfigurationExtensions_EnumerableParametersFixture+M</type>
<parameters>
<list name="0">Val1</list>
<list>Val2</list> <!-- no name -->
</parameters>
</components>
</autofac>
31 changes: 31 additions & 0 deletions test/Autofac.Configuration.Test/TestCulture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;
using System.Globalization;
using System.Threading;
using Xunit;

namespace Autofac.Configuration.Test
{
public static class TestCulture
{
public static void With(CultureInfo culture, Action test)
{
var originalCulture = Thread.CurrentThread.CurrentCulture;
var originalUICulture = Thread.CurrentThread.CurrentUICulture;
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
CultureInfo.CurrentCulture.ClearCachedData();
CultureInfo.CurrentUICulture.ClearCachedData();
try
{
test();
}
finally
{
Thread.CurrentThread.CurrentCulture = originalCulture;
Thread.CurrentThread.CurrentUICulture = originalUICulture;
CultureInfo.CurrentCulture.ClearCachedData();
CultureInfo.CurrentUICulture.ClearCachedData();
}
}
}
}
22 changes: 22 additions & 0 deletions test/Autofac.Configuration.Test/Util/TypeManipulationFixture.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
Expand Down Expand Up @@ -59,6 +60,27 @@ public void ChangeToCompatibleType_NoConversionNeeded()
Assert.Equal(15, actual);
}

[Theory]
[MemberData(nameof(ParsingCultures))]
public void ChangeToCompatibleType_UsesInvariantCulture(CultureInfo culture)
{
TestCulture.With(
culture,
() =>
{
var actual = TypeManipulation.ChangeToCompatibleType("123.456", typeof(double));
Assert.Equal(123.456, actual);
});
}

public static IEnumerable<object[]> ParsingCultures()
{
yield return new object[] { new CultureInfo("en-US") };
yield return new object[] { new CultureInfo("es-MX") };
yield return new object[] { new CultureInfo("it-IT") };
yield return new object[] { CultureInfo.InvariantCulture };
}

public class Convertible
{
public int Value { get; set; }
Expand Down

0 comments on commit 1635b86

Please sign in to comment.