Testable Voice Activated Toaster

In following up to last week’s voice activated toaster, I wanted to work on making my solution more testable.  To that end, I re-read The Art Of Unit Testing:

 I still find his explanation of Mocks versus Stubs confusing.  In any event, I dove right in and added a test project to my solution.  I first realized that Rhino Mocks works either with Interfaces or Abstract Classes – the Phidget API had neither.  I read Brownfield Application Development In .NET:

 and realized that I needed to add an anti-corruption layer to the Phidget API and use an Adapter Pattern to wrap the existing API.

Moving to my code, the 1st stumbling block is that the SpeechRecognitionEngine and Choices classes do not have a defined interface.  I refactored the CreateSpeechRecognitionEngine method to a more testable chunks of code:

 

        public static void SetupSpeechRecognition()

        {

            SpeechRecognitionEngine _speechRecognitionEngine = new SpeechRecognitionEngine();

            Choices _choices = new Choices();

 

            CreateSpeechRecognitionEngine(_speechRecognitionEngine);

            LoadGrammarIntoSpeechRecognitionEngine(_speechRecognitionEngine, _choices);

            _speechRecognitionEngine.RecognizeAsync(RecognizeMode.Multiple);

 

        }

 

        public static void CreateSpeechRecognitionEngine(SpeechRecognitionEngine speechRecognitionEngine)

        {

            SpeechRecognitionEngine _speechRecognitionEngine = speechRecognitionEngine;

            _speechRecognitionEngine.SetInputToDefaultAudioDevice();

            _speechRecognitionEngine.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(speechRecognitionEngine_SpeechRecognized);

        }

 

        public static void LoadGrammarIntoSpeechRecognitionEngine(SpeechRecognitionEngine speechRecognitionEngine, Choices choices)

        {

            SpeechRecognitionEngine _speechRecognitionEngine = speechRecognitionEngine;

 

            Choices _choices = choices;

            _choices.Add("Toast");

            _choices.Add("Stop");

            Grammar grammar = new Grammar(_choices);

 

            _speechRecognitionEngine.LoadGrammar(grammar);

        }

 

I then used the adapter pattern to make a testable Phidget API.  I created interfaces for a Phidget, Interface Kit, and a PhidgetException.  I then created Phidget, Interface, and PhidgetException classes that implemented the interface.   I also split out the all of the enums that the API uses into their own class – the values are the same thanks to Reflector.  My solution looked like this:

 

 

I then had some supporting classes to take care of the rest of the API.  The first was the event handlers.  For the sake of keeping the class count down, I put all of the event handers into one class:

 

namespace Com.Tff.VoiceActivatedToaster.Phidget.Events

{

    //Phidgit Events

    public delegate void AttachEventHandler(object sender, AttachEventArgs e);

    public delegate void DetachEventHandler(object sender, DetachEventArgs e);

    public delegate void ErrorEventHandler(object sender, ErrorEventArgs e);

    public delegate void ServerConnectEventHandler(object sender, ServerConnectEventArgs e);

    public delegate void ServerDisconnectEventHandler(object sender, ServerDisconnectEventArgs e);

 

    //Interface Kit Events

    public delegate void OutputChangeEventHandler(object sender, OutputChangeEventArgs e);

    public delegate void SensorChangeEventHandler(object sender, SensorChangeEventArgs e);

}

 

I then added individual classes for each event args.  The Event Subdirectory looked like so:

 

 

Hooking up the events to the Phidget API, I made some good progress.  I then had 3 public fields (sigh) on the Interface Kit: Inputs, Outputs, and Sensors.  My 1st thought was to create interfaces and wrapper classes like I have done so far – but I immediately got a frying pan to the face:

 

 

 

Crap – the constructors are marked internal.  I could not wrap the classes.  I then went to plan B – use Reflector and implement the same code they used.  I then got a frying pan to the back of the head with Plan B when I looked at their code:

 

 

 

They were wrapping their unmanged code so they have these pointers and references all over the place.  I took a deep breath (“OK, I can do this”) and tried to implement.  I tried to reference the unmanaged assembly and got this:

 

 

