Monday, August 22, 2011

Formatting to a String in Everest


I've never really liked strings for transporting data as they're memory pigs and introduce a huge performance penalty, however formatting to a string can be useful if you're debugging an application or just want to see the results of formatting. So I figured I'd do a short-ish post today and illustrate how this is done.

First, we'll need an instance, I've created a small sample message from the UV NE2008 assembly but it can be any instance that is IGraphable.

MCCI_IN000000UV01 instance = new MCCI_IN000000UV01(
    Guid.NewGuid(),
    DateTime.Now,
    MCCI_IN000000UV01.GetInteractionId(),
    ProcessingID.Training,
    "I",
    AcknowledgementCondition.Never);

Next, we'll define the formatter instance that is going to take this RMIM structure and render it using an ITS. I'm using XML ITS 1 with data types R1.

var formatter = new MARC.Everest.Formatters.XML.ITS1.Formatter();
formatter.ValidateConformance = false;
formatter.GraphAides.Add(typeof(MARC.Everest.Formatters.XML.ITS1.Formatter));


I've disabled conformance checking as I assume since we're formatting to a string, we're just fiddling with Everest. I'd recommend setting ValidateConformance to true if you're seriously trying to create a conformant message. Next, we create a StringWriter class and attach an XmlWriter with indentation turned on (makes it easier to read):

StringWriter sw = new StringWriter();
XmlWriter xw = XmlWriter.Create(sw, new XmlWriterSettings()
      { Indent = true }
);


We could just format the instance as is, however it is always recommended you use an XmlStateWriter when dealing with Everest, so that what this next line does:

XmlStateWriter xsw = new XmlStateWriter(xw);

Next, we just format our instance and flush (or close) the XmlWriter.

try
{
   formatter.Graph(xsw, instance);
}
finally
{
   xw.Close();
   sw.Flush();
}

Notice I'm using the Graph() method, this is a new construct introduced in Everest RC3. If you're using RC2 or prior you can call GraphObject() instead. Finally, you can get your string by calling the ToString() method on the string writer. I've decided to print out to the console for demonstrative purposes:

Console.WriteLine(sw.ToString());
Console.ReadKey();

And there you have it! An XML Instance as a string. I wouldn't recommend using strings too heavily in your production code, like I said they're horrible from a memory consumption and performance POV. Streams and Writers/Readers are much faster and flexible.

Cheers

-Justin

Sunday, August 21, 2011

Emitting Unit Tests from Assemblies Part 2


In my previous post I've illustrated how to setup the necessary utility functions for emitting C# code from assemblies. In this post I'll tie it all together and finish up the application so that we can generate equality unit tests from an assembly.

The first step is of course to define a program entry point.

static void Main(string[] args)
{

In my application this will load the assembly and generate unit tests for each of the types which inherit from ANY (the purpose of this application is to generate equality tests for Everest, you can modify this to suit your needs). I'm using a lambda expression to perform this operation:

var types = typeof(II).Assembly.GetTypes();
var anyTypes = Array.FindAll(types, o => !o.IsAbstract &&
    o.GetCustomAttributes(typeof(ObsoleteAttribute), true).Length == 0 &&
    typeof(ANY).IsAssignableFrom(o) &&

    o.GetMethod("Equals", new Type[] { o }) != null);

The lambda expression that searches each type looks confusing but can be easily explained. The variable types is an array of all types in the assembly which defines the II type (ie: the assembly we want to search), the lambda clauses find all types in that assembly that:


!o.IsAbstractWhere the type is not abstract (ie: we can instantiate an instance of the type)
o.GetCustomAttributes(typeof(ObsoleteAttribute), true).Length == 0The type is not obsolete (ie: there are no ObsoleteAttribute defined on the type)
typeof(ANY).IsAssignableFrom(o)The type can be assigned to a variable of type ANY (ie: is a ANY)
o.GetMethod("Equals", new
Type[] { o }) != null
The type has a method called Equals that accepts a parameter of itself (ie: equality can be determined between two instances of the type)


Next, we'll iterate through each of the types that we've found and will generate a unit test file (if I were a Java developer I'd call this an Iterator pattern to make it seem more impressive, but I like to keep things simple)

foreach (Type t in anyTypes)
     GenerateTestFile(t);

Before I go into the contents of the GenerateTestFile method, I'll explain a little bit about the structure of a Visual Studio unit test. All unit tests are represented as methods within a test class. The test class defines the test context as well as any setup and teardown code. Since I didn't want to store this as a string (very un-maintainable), I created a template file and added it as a resource called Templates.

GenerateTestFile does exactly what you'd expect, it generates the test file. First, it checks if T is a generic type definition and if it is, creates a generic type using the INT class (in .NET each generic class is a new type as it uses reified generics).

if (t.IsGenericTypeDefinition)
{
   // Create a generic type of INT
   List<Type> genericArguments = new List<Type>();
   foreach (Type genParm in t.GetGenericArguments())
       genericArguments.Add(typeof(INT));
   t = t.MakeGenericType(genericArguments.ToArray());
}

This little snippet of code will create a list (or array) of generic arguments of INT for each generic argument available in the type definition. For example, if it encounters QTY then QTY<INT> is created, for RTO the type RTO<INT,INT> is created.

Next we do some pretty standard .NET stuff. I always use this pattern for generating files. I'm not going to outline the code here are it is pretty easy to follow in the attached file

TextWriter tw = null;
try
{
   // Code Here

}
finally
{
   if(tw != null)

      tw.Close();
}

The complete source for this program is available here: http://pastebin.com/P06dRAnu

Remember, a piece of software is only as good as the testing and QA processes it passes through. Emitting unit tests from a target test assembly is a great start for mundane tests like Equality or Comparisons but you will eventually have to manually write unit tests for more complex logic in your application. As an example, Everest's test battery consists of 9,500 unit tests of which approximately 1,000 are hand written and the rest are generated.

Happy testing!