What's your favorite Kata? 70

Posted by Brett Schuchert Tue, 30 Jun 2009 20:22:00 GMT

I’m looking to collect several katas for the OkC CoCo Dojo to make sure we have plenty of future practice sessions already in place. Ultimately I want it to be at least bi-weekly (or weekly) and self sustaining. Along those lines, I’d like to hear what are your favorite katas.

I’d prefer you mention things you’ve tried yourself. Please post links and your impressions in response to the blog. I’ll collect them here, and let me know if you’d like me to credit you with pointing me to the idea (or for the idea itself if you created it).

FWIW, after a little thinking, my favorite kata based on the number of times I’ve used it in one manner or another is Monopoly®.

Another Kata: Expression Tokenizer 70

Posted by Brett Schuchert Mon, 29 Jun 2009 06:49:00 GMT

I continue to work on some examples for upcoming kata’s at the OkC CoCo. The next problem (previously mentioned here) is an implementation of the Shunting Yard Algorithm.

This past week I used that with a group in North Carolina and I discovered that it was much easier to tokenize the expression as I worked my way through it rather than attempt to make it easy to split into tokens up front.

I worked through just this smaller problem of converting an expression into tokens using the iterator pattern a few times and eventually got what I thought was a pretty good solution. I was wrong, I got it even tighter by making more appropriate use of the regular expression libraries in Java. (This is an example of where my regex mental model – based primarily on grep, vi and AWK – was inadequate when taking into consideration typical implementations of regex libraries with classes like Pattern and Matcher.)

Anyway, here’s a writeup for that Kata: http://schuchert.wikispaces.com/Katas.ExpressionTokenizer.

My final version turned into something crazy-short. I did not anticipate the final version. Part of it, as mentioned above, had to do with how I previously envisioned using regular expressions. Part of it might have been that it just took a few times for the patterns naturally occurring to become evident to me. In any case, working through this problem three times resulted in the following revelations:
  • Initially I though it would be hard, it was not and in fact much less work than what I was doing in the original problem. And it took a lot less time than I expected.
  • The second time around I was looking to duplicate the experience, which I did. But I saw quite a bit of improvement.
  • The final version was really an a-ah for me. Initially it was just like the second version. Then, once I had the tests in the kata written, I started messing around, looking for additional improvements (and heavily applying the DRY principle). I found them, exploited commonality and finally I got to the point where there was one thing I did not like, and fixing that led to a huge improvement, which led to a few more significant improvements.

Ultimately, I’ll have several useful take-aways from working on the problem several times.

If you’d like to see the “latest final version” of this, ping me. I’ll consider posting it to the blog, but I’d rather not give anything away without a specific request.

The Rush 60

Posted by Uncle Bob Fri, 26 Jun 2009 13:40:13 GMT

There’s nothing like the feeling of achievement when you get a complex software system working. It’s the feeling of the hunter making a hard fought kill. By the sheer power of your intellect you have imposed your will upon inanimate nature, and forced it to do your bidding. You feel the rush of power, the satisfaction of victory. You are the master!

That’s the good news.

The bad news is that you’ve made a mess of things along the way.

This is inevitable. It takes a great deal of focus and endurance to get a system working just right. While you are consumed by that focus, you have little room for niceties like small functions, nice names, decoupling, and cleanliness.

My apprentice and I just finished achieving a major milestone in FitNesse. It used to be that each new release of FitNesse was contained in a zip file that had all the files and directories laid out just perfectly. This is great for a brand new installation, but doesn’t work so well when you are upgrading. What we managed to get working last night was the ability for FitNesse to self-install from it’s jar file. Now, whether you are installing for the first time, or just upgrading, FitNesse will install itself into your environment appropriately.

If you’ve ever written a self-install like this, you know there are lots of niggling little details to attend to. While the problem is conceptually simple, the realization is a maze of complexity.

Last night, with dinner waiting on the table and getting cold, we got the last little problem licked, and saw the whole self-installation work as we wanted. We congratulated each other with a high-five, and then went upstairs to eat a well-deserved meal. Later that evening I went down to the office and checked in the code.

This morning I woke up, and while in the shower, I realized that we had a lot of work left to do. We need to go back over all that code and clean it up. I’m sure we left a swath of detritus while on the hunt.

The rush of victory should never be confused with the cold and crystalline concept of done. Once you get your systems to work, you still have to go back and clean up the wreckage left behind by the victorious battle. You are not done until the victorious code has been cleaned, polished, and oiled.

Shunting Yard Algorithm Kata 65

Posted by Brett Schuchert Thu, 25 Jun 2009 02:36:00 GMT

Next week (end of June 2009) I hoping to schedule the second OkC CoCo Dojo. The first Dojo was fun with a decent turnout. However, it was a bit “loose” (my fault). Loose is fine, but this time around I want to try a different approach and see how that works out.

The problem for this second Dojo is: http://schuchert.wikispaces.com/Katas.ShuntingYardAlgorithm.

