“Fit” is Ward Cunningham’s “Framework for Integrated Tests”. You can pick up a copy by starting from fit.c2.com.
I’ve used it for a while, and looked at some of its code along the way, but hadn’t sat down and really studied it systematically. My plan is to spend an hour at a time, just digging in to what I find and sharing my notes.
1. Download and Compile
I download a copy and pull it in to my IDE. I see there are some yellow flags (syntax warnings). One of them looks like a style difference:
if (x > y) return x+y; else return x*y;
This is legal but it complains about the fact that there’s an “else” clause following a “then” with a return. I’ll just change things along the way even though I don’t plan to feed this back to Ward.
I also put in an AllTests suite. Method fit.FrameworkTest.testRuns() fails, showing that I haven’t moved the examples directory to the right place. This has happened at least partly because I moved stuff around when I put it in Eclipse. I copy the examples folder in, and create an output/test folder. The test tries to run, but fails the actual test (not just from a bad folder name). But time is ticking, so I’m moving on.
I take a quick look around at the files that are there – a lot of them are fixtures, which I’ve at least subclassed before.
2. Parse
FileRunner and WikiRunner are the two executables I see. WikiRunner says it’s deprecated, so I delete it. FileRunner does three things: read its arguments, create a parse of the document, and run the fixture on the parse.
I know already that Parse is some sort of tree-structure representation of the document (like DOM but simpler). I’ll start by looking at ParseTest. The first test shows that it divides a string into 4 pieces: a leader, a tag, the body (inside the tag), and a trailer. The test just used “body”; I wonder what happens if you nest tags, so I try that (with a new test). Turns out it just accepts the new tags as part of the body. (That suggests how tags fit doesn’t care about are handled – they’re just left in the body.)
The next test shows what happens when tr and td tags are thrown into the mix: parsing is different. Parse has a parameter that tells which tags it’s interested in. It looks like we have a choice: when there are no interior tags, the information is put in “body”; when interior tags exist, they form a new level, inside “parts”. “Parts” is another parse, so the whole structure is recursive.
The next tests show that we can navigate to “sibling” nodes using “more”. To move deeper into the parse, we use “parts”; to move to a sibling node at a given level, we use “more”. I saw mentioned somewhere that Parse has a Lisp-like structure, and this is the place that makes that happen. (Lisp uses “car” to get to the head of a list, “cadr” to get to the second element, “caddr” to get to the third, etc. In the tests, we see code like p.parts.parts.more.body to get to the second cell of a table. My Lisp is rusty, but this gives me something to tie it to.)
The Parse has an abbreviation, “at(i,j,k)”. I really think of this as “at(table-index, tr-index, td-index)”. The test for this shows that if an index is too big, you get the last element in the list (at that level). Also, there are helper methods to get the first leaf and the last node in a list.
The next test shows that the parser throws an exception if a tag isn’t found where it’s expected. (So a table that is missing its td tag will complain.)
The Parse has a text() method that prints the human-readable form of an HTML text. It handles & references, blanks, etc.
Finally, there are a pair of tests for helper methods that deal with escape characters and white space.
3. Where are we?
My hour is over. Admittedly, some amount of it went into writing these notes. I’ve added a few tests that clarified some of what is going on. I have a little better understanding of the Parse structure (body versus parts, for example). I still don’t know what it does in the face of nested tables. (This used to be a problem; I think they may have fixed it, but there’s nothing in the tests to say one way or the other.)
I had hoped to get into the code for Parse itself, and that’s my plan for next time.
=====
The series: