Monday, March 17, 2008

Recursive it is.

Well, for the gtk# presenter injection issue, I determined that I could do the recursive method for in about fifteen lines of code, so I implemented that. I was stumped for quite some time because the recursion wasn't descending at all -- it turns out I was casting widgets to Gtk.Bin when I should have been casting to Gtk.Container.

The code:

public class ViewAttribute : Attribute {}

public class InjectAttribute : Attribute {}

[CastleComponent("bootstrapViews", typeof(BootstrapViews))]
public class BootstrapViews
{
private IWindsorContainer _container;

public BootstrapViews(IWindsorContainer container)
{
_container = container;
}

public void Bootstrap(Widget widget)
{
Container bin = widget as Container;
if (bin == null)
{
return;
}
foreach (Widget child in bin.Children)
{
Bootstrap(child);
}

object[] attrs = bin.GetType().GetCustomAttributes(typeof(ViewAttribute), false);
if (attrs.Length > 0)
{
foreach (FieldInfo field in bin.GetType().GetFields())
{
if (field.GetCustomAttributes(typeof(InjectAttribute), false).Length > 0)
{
field.SetValue(bin, _container.Resolve(field.FieldType));
}
}
}
}
}

Sunday, March 16, 2008

gtksharp and MVP

Switching gears to C#, since, though I love D, I need a working mocks library to write any significant code in it, and dmd bugs prevent dmocks from working correctly.

I'm using gtk#/stetic to create a GUI of moderate complexity, and of course I'm using the Model-View-Presenter pattern. Reminiscent of ASP.NET MVP issues, the main problem is getting a reference to a presenter into a view -- gtk# doesn't use a central object builder that I can hook into; everything happens in a Build method.

So I have three options that I can pursue in achieving a reasonable MVP model:
  1. Each custom widget gets a reference to the Castle container and resolves its presenter that way.
  2. I build my GUI, then do a depth-first traversal of all the components, looking for an attribute set: [View(Type register)] on the class, [Inject] on the presenter(s). Any such classes, I register with the container, then fill in their dependencies. This works for everything that inherits from Gtk.Bin, but I have to copy it for any other gtk classes that my widgets derive from.
  3. Possibly using inheritance, my widgets subclass a SmartPart class and register themselves with a singleton (using the typical singleton pattern) that will register them with the container and fill in dependencies. This means I spend less time at runtime looking at widgets.
Option #1 is not happening.
Option #3, using generics, is reasonably simple, and it works unless I have one view with multiple presenters.
Option #2 is the fully general solution, which I probably won't be implementing. It'd be great, except for the speed, but it's rather yagni.

Of course, the problem with #2 is that my constructors will have to be modified, or the presenters might do something foolish:

public MyWidget()
{
this.Build();
base(whatever);
}
// was:
// public MyWidget() : base(whatever)
// {
// this.Build();
// }

As an aside, has anyone had luck getting CruiseControl.net running on debian?

Wednesday, March 12, 2008

DUnit

I whipped together a quick unittest library, DUnit. Took less than an hour; apparently, SUnit took about two hours to write, so I'm in decent company.

This doesn't offer very much; in particular, there's no measure of progress. That's a deviation from the xUnit standard. And there's no way to control which tests get run. But I'm working on a better version already that offers those features.

On an unrelated note, dmd2 is too unstable to be usable, so dmocks is dead. I'll be updating it to dmd2.011, but probably no further, at least until dmd2 is in late beta or beyond.

Tuesday, February 26, 2008

Horrible...

Everything I said about templates? Double for mixins.

A short mixin can be a wonderful thing. Like for unittests:

string test(string name)()
{
return `
Stdout("` ~ name ~ `");
scope (failure) Stdout("failed").newline;
scope (success) Stdout("passed").newline;`
}
unittest
{
mixin(test!("test naming test"));
}


But mixins should be passive, delegating to concrete methods and classes whenever possible. Line numbers are that important.

Monday, February 18, 2008

New project woes

Got a university project that's decidedly not Agile. And I don't have any time to do requirements analysis in this weakly waterfall style. If it were Agile, I'd only have time for about four or five iterations....

It's tempting to ignore the customers at this point and just code up an initial project that fulfills some need. Then I'd have something to talk about. The one source I have wants the system to have insane amounts of detail -- if I asked him to fill it out, he'd refuse, I think. And there's only one person in the department who would benefit from the information.

Sunday, February 17, 2008

CTFE and testability

A lot of my code makes heavy use of CTFE. Really heavy. As in, more lines of code get executed at compile time than at runtime. How do I start to write unittests for it?

Answer: I don't.

That's rather harsh. Let's look at one case, or actually an abbreviated form of it. This is taken from DMocks:


string Methods (T, string name) () {
string methodBodies = "";
foreach (method; __traits(getVirtualFunctions, T, name)) {
alias typeof(method) func;
static if (is(ReturnType!(func) == void)) {
methodBodies ~= VoidMethod!(T.stringof, name, ParameterTypeTuple!(func));
} else {
methodBodies ~= ReturningMethod!(
T.stringof,
name,
ReturnType!(func),
ParameterTypeTuple!(func));
}
}
return methodBodies;
}

