Wednesday, January 16

Singleton

How to unit test a Singleton pattern?


using System;

public sealed class Singleton
{
   private static volatile Singleton instance;
   private static object syncRoot = new Object();

   private Singleton() {}

   public static Singleton Instance
   {
      get 
      {
         if (instance == null) 
         {
            lock (syncRoot) 
            {
               if (instance == null) 
                  instance = new Singleton();
            }
         }

         return instance;
      }
   }
}

Answer: Don't use a Singleton. Use Dependency Injection.

Monday, January 14

TDD


I am trying out some TDD on Mat Buckland’s AI example code from “Programming AI by Example”. I translated Telegram.h to Telegram.css:
// -----------------------------------------------------------------------
// Telegram.cs
// -----------------------------------------------------------------------

namespace WestWorld
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class Telegram
    {
        /// <summary>
        /// These telegrams will be stored in a priority queue. Therefore the >
        /// operator needs to be overloaded so that the PQ can sort the telegrams
        /// by time priority. Note how the times must be smaller than
        /// SmallestDelay apart before two Telegrams are considered unique.
        /// </summary>
        private const double SmallestDelay = 0.25;

        /// <summary>
        /// the entity that sent this telegram
        /// </summary>
        private int sender;

        /// <summary>
        /// the entity that is to receive this telegram
        /// </summary>
        private int receiver;
        
        /// <summary>
        /// the message itself. These are all enumerated in the file "MessageTypes.h"
        /// </summary>
        private int msg;

        /// <summary>
        /// Messages can be dispatched immediately or delayed for a specified amount
        /// of time. If a delay is necessary this field is stamped with the time 
        /// the message should be dispatched.
        /// </summary>
        private double dispatchTime;

        // any additional information that may accompany the message
//        void*        ExtraInfo;

        /// <summary>
        /// Initializes a new instance of the <see cref="Telegram"/> class.
        /// </summary>
        public Telegram()
        {
            this.sender = 0;
            this.receiver = 0;
            this.msg = 0;
            this.dispatchTime = 0;
        }

        /// <summary>
        /// Gets or sets the sender.
        /// </summary>
        /// <value>
        /// The sender.
        /// </value>
        public int Sender
        {
            get { return this.sender; }
            set { this.sender = value; }
        }

        /// <summary>
        /// Gets or sets the receiver.
        /// </summary>
        /// <value>
        /// The receiver.
        /// </value>
        public int Receiver
        {
            get { return this.receiver; }
            set { this.receiver = value; }
        }

        /// <summary>
        /// Gets or sets the message.
        /// </summary>
        /// <value>
        /// The message.
        /// </value>
        public int Message
        {
            get { return this.msg; }
            set { this.msg = value; }
        }

        /// <summary>
        /// Gets or sets the dispatch time.
        /// </summary>
        /// <value>
        /// The dispatch time.
        /// </value>
        public double DispatchTime
        {
            get { return this.dispatchTime; }
            set { this.dispatchTime = value; }
        }

        /// <summary>
        /// Implements the operator ==.
        /// </summary>
        /// <param name="t1">The t1.</param>
        /// <param name="t2">The t2.</param>
        /// <returns>
        /// The result of the operator.
        /// </returns>
        public static bool operator ==(Telegram t1, Telegram t2)
        {
            double temp = Math.Abs(t1.DispatchTime - t2.DispatchTime);

            return Math.Abs(t1.DispatchTime - t2.DispatchTime) < Telegram.SmallestDelay && 
                t1.DispatchTime == t2.DispatchTime;
        }

        /// <summary>
        /// Implements the operator !=.
        /// </summary>
        /// <param name="t1">The t1.</param>
        /// <param name="t2">The t2.</param>
        /// <returns>
        /// The result of the operator.
        /// </returns>
        public static bool operator !=(Telegram t1, Telegram t2)
        {
            return Math.Abs(t1.DispatchTime - t2.DispatchTime) > Telegram.SmallestDelay && 
                t1.DispatchTime != t2.DispatchTime;
        }

        /// <summary>
        /// Implements the operator &lt;.
        /// </summary>
        /// <param name="t1">The t1.</param>
        /// <param name="t2">The t2.</param>
        /// <returns>
        /// The result of the operator.
        /// </returns>
        public static bool operator <(Telegram t1, Telegram t2)
        {
            if (t1 == t2)
            {
                return false;
            }
            else
            {
                return t1.DispatchTime < t2.DispatchTime;
            }
        }

        /// <summary>
        /// Implements the operator &gt;.
        /// </summary>
        /// <param name="t1">The t1.</param>
        /// <param name="t2">The t2.</param>
        /// <returns>
        /// The result of the operator.
        /// </returns>
        public static bool operator >(Telegram t1, Telegram t2)
        {
            if (t1 == t2)
            {
                return false;
            }
            else
            {
                return t1.DispatchTime > t2.DispatchTime;
            }
        }

        /// <summary>
        /// Determines whether the specified <see cref="System.Object"/> is equal to this instance.
        /// </summary>
        /// <param name="obj">The <see cref="System.Object"/> to compare with this instance.</param>
        /// <returns>
        ///   <c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.
        /// </returns>
        public override bool Equals(object obj)
        {
            return (Telegram)obj == this;
        }

        /// <summary>
        /// Returns a hash code for this instance.
        /// </summary>
        /// <returns>
        /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
        /// </returns>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }
}
The test class is TestTelegram.cs:
namespace TestWestWorld
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    using WestWorld;

    /// <summary>
    /// Tests for the Telegram class
    /// </summary>
    [TestClass]
    public class TestTelegram
    {
        /// <summary>
        /// Test context
        /// </summary>
        private TestContext testContextInstance;

        /// <summary>
        /// Initializes a new instance of the <see cref="TestTelegram"/> class.
        /// </summary>
        public TestTelegram()
        {
            // TODO: Add constructor logic here
        }

        /// <summary>
        /// Gets or sets the test context which provides
        /// information about and functionality for the current test run.
        /// </summary>
        public TestContext TestContext
        {
            get
            {
                return this.testContextInstance;
            }

            set
            {
                this.testContextInstance = value;
            }
        }

        #region Additional test attributes

        // You can use the following additional attributes as you write your tests:

        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }

        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }

        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }

        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        #endregion

        /// <summary>
        /// Tests the telegram equals == operator
        /// </summary>
        [TestMethod]
        public void TestTelegramEqualsOperator()
        {
            Telegram telegram1 = new Telegram();
            Telegram telegram2 = new Telegram();

            Assert.IsTrue(telegram1 == telegram2);
        }

        /// <summary>
        /// Tests the telegram not equals operator.
        /// </summary>
        [TestMethod]
        public void TestTelegramNotEqualsOperator()
        {
            Telegram telegram1 = new Telegram();
            Telegram telegram2 = new Telegram();

            Assert.IsFalse(telegram1 != telegram2);
        }

        /// <summary>
        /// Tests the telegram equals method.
        /// </summary>
        [TestMethod]
        public void TestTelegramEqualsMethod()
        {
            Telegram telegram1 = new Telegram();
            Telegram telegram2 = new Telegram();

            Assert.IsTrue(telegram1.Equals(telegram2));
        }

        /// <summary>
        /// Tests the telegram not equals method.
        /// </summary>
        [TestMethod]
        public void TestTelegramNotEqualsMethod()
        {
            Telegram telegram1 = new Telegram();
            Telegram telegram2 = new Telegram();

            telegram1.DispatchTime = 25;
            Assert.IsFalse(telegram1.Equals(telegram2));
        }

        /// <summary>
        /// Tests the telegram not equals operator when the object members
        /// have been set to different values.
        /// </summary>
        [TestMethod]
        public void TestTelegramEqualsOperatorWhenObjectNotSame()
        {
            Telegram telegram1 = new Telegram();
            Telegram telegram2 = new Telegram();

            telegram1.DispatchTime = 25;
            Assert.IsFalse(telegram1 == telegram2);
        }

        /// <summary>
        /// Tests the telegram not equals operator when the object members
        /// have been set to different values.
        /// </summary>
        [TestMethod]
        public void TestTelegramNotEqualsOperatorWhenObjectNotSame()
        {
            Telegram telegram1 = new Telegram();
            Telegram telegram2 = new Telegram();

            telegram1.DispatchTime = 25;
            Assert.IsTrue(telegram1 != telegram2);
        }

        /// <summary>
        /// Tests the telegram less than operator when the object members
        /// have been set to different values.
        /// </summary>
        [TestMethod]
        public void TestTelegramLessThanOperatorWhenObjectIsSame()
        {
            Telegram telegram1 = new Telegram();
            Telegram telegram2 = new Telegram();

            Assert.IsFalse(telegram1 < telegram2);
        }

        /// <summary>
        /// Tests the telegram less than operator when the object members
        /// have been set to different values.
        /// </summary>
        [TestMethod]
        public void TestTelegramLessThanOperatorWhenObjectIsNotSame()
        {
            Telegram telegram1 = new Telegram();
            Telegram telegram2 = new Telegram();

            telegram1.DispatchTime = 25;
            Assert.IsFalse(telegram1 < telegram2);
        }

        /// <summary>
        /// Tests the telegram less than operator when the object members
        /// have been set to different values.
        /// </summary>
        [TestMethod]
        public void TestTelegramLessThanOperatorWhenObjectNotSameButLess()
        {
            Telegram telegram1 = new Telegram();
            Telegram telegram2 = new Telegram();

            telegram2.DispatchTime = 25;
            Assert.IsTrue(telegram1 < telegram2);
        }

        /// <summary>
        /// Tests the telegram greater than operator when the object members
        /// have been set to different values.
        /// </summary>
        [TestMethod]
        public void TestTelegramGreaterThanOperatorWhenObjectIsSame()
        {
            Telegram telegram1 = new Telegram();
            Telegram telegram2 = new Telegram();

            Assert.IsFalse(telegram1 > telegram2);
        }

        /// <summary>
        /// Tests the telegram greater than operator when the object members
        /// have been set to different values.
        /// </summary>
        [TestMethod]
        public void TestTelegramGreaterThanOperatorWhenObjectIsNotSame()
        {
            Telegram telegram1 = new Telegram();
            Telegram telegram2 = new Telegram();

            telegram1.DispatchTime = 25;
            Assert.IsFalse(telegram1 < telegram2);
        }

        /// <summary>
        /// Tests the telegram greater than operator when the object members
        /// have been set to different values.
        /// </summary>
        [TestMethod]
        public void TestTelegramGreaterThanOperatorWhenObjectNotSameButLess()
        {
            Telegram telegram1 = new Telegram();
            Telegram telegram2 = new Telegram();

            telegram2.DispatchTime = 25;
            Assert.IsTrue(telegram1 < telegram2);
        }
    }
}

