March 2, 2017

An Exception Handling String Formatter

A string extension class to safely use string.Format().
public static class StringExtensions
{
    // Safe format, capture any Format Exceptions.
    public static string TryFormat(
        this string formatText,
        params object[] parameters)
    {
        string res = "";
        try
        {
            res = string.Format(formatText, parameters);
        }
        catch (FormatException fe)
        {
            string msg = "Formatting string error : formatText=" + formatText + 
                                ", parameters=\'" +
                              string.Join( ",", parameters ) + "\', exception=" + fe;
            Trace.WriteLine("string.Format code needs fixing - " msg);
            res = formatText;
            Debug.Assert(false, msg);
        }
        return res;
    }
}
I have seen this method take down a complete application because too few parameters were passed.

Thread Safe Enum Access Using Interlocked

Here is an example class that makes reading and writing an enum property thread safe (when writing or reading the enum value)
/// <summary>
///     A thread safe MyEnum.
/// </summary>
public class ThreadSafeMyEnum
{
 // Volatile is not needed (esp. on x64 or x86) : 
 // http://stackoverflow.com/questions/7177169/how-to-apply-interlocked-exchange-for-enum-types-in-c 
 // http://stackoverflow.com/questions/425132/a-reference-to-a-volatile-field-will-not-be-treated-as-volatile-implications
 private int _enumAsInt;

 public MyEnum Value // added for convenience
 {
  get { return ( MyEnum ) Interlocked.CompareExchange( ref _enumAsInt, 0, 0 ); }
  set { Interlocked.Exchange( ref _enumAsInt, ( int ) value ); }
 }
}

NUnit Parameterised Tests

NUnit can have class level parameterised tests:


[ TestFixture( MachineEnum.None ) ]
[ TestFixture( MachineEnum.Lathe ) ]
[ TestFixture( MachineEnum.Miller ) ]
public class SomeTests
{
  private readonly MachineEnum _machineEnum = MachineEnum.None;

  public SomeTests(
  MachineEnum machineEnum )
  {
    _machineEnum = machineEnum;
  }
  ...
}

Also the tests can be paramterised at the test level. Make sure the TestCase parameter match the order and type of the test method.

  [Test]
  [TestCase("some value", null,         ExpectedResultEnum.Paramater1Used)]
  [TestCase("some value", "over ride",  ExpectedResultEnum.Paramater2Used)]
  [TestCase("some value", "over ride",  ExpectedResultEnum.Paramater1Used)]
  [TestCase(null,         null,         ExpectedResultEnum.Paramater1Used)]
  public async Task ParamterisedTest(
    string param1,
    string param2,
    ExpectedResultEnum expectedResult)
{
    // Arrange

    // Act

    // Assert
    Assert.Multiple(() =>
    {
      Assert.That(var1 == null, Is.False);
      Assert.That(var2.Id, Is.EqualTo(expectedResult));
    });
    ...
}