Plan B is officially dead.  I then went to Plan C – use the Phidget API in my API.  I hated to do it, but I did it.  Here is the relevant code snippet:

 

    public class InterfaceKit : Phidget, IInterfaceKit

    {

        Phidgets.InterfaceKit _interfaceKit = null;

 

        //Have to use the Pdigit API b/c the Constructors are marked as internal

        public Phidgets.InterfaceKitDigitalInputCollection inputs;

        public Phidgets.InterfaceKitDigitalOutputCollection outputs;

        public Phidgets.InterfaceKitAnalogSensorCollection sensors;

 

        public InterfaceKit()

        {

            _interfaceKit = new Phidgets.InterfaceKit();

        }

 

 

I then hooked up my console application to the API and got nothing:

 

 

I then ran out of time: 5 hours of coding for Unit Test – and I have yet to write a single test.  I am just refactoring a poorly-written API to make the classes testable.

 

I’ll keep plugging away.

 

 

 

Advertisements

Voice Activated Toaster

I have played around with both the Speech API and the Phidget API over the last 5-7 years or so.  For the speech API, I created a home automation system to use the speech engine to control a house’s sound system, a cook’s recipe system, and to read the news and weather to a causal listener.  If patents weren’t $10,000, I would have sent something in – my neighbor in Alexandria worked at the Patent Office and thought it had a good chance to get approved, but I digress.  For the Phidget API, I did something similar to Brian Peek’s animated light show on Coding-4-Fun’s where I synched my Christmas’s lights to music.

I recently got back into both APIs to build a voice-activated toaster.  I plan to expand the project to include mocking of these external dependencies (the Phidget board/Toaster and the speech engine). 

To build the connection to the toaster, I used the Phidget 0/0/4 Interface kit.  I then wired it up like Brian did:

To handle the voice input, I used a cheap wireless microphone system from radio shack and hooked it into my microphone port. 

I used an old toaster that was hanging around my attic.

 I then slapped up a quick console application.  The application creates a connection to the Phidget board, starts up a speech recognition engine and listens for the word “Toast”.  Once recognized, the Phidget channel opens and the toaster is activated.  Once the word “Stop” is heard, the toaster is deactivated.

Here is the console output:

and here is the toaster in action:

 

I recognize that the code is not ready for prime time (heck, does not even have error handling), but I wanted to get a working skeleton down before throwing in my unit tests and mocking framework.  There will be more on that next week.  Here are the 80 lines of code that I needed to write to get it working:

 

namespace Com.Tff.VoiceActivatedToaster

{

    class Program

    {

        private static InterfaceKit interfaceKit = null;

 

        static void Main(string[] args)

        {

            Console.WriteLine("Starting");

            CreateSpeechRecognitionEngine();

            CreatePhigitInterface();

            Console.ReadKey();

        }

 

        private static void CreateSpeechRecognitionEngine()

        {

            SpeechRecognitionEngine speechRecognitionEngine = new SpeechRecognitionEngine();

           

            Choices choices = new Choices();

            choices.Add("Toast");

            choices.Add("Stop");

            Grammar grammar = new Grammar(choices);

 

            speechRecognitionEngine.LoadGrammar(grammar);

            speechRecognitionEngine.SetInputToDefaultAudioDevice();

            speechRecognitionEngine.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(speechRecognitionEngine_SpeechRecognized);

            speechRecognitionEngine.RecognizeAsync(RecognizeMode.Multiple);

            Console.WriteLine("Computer is listening");

        }

 

        static void speechRecognitionEngine_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)

        {

            Console.WriteLine("{0} was recognized with {1} confidence", e.Result.Text, e.Result.Confidence.ToString());

            if (e.Result.Text == "Toast")

            {

                interfaceKit.outputs[0] = true;

            }

 

            if (e.Result.Text == "Stop")

            {

                interfaceKit.outputs[0] = false;

            }

        }

 

        private static void CreatePhigitInterface()

        {

            interfaceKit = new InterfaceKit();

            interfaceKit.open();

 

        }

    }

}

 

 

ASP.NET MVC 2 RoutingEngineSiteMapProvider

Continuing my thought on RoutingEngineSiteMapProvider, I worked with Rob Seder on Sunday for a bit

I was thinking of Maarten Balliau’s solution on CodePlex to a MVCSiteMapProvider and was wondering if there is an easier way. We tried inheriting from StaticSiteMapProvider and copy/pasting the code from XmlSiteMapProvider and re-writing it(like Maarten did), created our own implementation for the SiteMapProvider, and then giving up.

