patterncsharpMinor
String formatting of unit types
Viewed 0 times
formattingstringunittypes
Problem
I have a units of measure library that I added string formatting to. Here is sample code:
```
[Test]
public void FormatSpeed()
{
var speed = Speed.FromMetresPerSecond(1.2);
using (Thread.CurrentThread.UsingTempCulture(CultureInfo.InvariantCulture))
{
Assert.AreEqual("1.20\u00A0m/s", speed.ToString("F2"));
Assert.AreEqual("1.20 m⋅s⁻¹", speed.ToString("F2 m⋅s⁻¹"));
Assert.AreEqual("1.2\u00A0m/s", speed.ToString());
Assert.AreEqual("1.2\u00A0m⋅s⁻¹", speed.ToString("m⋅s⁻¹"));
Assert.AreEqual("1200\u00A0mm⋅s⁻¹", speed.ToString("mm⋅s⁻¹"));
Assert.AreEqual("4.32\u00A0km/h", speed.ToString(SpeedUnit.KilometresPerHour));
Assert.AreEqual("4.3\u00A0km/h", speed.ToString("F1", SpeedUnit.KilometresPerHour));
}
var sv = CultureInfo.GetCultureInfo("sv-SE");
Assert.AreEqual("1,20\u00A0m/s", speed.ToString("F2", sv));
Assert.AreEqual("1,20 m⋅s⁻¹", speed.ToString("F2 m⋅s⁻¹", sv));
Assert.AreEqual("1,2\u00A0m/s", speed.ToString(sv));
Assert.AreEqual("1,2\u00A0m⋅s⁻¹", speed.ToString("m⋅s⁻¹", sv));
Assert.AreEqual("1200\u00A0mm⋅s⁻¹", speed.ToString("mm⋅s⁻¹", sv));
Assert.AreEqual("4,32\u00A0km/h", speed.ToString(SpeedUnit.KilometresPerHour, sv));
Assert.AreEqual("4,3\u00A0km/h", speed.ToString("F1", SpeedUnit.KilometresPerHour, sv));
}
[Test]
public void FormatAngle()
{
var angle = Angle.FromDegrees(1.2);
using (Thread.CurrentThread.UsingTempCulture(CultureInfo.InvariantCulture))
{
Assert.AreEqual("0.020943951023932\u00A0rad", angle.ToString());
Assert.AreEqual("1.200°", angle.ToString("F3°"));
Assert.AreEqual("1.2°", angle.ToString(AngleUnit.Degrees));
Assert.AreEqual(" 1.2 ° ", angle.ToString(" F1 ° "));
Assert.AreEqual(" 0.02 rad", angle.ToString(" F2 "));
Assert.AreEqual("1.200°", angle.ToString("F3", AngleUnit.Degrees));
Assert.AreEqual("0.02\u00A0rad", angle.ToString("F2", AngleUnit.Radians));
}
var
```
[Test]
public void FormatSpeed()
{
var speed = Speed.FromMetresPerSecond(1.2);
using (Thread.CurrentThread.UsingTempCulture(CultureInfo.InvariantCulture))
{
Assert.AreEqual("1.20\u00A0m/s", speed.ToString("F2"));
Assert.AreEqual("1.20 m⋅s⁻¹", speed.ToString("F2 m⋅s⁻¹"));
Assert.AreEqual("1.2\u00A0m/s", speed.ToString());
Assert.AreEqual("1.2\u00A0m⋅s⁻¹", speed.ToString("m⋅s⁻¹"));
Assert.AreEqual("1200\u00A0mm⋅s⁻¹", speed.ToString("mm⋅s⁻¹"));
Assert.AreEqual("4.32\u00A0km/h", speed.ToString(SpeedUnit.KilometresPerHour));
Assert.AreEqual("4.3\u00A0km/h", speed.ToString("F1", SpeedUnit.KilometresPerHour));
}
var sv = CultureInfo.GetCultureInfo("sv-SE");
Assert.AreEqual("1,20\u00A0m/s", speed.ToString("F2", sv));
Assert.AreEqual("1,20 m⋅s⁻¹", speed.ToString("F2 m⋅s⁻¹", sv));
Assert.AreEqual("1,2\u00A0m/s", speed.ToString(sv));
Assert.AreEqual("1,2\u00A0m⋅s⁻¹", speed.ToString("m⋅s⁻¹", sv));
Assert.AreEqual("1200\u00A0mm⋅s⁻¹", speed.ToString("mm⋅s⁻¹", sv));
Assert.AreEqual("4,32\u00A0km/h", speed.ToString(SpeedUnit.KilometresPerHour, sv));
Assert.AreEqual("4,3\u00A0km/h", speed.ToString("F1", SpeedUnit.KilometresPerHour, sv));
}
[Test]
public void FormatAngle()
{
var angle = Angle.FromDegrees(1.2);
using (Thread.CurrentThread.UsingTempCulture(CultureInfo.InvariantCulture))
{
Assert.AreEqual("0.020943951023932\u00A0rad", angle.ToString());
Assert.AreEqual("1.200°", angle.ToString("F3°"));
Assert.AreEqual("1.2°", angle.ToString(AngleUnit.Degrees));
Assert.AreEqual(" 1.2 ° ", angle.ToString(" F1 ° "));
Assert.AreEqual(" 0.02 rad", angle.ToString(" F2 "));
Assert.AreEqual("1.200°", angle.ToString("F3", AngleUnit.Degrees));
Assert.AreEqual("0.02\u00A0rad", angle.ToString("F2", AngleUnit.Radians));
}
var
Solution
The only suggestion I would make is to extract each culture's tests to it's own unit tests. Each unit test should be testing one aspect of your code, whereas yours are each testing at least two.
Point 1: the only two overloads you need are
Point 2: you should not be adding composites like that, at all. It's just noise. If you really need that info to be passable to the
Point 3: I don't know enough about C# to be able to answer that exactly, but I would assume you should be using the literal space everywhere, or the
Your unit tests have good content, but they need better names:
This makes it a little more clear as to what the tests are doing by name, so that when you look at the test explorer you can see you already have tests that cover certain aspects.
Point 1: the only two overloads you need are
.ToString(string) and .ToString(string, IFormatProvider). Everything else is just noise.Point 2: you should not be adding composites like that, at all. It's just noise. If you really need that info to be passable to the
.ToString call, then you should consider a third and fourth overload: .ToString(string format, string unit), and .ToString(string format, string unit, IFormatProvider formatProvider).Point 3: I don't know enough about C# to be able to answer that exactly, but I would assume you should be using the literal space everywhere, or the
\u00A0 everywhere. Pick one or the other, but don't mix-and-match.Your unit tests have good content, but they need better names:
public void FormatSpeed_1p2_Invariant()
public void FormatSpeed_1p2_Sv_Se()
public void FormatAngle_1p2_Invariant()
public void FormatAngle_1p2_Sv_Se()This makes it a little more clear as to what the tests are doing by name, so that when you look at the test explorer you can see you already have tests that cover certain aspects.
Code Snippets
public void FormatSpeed_1p2_Invariant()
public void FormatSpeed_1p2_Sv_Se()
public void FormatAngle_1p2_Invariant()
public void FormatAngle_1p2_Sv_Se()Context
StackExchange Code Review Q#112075, answer score: 4
Revisions (0)
No revisions yet.