Quick Intro To BDD Style Table Syntax 286

Posted by Brett Schuchert Wed, 22 Sep 2010 04:54:00 GMT

Here it is a over a year after I wrote several FitNesse tutorials. Several months back Bob added some new ways to write scenarios using a placeholder syntax and an alternative way to render script tables. What you end up with is something just a little less table-like.

This is a very quick and dirty writeup I’ve been meaning to put together for nearly half a year. So while it’s not pretty, it works, shows the basics and may make you aware of something you didn’t know was there – unless you’ve been reading the release notes.

Alternative Script Table Syntax

Comments and requests welcome.

Brett

Rough Notes on using FitNesse with C++ 135

Posted by Brett Schuchert Sat, 31 Jul 2010 03:09:00 GMT

I’ve been working with FitNesse.slim, using the cslim implementation to execute C++ code. I have some rough notes online. These should be enough to get started, though you’ll need to be using G++ 4.4 or later.

In any case, have a look. Give me some feedback if you’d like. I’ll be working on these over the next month or so: http://schuchert.wikispaces.com/cpptraining.ExecutingBinaryOperators

Preprocessor seams and assignment of responsibility 110

Posted by Brett Schuchert Thu, 22 Jul 2010 15:32:00 GMT

In my previous blog I mentioned adding a single method to the cslim library:
cslim/include/CSlim/SlimListSerializer.h:
void SlimList_Release(char *serializedResults);
cslim/src/CSlim/SlimListSerializer.c:
void SlimList_Release(char *serializedResults)
{
  if(serializedResults)
    free(serializedResults);
}
Now I’m going to explain how I came across this need, what it took to figure it out and then why I picked this solution.

Background

In FitNesse, Query Table Results are a list of list of list:
  • The outer-most list represents “rows”. It collects all objects found. It has zero or more entries.
  • The inner-most list represents a single field. It is a key value pair. It is a list of size 2. The first entry is the name of the field (column to FitNesse). The second field is the value. Both are strings.
  • The middle list represents a single object. It is a collection of fields. It has zero or more entires.

I understand the need for this representation and it takes a little bit to get it built correctly. So much so, I built a simple tool to do it in java.

C++ is no different. In fact, the authors of cslim though the same thing and they created a C Abstract Data Type to help out (and an add-on method to create the correct final form):

  • SlimList
  • SlimList_Serializer

They use C because it can be used by both C and C++. I’m using C++ and I wanted to make building query results even easier, so I built a QueryResultAccumulator. The most recent source is in the previous blog and I’ll be putting it on github after I’ve had some more time to work on it.

Here’s the progression to my QueryResultAccumulator class:

  • Wrote a Query-Table based fixture and followed the example provided with cslim (thank you for that!)
  • Moved the code from functions into methods on a class
  • Extracted a class, called SlimListWrapper, which made the fixture code easier to follow.
  • Went to get takeout and realized that I had named the class incorrectly and that it was really accumulating query results (thus the name). The SlimList was a mechanism, not an intent.
  • Refactored the class into QueryResultAccumulator (I left the original alone, created a new class, copied code from one to the other and changed it around a bit.

Now it might sound like I didn’t have any tests. In fact, I did. I had my original Acceptance Test in FitNesse. I kept running that, so in a sense I was practicing ATDD.

I was not happy with that, because I was not sure that I had properly handled memory allocation correctly. In fact, I had not. The final result is dynamically allocated and I was not releasing that. So I “fixed” it. (It needs to be released after the return from slim back to FitNesse, so the typical pattern is to lazily delete it, or release it in a “destroy” method called after the execution of a single table.)

I have a memory leak?!

I am simplifying this story a bit. So I’m skipping some intermediate results. Ultimately I wrote the following test to check that you could use a single query result accumulator for multiple results correctly:
TEST(QueryResultAccumulator, CanProduceFinalResultsMultipleTimes) {
    QueryResultAccumulator accumulator;
    accumulator.produceFinalResults();
    accumulator.produceFinalResults();
}

This caused a memory leak of 60 bytes. It was at this point I was up too late and banging my head against a wall. About 3 hours later I figured that out and went to bed. I fixed the problem and sent a patch to authors of cslim in maybe 45 minutes. So I should have gotten more sleep.

Where is that damn thing

In any case, I visually checked the code. I debugged it. I did everything I could initially think of, and I was convinced that my code was correct. (As we’ll see it both was and was not due to a preprocessor seam in cslim.) I got to the point where I even tried different versions of gcc. (I found a parsing error in g++ 4.5 when handling templates, so in desperation and late at night I wasted 5 minutes switching my compiler.) I had the following code in my class:
  if(result)
    free(result);

This was the correct thing, but it was in the wrong location. Again, this was related to a preprocessor seam in cslim.

Eureka!

I looked at the cslim code and confirmed it was doing basic C stuff, nothing surprising. It was at that point that I remembered something important:
cslim depends on CppUTest and uses a different malloc/free

Ah ha! That’s it. So I tired to recompile my C++ code to use the same thing. However, I was not able to do that. CppUTest’s memory tracking implementation does not work with many of the C++ standard classes like <string> and <vector>. So I could not compile my code using the same approach.

I’m glad this happened becuase it made me realize that it was the wrong place anyway. Here’s the logic:

  • CSlim has a preprocessor seam, comile with or without -Dfree=cpputest_free, -Dmalloc=cpputest_malloc
  • I’m using a class in cslim to do the allocation, where the policy of allocation is stored
  • I should not release the memory but instead allow the cslim library to release the memory becaue it has the allocation policy, and therefore the release policy.
About 2 minutes later, I had added a single function to the library:
cslim/include/CSlim/SlimListSerializer.h:
void SlimList_Release(char *serializedResults);
cslim/src/CSlim/SlimListSerializer.c:
void SlimList_Release(char *serializedResults)
{
  if(serializedResults)
    free(serializedResults);
}

I updated my QueryResultAccumulator to use SlimList_Release and my false positive disappeared.

It also turns out that this improved symmetry in the library. To allocate and release entries in an SlimList you use the following functions:

  • SlimList* SlimList_Create()
  • void SlimList_Destroy(SlimList*);

Now to serlalize a list and release the memory later you use:

  • SlimList_Serialize
  • SlimList_Release

As I write this, I think there’s a better name. I’ll let the authors give it a better name (like SlimList_Release_Serialization_Results). But in any case, if you use a function in the cslim library that allocates something, you use another method in the cslim library to release it.

Since the libray has a preprocessor seam, that symmetry removes a false-positive memory leak.

What took so long?

I had an interesting time with this. Originally I had not released that memory in the class but rather in the unit test. I was working too late and not thinking clearly. I realized that my class needed to manage that.

When I called free in the unit test, it was calling the correct version of free, cpputest_free, becasue it was a unit test using CppUTest. When I moved the code into the class, which has no knowledge of CppUTest (nor can it), the flow of the code was correct, but the compilation (preprocessor symbols) were different and it caused a false positive.

Since I changed the code, I assumed it was a problem with how I changed the code. To me more clear, I though it was a code-flow problem, not a preprocessor seam problem. So I spent a lot of time verifyig my code. Once I determined it was correct, I then moved into debugger mode.

It was not long after that when I finally figured out what was going on.

Conslusions

As with many things in life, this is intuitive once you understand it!-)

That cslim depends on CppUTest might be questionable. However, if I treat cslim as a (mostly) black box, and I don’t know its allocation policy, I should not assume a deallocation policy.

By putting the responsiblity in the correct library level, it fixed the problem and added symmetry to the overall solution.

I also really enjoyed this (after it was done). I’ve come across memory leaks using CppUTest in the past. Often they were my fault. Sometimes they were not. This was interesting because it both was and was not my fault. I originally had written the code incorrectly. When I put he correct steps in my code, I still had wrong code because I put the responsibility in the wrong place. It really was only correct after I moved the actual implementation into the library and then called it from my code that I had finally written it correctly.

Some C++ Fixtures for FitNesse.slim 123

Posted by Brett Schuchert Thu, 22 Jul 2010 05:32:00 GMT

I continue working on these. I was stuck in the airport for 5 hours. Between that and the actual flight, I managed to create three different test examples against a C++ RpnCalculator. Each example uses a different kind of fixture. I had a request from @lrojas to publish some results on the blog. So this is that, however these are in progress and rough.

