CommonLisp Testing: announcing Lisp-Unit2

I recently published lisp-unit2 which is a major refactoring of the lisp-unit library. I am one of the biggest public users of lisp-unit (accounting for 15 of the 28 libraries depending on it in quicklisp). I also have some very large internal test suites for non-public applications. I have been using lisp-unit regularly for at least the past 5 years and perhaps longer. After such extended use, I finally had an issue that made me start refactoring lisp-unit. (I could not find where a “compiler error” message was being printed from, which ended up not even being lisp-unit’s fault, but lisp-unit didn’t help me find it). This compounded with years of “wouldn’t it be nice if lisp-unit did” made me finally go about fixing all my gripes.

The things I most wanted to change were:

  • Lots of flags that are not obvious, that do odd things. I always ended up setting all of them to true from their default state, so having 3-4 flags that always need to be remembered to be set was strange
  • No go-to-definition. I always want to be able to go to definition from the test name and couldn’t
  • Tags/Suites. I always had wrapper macros that allowed me to organize my tests into suites. Eventually lisp-unit added tags, but the syntax was a bit odd and the usage was not always obvious.
  • Better Signal Testings. I like conditions and frequently need to test protocols that use them. Lisp-unit was deficient here
  • No easy context control. Databases and the like all had to be handled by wrapping the test body in layers of with-resource-context style macros
  • Tests were not compiled till they were run, so compiler errors/warnings often got caught later than needed and were harder to track down than they should be

All of these and more were accomplished in lisp-unit2. (Check out the README for documentation and more details).

I gathered some statistics about which test libraries were being used the most as judged by number of dependencies in quicklisp. The libraries from the CLiki Page on Test Frameworks were cross referenced with quicklisp (because some are defunct). The number listed is the number of systems in quicklisp which require one the testing libraries.

LIFT (48)
STEFIL (46) - there seems to be two branches
-- HU.DWIM.STEFIL (30)
-- STEFIL (16)
FIVEAM (45)
LISP-UNIT (28)
RT (25)
EOS (20)
CL-TEST-MORE (14)
UNIT-TEST (9)
PTESTER (5)
XLUNIT (3)
CLUNIT (1)
TESTBILD (1)

After later analysis, I could probably have gotten by writing extensions to STEFIL, but with my already long-term investment in lisp-unit. I don’t think I spent more time updating lisp-unit than I would have learning STEFIL, writing the extensions I needed and converting all my tests. Hopefully lisp-unit2 fills a need that others have as well.

The most interesting things for me while refactoring were handling the dynamic contexts and using signals to orchestrate output, debugging, results collection etc. These two abstractions combined really nicely to offer all the flexibility I wanted in output and debugging. I think that these abstractions will also allow lisp-unit2 to be highly extensible in an easy to manage way. I also liked that it was easy to write a meta-test-suite for lisp-unit2 in lisp-unit2 using these systems.

Reading and Writing IP Addresses in common lisp with help from #lisp

Last week I had been refactoring some code related to IP Addresses in our internal software at Acceleration.net. In our old code, I came across a pretty speedy ip-address printer that was faster than a naive approach by a good margin. A few days latter Stas Boukarev (stassats) happened to be discussing optimizing this function in #lisp. I sent him our slightly optimized version and after pasting back and forth, by the end of the day he had a very rapid function.