string ReturningMethod (string type, string name, T, U...)() {
string qualified = type ~ `.` ~ name;
string args = String!(U)();
string argArgs = Arguments!(U);
string nameArgs = `"` ~ qualified ~ (U.length == 0 ? `"` : `", ` ~ Arguments!(U)());
string retArgs = T.stringof ~ (U.length == 0 ? `` : `, ` ~ args);
return `some very long string that uses those strings I just assigned above`;
}
// VoidMethod looks pretty much like ReturningMethod.


That is terribly ugly, of course. If I could do it at runtime, I could introduce about two classes for the first template, then use tango.text.convert.Layout and public static format strings to deal with ReturningMethod. I'd do it with a format string looking like this:


public const string methodOutline = `{0} {1} ({2}) {{{
{{0}}
}}}`;
public const string methodBodyPart1 = `{0} {1} ...`;
public const string methodBodyPart2 = `{0} {1} ...`; // and so on


Of course, Layout won't work at compile time. Even if it did, I'd be left with a glob of functions to go through for my "unit" tests. But at that rate, I might as well complete the integration test by running the code that mixes in this giant string.

So I've been thinking of how to do it. The answer lies in two parts:

  1. Write a compile-time string formatting function.

  2. Implement any method I want to test as a string that I mix in.



The former makes it much easier to make sure the result string has the right arguments in the right place. The latter means I can test each in isolation by providing default implementations of templates that I'm not testing.

But for now, I've got some ugly, unmaintainable blobs of code to rewrite. The joy.

Continuous Integration for D

You don't need to use Agile to benefit from a Continuous Integration server. The basic idea is, you've got a server that checks out your code whenever there are updates, builds it according to a build script, and (almost always) runs some scripted tests on it.

I'm pondering how to set one up for D, using a daemon of some sort. The approach looks something like this:


  • A config file with the repository information and where to check it out to.

  • A DSSS file in the root of the repository.

  • A list of directories that contain tests. These should only contain tests; perhaps an exclude option for files and directories that contain helper methods.



The build process isn't that exciting:

  • Check for updates; if none, sleep.

  • Run dsss build.

  • Recursively go through the test directories, running rebuild on each .d file and executing the resulting executable.

  • Publish the results.



This requires that each test file contain a main() method. However, it has the benefit that the main executable does not contain unit tests, enforcing or at least encouraging separation of concerns and design practices that do require tests to have private access to the tested modules.

Ugh.

Stack traces are beautiful. If you are ever in control of a standard library, make sure your exceptions have stack traces.

I'm trying to do TDD without them, and that means inserting a lot of tracing code, which is a bad sign.

Saturday, February 16, 2008

Did it...

Got the assertions stuff done, at least the basic stuff. The list stuff is annoying -- and not fully tested -- but should work with with builtin arrays (which, in D, are actually resizeable, sliceable, and everything you'd expect from a thorough library implementation) as well as just about any collection class that Tango contains.

The annoying part is formatting everything without taking mounds of code for it. I've got that working, aside from negation.

Now I'm working on test cases for everything else I've written. It's much easier to build stuff with Descent for an IDE and Rebuild, but still difficult enough that it's difficult to support a proper TDD model.

Hi!

The intent of this blog is to encourage me to code. As such, I may update infrequently or say stuff that seems quite inane. Also, most of my posts will relate strongly to my code and be irrelevant for most other people.

My code, since I've mentioned it, is mostly in the D programming language. I've got a collection of libraries called Felt in various stages of development, aiming at being a Castle clone. Or maybe I'm trying to catch up with Ayende @ Rahien. The code's all at the Felt dsource page.

Anyway, I'll catch up with you later.

felt assertions

I'm working on an assertions library right now. Library? Well, just a couple files, two structs, an exception class, and a half dozen functions.

It's in the D programming language. It depends on Tango Variant, which can actually handle structs of nontrivial sizes. Phobos Variant can't. And it should work with D1 and D2.

I need to get my hands on Tango for D2. Even if Phobos were decent, I can't afford to write so many version statements. It just isn't worth my time. But the reflection capabilities introduced in D2 are great.

The final product will look something like this:
expect(4).equals(4);
expect([1, 2, 3, 4]).has(2).where((int x) { return x % 2 == 0; });

// should be 2 where the constraint is false
expect([1, 2, 3, 4]).has(2).not.where((int x) { return x % 2 == 0; });

// should be other than two where the constraint is false
expect([1, 2, 3, 4]).not.has(2).where((int x) { return x % 3 == 0; });
expect([1, 2, 3, 4]).hasOne.sameAs(2);
expect(true);
expect(null).isNull;
o = new Object;
auto p = o;
expect(o).sameAs(p);
p = new Object;
expect(p).not.sameAs(o);

It'll be ready some time today. And then I should stop slacking and get Felt.Sleeper working. Or fix interfaces with dmocks.