A helper method for unit testing Comparators

For the poker game I'm not writing, I wrote a Comparator to rank the player's hands.

Now to write a unit tests for that Comparator. Generally I find that it's hard to write test cases for Comparators. You end up having to puzzle over whether to use < 0 or > 0, and the orders of the arguments is significant:
public void testFlushIsAboveStraight() {
PokerHand flush = PokerHand.fromString(" 2c 5c 6c 10c Qc");
PokerHand straight = PokerHand.fromString(" 7c 8d 9h 10s Jh");
assertTrue(new PokerHandComparator().compare(flush, straight) > 0);
Another problem with this test is that when it fails, the error message isn't particularly useful:
at PokerEngineTest.testFlushIsAboveStraight(

Recently I created a Comparator test that I think is quite natural and human readable:
void testSortingHands() {
PokerHand.fromString(" 3h 4h 4s Kc As"), // low pair
PokerHand.fromString(" 3h 4h 6s Ac As"), // high pair
PokerHand.fromString(" 3d 4d 4h 9c 9s"), // two pairs
PokerHand.fromString(" 4h 6d 10s 10c 10d"), // three of a kind
PokerHand.fromString(" 7c 8d 9h 10s Jh"), // straight
PokerHand.fromString(" 2c 5c 6c 10c Qc") // flush

This code uses a helper assert method I wrote for testing comparators. This method can be used to test any Comparator (or Comparable) in a human-readable way:
private <T> void assertElementsOrderedLikeThis(
Comparator <? super T> comparator, T... elements) {
List<T> expectedOrder = Arrays.asList(elements);

List<T> shuffledAndSorted = new ArrayList<T>(expectedOrder);
Collections.shuffle(shuffledAndSorted, new Random(0));
Collections.sort(shuffledAndSorted, comparator);
assertEquals(expectedOrder, shuffledAndSorted);

List<T> reversedAndSorted = new ArrayList<T>(expectedOrder);
Collections.sort(reversedAndSorted, comparator);
assertEquals(expectedOrder, reversedAndSorted);
Another nice thing about this approach is that in the event of a test failure, the error message includes the expected and actual values.

A PDF Printer for Mac OS X

Some applications don't use the built-in print dialog on Mac OS X, which usually means no PDF printing. Fortunately, some kind soul has created a PDF printer that is easily installed on Mac OS X.

Its mechanics are similar to PDF 995 for Windows:
  1. install the virtual printer
  2. print a document to the virtual printer
  3. a PDF file of the printout shows up on your desktop!

I used this tool with CorelDraw 11's print-merge functionality to prepare a hundred pages of personalized invitations. This was a slight bit faster than printing 100 pages and then scanning them!

Subversion and case-insensitive filesystems

My Mac's filesystem is case-insensitive. It thinks Foo and foo are the same file.

Subversion's filesystem is case-sensitive. It thinks Foo and foo are different files.

As you can imagine, this mismatch has hilarious consequences. If your repository contains a directory with both Foo and foo, then svn crashes hard when you try to checkout that directory:

svn: In directory 'project/src/com/publicobject'
svn: Can't copy 'project/src/com/publicobject/.svn/tmp/text-base/Foo.svn-base' to 'project/src/com/publicobject/Foo.tmp': No such file or directory

The solution for me was to:
  1. checkout the directory on a case-sensitive filesystem (ie. a linux machine)
  2. delete one of the offending files
  3. commit the delete

Bonus Material: how did I get myself in this situation?
I renamed a file from to Subversion cannot actually rename a file. Instead, it fakes it by creating a copy and then deleting the original. As you can imagine, this doesn't work too well on a case-insensitive file system...

CodeSearch-Plugin M9

Today's update is pretty sparse - I cleaned up the new intersect & union features so that you can kick off a new query to intersect and union against. I also drew up some custom icons for union and intersection.

My next tasks include a lot of polishing:
  • making the tabs closeable by middle click and via a context menu
  • making the results openable with F4
  • cleaning up handing of local files
  • Debugging HTTP? Get Charles

    Charles is an amazing tool that every web developer should have in their toolchest. It records the HTTP conversations between your browser and the web and lets you analyze them. It can even record HTTPS conversations and remove the encryption.

    Charles Screenshot

    Some questions that Charles will quickly answer:

    • what cookies are we sending to the browser?
    • which POST parameters are coming from the browser?
    • how many AJAX requests is my form sending?
    • why is this webpage slow?

    Charles tool is fully-capable shareware, so you can try it out before you pony up the necessary $50.

    CodeSearch-Plugin M8

    Today's update of CodeSearch-Plugin allows you to intersect the results of one query with another query. This allows you to search for code that contains both spline and Graphics2D, neither of which is particularly useful on its own.

    I've also fixed the preflight dialog's handling of ENTER etc., which was quite annoying to some users!

    CodeSearch-Plugin M7

    The newest CodeSearch-Plugin remembers what you searched for last time (including file-types & case-sensitivity), so you can search for it again. Unfortunately, this version has an unfortunate bug - when you change and then tab out of any of the text fields, it tends to kick off your query early. Hopefully I fix this tomorrow!

    The problem is that JComboBox's setAction() method is essentially useless because it doesn't differentiate between an edit and pressing 'enter'. I'll have to investigate to find a workaround. Perhaps I can install the action on the inner text field?

    CodeSearch-Plugin M6

    CodeSearch-Plugin now has options in the preflight search dialog to select the Google Code Search filetype and package. For command line search, you can now add extra arguments from the preflight dialog.

    I've also fixed the renderers so that the filename shows up on the left, and its path on the right. This works especially well when the search results panel is narrow because the most important text is also the most visible.

    CodeSearch-Plugin M5

    I've made 2 new updates to the CodeSearch-Plugin.
  • Multiple tabs
  • Expand All, Collapse All, Next, Previous buttons

    I've also come up with a very interesting feature - 'Intersect With' to combine multiple searches in an interesting way.
  • CodeSearch-Plugin M4

    Preflight Search dialog

    I've added some fixes to my codesearch-plugin project:

  • whole words only, a convenient way to focus your regex
  • search field is populated with the selected text
  • search terms are remembered
  • settings are application-wide

    You can install the plugin right in IntelliJ - instructions are here.