Testing

Beyond the Event Horizon: WinForms Plumbing

WinFormsPlumbingIn my last post in this series about testing event configurations, I discovered that my code base thus far doesn’t work with the WinForms event system.  After examining the classes in the System.Windows.Forms namespace, I figured out that I’m going to need to put some plumbing in place before I can even think about writing a query to lock down the event configuration for WinForms.

This article might not make a lot of sense if you haven’t read the previous entry, and that article might be confusing if you haven’t read them all, so here’s a table of contents describing where we’ve been so far:

  1. Beyond the Event Horizon: Delegate Basics” — Explores the useful Delegate.GetInvocationList method.
  2. Beyond the Event Horizon: Event Basics” — Explains the relationship between Delegates and Events, and how the compiler implements simple events.
  3. Beyond the Event Horizon: Events You Don’t Own” — Shows how to use reflection to retrieve delegates for events declared on classes you can’t or won’t change.
  4. Beyond the Event Horizon: Event Complications” — Completes the toolset introduced in part 3 by handling inherited events and events of any delegate type.
  5. Beyond the Event Horizon: WinForms Event System” — In which we discover that part 4 did not complete the toolset after all. 

You can download the code associated with these articles from GitHub.  While I hope the code is interesting to you, it’s only a reimplementation of features already available the the ApprovalTests library.  You can download ApprovalTests from SourceForge or NuGet and start using these features immediately.  If you need help getting started with ApprovalTests, check out Llewellyn Falco’s video series on YouTube.

To pick up on where we left off, I need to make some plumbing.  First I need to create a public wrapper for the inaccessible ListEntry class.  Then I need to create an enumerable adapter for the EventHandlerList class.

Speaking the Unspeakable

I’ll start with creating the public wrapper for ListEntry that will take care of all the reflection necessary to access it’s fields. First, I’ll need to figure out how to get an instance of ListEntry so I can write tests for the wrapper implementation. Here is my test skeleton:

[TestMethod]
public void RetrieveListEntryWithReflection()
{
    // Create an object which should contain a EventHandlerList with something in it
    // Get the private property Component.Events
    // Get the private field head
    // Assert that head's type is named "ListEntry"
}

I know that ListEntry is nested in EventHandlerList and that EventHandlerList.head is the only direct reference to a ListEntry value on EventHandlerList. I also want to guard against the possibility that a random type happens to have a field called “events” which has nothing to do with events. Here’s a prototype:

[TestMethod]
public void RetrieveListEntryWithReflection()
{
    // Create an object which should contain a EventHandlerList with something in it
    var value = new DemoForm();

    // Get the private field Component.events
    BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
    var listInfo = value.GetType().EnumerateFieldsWithInherited(bindingFlags).SingleOrDefault(fi => fi.Name == "events" && typeof(EventHandlerList).IsAssignableFrom(fi.FieldType));
    Assert.IsNotNull(listInfo);
    var eventHandlerList = listInfo.GetValue(value);
    Assert.IsNotNull(eventHandlerList);

    // Get the private field head
    var headInfo = eventHandlerList.GetType().GetField("head", bindingFlags);
    Assert.IsNotNull(headInfo);
    var head = headInfo.GetValue(eventHandlerList);
    Assert.IsNotNull(head);

    // Assert that head's type is named "ListEntry"
    Assert.AreEqual("ListEntry", head.GetType().Name);
}

This isn’t pretty, but it works.  I see a couple groupings that I can make into methods.  It makes sense to pull out a method that gets the EventHandlerList and one that extracts the ListEntry called “head”.

Here are some tests for a new method, GetEventHandlerList:

[TestMethod]
public void GetEventHandlerList()
{
    Assert.IsNotNull(new DemoForm().GetEventHandlerList());
}

[TestMethod]
public void PocoHasNoEventHandlerList()
{
    Assert.IsNull(new Poco().GetEventHandlerList());
}

[TestMethod]
public void SpoilerHasNoEventHandlerList()
{
    Assert.IsNull(new Spoiler().GetEventHandlerList());
}

[TestMethod]
public void NullHasNoEventHandlerList()
{
    Assert.IsNull(ReflectionUtility.GetEventHandlerList(null));
}

Spoiler is a little class that contains a field called “events” which has noting to do with raising events.

public class Spoiler
{
    private string events = "I spoil ur reflektion.";
}

Now I need to create the method to get these tests to compile.

public static EventHandlerList GetEventHandlerList(this object value)
{
    return null;
}

With this change stub, the null, Poco and Spoiler tests pass.  To get the DemoForm test to pass I will need to copy some code from RetrieveListEntryWithReflection.  After copying the relevant section and deleting this calls to Assert I get this:

