I have a bug report where double.Parse(input)
is throwing the following exception with the input "0.69803923368454"
:
FormatException: Unknown char: .
System.Double.Parse (System.String s, NumberStyles style, IFormatProvider provider) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System/Double.cs:209)
System.Double.Parse (System.String s) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System/Double.cs:180)
After some searching it seems that this issue occurs when the default culture does not support the decimal character .
(see float.Parse fails on decimals and commas);
I need to create a unit test which reproduces this issue by forcing a different default culture for the duration of the test. Naturally this must not interfere with any existing unit test. I am using the unit testing framework which is provided with Visual Studio.
Here is what I have tried, but unfortunately this does not cause the reported error to occur:
[TestMethod]
private void DoubleParseWithCultureOverride() {
var restoreCulture = Thread.CurrentThread.CurrentCulture;
var restoreUICulture = Thread.CurrentThread.CurrentUICulture;
try {
// Arrange
Thread.CurrentThread.CurrentCulture = new CultureInfo("ko-KR");
Thread.CurrentThread.CurrentUICulture = new CultureInfo("ko-KR");
// Act
double value = double.Parse("0.69803923368454");
// Assert
Assert.AreEqual(0.69803923368454, value);
}
finally {
Thread.CurrentThread.CurrentCulture = restoreCulture;
Thread.CurrentThread.CurrentUICulture = restoreUICulture;
}
}
I was expecting the above unit test to fail (i.e. become red in the test explorer panel), but it passed. At the moment I am purely attempting to force the error with standard Mono/.NET usage. I intend to replace the "Act" section with application specific logic.
You've just picked a culture which happens to use .
as a decimal point:
var culture = new CultureInfo("ko-KR");
Console.WriteLine(culture.NumberFormat.NumberDecimalSeparator); // Prints .
I typically use French (fr-FR
) for this - and that does fail with your current code.
Alternatively, you could construct your own CultureInfo
specifically for testing, with whatever separator you want.
For testing like this, you might want a simpler way of setting the culture, too. Options:
Write a method taking an action to execute "within" a culture, then call it as:
ExecuteInCulture("fr-Fr", () =>
{
// Parse a double, or whatever
});
Create an IDisposable
implementation which sets the culture and restores it on Dispose
:
using (CultureHelper.SetCulture("fr-FR"))
{
// Parse a double, or whatever
}
The former approach is probably cleaner - it's not like you've really got a "resource" here.
See more on this question at Stackoverflow