That afternoon I then looked at inheriting from XMLSiteMapProvider and intercepting the NodeCreation to plug in a MvcSiteMapNode.  I just created a basic node like so:

        public MvcSiteMapNode(SiteMapProvider provider, string key, string url, string title, string description, IList roles, NameValueCollection attributes, NameValueCollection explicitResourceKeys, string implicitResourceKey):

            base(provider, key, url, title, description,roles,attributes,explicitResourceKeys,implicitResourceKey)

        {

        }

 

        public string Controller { get; set; }

        public string Action { get; set; }

 

The rest of the constructiors were omitted for brevity

I then tried to intercept the call in BuildSiteMap method. 

    public class RoutingEngineSiteMapProvider: XmlSiteMapProvider

    {

        public override SiteMapNode BuildSiteMap()

        {

            SiteMapNode siteMapNode = base.BuildSiteMap();

            MvcSiteMapNode mvcSiteMapNode = ConvertSiteMapNodeIntoMvcSiteMapNode(siteMapNode);

            return mvcSiteMapNode;

        }

 

        private MvcSiteMapNode ConvertSiteMapNodeIntoMvcSiteMapNode(SiteMapNode siteMapNode)

        {

            MvcSiteMapNode mvcSiteMapNode = new MvcSiteMapNode(siteMapNode.Provider,siteMapNode.Key,

                siteMapNode.Url,siteMapNode.Title, siteMapNode.Description);

 

            mvcSiteMapNode.Controller = "Test Controller";

            mvcSiteMapNode.Action = "Test Action";

 

            return mvcSiteMapNode;

        }

    }

 

Surprisingly, it worked.  However, when I went to add a line to check on the nodes themselves in BuildSiteMapNode() like this:

            int counter = mvcSiteMapNode.ChildNodes.Count;

 

Things went bad – Stack Overflow.  I was in recursive hell.

I then tried to intercept AddNode like this:

        protected override void AddNode(SiteMapNode node)

        {

            base.AddNode(node);

        }

 

The problem is that this method is not called when I spun up the site.

Grrrr… I am out of patience on this.  Looking at the code in Reflector makes me appreciate best practices all that more.  Node6  Microsoft, really?  What happens if there is a 7th level node?  No exception is thrown.

The last thing I can think of is to copy/paste the code in BuildSiteMap() and then getting rid of the XMLReader completely.  However, this would be a mucho breaking change because the method violates the Open/Closed Principle and the IoC tenant and I really don’t have the time to track down all of the dangling dependencies in this API.

ASP.NET MVC and Menu Trimming

One of the nice features with ASP.NET is menu trimming pretty much out of the box.  You need to:

Create a SiteMap:

<?xml version="1.0" encoding="utf-8" ?>

<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >

  <siteMapNode url="" title=""  description="">

    <siteMapNode url="/Public" title="Public"  description="">

        <siteMapNode url="/Public/PublicContent1" title="Public Content #1"  description="" />

        <siteMapNode url="/Public/PublicContent2" title="Public Content #2"  description="" />

    </siteMapNode>

    <siteMapNode url="/Private" title="Private"  description="">

      <siteMapNode url="/Private/PrivateContent1" title="Private Content #1"  description="" />

      <siteMapNode url="/Private/PrivateContent2" title="Private Content #2"  description="" />

    </siteMapNode>

  </siteMapNode>

</siteMap>

 

Add the sitemap to your web.config:

    <siteMap defaultProvider="DefaultSiteMapProvider" enabled="true">

      <providers>

        <add name="DefaultSiteMapProvider" type="System.Web.XmlSiteMapProvider" siteMapFile="Web.sitemap"

             securityTrimmingEnabled="true" />

      </providers>

    </siteMap>

 

Add some roles to your web.config that protect certain areas

  <location path="~/Private">

    <system.web>

      <authorization>

        <deny users="*"/>

        <allow roles="admin"/>

      </authorization>

    </system.web>   

  </location>

 

Add a SiteMapDataProvider and a menu to your form that uses your SiteMapDataProvider:

            <div class="clear hideSkiplink">

                <asp:SiteMapDataSource ID="siteMapDataSource" runat ="server" ShowStartingNode="false" />

                <asp:Menu ID="NavigationMenu" runat="server" CssClass="menu" EnableViewState="false"

                    IncludeStyleBlock="false" Orientation="Horizontal" DataSourceID="siteMapDataSource">