Tuesday, January 3

When getting data to a DataGrid in VS 2010, don't set the AutoGenerateColumns to 'true' and then add your own columns. You get double columns.

Sunday, August 10

So now what?

From MSDN:
Command-line compilation can be used to build applications with more complexity, although the compiler does not support WPF applications that include Extensible Application Markup Language (XAML) source code. Furthermore, command-line compilation does not support the full range of build requirements of typical WPF applications, including configuration management and ClickOnce manifest generation. To support these and other more complex build requirements, WPF integrates with and extends MSBuild.


You can't use the command line to compile XAML applications. Why?

Tuesday, July 29

NAnt and .NET 3.5

From an old entry by Jeffrey Palermo:

Unfortunately, we don't have a .Net 3.5-compatible NAnt distribution
yet, but it's trivial to get the latest version (.85) working with
.Net 3.5 and a Visual Studio 2008 solution.  Open up you nant.exe
config file, and add the following framework node just below your net-2.0 node.  Not much of a change, and it's working well for me.

<framework name="net-3.5"
    family="net"
    version="3.5"
    description="Microsoft .NET Framework 3.5"
    runtimeengine=""
    sdkdirectory="${path::combine(sdkInstallRoot, 'bin')}"
    frameworkdirectory="${path::combine(installRoot, 'v3.5')}"
    frameworkassemblydirectory="${path::combine(installRoot, 'v2.0.50727')}"
    clrversion="2.0.50727">

    <task-assemblies>
        <!-- include .NET specific assemblies -->
    <include name="tasks/net/*.dll" />
    <!-- include .NET 2.0 specific assemblies -->
    <include name="tasks/net/2.0/**/*.dll" />
    <!-- include Microsoft.NET specific task assembly -->
    <include name="NAnt.MSNetTasks.dll" />
    <!-- include Microsoft.NET specific test assembly -->
    <include name="NAnt.MSNet.Tests.dll" />
    </task-assemblies>

  <project>
        <readregistry property="installRoot"
            key="SOFTWARE\Microsoft\.NETFramework\InstallRoot"
            hive="LocalMachine" />

    <readregistry property="sdkInstallRoot"
            key="SOFTWARE\Microsoft\.NETFramework\sdkInstallRootv2.0"
            hive="LocalMachine"
            failonerror="false" />
    </project>

  <tasks>
        <task name="csc">
            <attribute name="exename">csc</attribute>
      <attribute name="supportsnowarnlist">true</attribute>
      <attribute name="supportswarnaserrorlist">true</attribute>
      <attribute name="supportskeycontainer">true</attribute>
      <attribute name="supportskeyfile">true</attribute>
      <attribute name="supportsplatform">true</attribute>
      <attribute name="supportslangversion">true</attribute>
      </task>

      <task name="vbc">
      <attribute name="exename">vbc</attribute>
      <attribute name="supportsdocgeneration">true</attribute>
      <attribute name="supportsnostdlib">true</attribute>
      <attribute name="supportsnowarnlist">true</attribute>
      <attribute name="supportskeycontainer">true</attribute>
      <attribute name="supportskeyfile">true</attribute>
      <attribute name="supportsplatform">true</attribute>
      <attribute name="supportswarnaserrorlist">true</attribute>
      </task>

      <task name="jsc">
      <attribute name="exename">jsc</attribute>
      <attribute name="supportsplatform">true</attribute>
      </task>

      <task name="vjc">
      <attribute name="exename">vjc</attribute>
      <attribute name="supportsnowarnlist">true</attribute>
      <attribute name="supportskeycontainer">true</attribute>
      <attribute name="supportskeyfile">true</attribute>
      </task>

      <task name="resgen">
      <attribute name="exename">resgen</attribute>
      <attribute name="supportsassemblyreferences">true</attribute>
      <attribute name="supportsexternalfilereferences">true</attribute>
      </task>

      <task name="al">
      <attribute name="exename">al</attribute>
      </task>

      <task name="delay-sign">
      <attribute name="exename">sn</attribute>
      </task>

      <task name="license">
      <attribute name="exename">lc</attribute>
      <attribute name="supportsassemblyreferences">true</attribute>
      </task>

      <task name="ilasm">
      <attribute name="exename">ilasm</attribute>
      </task>

      <task name="ildasm">
      <attribute name="exename">ildasm</attribute>
      </task>
    </tasks>
</framework>

Next, change the following in your NAnt build:

<property name="nant.settings.currentframework" value="net-3.5" />


Monday, July 28

Automated Unmaintainable Code

Still working on Nant, just not making a lot of progress.
A long time ago, I came across a humorous article on how to write
unmaintainable code. One of the points was to use the C continuation
operator to break up #defines so that a global search could not find
them. I use the global search quite a bit, so this one stuck in
my head as particularly bad. The other day, I was looking at some
open-source code. It was not indented, so I did a Ctrl-Shift-F in
Eclipse to reformat it. I ran the program, and received an exception.
So I copied the message and did a search to see what was causing
said exception. The search turned up no hits. I kept cutting
down on the words, and eventually, after about half of it was gone,
I found it. The reformat had broken up the string into several short
strings concatenated together. Somehow I find this offensive. It's
a good thing I don't use the Ctrl-Shift-F very often.

Tuesday, July 15

Supremacy: First Look

Lots and lots of code, no surprise there. XAML, which I have had zero
experience using. Well, that's what I wanted. The organization looks fine.
One major obstacle: I only have Visual Studio 2008 Express, which does not
support sub projects. Ok, have to resort to an old method: take it all
apart, and see if I can put it together to make it work.
Maybe I can install NAnt and build it that way?