I added a pretty speedy IP address parser and the result of this work is cl-cidr-notation (https://github.com/AccelerationNet/cl-cidr-notation). This provides fast portable functions for reading ip-addresses and cidr blocks from strings into ints and for writing those ints back into dotted-quad notation (3.4.5.6), and cidr blocks into their standard notation (0.0.0.0/30). It can also efficiently print range strings (0.1.2.3-3.4.5.6).

Group-By Refactor

As always, as soon as I release a library, I can see all the mistakes I was happy leaving in until other people could see it. In Group-By I found all sorts of inconsistencies in my approach, and so to make this tiny library better I rewrote the important bits. The main problem was that this started as an alist grouping mechanism. But alists became untenable at depths greater than 1 or 2, or if linear lookup was unacceptably slow. For more efficiency I had looked at grouping into hash table; for a usable interface I looked at grouping into CLOS tree-nodes. Then I combined all three approaches into a monstrosity. The problem with this approach was that it conflated wanting a nice/usable interface (which CLOS can provide), with the efficiency issues of looking up children via a hash table or list. As such I had this strange mirroring of awful to use datastructure backends, barely wrapped in a nicer CLOS interface.

No more, now the structure of multiple groupings is a CLOS tree of grouped-list objects, while the children are stored in a single hashtable or list on each tree node (with methods defined so you should never have to worry about the implementation other than to adjust performance). This greatly simplified my ability to think about what this library was doing, and cleaned up what I considered to be some fairly glaring ugliness. Overall i think this refactoring was a victory.

It would be nice to switch implementations from list to hashtable when we noticed the number of children increasing past a certain threshold, but I have left that for a later date.

Munich, Eagles Nest, and Salzberg

<Sorry for no updates till now; it has been hard to get free internet at our hotels.  I will try to improve the formatting of this article in the future.  For now I just want to try to get as much down as possible.>

Plane Flight

Airport security was far more friendly and I left Orlando TSA a nice comment on their comment card.  I had been so nervous about air travel security that to be treated with such kindness and respect by all employees was a nice treat.  Our trip started with a 3 hour delay on our first flight which caused us to miss our DC to Munich connection.  Instead half our party was rerouted on a DC to to Frankfurt flight and the rest were rescheduled for the next day.  After much cajoling with United staff they were convinced that we should all be put on the 10 pm flight to Munich with a connection to Frankfurt.  The rest of the flights were relatively uneventful, save for my and Shannon’s luggage being left in Frankfurt. (It arrived at our hotel later in the day.)

Munich

Finally we were happily at our hotel with very little sleep.  After an all too brief nap we headed out for dinner and some of Munich’s famous Bier.  We wandered (via underground) to Marienplatz and saw the Rathaus/Glockenspiel at night (which was gorgeous).  I have been in constant awe of all the beautiful architecture we have seen.  It seems that here they actually care about the way things look.  We found the Hackerhaus Restaurant, we John and I had a sampler platter of traditional German foods.  I had sausage roast pork, boiled beef, and a beef & beef-liver meatball.  All the food (even the liver ball) was delicious.

After dinner we took in the Munich saturday nightlife.  The first pub we stopped at had cask beer which was something I hope to have frequently here.  We drank with some very nice Germans and toasted our arrival in their country (Prost!).  They convinced us that litres of beer are superior to half litres.

Sunday we took in the Glockenspiel in the morning and then had a traditional Munich Bratwurst for lunch.  It was white and much softer than the brats I am used to, but still delicious.  By the end of the meal I had been about sauerkrauted out.  The rest of the afternoon was spent at the Munich Technology Museum (biggest in the world) and their English Gardens.

The technology museum was about the coolest museum that I have ever been to.  It was essentially a museum that contained the history of every type of technology that humans have endeavored at.  We covered about a fifth of the museum in about 3-4 hours, focusing on airflight, ships, computers, the Altima Cave, and musical instruments. I also walked through areas of glass, ceramics, astronomy, measurement devices, and other areas I cannot remember right now.  Some highlights for me were: A Cray One super computer, an IBM System 360, a Curta hand calculator (including a clear version that aloud some examination of the inner workings), and boats of all variety (including U-1 the first/prototype german u-boat).

After everyone was museumed out, we decided to head through the English Gardens back to our hotel.  We stopped at the beer garden in the center for a brief rest and imbibement (Ein Dunkle Beir – One Dark Beer).  The garden was beautiful and offered a great view of the skyline.  After our beer and coffee, we decided to head back to the hotel for a rest before heading out to dinner at Hofbreauhaus.  While it was a tad more commercialized than what I remember when I was 10, it was still a good time (though the food was much less good than the night before, but what can you expect from a buffet).  It was here I heard my favorite anti-American joke thus far: “What do you call a person who knows two languages? Bilingual.  What do you call a person who knows only one? American.”  This was told by a German entertaining Italians claiming to know 5 languages (and was extremely nice during the entire meal).  

<tipsier now after returning from Nuremberg pubbing>

After dinner we took our entire party around the corner to introduced the rest of the group to some cask beer from the same bar as the previous night.  This led to drunken conversation with my father-in-law about how to improve businesses, particularly Acceleration.  His suggestion was to institute a system of employee incentives and rewards for new business.  After finishing my 2nd and a half liter the rents returned to the hotel.  We stayed out drunkenly chatting with a swede we met on the street.  We visited the hard rock Munich (where they played the crappiest American music they could find), in deference to my sister/law’s desire to drink some vodka instead of beer.  While everybody else went to bed I decided to stay up and drink some more with my brother/law Brian and his wife Sarah.  This devolved into a heated discussion over whether it is better to believe in the message of Jesus or the divinity of the man (obviously with no clear answer), until we were chased off by the hotel front desk for being too loud.

Eagles Nest

A very hungover morning and a nap in the car later, we arrived at Eagle’s Nest.  Gorgeous, nothing more can improve that sentiment.  The alps are so very pretty and I got to climb some mountains in my Birks.  (A nice german man asked if my shoes had been stolen).  The thing that seemed so strange to me is that in spending something like 150 million dollars they didn’t manage to make any bedrooms.  Its not like this place is close to anything (at least a half hour ride now to anything that resembles a town).  Why would you buld one of the most gorgeous retreats in the world placement wise and not bother to allow anyone to stay there over night? (Seriously there are like 3 rooms that are not the kitchen.)  Oh well, I guess that they were not thinking things through so clearly at this time.  

Salzburg / Mozart Dinner

After our visit to Eagles Nest we headed to Salzburg for a trip to the Mozart Dinner Concert.  If you get the chance this is definitely worth it.  Old Salzburg is more beautiful yet than even Munich, on the trip we saw engravings eulogizing Schubert and statues dedicated to Mozart.  We wandered through old Salzburg to get to our destination, St. Peters Cloister.  We ate and enjoyed immensely the concert in the Baroque Hall of St. Peter’s, which focused on Mozart’s better known instrumental pieces and excerpts of his operas.  The singing and playing was heavenly, especially in this ancient room.  The performance was by a string sextet including two violins, a viola, cello, double bass, harpsichord, and two vocalists.  It could not have been more wonderful.  After this wonderful dinner, we went back to our Mariott hotel in the newer part of Salzburg.

Salzburg Shopping

The next morning, we went back into the old city, to view it during the day and do a bit of shopping for all the nice people back at home.  We saw a huge amount of gorgeous architecture and visited a beautiful old baroque church that had been in continuous existence since the 1200 hundreds.  We visited a market that had fresh and cooked food where I was able to pick up a hotdog.  It was almost American, but with a tougher skin, and instead of sitting in a bun, it was jammed down a hole in the middle of a baguette.  We came back for our departure via a park where we purchased a couple paintings.  On the way we grabbed a quick lunch at a cafe where I was (finally) able to satiate my need for a cheese burger (with ham instead of bacon).  Culture Note: there is nothing that the Germans will not put pig on; I like that in a people.

~ Fin ~

I will write more when I get a chance, thanks to those at home, and sorry if this is less legible than it currently seems.  I will make another post linking to our pictures ASAP

The Principles of Beautiful Design

My friend and former coworker Jason Beaird recently finished his first book The Principles of Beautiful Design.  I haven’t had a chance to read it all yet, but I wanted to go ahead and put something up to help spread the work.  As you would expect from a book with this title the book is beautiful and an easy fun read.  It helps explain what makes something more visually appealing than the alternatives in a way that even us color blind computer programmers can understand.

Thanks Jason and Congrats!