I’m still trying different forms to figure out what I like the best.

By the way, that lastValue stuff in the fixtures has to do with the fact that all of the hook methods return a char* but I’m responsible for cleaning up after myself.

A Decision Table

!|ExecuteBinaryOperator    |
|lhs|rhs|operator|expected?|
|3  |4  |-       |-1       |
|5  |6  |*       |30       |

And Its Fixture Code

#include <stdlib.h>
#include <stdio.h>
#include <string>
#include "RpnCalculator.h"
#include "OperationFactory.h"
#include "Fixtures.h"
#include "SlimUtils.h"

struct ExecuteBinaryOperator {
    ExecuteBinaryOperator() {
        lastValue[0] = 0;
    }

    int execute() {
        RpnCalculator calculator(factory);
        calculator.enterNumber(lhs);
        calculator.enterNumber(rhs);
        calculator.executeOperator(op);
        return calculator.getX();
    }

    static ExecuteBinaryOperator* From(void *fixtureStorage) {
        return reinterpret_cast<ExecuteBinaryOperator*>(fixtureStorage);
    }

    OperationFactory factory;
    int lhs;
    int rhs;
    std::string op;
    char lastValue[32];
};

extern "C" {
void* ExecuteBinaryOperator_Create(StatementExecutor* errorHandler, SlimList* args) {
    return new ExecuteBinaryOperator;
}

void ExecuteBinaryOperator_Destroy(void* self) {
    delete ExecuteBinaryOperator::From(self);
}

static char* setLhs(void* fixture, SlimList* args) {
    ExecuteBinaryOperator *self = ExecuteBinaryOperator::From(fixture);
    self->lhs = getFirstInt(args);
    return self->lastValue;
}

static char* setRhs(void* fixture, SlimList* args) {
    ExecuteBinaryOperator *self = ExecuteBinaryOperator::From(fixture);
    self->rhs = getFirstInt(args);
    return self->lastValue;
}

static char* setOperator(void *fixture, SlimList* args) {
    ExecuteBinaryOperator *self = ExecuteBinaryOperator::From(fixture);
    self->op = getFirstString(args);
    return self->lastValue;
}
static char* expected(void* fixture, SlimList* args) {
    ExecuteBinaryOperator *self = ExecuteBinaryOperator::From(fixture);
    int result = self->execute();
    snprintf(self->lastValue, sizeof(self->lastValue), "%d", result);
    return self->lastValue;
}

SLIM_CREATE_FIXTURE(ExecuteBinaryOperator)
    SLIM_FUNCTION(setLhs)
    SLIM_FUNCTION(setRhs)
    SLIM_FUNCTION(setOperator)
    SLIM_FUNCTION(expected)
SLIM_END

}
There’s a bit of duplication. I’ve been experimenting with pointers to member functions and template functions to make it better. I really should be using lambdas, but I’m not there yet. I have them available in some form since I’m using gcc 4.5. I simply compile with the option -sdd=c++0x. Even so, I’m not quite ready to do that.

A Script Table

!|script           |ProgramTheCalculator                   |
|startProgramCalled|primeFactorsOfSum                      |
|addOperation      |sum                                    |
|addOperation      |primeFactors                           |
|saveProgram                                               |
|enter             |4                                      |
|enter             |13                                     |
|enter             |7                                      |
|execute           |primeFactorsOfSum                      |
|check             |stackHas|3|then|2|then|2|then|2|is|true|

And Its Fixture Code

#include <stdlib.h>
#include <stdio.h>
#include <string>
#include "RpnCalculator.h"
#include "OperationFactory.h"
#include "SlimUtils.h"
#include "SlimList.h"
#include "Fixtures.h"

struct ProgramTheCalculator {
    ProgramTheCalculator() : calculator(factory) {
    }

    static ProgramTheCalculator* From(void *fixtureStorage) {
        return reinterpret_cast<ProgramTheCalculator*>(fixtureStorage);
    }

    OperationFactory factory;
    RpnCalculator calculator;
};