In this second Dojo, we will start with several examples with their expected results already written, as well as a link to an algorithm. The goal is to make it through as many examples as possible (in the order listed) in the time allotted.

Unlike the first Dojo where there was a brief problem description and I sort of served as a customer, in this case we have a documented algorithm and a series of examples that:

  • Explicitly define desired results
  • Are written in a particular order to make it easy to grow the algorithm without having to take large steps

If you want to give this a try, the link above has the description I’ll be starting with.

Comments welcome!

Remote Ping-Pong Challenge: Your turn, who's next? (Java) 32

Posted by Brett Schuchert Fri, 19 Jun 2009 06:11:00 GMT

So I want to try a form of TDD using Ping-Pong. Problem is, you are not where I can pair with you directly. So I figured we’d try a slower-form. I’ll post the beginning of a problem. First person to post the next response “wins” – that’s where the next person should pick up from. We’ll continue until the problem is “finished.”

Interested? First the ground rules, then the problem and the starting code. This is Java. However, if someone responds in another language, that’s cool. I might try and follow up, but you’re welcome to do so yourself. I can imagine having multiple threads going on at the same time. (If you’d like your own language thread, ask and I’ll post another blog entry for that particular language.)

Ground Rules

  • Follow the three rules of TDD + Refactoring.
  • Fix the one failing test.
  • Add one to three more tests before posting.
  • Make sure you leave one and only one failing test for the next person to fix. (Meaning you can add two passing tests but leave a third test failing, or you can just add one failing test).
  • You can/should refactor the test code and the production code
  • If you feel a test is wrong, you may change it, but be prepared to justify it.
  • I’ll serve as the customer, so I get to define what is “correct” – however, I can be argued with and I can lose arguments (see some of my other blog postings for evidence).
  • Feel free to respond with comments/suggestions rather than additional tests.
  • Feel free to apply refactorings like extract method, rename, split loop, ... Keep the code clean!

The Problem

Translate infix notation to postfix notation. Consider reviewing The Shunting Yard Algorithm. But that’s a guideline.

The Start

Here is the test and production code. Note, when you respond, surround your code with one of the following pairs of HTML tags:
  • <typo:code>, and </typo:code>
  • <pre>, and </pre>

InfixToPostfixConverterTest

package com.om.example;

import static org.junit.Assert.assertEquals;

import java.util.ArrayList;
import java.util.Collection;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

@RunWith(Parameterized.class)
public class InfixToPostfixConverterTest {
   private final String infix;
   private final String expectedPostfix;

   @Parameters
   public static Collection<String[]> data() {
      ArrayList<String[]> values = new ArrayList<String[]>();

      addTestCase(values, null, "");
      addTestCase(values, "", "");
      addTestCase(values, "45", "45");
      addTestCase(values, "+", "+");
      addTestCase(values, "3 + 8", "3 8 +");

      return values;
   }

   private static void addTestCase(ArrayList<String[]> values, String infix,
         String expectedPostfix) {
      values.add(new String[] { infix, expectedPostfix });
   }

   public InfixToPostfixConverterTest(String infix, String expectedPostfix) {
      this.infix = infix;
      this.expectedPostfix = expectedPostfix;
   }

   @Test
   public void checkTranslation() {
      InfixToPostfixConverter converter = new InfixToPostfixConverter();
      String result = converter.translate(infix);

      assertEquals(expectedPostfix, result);
   }
}

InfixToPostfixConverter

package com.om.example;

public class InfixToPostfixConverter {
   public String translate(String string) {
      if(null == string)
         return "";

      return string;
   }
}

Infinitest for Java, have you tried it? 10

Posted by Brett Schuchert Thu, 18 Jun 2009 16:35:00 GMT

Background

About 2 years ago, I was working with Ben Rady and he demonstrated something he was working on at the time: Infinitest. As often I am, I was a little interested but mostly skeptical – don’t know if that came across or not.

