The test that I'm going to implement this time is the following:

  • Add 3 Bookmarks, call GetEnumerator and verify that the 3 Bookmarks are enumerated

    3 seems excessive, I think 2 will be sufficient; here is the test:

    [Test]
    public void EnumeratorContainsOnlyAddedItems()
    {
        collection.Add(exampleDotComLabel, exampleDotComUri);
       
    collection.Add(exampleDotNetLabel, exampleDotNetUri);

        IEnumerator<KeyValuePair<string, Uri>> enumerator =
            collection.GetEnumerator();

        Assert.IsTrue(EnumeratorContains(enumerator,
           
    exampleDotComLabel, exampleDotComUri));
       
    Assert.IsTrue(EnumeratorContains(enumerator,
            exampleDotNetLabel, exampleDotNetUri));
    }

  • And to get this to work I need to implement the test helper – EnumeratorContains.

    private bool EnumeratorContains(
        IEnumerator<KeyValuePair<string, Uri>> enumerator,
           string label, Uri uri)
    {
        while (enumerator.MoveNext())
        {
            KeyValuePair<string, Uri> bookmark = enumerator.Current;
            if (bookmark.Key.Equals(label) &&
                bookmark.Value.Equals(uri))
                return true;
        }

        return
    false;
    }

    Don’t you just love that generics syntax. I am starting to get the C++ template shivers again. There is a big problem with this code but lets get it to work before starting to fix it. Here is the implementation I need to get the test to pass:

    public IEnumerator<KeyValuePair<string, Uri>> GetEnumerator()
    {
        return dictionary.GetEnumerator();
    }

    This is simple enough, and the tests pass. Now that it works what was that issue? It seems to me that returning a KeyValuePair<string, Uri> exposes too much of the underlying storage mechanism. What if someone wanted to come along and change it? You are potentially looking at a change to the interface or if you are unwilling to do that you would have to adapt to the new interface. Also, the syntax as I mentioned before is not the prettiest. My solution to this problem is to introduce a class called Bookmark. Let’s rewrite the test.

    [Test]
    public void EnumeratorContainsOnlyAddedItems()
    {
        collection.Add(exampleDotComLabel, exampleDotComUri);
       
    collection.Add(exampleDotNetLabel, exampleDotNetUri);

        IEnumerator<Bookmark> enumerator = collection.GetEnumerator();

        Assert.IsTrue(EnumeratorContains(enumerator,
            exampleDotComLabel, exampleDotComUri));
       
    Assert.IsTrue(EnumeratorContains(enumerator,
            exampleDotNetLabel, exampleDotNetUri));
    }

    I left out the EnumeratorContains method as an exercise for you, the reader. Here is the corresponding implementation:

    public IEnumerator<Bookmark> GetEnumerator()
    {
        foreach (KeyValuePair<string, Uri> bookmark in dictionary)
            yield return new Bookmark(bookmark.Key, bookmark.Value);
    }

    and the simplest Bookmark class implementation:

    public class Bookmark
    {
        private string label;
        private Uri uri;

        public Bookmark(string label, Uri uri)
        {
            this.label = label;
            this.uri = uri;
        }

        public string Label
        {
            get { return label; }
        }

        public Uri Uri
        {
            get { return uri; }
        }
    }

    When I compile and run this the tests pass. I don’t like that we have to create a new Bookmark to enumerate over the bookmarks so thats where I will pick up next time.