extern "C" {

void* ProgramTheCalculator_Create(StatementExecutor* errorHandler, SlimList* args) {
    return new ProgramTheCalculator;
}

void ProgramTheCalculator_Destroy(void *fixture) {
    delete ProgramTheCalculator::From(fixture);
}

static char* startProgramCalled(void *fixture, SlimList *args) {
    auto *self = ProgramTheCalculator::From(fixture);
    self->calculator.createProgramNamed(getFirstString(args));
    return remove_const("");
}

static char* addOperation(void *fixture, SlimList *args) {
    auto *self = ProgramTheCalculator::From(fixture);
    self->calculator.addOperation(getFirstString(args));
    return remove_const("");
}

static char* saveProgram(void *fixture, SlimList *args) {
    auto *self = ProgramTheCalculator::From(fixture);
    self->calculator.saveProgram();
    return remove_const("");
}

static char* enter(void *fixture, SlimList *args) {
    auto *self = ProgramTheCalculator::From(fixture);
    self->calculator.enterNumber(getFirstInt(args));
    return remove_const("");
}

static char* execute(void *fixture, SlimList *args) {
    auto *self = ProgramTheCalculator::From(fixture);
    self->calculator.executeOperator(getFirstString(args));
    return remove_const("");
}

static char* stackHasThenThenThenIs(void *fixture, SlimList *args) {
    auto *self = ProgramTheCalculator::From(fixture);
    for(int i = 0; i < 4; ++i) {
            if(self->calculator.getX() != getIntAt(args, i))
                return remove_const("false");
            self->calculator.executeOperator("drop");
    }

      return remove_const("true");
}

SLIM_CREATE_FIXTURE(ProgramTheCalculator)
    SLIM_FUNCTION(startProgramCalled)
    SLIM_FUNCTION(addOperation)
    SLIM_FUNCTION(saveProgram)
    SLIM_FUNCTION(enter)
    SLIM_FUNCTION(execute)
    SLIM_FUNCTION(stackHasThenThenThenIs)
SLIM_END

}
This one is a bit more regular. I am using the updated auto keyword in this code. The fixture is just holding the calculator and its OperationFactory (not my preferred name, but that’s what students wanted to call things like +, -, etc, operations not operators).

The Dreaded Query Table

It’s a bit of a pain to produce query results. So much so, I wrote a simple library in Java to make it easier. I can create a well-formed query result from a single object or a list of objects and even do basic transforms (in names and in paths to data). I started using the jakarta bean utils, but my use was so simple (2 methods), I ripped out that library and just hand-wrote the methods I needed. It was not a case of “not invented here syndrom.” I started by using the library, and I had tests. I didn’t like the size of the library relative to how much I was using it, so I just got rid of it.

Well here I am working C++ and I felt compelled to make it easier work with query results in C++.

First the FitNesse table, then the fixture and finally the support class. I have tests for it as well, I’m not going to show those, however.
!|Query: SingleCharacterNameOperators|
|op                                  |
|+                                   |
|*                                   |
|/                                   |
|!                                   |
|-                                   |

And Its Fixture Code

#include <stdlib.h>
#include <stdio.h>
#include <vector>
#include <string>
#include <memory>
#include "RpnCalculator.h"
#include "OperationFactory.h"
#include "Fixtures.h"
#include "SlimUtils.h"
#include "QueryResultAccumulator.h"

struct SingleCharacterNameOperators {
    OperationFactory factory;
    RpnCalculator calculator;

    SingleCharacterNameOperators() :
        calculator(factory), result(0) {
    }

    ~SingleCharacterNameOperators() {
        delete result;
    }
    static SingleCharacterNameOperators* From(void *fixtureStorage) {
        return reinterpret_cast<SingleCharacterNameOperators*> (fixtureStorage);
    }

    void resetResult(char *newResult) {
        delete result;
        result = newResult;
    }

    void conditionallyAddOperatorNamed(const std::string &name) {
        if (name.size() == 1) {
            accumulator.addFieldNamedWithValue("op", name);
            accumulator.finishCurrentObject();
        }
    }

    void buildResult() {
        v_string names = calculator.allOperatorNames();
        buildResult(names);
    }