<%                    <Items>

                        <asp:MenuItem NavigateUrl="~/Default.aspx" Text="Home"/>

                        <asp:MenuItem NavigateUrl="~/About.aspx" Text="About"/>

                    </Items>–%>

                </asp:Menu>

 

(Note that I left in the out of the box VS2010 template items for reference)

Voila – menu trimming

Behind the scenes, ASP.NET runtime knows to look for Web.Sitemap and then to look in your web.config for the roles

 

Once you move to MVC2, I thought all hope was lost.  No more server controls.  No more auto menu trimming.  No more free ice cream.  But, I was wrong.  You can use ASP.NET Server controls in your MVC2 project and things work just fine.   This is what I did:

I added a site map

<?xml version="1.0" encoding="utf-8" ?>

<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >

  <siteMapNode url="" title=""  description="">

    <siteMapNode url="" title="Home"  description="">

      <siteMapNode url="Home/Index" title="Index"  description="" />

      <siteMapNode url="Home/About" title="About Us"  description="" />

    </siteMapNode>

    <siteMapNode url="" title="User Input"  description="">

      <siteMapNode url="UserInput/Index" title="Index"  description="" />

    </siteMapNode>

    <siteMapNode url="" title="Private" description="">

      <siteMapNode url="Private/CurrentTime" title="Current Time"  description="" />

    </siteMapNode>

  </siteMapNode>

</siteMap>

 

The first thing to realize is that you are no longer mapping to physical file locations – you are still using the routing engine.  Note that my siteamp does not have a .aspx suffix nor a \Views subdirectory listed.  Also, if you have the file location on disk but no controller, you get a 404:

I then added the same SiteMapProvider and Location syntax to the web.config.  The then added the SiteMapDataSource to the Master page with the menu.

            <div id="menucontainer">

                <form runat="server">

                    <asp:SiteMapDataSource runat="server" ID="smds" ShowStartingNode="false" />

                    <asp:Menu runat="server" ID="aspmenu" DataSourceID="smds" />

                </form>

<%                <ul id="menu">             

                    <li><%: Html.ActionLink("Home", "Index", "Home")%></li>

                    <li><%: Html.ActionLink("About", "About", "Home")%></li>

                </ul>–%>

            </div>

 

(Note that I left in the out of the box VS2010 template items for reference)

(also note that I had to add a form tag around the provider and menu)

I ran it – to my <slight> surprise, it worked – sorta:

I worry about the formatting later – at least it is showing up.  Alas, no menu trimming though!

Interestingly, looking at the HTTP via Fiddler, you can see the view state:

 Here are the problems:

·         Hard-Coded URLs in the sitemap

·         Permissions tied to File System locations

·         View State in MVC – Say it aint’s so!

 

I wonder if there is a way to create a SiteMap provider based on the Routing Engine?  A quick search showed this one  here and here.

But I wanted to try to extend the XMLSiteMapProvider to account for the routes.  But then, it is not an XMLSiteMapProvider.  In fact, it is a RoutingEngineSiteMapProvider.

My next blog post continues this idea/rabbit hole.

 

MVC Gators and VS2010

I start with an opening statement like this on a View:

</head>

<body>

    <% using (Html.BeginForm()) { %>

</body>

</html>

 

And then I add a closing gator

<% } %>

 

As soon as I hit enter to the closing gator, VS2010 reformats the code to this:

<body>

    <% using (Html.BeginForm())

       { %>

    <% } %>

</body>

 

Note how the opening gator gets moved down a line.

I think this is better b/c it is more in-line with our Server-side best practices – though it is against most Javascript best practices (and the examples in the book).  I assume there is a setting in VS2010 to not automatically put in the line break…

Also, note to self:

If you write your gator like this:

<%= Html.Label(TempData["message"].ToString()); %>

 

You will get an error message like this:

Remove the semicolon at the end and things work.  The “=” in the Gator means you don’t use a semicolon at the end…

Ugh – They forgot to turn of trace

I Binged Gun Safety (my daughter shot at camp 2 weeks ago and wants to do it again).  The 4th link is from magicyellow – which I assume is the Yellow Pages.  Check out the screen shot of the page’s footer:

 
My favorite SQL was this:

SQL =

INSERT INTO    logs_sc (code,

                                                     event,

                                                     client,

                                                     source,

                                                     sourceSite,

                                                     sourceQuery,

                                                     clientIP,

                                                     admin,

                                                     vid,

                                                     MYCatID,

                                                     locID,

                                                    

                                                     userAgent,

                                                     aid,

                                                    

                                                     siteID)

                                      VALUES (‘SCL’,

                                                     ‘[283868|USNC  ]’,

                                                     ‘[56959191.51529074]’,

                                                     http://www.bing.com/search?q=Cary%2C+NC+Gun+Club&form=QBLH&qs=n&sk=&#8217;,

                                                     http://www.bing.com/search&#8217;,

                                                     ‘q=Cary%2C+NC+Gun+Club&form=QBLH&qs=n&sk=’,

                                                     ‘98.101.143.134’,

                                                     0,

                                                     0,

                                                     283868,

                                                     ‘USNC  ‘,

                                                    

                                                     ‘Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 1.1.4322; .NET CLR 3.5.21022; .NET CLR 1.0.3705; .NET CLR 3.5.30729; MS-RTC EA 2; .NET CLR 3.0.30729; MS-RTC LM 8; .NET4.0C; .NET4.0E;’,

                                                     ‘0’,

                                                    

                                                     1)

 

In case I was wondering what info they were collecting about me in my visit….

 And

Yup – they left all of their trace information on when they want to production.  I emailed them to fix it right away – I wonder how long it will take them to read my email?

 

ASP.NET MVC2 In Action

I started working through ASP MVC2 In Action

 

A couple of nit-pciks

1) They abuse the var keyword and don’t follow best practices in terms of variable naming.  For example, on page 18:

            var model = new GuestBookEntry();

            return View(model)

 

Using var here is just lazy and using the variable “model” leads to confusion– it should be:

            GuestBookEntry guestBookEntry = new GuestBookEntry();

            return View(guestBookEntry);

 

Because that is what the controller is actually returning

2) They don’t fully-qualify the model on the views.  For example, on page 18 again:

<%@ Page Title=""

    Language="C#"

    MasterPageFile="~/Views/Shared/Site.Master"

    Inherits="System.Web.Mvc.ViewPage<GuestBookEntry>" %>

 

It should be

<%@ Page Title=""

    Language="C#"

    MasterPageFile="~/Views/Shared/Site.Master"

    Inherits="System.Web.Mvc.ViewPage<Com.Tff.GuestBook.Models.GuestBookEntry>" %>

 

I don’t know any way to NOT use the namespace using MVC (they must, unless their book code doesn’t compile OR they are putting everything in the same namespace – Ugh!)

I DO like the fact that they put line breaks in the View definition – it is much more readable.

Aside from the nit-picks, I have 1 larger beef.

I believe that having more models (DTOs, POCOs, whatever you want to call them) is better than have 1 uber-model that you shoe horn into all situations.  In fact, having a use-case specific model follows the single-responsibility principle very well.  I DON’T agree with the use of nested classes.  For example, on page 29 they recommend (constructor is mine – I put it in the get the View to match their screen shots)

    public class CustomerSummary

    {

public CustomerSummary(string name, string serviceLevel, string orderCount, string mostRecentOrderDate, bool active)

        {

            this.Name = name;

            this.ServiceLevel = serviceLevel;

            this.OrderCount = orderCount;

            this.MostRecentOrderDate = mostRecentOrderDate;

            this.Input = new CustomerSummaryInput();

            this.Input.Active = active;

        }

 

        public string Name { get; set; }

        public string Active { get; set; }

        public string ServiceLevel { get; set; }

        public string OrderCount { get; set; }

        public string MostRecentOrderDate { get; set; }

        public CustomerSummaryInput Input { get; set; }

 

    }

 

    public class CustomerSummaryInput

    {

        public int Number { get; set; }

        public bool Active { get; set; }

    }

 

Yuck!

There should be a CustomerSummary class and a CustomerInput class.  If you need to link the two – that is what primary keys are for (heck, they start that with the Number property in CustomerSummaryInput.  This nested class combines 2 different things (displaying the customer and getting new customer info).  If there needs to be a customer base class (FirstName, LastName, Active) and then derived classes with the ServiceLevel, etc…, that is much more cleaner.