public static EventHandlerList GetEventHandlerList(this object value)
{
    BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
    var listInfo = value.GetType().EnumerateFieldsWithInherited(bindingFlags)
        .SingleOrDefault(fi => fi.Name == "events" &&
                         typeof(EventHandlerList).IsAssignableFrom(fi.FieldType));
    var eventHandlerList = listInfo.GetValue(value);
    return (EventHandlerList)eventHandlerList;
}

With this implementation my DemoForm tests pass but my other three fail.  There is also some redundancy with methods and constants already provided by ReflectionUtility.  So, after a little refactoring I get this:

public static EventHandlerList GetEventHandlerList(this object value)
{
    var lists = from fieldInfo in GetType(value).EnumerateFieldsWithInherited(NonPublicInstance)
                where 
                    fieldInfo.Name == "events" &&
                    typeof(EventHandlerList).IsAssignableFrom(fieldInfo.FieldType)
                select fieldInfo.GetValue<EventHandlerList>(value);

    return lists.SingleOrDefault();
}

This implementation passes all four of the tests (DemoForm, Poco, Spoiler and Null).  So what did I do?  First I eliminated the local declaration of the binding flags and used the constant already defined by ReflectionUtility.  To get past the first null reference exception (caused by the Null test), I used my customized version of GetType, which returns typeof(void) when the input is null.  The where clause survived intact, but I modified the select clause.  I used my own custom GetValue<> method to handle casting from object. to the EventHandlerList type.  For Null, Poco and Spoiler, nothing on the type matches the constraints, so the select statement never executes, so I don’t need additional null checking there.  Finally I unpack the matching value, or return null if there were no matches.

Now I can update RetrieveListEntryWithReflection to use this method.

[TestMethod]
public void RetrieveListEntryWithReflection()
{
    // Create an object which should contain a EventHandlerList with something in it
    var value = new DemoForm();

    // Get the private field Component.events
    var eventHandlerList = value.GetEventHandlerList();
    Assert.IsNotNull(eventHandlerList);

    // Get the private field head
    BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
    var headInfo = eventHandlerList.GetType().GetField("head", bindingFlags);
    Assert.IsNotNull(headInfo);
    var head = headInfo.GetValue(eventHandlerList);
    Assert.IsNotNull(head);

    // Assert that head's type is named "ListEntry"
    Assert.AreEqual("ListEntry", head.GetType().Name);
}

The next chunk of RetrieveListEntryWithReflection pulls the head field from the EventHandlerList. When it comes to extracting the head, I have the advantage of being able to restrict the input to EventHandlerList instances. This means I don’t have to worry so much about spoilers, but I still need to check for nulls.  Here are some tests:

[TestMethod]
public void DemoFormEventHandlerListHasHead()
{
    var eventHandlerList = new DemoForm().GetEventHandlerList();
    Assert.AreEqual("ListEntry", eventHandlerList.GetHead().GetType().Name);
}

[TestMethod]
public void ButtonHasNoHead()
{
    Assert.IsNull(new Button().GetEventHandlerList().GetHead());
}

[TestMethod]
public void NullHasNoHead()
{
    Assert.IsNull(ReflectionUtility.GetHead(null));
}

Note the second test ButtonHasNoHead. Button is a control and has many things in common with Form, but in this case GetEventHandlerList returns null because I haven’t wired up any of Button‘s events.

Here’s a first draft of GetHead copied from  RetrieveListEntryWithReflection:

public static object GetHead(this EventHandlerList value)
{
    BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
    var headInfo = value.GetType().GetField("head", bindingFlags);
    var head = headInfo.GetValue(value);
    return head;
}

With GetHead I have no choice but to return an object, because the ListEntry type remains un-nameable.  This method is not well protected from null reference exceptions and two of my tests are failing because of that.  More refactoring is in order.

public static object GetHead(this EventHandlerList value)
{
    var headInfo = GetType(value).GetField("head", NonPublicInstance);
    return headInfo == null ? null : headInfo.GetValue(value);
}

Again I used the binding flags defined by ReflectionUtility, and the customized GetType method.  One more null check and all my tests are good to go.

I now have a method to retrieve objects of the right type (ListEntry) that I can use for testing.  I can also update RetrieveListEntryWithReflection to use the new method.

[TestMethod]
public void RetrieveListEntryWithReflection()
{
    // Create an object which should contain a EventHandlerList with something in it
    var value = new DemoForm();

    // Get the private field head
    var head = value.GetEventHandlerList().GetHead();
    Assert.IsNotNull(head);

    // Assert that head's type is named "ListEntry"
    Assert.AreEqual("ListEntry", head.GetType().Name);
}

In fact, I can use ApprovalTests to make this test not only more explicit, but shorter too.