    void buildResult(v_string &names) {
        for (v_string::iterator iter = names.begin(); iter != names.end(); ++iter)
            conditionallyAddOperatorNamed(*iter);

        resetResult(accumulator.produceFinalResults());
    }

    QueryResultAccumulator accumulator;
    char *result;
};

extern "C" {
void* SingleCharacterNameOperators_Create(StatementExecutor* errorHandler,
        SlimList* args) {
    return new SingleCharacterNameOperators;
}

void SingleCharacterNameOperators_Destroy(void *fixture) {
    delete SingleCharacterNameOperators::From(fixture);
}

static char* query(void *fixture, SlimList *args) {
    auto *self = SingleCharacterNameOperators::From(fixture);
    self->buildResult();
    return self->result;
}

SLIM_CREATE_FIXTURE(SingleCharacterNameOperators)
    SLIM_FUNCTION(query)SLIM_END
SLIM_END

And the Helper Class

QueryResultAccumulator.h
#pragma once
#ifndef QUERYRESULTACCUMULATOR_H_
#define QUERYRESULTACCUMULATOR_H_

class SlimList;
#include <vector>
#include <string>
class QueryResultAccumulator {
public:
    typedef std::vector<SlimList*> v_SlimList;
    typedef v_SlimList::iterator iterator;

    QueryResultAccumulator();
    virtual ~QueryResultAccumulator();

    void finishCurrentObject();
    void addFieldNamedWithValue(const std::string &name, const std::string &value);
    char *produceFinalResults();

private:
    SlimList* allocate();
    void releaseAll();
    void setInitialConditions();

private:
    v_SlimList created;
    SlimList *list;
    SlimList *currentObject;
    int lastFieldCount;
    int currentFieldCount;
    char *result;

private:
    QueryResultAccumulator(const QueryResultAccumulator&);
    QueryResultAccumulator& operator=(const QueryResultAccumulator&);
};

#endif

I know there are too many fields. The counts help with validating correct usage. I also wrote it so one instance could be re-used and I tried to make sure it was in a “ready to receive fields” state when necessary. In any case, this error checking helped find a defect I introduced while refactoring.

QueryResultAccumulator.cpp
#include "QueryResultAccumulator.h"
#include "DifferentFieldCountsInObjects.h"
#include "InvalidStateException.h"

extern "C" {
#include "SlimList.h"
#include "SlimListSerializer.h"
}

QueryResultAccumulator::QueryResultAccumulator() : result(0) {
    setInitialConditions();
}

QueryResultAccumulator::~QueryResultAccumulator() {
    releaseAll();
    SlimList_Release(result);
}

void QueryResultAccumulator::setInitialConditions() {
    releaseAll();
    list = allocate();
    currentObject = allocate();
    lastFieldCount = -1;
    currentFieldCount = -1;
}

SlimList* QueryResultAccumulator::allocate() {
    SlimList *list = SlimList_Create();
    created.push_back(list);
    return list;
}

void QueryResultAccumulator::releaseAll() {
    for (iterator i = created.begin(); i != created.end(); ++i)
        SlimList_Destroy(*i);
    created.clear();
}

void QueryResultAccumulator::finishCurrentObject() {
    if(lastFieldCount >= 0 && lastFieldCount != currentFieldCount)
        throw DifferentFieldCountsInObjects(lastFieldCount, currentFieldCount);

    SlimList_AddList(list, currentObject);
    currentObject = allocate();

    lastFieldCount = currentFieldCount;
    currentFieldCount = -1;
}

void QueryResultAccumulator::addFieldNamedWithValue(const std::string &name, const std::string &value) {
    SlimList *fieldList = allocate();
    SlimList_AddString(fieldList, name.c_str());
    SlimList_AddString(fieldList, value.c_str());
    SlimList_AddList(currentObject, fieldList);
    ++currentFieldCount;
}

char* QueryResultAccumulator::produceFinalResults() {
    if(currentFieldCount != -1)
        throw InvalidStateException("Current object not written");

    SlimList_Release(result);
    result = SlimList_Serialize(list);
    setInitialConditions();
    return result;
}
Note, this code uses a method I added to the cslim library: SlimListSerializer.h – in include/CSlim
void SlimList_Release(char *serializedResults);
SlimListSerializer.c – in src/CSlim
void SlimList_Release(char *serializedResults)
{
  if(serializedResults)
    free(serializedResults);
}

I needed to add these methods due to a false-positive memory leak indicated when using CppUTest to test this code. That’s another blog.

FitNesse, C++ and cslim, step-by-step instructions 112

Posted by Brett Schuchert Tue, 20 Jul 2010 04:26:00 GMT

Title says it all: http://schuchert.wikispaces.com/cpptraining.GettingStartedWithFitNesseInCpp

First draft. If you have problems, please let me know.

First Pass Completed: Rough Draft TDD Demonstration Videos 131

Posted by Brett Schuchert Mon, 05 Apr 2010 06:15:00 GMT

As promised, I’ve made a complete sweep through a series of videos. You can find all of them: here.

These videos include several warts and false starts. Depending on the interest and feedback, I’ll redo these at some point in the future.

Question: Should I repeat this series in C#, or some other language? Some people have expressed interest in this. It’s probably 15 hours of work in C#, so I’d need to know it was worth the effort. What’s your opinion on that?

The videos are meant to be watched in order. The link above is to an album that is in the correct order. Here are the direct links (also in the intended order):
  • Getting Started
  • Adding Basic Operators
  • Removing Duplication
  • Extracting to Strategy
  • Removing Duplication via Refactoring or Removing Duplication via Tdd using Mockito
  • Introducing an Abstract Factory
  • Adding a Sum operator
  • Adding Prime Factors Operator
  • Composing Operators and Programming the Calculator
  • Using FitNesse to Program the Calculator

I’ve already received several comments both here on the blog as well as with the videos. I’ll keep track of those comments and incorporate the ones that fit for me.

Each video has a link on its page to download it. However, to download a video, you will have to create an account and log in. So here are the links, these won’t work without first creating an account (I’ll update original blog with these as well):
  • Getting Started Download
  • Adding Basic Ops Download
  • Removing Duplication Download
  • Extracting to Strategy
  • Removing Dups/Refactoring Download
  • Removing Dups/Tdd Download
  • Abstract Factory Download
  • Sum Operator Download
  • Prime Factors Download
  • Composing Math Operators Download
  • Using FitNesse Download

One way to configure FitNesse for team Development 510

Posted by Brett Schuchert Fri, 19 Feb 2010 20:12:00 GMT

Here are some notes (and instructions) on a way to configure FitNesse for use in a team environment: Page Hierarchy For Team Development.

Comments and suggestions welcome.

Slim table examples with fixtures in C# 97

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

Calling C# and FitNesse Users 56

Posted by Brett Schuchert Sat, 06 Jun 2009 05:43:00 GMT

Are you using C# and FitNesse? Considering moving to FitNesse.Slim?

I eventually plan to port several FitNesse.Slim tutorials written in Java to C#. It’s a bit of work so I want to make sure there’s enough interest now (this is about when not if). Given that C# and Java are similar languages, I’m not convinced it’s really necessary right now. I’m under the impression that the user base for FitNesse.Slim + C# is small, but I’m often wrong. I have other things I want to get around to writing, so I’m trying to get a temperature reading to know what might be useful next.

If this would help you or your team, what would you like to see?
  • Just the basics, all the tables and an example of each (quick to do)
  • Something more comprehensive, building story tests and working through to TDD to build a system from the ground up?
  • A full porting of the existing tutorials as is?
  • ...

I’m really looking for some user stories from some actual candidate users. If that’s you or you know someone and you like being a proxy, please respond.

Thanks!

Brett

Updates for using .Slim in FitNesse 16

Posted by Brett Schuchert Wed, 03 Jun 2009 03:54:00 GMT

Bob Koss and I are teaching an XP Immersion this week and he’s going to be using FitNesse with both .Net and Java. It’s been some time since I checked the instructions or updated to the latest Slim.Net component.

First off, Mike Stockdale has been busy and made several improvements (kudos). Also, I updated the instructions in two of my tutorials to make sure they were current:
  • Using Slim .Net in FitNesse
  • FitNesse Tutorial 0, C# Details

Comments and corrections welcome!

Older posts: 1 2 3