Beer haiku

August 17, 2007 by deinotes

Sent to Beer Haiku Daily

Suffusion of hops
An East India Pale Ale
Like Tui? Yeah, right.

Tui is a mass-market New Zealand beer. It’s definitely not hoppy enough to be called IPA. They have a long-running billboard campaign with an unlikely statement (e.g. “I slept on a mate’s couch”) on the left, and the words “Yeah, right” on the right. RealBeer.co.nz did a spoof of that. They are also the ones that gave me the link to the beer haiku site. Sweet as.

Stupid Team Explorer Features

July 18, 2007 by deinotes

I couldn’t connect to TFS this morning. No-one else was having problems, just me. Restarting Visual Studio had no effect. Rebooting had no effect. I was about to Remote Desktop into the TFS server to see if I’d lost some permissions somewhere when the solution occurred to me.

I’d been recording some scripts for load testing, and to do so I’d set an http proxy in my Internet Explorer settings. Team Explorer apparently uses that proxy setting, too. Since the recording proxy wasn’t running, Team Explorer couldn’t connect to TFS.

Grumble.

Performance counter permissions

April 30, 2007 by deinotes

Am I doing this wrong? I would expect the code below to either allow me to create the performance counter category, or to throw a SecurityException when I Demand the permission to Administer performance counters. When I run it as an underpriveleged user, it does neither.

using System;
using System.Diagnostics;

namespace TestDemand
{
    class Program
    {
        private string _categoryName = "Bogus Category";
        private string _machineName = ".";

        static void Main(string[] args)
        {
            Program p = new Program();
            if (0 < args.Length &&
                "-d" == args[0].Substring(0, 2).ToLower())
            {
                p.DeleteCategory();
            }
            else
            {
                p.CreateCategory();
            }
        }

        private void CreateCategory()
        {
            try
            {
                if (!Demand(PerformanceCounterPermissionAccess.Read))
                {
                    Console.WriteLine("Failure: Could not get permission to read Performance Counter Categories");
                    return;
                }

                if (PerformanceCounterCategory.Exists(this._categoryName, this._machineName))
                {
                    Console.WriteLine("Failure: Category \"{0}\" already exists.", this._categoryName);
                    return;
                }

                if (Demand(PerformanceCounterPermissionAccess.Administer))
                {
                    Console.WriteLine("Got permission to Administer Performance Counter Categories");
                }
                else
                {
                    Console.WriteLine("Success: Could not get permission to Administer Performance Counter Categories");
                    return;
                }

                CounterCreationDataCollection counters = new CounterCreationDataCollection();
                counters.Add(new CounterCreationData("Some counter", "Counter help text",
                                                                           PerformanceCounterType.NumberOfItems32));
                PerformanceCounterCategory.Create(this._categoryName, "Category help string",
                    PerformanceCounterCategoryType.SingleInstance, counters);
            }
            catch (Exception e)
            {
                Console.WriteLine("Failure: {0}", e.Message);
                Console.WriteLine(e.StackTrace);
                return;
            }
            if (PerformanceCounterCategory.Exists(this._categoryName))
            {
                Console.WriteLine("Success: Category successfully created");
            }
            else
            {
                Console.WriteLine("Failure: No error but category was not created");
            }
        }
        private void DeleteCategory()
        {
            if (!Demand(PerformanceCounterPermissionAccess.Administer))
            {
                Console.WriteLine("Failure: Could not get permission to Administer Performance Counter Categories");
            }
            PerformanceCounterCategory.Delete(this._categoryName);
            if (PerformanceCounterCategory.Exists(this._categoryName))
            {
                Console.WriteLine("Failure: Category was not deleted");
            }
            else
            {
                Console.WriteLine("Success: Category successfully deleted");
            }
        }

        private bool Demand(PerformanceCounterPermissionAccess access)
        {
            bool result = true;
            try
            {
                PerformanceCounterPermission permission = new PerformanceCounterPermission();
                permission.PermissionEntries.Add(new PerformanceCounterPermissionEntry(
                    access, _machineName, _categoryName));
                permission.Demand();
            }
            catch (System.Security.SecurityException)
            {
                result = false;
            }
            return result;
        }
    }
}

Outlook error 800ccc0e

April 16, 2007 by deinotes

If you’re getting this error, and it’s not your firewall or antivirus settings, it may be your ISP.

Everyone in the house but me uses Outlook 2000 for their email (or did until this morning, when I switched Gareth over to Thunderbird). I use Gmail’s web interface. Lisa has been sending and receiving emails without problems, but Gareth has not been able to send email for some time, persistently getting error 0×800ccc0e.

Search for this error code in Google, and what you’ll get told is that your firewall or antivirus software is blocking port 25. It wasn’t until the bottom of the third page of hits that anyone made the obvious point that it could be my ISP blocking port 25. Obviously they let out SMTP to well known mail providers such as Google, but not to my dodgy hosting provider in the states, which explains why Lisa can get her mail but Gareth can’t – Lisa’s mail is forwarded from morrish.org to gmail.com, but Gareth’s isn’t (he has less of a spam problem). Said dodgy provider is aware of this, and also provides SMTP on port 587, which Telecom does not block.

Mutation Testing

March 30, 2007 by deinotes

Recently I came to the realisation that 100% code coverage by unit tests, while desirable, does not guarantee that anyone is checking the output of the code being called. While thinking about this, I ran across the concept of mutation testing, whereby you break your code, one line at a time, and make sure that doing so causes a test to fail. If it doesn’t, you don’t have enough tests.

Jester appears to be the dominant mutation testing tool. It is tightly coupled with the Java language and JUnit. There is a port to C# and NUnit, called Nester, but it is alpha-release and has been since 2004. This MSDN post explains how to do mutation testing on the IL directly, and comes with some fairly hairy code (VS 2003) to do so.

I started playing around with this, writing a small, buggy DLL, and equally small test jig, looking at the IL output by ildasm, and changing stuff at random. It doesn’t help that the IL output of this code does not include any of the 12 operators discussed in James McCaffrey’s post. But with the help of the IL spec I was able to change some code. And every change broke a test. But my code is still wrong!

My unit tests have 100% code coverage, and any changes to the inequality operators cause a test to fail. Is this just a limitation of the unit test, code coverage and mutation testing approaches? Is there some mutation I’m missing that will break my code but let my tests pass?

    public class MyMath
    {
        public int Max(int value1, int value2, int value3)
        {
            if (value2 < value3)
                return value3;
            if (value1 < value2)
                return value2;
            return value1;
        }
    }

    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            MyMath a = new MyMath();
            Assert.AreEqual(3, a.Max(1, 2, 3));
            Assert.AreEqual(3, a.Max(1, 3, 2));
            Assert.AreEqual(3, a.Max(3, 2, 1));
            // above three tests pass with 100% code coverage 

            //Assert.AreEqual(3, a.Max(3, 1, 2));
            // this test fails
        }
    }