[TestMethod]
public void RetrieveListEntryWithReflection()
{
    var head = new DemoForm().GetEventHandlerList().GetHead();
    ApprovalTests.Approvals.Verify(head.GetType().FullName);
}

By approving the the full name, I feel more confident I’m getting the right type instead of some other type which might happen to have the same name in a different namespace.

Wrapping ListEntry

Because ListEntry is unspeakable outside an EventHandlerList instance, I’m forced to start my wrapper with a constructor that takes an object as its input.

public class ListEntryWrapper
{
    public ListEntryWrapper(object value)
    {

    }
}

Since I must pass an object I can’t rely on the compiler to require that it is a ListEntry. I need to verify this at runtime, then decide what I should do if something other than a ListEntry instance is provided.  I’ll do this by getting my hands on ListEntry’s Type using reflection, and comparing it to the type passed into the constructor.

private static readonly Lazy<Type> ListEntryType =
    new Lazy<Type>(() => typeof(EventHandlerList).GetNestedType("ListEntry", BindingFlags.NonPublic));

public ListEntryWrapper(object value)
{
    if (ReflectionUtility.GetType(value) == ListEntryType.Value)
    {
        // Do something with a genuine ListEntry instance.
    }
}

Since I know the nested type’s name, getting a reference to its Type is not too difficult.  Since every ListEntryWrapper will need access to this information and the information doesn’t change, I store the Type in a static, read only and Lazy field.  Using Lazy might be premature optimization, but I haven’t had much chance to play with Lazy and this seems like a good learning opportunity.

I don’t want to put the burden of type-checking on the caller, so I’ll use the NullObject pattern if the wrong type is passed in.  When the caller gives me the wrong kind of object I will just let the reference pass out of scope and implement appropriate “do-nothing” behavior in the wrapper’s properties. Since the ListEntry is part of a single-linked list, do-nothing implies that ListEntryWrapper’s properties should return null.

On the other hand, if the object really is a ListEntry I should store a reference to it so that I can reflect over the value later.

private readonly object listEntry;

public ListEntryWrapper(object value)
{
    if (ReflectionUtility.GetType(value) == ListEntryType.Value)
    {
        this.listEntry = value;
    }
}

Since ListEntry is unspeakable, all it’s members are unspeakable, and each member must be accessed through reflection.  Here’s a test I can use to get feedback, while I build with the correct type, and one which shows the result when the type is incorrect. I also pulled the ceremony around getting a ListEntry instance into a convenience method.

[TestMethod]
public void ListEntryIsWrapped()
{
    var listEntryWrapper = new ListEntryWrapper(GetListEntry());
    ApprovalTests.Approvals.Verify(listEntryWrapper.WritePropertiesToString());
}

[TestMethod]
public void WrongObjectIsntWrapped()
{
    var listEntryWrapper = new ListEntryWrapper(new object());
    ApprovalTests.Approvals.Verify(listEntryWrapper.WritePropertiesToString());
}

At the moment, both tests produce the same uninteresting results:

ListEntryWrapper
{
}

I should see some differentiation once I create accessors for each of ListEntry’s members: key, handler and next.

private static readonly Lazy<FieldInfo> KeyInfo =
    new Lazy<FieldInfo>(
        () => ListEntryType.Value.GetField("key", BindingFlags.NonPublic | BindingFlags.Instance));

public object Key
{
    get
    {
        return this.listEntry == null ? 
            null :
            KeyInfo.Value.GetValue(this.listEntry);
    }
}

Here is the result for the actual list entry:

ListEntryWrapper
{
    Key: System.Object
}

And the result for the NullObject scenario:

ListEntryWrapper
{
    Key: NULL
}

I can repeat this technique to implement the remaining properties. Things go fine for Handler, but I run into a problem implementing Next. To keep the linked list going, I need to wrap ListEntry.next in a new ListEntryWrapper. But, if the ListEntry is a singleton or the last link in the list, then “next” should be null.  The ListEntryWrapper constructor uses the customized GetType method to retrieve typeof(void) when value is null.  Since typeof(void) is not ListEntry’s type, the wrapper reverts to it’s NullObject behavior… and the linked list terminates with a NullObject followed by a null.  There is one extra link in the chain.  To avoid having to remember this whenever I use the wrapper, Next needs some special logic.

public ListEntryWrapper Next
{
    get
    {
        if (this.listEntry == null)
        {
            return null;
        }

        object nextValue = NextInfo.Value.GetValue(this.listEntry);
        return nextValue == null ? null : new ListEntryWrapper(nextValue);
    }
}