Since then he and others (e.g., Rod Coffin have made amazing strides and created plugins for both Eclipse and IntelliJ.

Taking it for a test run

Earlier this month, I finally decided to give it a test drive. When I made that announcement, Ben made the following (bold?) statement:
For me, using Infinitest is as different from TDD as TDD is from not testing

So is that true? Is using a continuous test execution tool as different from not using one as using TDD is from not testing? I’m not sure I’m there yet. However, I will say my brain is having some difficulty getting used to the cool feedback.

Here are two recent experiences I had using it.

Classpath Issues

Back at the end of 2006 I wrote a class on using JPA and EJB 3. I’ve not really done much to update that material in some years but recently I had an email from someone trying to work through the first tutorial with little success. Over the past few years there’s been some bit-rot. The embeddable container is not really up to date, EJB 3.1 includes an embeddable container as part of its spec, Hibernate has been updated, etc. So I spent a few hours tracking down updated jar files and building my classpath. I had already installed Infinitest and I noticed as added I something to my classpath, Infinitest would kick off and show a stack trace (my code was doing that in a @Before method). So I sped up what I was doing:
  • I directly edited the .classpath file in Eclipse
  • Saved what I was doing
  • Waited about a second
  • Noticed the new stack trace
  • Found the next jar file I needed to add
  • Repeat until tests passed.

Might sound like a bit of overkill, but in the end I built a classpath from scratch and I ended up adding 13 jar files. So it saved some time.

Note, I wasn’t looking for this. I had only installed Infinitest the day before so this was unexpected and welcome! Oh, and before my @Before method was handling the exception properly, Infinitest showed that the code had a problem (it was in the @After with a null pointer exception), which it indicated as an error like a syntax error or a validation error. Nice!

Using Mockito

I’ve recently been using Mockito. You can review a previous blog entry for that example. Today we’re holding the first coding dojo at the recently opened OkC CoCo. Last night I started working on the next problem I want to use for the next dojo. It involves practicing using a mockist approach. I set up my classpath, started writing tests and immediately I noticed what looked like a syntax error on the verification step of my first unit test. I was confused thinking I had an actual syntax error since I’m not quite to the point of touch-typing Mockito based tests (I did update Eclipse so I could more easily find the static imports).

Next, I updated my test to use the @Mock annotation. I removed the hand-written initialization and immediately I noticed a “syntax” error – null pointer exception. I was immediately (OK 1 second later) showed the impact of removing a single line of code. I added the missing line to auto-initialize the @Mock annotated fields but I did it incorrectly, so the error remained. I finally got the line correct and the “syntax error” went away.

Observations

Wow. That’s what I have to say so far. I’m not entirely sure the before and after of using Infinitest is the same size as moving from not testing to using TDD. Maybe it’s the same as moving from being Test Infected to practicing TDD. I was Test Infected several years before I practiced TDD.

I was also about as skeptical that moving to TDD from being Test Infected was useful. I was wrong. History tends to repeat itself, so I’m guessing, based on my initial resistance, that this is the future.

Embrace it.

Challenge: How would you start this problem? 21

Posted by Brett Schuchert Wed, 17 Jun 2009 05:16:00 GMT

On Thursday, we’re holding our first Coding Dojo at the recently opened OkC CoCo. This isn’t the first Coding Dojo to happen in Oklahoma City. Some time back, Dave Nicolette held a Randori with a Fishbowl at the OkC Java User’s Group, and that’s the format I’ll be using for this problem. It was a blast then and I’m hoping it’ll be the same this time around.

This first DoJo is with C#, though I hope we manage to use several languages over time. I’d like to sneak in Smalltalk as soon as we have enough of a critical mass so we don’t lose people. I also plan to slowly introduce BDD (maybe not so slowly, who knows – depends on the group).

The recent refactoring exercises (here and here), they come from this problem. We’ll be starting from scratch, so you can probably imagine that those refactoring examples are not going to come up right away (actually probably not at all given the time).

So your challenge this time is not one of refactoring but rather one of an initial value problem. Given the problem statement, how would you go about starting it? I’m assuming TDD, do you make that same assumption? If so, what’s your first test? Your first few tests? What features do you try to tackle first? What questions do you ask yourself about the problem?

I’ve used this problem several times and it’s a great problem to practice many things including:
  • Test Driven Development
  • refactoring (lower case r deliberate – can you guess why?)
  • Refactoring to Design Patterns
  • Most of the SOLID principles

Anyway, how would you go about starting this problem? Or better yet, give it a try and post your first few tests (in the order you create them).

I’ll be interested in seeing how people start and I’ll compare it to what I’ve done (hint, I use this as a class-driven thing, so I’m pretty flexible on how to start it).

p.s. As a result of studying the manual for my HP 32SII, I have a much better understanding of just how its stack works. I have a EE and CS background, so the stack implementation makes sense, but I left some of its details out of the problem.

Hiding global methods, a C++ example 32

Posted by Brett Schuchert Fri, 12 Jun 2009 15:13:00 GMT

Background

This is a continuation of this discussion. A few of the postings by GBGames have been swallowed so the context is somewhat lost. What follows is an excerpt from an email he sent me and some example C++ code that demonstrates making global methods “testable” in a sense. Or rather, making your code not use global methods during test.

The Offending Method

Here is a method that GBGames has under test:
void SDLHardwareLayer::initializeHardware()
{
    const SDL_version * sdlVersion = SDL_Linked_Version();
    if (sdlVersion->minor < 2 && sdlVersion->major < 2)
    {
        //Error message
    }
    else if (SDL_Init(SDL_INIT_VIDEO |
            SDL_INIT_AUDIO |
            SDL_INIT_NOPARACHUTE) < 0)
    {
        //Error message
    }
    else
    {
        m_screen = SDL_SetVideoMode(m_x, m_y, m_bitDepth, SDL_DOUBLEBUF);
        if (NULL != m_screen)
        {
            SDL_WM_SetCaption(m_title.c_str(), 0);
        }
    }
}

This is how this code is organized:

So What’s Wrong?

One problem he notes is that the test code driving this production code causes windows to pop up during testing. Is this a problem? If it works, then it may be OK. However, you can remove that and also make test-ability a bit easier. You’ll be testing interactions and responses rather than directly using the library through its global functions.

Global Functions Considered Harmful

First off, this code as written directly uses global functions. If you leave this code unchanged, then the only option you have to “fix” the problem of windows popping up is a link-seam (see Working Effective with Legacy Code, page 233-234. In a nutshell, a link seam will link different versions of a library, one for testing, one for actual execution. So you’ll need some “make fu” to get the link seam working in a manner that easily allows building for testing versus building for execution. Since we’re using C++ and we own this code, I chose a different route:
  • Change this code to use an object that uses the library
  • That object implements an interface (a base class with all pure virtual methods)
  • Change this code so that it acquires this object through a factory (I could have simply used constructor injection, but I’ve already written it using a configurable factory [really singleton] – but it would have been simpler if I had injected the interface)
  • Created a test double that can be used when writing new test doubles making code maintenance a bit easier (mentioned in the other blog posting).
  • Write test-method specific test doubles

Changing Code to Use Factory + Object w/virtual Methods

Rather than directly calling the various global SDL_* methods, e.g.:
const SDL_version * sdlVersion = SDL_Linked_Version();
I instead use a factory to get an instance and call
const SDL_version * sdlVersion = SdlLayerFactory::getInstance()->SDL_Linked_Version();

Base Interface

To make this work, I created a base interface representing all of the methods needed by the SDLHardwareLayer::initializeHardware:
#pragma once

struct SDL_version;

class SdlLayerInstanceDelegator {
public:
  virtual ~SdlLayerInstanceDelegator(void) = 0;

  virtual const SDL_version *SDL_Linked_Version() = 0;
  virtual int SDL_Init(int bitMask) = 0;
  virtual void *SDL_SetVideoMode(int x, int y, int bitDepth, int mode) = 0;
  virtual void SDL_WM_SetCaption(const char *title, int someIntValue) = 0;

protected:
  SdlLayerInstanceDelegator();

private:
  SdlLayerInstanceDelegator(const SdlLayerInstanceDelegator &rhs);
  SdlLayerInstanceDelegator &operator = (const SdlLayerInstanceDelegator &);
};

Real Calls Global Methods

Getting rid of the direct call to the global method makes this work. However, you still need to call those global methods somewhere. That’s where the “real” version of the interface comes in. The real version of this class simply calls the global methods (code only, not showing header file right now):
const SDL_version *RealSdlLayerInstanceDelegator::SDL_Linked_Version() {
  return ::SDL_Linked_Version();
}

int RealSdlLayerInstanceDelegator::SDL_Init(int bitMask) {
  return ::SDL_Init(bitMask);
}

void *RealSdlLayerInstanceDelegator::SDL_SetVideoMode(int x, int y, int bitDepth, int mode) {
  return ::SDL_SetVideoMode(x, y, bitDepth, mode);
}

void RealSdlLayerInstanceDelegator::SDL_WM_SetCaption(const char *title, int someIntValue) {
  ::SDL_WM_SetCaption(title, someIntValue);
}

The Factory: Inversion of Control

The original code directly used global methods. We need to invert this relationship so that rather than depending directly on those methods, it depends on an interface. Then if it happens that it uses a “real” version, the underlying code will call the actual library. If, however, it is instead using a test double, it will not. It will do whatever the test double dictates.

We cannot leave the decision of which object to talk to in the SdlHardwareLayer class. Instead, I’ve used a configurable factory (singleton). A test can configure the factory, call the method under test, and then reset the factory back after the test.

The SdlLayerFactory allows such use(again, code only, no header file):
SdlLayerInstanceDelegator *SdlLayerFactory::instance = 0;

SdlLayerInstanceDelegator *SdlLayerFactory::getInstance() {
  return instance;
}

SdlLayerInstanceDelegator *SdlLayerFactory::replaceInstance(SdlLayerInstanceDelegator *replacement) {
  SdlLayerInstanceDelegator *original = instance;
  instance = replacement;
  return original;
}

Handling Growing Interfaces

One problem with “interfaces” in any language is that as you add methods to them, their implementations need to be updated. Since the SdlLayerInstanceDelegator class is not complete yet, this will case problems with test doubles. There are three ways to handle this problem: * Deal with it, as you add new methods to the interface, update all existing classes * Use a mocking library – I have not used any for C++, but if this were Java I’d use Mockito and if this were .Net I’d use Moq. * Create a base test double that implements all of the methods. All test doubles derive from that and only implement the methods needed for test.

The last option does not fix the problem, it controls it. When new methods are added, you update one test double class and all other classes still work.

This may not sound like much of an issue, but in general you’ll have many small test doubles rather than a few large test doubles (or at least that’s the standard recommendation). Why? Because a small, focused test double is less likely to be broken. It also better expressed your intention.

Here is that test double (header file excluded again): TestDoubleSdlLayerInstanceDelegator.h

#pragma once
#include "SdlLayerInstanceDelegator.h"

class TestDoubleSdlLayerInstanceDelegator: public SdlLayerInstanceDelegator {
public:
  TestDoubleSdlLayerInstanceDelegator();
  virtual ~TestDoubleSdlLayerInstanceDelegator();

  const SDL_version *SDL_Linked_Version();
  int SDL_Init(int bitMask);
  void *SDL_SetVideoMode(int x, int y, int bitDepth, int mode);
  void SDL_WM_SetCaption(const char *title, int someIntValue);
};

TestDoubleSdlLayerInstanceDelegator.cpp

#include "TestDoubleSdlLayerInstanceDelegator.h"

TestDoubleSdlLayerInstanceDelegator::TestDoubleSdlLayerInstanceDelegator(){}

TestDoubleSdlLayerInstanceDelegator::~TestDoubleSdlLayerInstanceDelegator(){}

const SDL_version *TestDoubleSdlLayerInstanceDelegator::SDL_Linked_Version() {
  return 0;
}

int TestDoubleSdlLayerInstanceDelegator::SDL_Init(int bitMask) {
  return 0;
}

void *TestDoubleSdlLayerInstanceDelegator::SDL_SetVideoMode(int x, int y, int bitDepth, int mode) {
  return 0;
}

void TestDoubleSdlLayerInstanceDelegator::SDL_WM_SetCaption(const char *title, int someIntValue){}

A Test

Finally, we need some tests and some test-specific test-doubles:
#include <CppUTest/TestHarness.h>

#include "sdl.h"
#include "SdlLayerFactory.h"
#include "SdlHardwareLayer.h"
#include "TestDoubleSdlLayerInstanceDelegator.h"

TEST_GROUP(SdlHardwareLayerTest) {
  virtual void setup() {
    original = SdlLayerFactory::getInstance();
    layer = new SdlHardwareLayer;
  }

  virtual void teardown() {
    if(SdlLayerFactory::getInstance() != original)
      delete SdlLayerFactory::getInstance();

    SdlLayerFactory::replaceInstance(original);
    delete layer;
  }

  SdlLayerInstanceDelegator *original;
  SdlHardwareLayer *layer;
};

struct MajorMinorSdlhardwareLayer : public TestDoubleSdlLayerInstanceDelegator {
  struct SDL_version v;

  MajorMinorSdlhardwareLayer() {
    v.major = 0;
    v.minor = 0;
  }

  const SDL_version *SDL_Linked_Version() {
    return &v;
  }
};

TEST(SdlHardwareLayerTest, ItGeneratsErrorWithLowMajorMinorVersionNumber) {
  SdlLayerFactory::replaceInstance(new MajorMinorSdlhardwareLayer);
  try {
    layer->initializeHardware();
    FAIL("Should have thrown int value");
  } catch (int value) {
    LONGS_EQUAL(1, value);
  }
}

struct InitFailingSdlHardwareLayer : public MajorMinorSdlhardwareLayer {
  InitFailingSdlHardwareLayer () {
    v.major = 3;
    v.minor = 3;
  }

  int SDL_Init(int bitMask) {
    return -1;
  }
};

TEST(SdlHardwareLayerTest, ItGeneratesErrorWhenInitReturnsLessThan0) {
  SdlLayerFactory::replaceInstance(new InitFailingSdlHardwareLayer);
  try {
    layer->initializeHardware();
    FAIL("Should have thrown int value");
  } catch (int value) {
    LONGS_EQUAL(2, value);
  }
}

Notice that there are two test doubles. Also notice that I create them as full (implicitly) inlined classes. Virtual methods and inline methods do not interact well. C++ will make a copy of the method bodies in every .o and increase link times. However, these test classes are only used in one place, so this really does not cause any problems.

In lieu of a mocking library, this is how I’d really write this code.

The Final Big Picture

Here’s an image of the completed product:

Summary

So is this overkill? Is using the actual SDL library causing problems? Is it OK for windows to appear during test? I’m neutral on that subject. The question I want to know is: are the tests working?

  • Do they add value or are they busy work.
  • Do they allow me to make small, incremental steps towards a complete, working implementation
  • Do they run fast enough?
  • Will they run in any environment? (Can I run on a headless system?)
  • Can I run multiple tests at the same time? (Not generally an issue, but it can be.)

If the SDL library is not causing a problem, then this might be overkill. However, on a long-lived project, this little amount of extra work will pay big dividends.

Oh, how long did this really take? Around 1.5 hours. But that included:
  • Starting a Windows XP VM
  • Creating a new projec
  • Setting up the link paths and include paths
  • Creating the initial file and the necessary support to get it to compile
  • Writing the additional classes

In fact, the actual work was probably < 30 minutes total. So while this might look big, in fact it is not. It’s nearly an idiom, so it’s mostly a matter of putting the hooks in place. So is full isolation from SDL worth 30 minutes?

Yes!

All your source files are belong to us

If this looks like a complete example, it is. I have this building and running in Visual Studio 2008. I took GBGame’s original method and got it to compile and link with a minimal set of additional source files. Then I made the structural changes to support test. And here’s all of the source code, file by file:

sdl.h

#pragma once

extern "C" {
  const int SDL_INIT_VIDEO = 1;
  const int SDL_INIT_AUDIO = 2;
  const int SDL_INIT_NOPARACHUTE = 4;
  const int SDL_DOUBLEBUF = 8;

  struct SDL_version {
    int major;
    int minor;
  };

  const SDL_version *SDL_Linked_Version();
  int SDL_Init(int bitMask);
  void *SDL_SetVideoMode(int x, int y, int bitDepth, int mode);
  void SDL_WM_SetCaption(const char *title, int someIntValue);
};

sdl_implementation.cpp

#include "sdl.h"

const SDL_version *SDL_Linked_Version() {
  return 0;
}

int SDL_Init(int bitMask) {
  return  - 1;
}

void *SDL_SetVideoMode(int x, int y, int bitDepth, int mode) {
  return 0;
}

void SDL_WM_SetCaption(const char *title, int someIntValue){}

SdlHardwareLayer.h
#pragma once

#include <string>

class SdlHardwareLayer {
public:
  SdlHardwareLayer();
  virtual ~SdlHardwareLayer();
  void initializeHardware();

private:
  int m_x;
  int m_y;
  int m_bitDepth;
  std::string m_title;
  void *m_screen;
};

SdlHardwarelayer.cpp

#include "SdlHardwareLayer.h"

#include "sdl.h"
#include "SdlLayerFactory.h"
#include "SdlLayerInstanceDelegator.h"

SdlHardwareLayer::SdlHardwareLayer() {
}

SdlHardwareLayer::~SdlHardwareLayer() {
}

void SdlHardwareLayer::initializeHardware() {
    const SDL_version * sdlVersion = SdlLayerFactory::getInstance()->SDL_Linked_Version();
    if (sdlVersion->minor < 2 && sdlVersion->major < 2) {
      throw 1;
    }
    else if (SdlLayerFactory::getInstance()->SDL_Init(SDL_INIT_VIDEO |
            SDL_INIT_AUDIO |
            SDL_INIT_NOPARACHUTE) < 0) {
              throw 2;
    }
    else {
        m_screen = SDL_SetVideoMode(m_x, m_y, m_bitDepth, SDL_DOUBLEBUF);
        if (0 != m_screen) {
            SDL_WM_SetCaption(m_title.c_str(), 0);
        }
    }
}

SdlLayerFactory.h
#pragma once

class SdlLayerInstanceDelegator;

class SdlLayerFactory
{
public:
  static SdlLayerInstanceDelegator *getInstance();
  static SdlLayerInstanceDelegator *replaceInstance(SdlLayerInstanceDelegator *replacement);

private:
  static SdlLayerInstanceDelegator *instance;

  SdlLayerFactory();
  ~SdlLayerFactory();
};

SdlLayerFactory.cpp

#include "SdlLayerFactory.h"

SdlLayerInstanceDelegator *SdlLayerFactory::instance = 0;

SdlLayerFactory::SdlLayerFactory(){}

SdlLayerFactory::~SdlLayerFactory(){}

SdlLayerInstanceDelegator *SdlLayerFactory::getInstance() {
  return instance;
}

SdlLayerInstanceDelegator *SdlLayerFactory::replaceInstance(SdlLayerInstanceDelegator *replacement) {
  SdlLayerInstanceDelegator *original = instance;
  instance = replacement;
  return original;
}

SdlLayerInstanceDelegator.h
#pragma once

struct SDL_version;

class SdlLayerInstanceDelegator {
public:
  virtual ~SdlLayerInstanceDelegator(void) = 0;

  virtual const SDL_version *SDL_Linked_Version() = 0;
  virtual int SDL_Init(int bitMask) = 0;
  virtual void *SDL_SetVideoMode(int x, int y, int bitDepth, int mode) = 0;
  virtual void SDL_WM_SetCaption(const char *title, int someIntValue) = 0;

protected:
  SdlLayerInstanceDelegator();

private:
  SdlLayerInstanceDelegator(const SdlLayerInstanceDelegator &rhs);
  SdlLayerInstanceDelegator &operator = (const SdlLayerInstanceDelegator &);
};

SdlLayerInstanceDelegator.cpp

#include "SdlLayerInstanceDelegator.h"

SdlLayerInstanceDelegator::SdlLayerInstanceDelegator(){}

SdlLayerInstanceDelegator::~SdlLayerInstanceDelegator(){}

TestDoubleSdlLayerInstanceDelegator.h
#pragma once
#include "SdlLayerInstanceDelegator.h"

class TestDoubleSdlLayerInstanceDelegator: public SdlLayerInstanceDelegator {
public:
  TestDoubleSdlLayerInstanceDelegator();
  virtual ~TestDoubleSdlLayerInstanceDelegator();

  const SDL_version *SDL_Linked_Version();
  int SDL_Init(int bitMask);
  void *SDL_SetVideoMode(int x, int y, int bitDepth, int mode);
  void SDL_WM_SetCaption(const char *title, int someIntValue);
};

TestDoubleSdlLayerInstanceDelegator.cpp

#include "TestDoubleSdlLayerInstanceDelegator.h"

TestDoubleSdlLayerInstanceDelegator::TestDoubleSdlLayerInstanceDelegator(){}

TestDoubleSdlLayerInstanceDelegator::~TestDoubleSdlLayerInstanceDelegator(){}

const SDL_version *TestDoubleSdlLayerInstanceDelegator::SDL_Linked_Version() {
  return 0;
}

int TestDoubleSdlLayerInstanceDelegator::SDL_Init(int bitMask) {
  return 0;
}

void *TestDoubleSdlLayerInstanceDelegator::SDL_SetVideoMode(int x, int y, int bitDepth, int mode) {
  return 0;
}

void TestDoubleSdlLayerInstanceDelegator::SDL_WM_SetCaption(const char *title, int someIntValue){}

RealSdlLayerInstanceDelegator.h
#pragma once
#include "SdlLayerInstanceDelegator.h"

class RealSdlLayerInstanceDelegator : public SdlLayerInstanceDelegator
{
public:
  RealSdlLayerInstanceDelegator();
  virtual ~RealSdlLayerInstanceDelegator();

  const SDL_version *SDL_Linked_Version();
  int SDL_Init(int bitMask);
  void *SDL_SetVideoMode(int x, int y, int bitDepth, int mode);
  void SDL_WM_SetCaption(const char *title, int someIntValue);
};

RealSdlLayerInstanceDelegator.cpp

#include "RealSdlLayerInstanceDelegator.h"
#include "sdl.h"

RealSdlLayerInstanceDelegator::RealSdlLayerInstanceDelegator(){}

RealSdlLayerInstanceDelegator::~RealSdlLayerInstanceDelegator(){}

const SDL_version *RealSdlLayerInstanceDelegator::SDL_Linked_Version() {
  return ::SDL_Linked_Version();
}

int RealSdlLayerInstanceDelegator::SDL_Init(int bitMask) {
  return ::SDL_Init(bitMask);
}

void *RealSdlLayerInstanceDelegator::SDL_SetVideoMode(int x, int y, int bitDepth, int mode) {
  return ::SDL_SetVideoMode(x, y, bitDepth, mode);
}

void RealSdlLayerInstanceDelegator::SDL_WM_SetCaption(const char *title, int someIntValue) {
  ::SDL_WM_SetCaption(title, someIntValue);
}

SdlHardwareLayerTest.h
#include <CppUTest/TestHarness.h>

#include "sdl.h"
#include "SdlLayerFactory.h"
#include "SdlHardwareLayer.h"
#include "TestDoubleSdlLayerInstanceDelegator.h"

TEST_GROUP(SdlHardwareLayerTest) {
  virtual void setup() {
    original = SdlLayerFactory::getInstance();
    layer = new SdlHardwareLayer;
  }

  virtual void teardown() {
    if(SdlLayerFactory::getInstance() != original)
      delete SdlLayerFactory::getInstance();

    SdlLayerFactory::replaceInstance(original);
    delete layer;
  }

  SdlLayerInstanceDelegator *original;
  SdlHardwareLayer *layer;
};

struct MajorMinorSdlhardwareLayer : public TestDoubleSdlLayerInstanceDelegator {
  struct SDL_version v;

  MajorMinorSdlhardwareLayer() {
    v.major = 0;
    v.minor = 0;
  }

  const SDL_version *SDL_Linked_Version() {
    return &v;
  }
};

TEST(SdlHardwareLayerTest, ItGeneratsErrorWithLowMajorMinorVersionNumber) {
  SdlLayerFactory::replaceInstance(new MajorMinorSdlhardwareLayer);
  try {
    layer->initializeHardware();
    FAIL("Should have thrown int value");
  } catch (int value) {
    LONGS_EQUAL(1, value);
  }
}

struct InitFailingSdlHardwareLayer : public MajorMinorSdlhardwareLayer {
  InitFailingSdlHardwareLayer () {
    v.major = 3;
    v.minor = 3;
  }

  int SDL_Init(int bitMask) {
    return -1;
  }
};

TEST(SdlHardwareLayerTest, ItGeneratesErrorWhenInitReturnsLessThan0) {
  SdlLayerFactory::replaceInstance(new InitFailingSdlHardwareLayer);
  try {
    layer->initializeHardware();
    FAIL("Should have thrown int value");
  } catch (int value) {
    LONGS_EQUAL(2, value);
  }
}

RunAllTests.cpp
#include <CppUTest/CommandLineTestRunner.h>

int main(int ac, char **av) {
  return CommandLineTestRunner::RunAllTests(ac, av);
}

Another Refactoring Exercise: Design Patterns Recommended!-) 47

Posted by Brett Schuchert Wed, 10 Jun 2009 01:57:00 GMT

Well the previous exercise was fun so here’s another one. The following code is taken from the same problem, an RPN calculator. Originally, the interface of the calculator was “wide”; there was a method for each operator. E.g., plus(), minus(), factorial(). In an effort to fix this, a new method, perform(String operatorName) was added and ultimately the interface was fixed gradually to remove those methods.

Changing he calculator API in this way is an example of applying the open/closed principle. However, the resulting code is just a touch ugly (I made it a little extra ugly just for the hack [sic] of it). This code as written does pass all of my unit tests.

Before the code, however, let me give you a little additional information:
  • I changed the calculator to use BigDecimal instead of int
  • Right now the calculator has three operators, +, – !
  • Eventually, there will be many operators (50 ish)
  • Right now there are only binary and unary operators, however there will be other kinds: ternary, quaternary, and others such as sum the stack and replace just the sum on the stack or calculate the prime factors of the top of the stack so take one value but push many values

So have a look at the following code and then either suggest changes or provide something better. There’s a lot that can be done to this code to make it clearer and make the system easier to extend.

The Perform Method

   public void perform(String operatorName) {
      BigDecimal op1 = stack.pop();

      if ("+".equals(operatorName)) {
         BigDecimal op2 = stack.pop();
         stack.push(op1.add(op2));
         currentMode = Mode.inserting;
      } else if ("-".equals(operatorName)) {
         BigDecimal op2 = stack.pop();
         stack.push(op2.subtract(op1));
         currentMode = Mode.inserting;
      } else if ("!".equals(operatorName)) {
         op1 = op1.round(MathContext.UNLIMITED);
         BigDecimal result = BigDecimal.ONE;
         while (op1.compareTo(BigDecimal.ONE) > 0) {
            result = result.multiply(op1);
            op1 = op1.subtract(BigDecimal.ONE);
         }
         stack.push(result);
      } else {
         throw new MathOperatorNotFoundException();
      }
   }

Unlike the last example, I’ll provide the entire class. Feel free to make changes to this class as well. However, for now focus on the perform(...) method.

One note, Philip Schwarz recommended a change to what I proposed to avoid the command/query separation violation. I applied his recommendation before posting this updated version.

The Whole Class

package com.scrippsnetworks.calculator;

import java.math.BigDecimal;
import java.math.MathContext;

public class RpnCalculator {
   private OperandStack stack = new OperandStack();
   private Mode currentMode = Mode.accumulating;

   enum Mode {
      accumulating, replacing, inserting
   };

   public RpnCalculator() {
   }

   public void take(BigDecimal value) {
      if (currentMode == Mode.accumulating)
         value = determineNewTop(stack.pop(), value);

      if (currentMode == Mode.replacing)
         stack.pop();

      stack.push(value);
      currentMode = Mode.accumulating;
   }

   private BigDecimal determineNewTop(BigDecimal currentTop, BigDecimal value) {
      BigDecimal newTopValue = currentTop;
      String digits = value.toString();
      while (digits.length() > 0) {
         newTopValue = newTopValue.multiply(BigDecimal.TEN);
         newTopValue = newTopValue.add(new BigDecimal(Integer.parseInt(digits
               .substring(0, 1))));
         digits = digits.substring(1);
      }

      return newTopValue;
   }

   public void enter() {
      stack.dup();
      currentMode = Mode.replacing;
   }

   public void perform(String operatorName) {
      BigDecimal op1 = stack.pop();

      if ("+".equals(operatorName)) {
         BigDecimal op2 = stack.pop();
         stack.push(op1.add(op2));
         currentMode = Mode.inserting;
      } else if ("-".equals(operatorName)) {
         BigDecimal op2 = stack.pop();
         stack.push(op2.subtract(op1));
         currentMode = Mode.inserting;
      } else if ("!".equals(operatorName)) {
         op1 = op1.round(MathContext.UNLIMITED);

         BigDecimal result = BigDecimal.ONE;
         while (op1.compareTo(BigDecimal.ONE) > 0) {
            result = result.multiply(op1);
            op1 = op1.subtract(BigDecimal.ONE);
         }
         stack.push(result);
      } else {
         throw new MathOperatorNotFoundException();
      }
   }

   public BigDecimal getX() {
      return stack.x();
   }

   public BigDecimal getY() {
      return stack.y();
   }

   public BigDecimal getZ() {
      return stack.z();
   }

   public BigDecimal getT() {
      return stack.t();
   }
}

Slim table examples with fixtures in C# 77

Posted by Brett Schuchert Tue, 09 Jun 2009 04:15:00 GMT

There was not a lot of interest in a series of tutorials. Some, yes, but not very much. So I’m not going to be spending much time right now writing FitNesse.Slim tutorials for C#.

However, I think it’s a good idea to at least have some examples of each of the tables so those few that are so inclined, have something from which to start.

Have a look: C# Slim Examples

Older posts: 1 2