Now, if an object of the wrong type is passed in, listEntry will be null and Next will be null.  If the correct type is passed in, listEntry will be populated, but GetValue will return null when listEntry is the last link in the list.  When that happens, the property will return null; otherwise it will wrap the non-null value and return it.  This behavior is more intuitive and now the results look correct.  Here are the final results for the wrapped ListEntry.

ListEntryWrapper
{
    Key: System.Object
    Handler: System.EventHandler
    Next: NULL
}

To round out my tests, I should add one that covers the case where the ListEntry is not a singleton.

[TestMethod]
public void ListHasMoreThanOneEntry()
{
    var button = new Button();
    button.Click += (s, e) => { return; };
    button.LostFocus += (s, e) => { return; };
    var wrapper = new ListEntryWrapper(button.GetEventHandlerList().GetHead());
    ApprovalTests.Approvals.Verify(wrapper.WritePropertiesToString());
}

This test works as expected, and produces these results:

ListEntryWrapper
{
    Handler: System.EventHandler
    Key: System.Object
    Next: EventReflection.Demo.ListEntryWrapper
}

With this last bit, I have a wrapper for ListEntry that allows me to manipulate these objects like normal public types.  Now, I can turn to the next problem, which is that EventHandlerList doesn’t implement an IEnumerable interface.

Making EventHandlerList into a… List

Other than a few CRUD operations (add/remove/find) EventHandlerList is just a reference to one ListEntry, called “head”. To access any other list entries beyond “head”, you have to go through “head”. I’ll know that I’ve visited all the entries when I find a ListEntry where the “next” parameter is a null reference.

The procedure outlined about is called “walking” the list. It should be fairly easy to implement now that I have ListEntryWrapper to work with, and because I also already wrote the reflection to retrieve the “head” as part of testing ListEntryWrapper. Rather than creating a wrapper class that implements IEnumerable<ListEntryWrapper> I can simply take advantage of the yield statement and have the compiler generate the enumerable class for me.

I’ll create a method to produce the Button from ListHasMoreThanOneEntry, and reuse it in my next test. If I’m successful, a test like this should show two ListEntryWrappers in the result.

[TestMethod]
public void AsEnumerableMethodAdaptsEventHandlerList()
{
    var button = GetTestButton();
    ApprovalTests.Approvals.VerifyAll(
        button.GetEventHandlerList().AsEnumerable(),
        e => e.WritePropertiesToString());
}

I stub out a new extension method and call it AsEnumerable because that describes what the method does. Although there are methods called AsEnumerable in the framework, their parameters do not have types compatible with EventHandlerList, so I will need to provide the implementation. Of course, before I get too far ahead of myself, I should make sure my AsEnumerable implementation can handle nulls.

[TestMethod]
public void NullListIsEmpty()
{
    var button = new Button();
    Assert.IsFalse(button.GetEventHandlerList().AsEnumerable().Any());
}

I’ve decided to handle null by returning an empty set rather than throwing an exception or returning null. This will save me the trouble of checking for null when querying, since LINQ can handle empty sets just fine.

Here is an AsEnumerable implementation that satisfies both tests:

public static IEnumerable<ListEntryWrapper> AsEnumerable(this EventHandlerList source)
{
    object value = source.GetHead();
    if (value == null)
    {
        yield break;
    }

    for (var head = new ListEntryWrapper(value); head != null; head = head.Next)
    {
        yield return head;
    }
}

And the results show two items in the list.

ListEntryWrapper
{
    Handler: System.EventHandler
    Key: System.Object
    Next: EventReflection.Demo.ListEntryWrapper
}

ListEntryWrapper
{
    Handler: System.EventHandler
    Key: System.Object
    Next: NULL
}

A just like that, I can now bring all the power of LINQ to bear on EventHandlerList.

Relationship With EventApprovals

The classes in ApprovalTests track pretty closely to what I’ve shown here.  The enumerable adapter is hosted in ApprovalUtilities.Reflection.HandlerListHelper.  This class also contains the GetHead method.  The AsEnumerable method is implemented with a while loop, but this detail has no effect.  ILSpy shows that the compiler converts this loop into a for loop like I’ve shown above.

In ApprovalTests, you can find the wrapper class in ApprovalUtilities.Reflection.HandlerListEntry.  Because the ApprovalTests libraries target .NET 3.5, Lazy<T> isn’t available.  The properties are still lazy, but the laziness is implemented by hand.  I created a GetField<T> method which took the field name as a parameter and leveraged the methods in ReflectionUtilities rather than specifying the binding flags a second time.  Conceptually, both wrappers work the same, including the extra null checking in the Next property.

Up Next

The plumbing is done and I can return to the domain problem of querying for events that have handlers attached.  Check back soon for the thrilling conclusion to this blog series: “Beyond the Event Horizon: Testing WinForms”.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s