Recently, I was refactoring a system at work and ran across a rather hard-to-track down bug after writing a unit test. The data structure was an ordered list of what were essential ordered 3-tuples. At first, the goal of the refactoring was to move classes into new packages then verify that nothing was broken. Along the way of doing the testing I was alerted to the fact that the default set in the ordered set had changed and that needed to be updated as well and this is where the problem reared it’s ugly head.
I made the changes to the default set to mimic those on the server and then when I compared the new set to the set on the server, I was coming up short on the number of tuples. Doing a diff of the rules showed two cases:
- Incorrect tuples
- Duplicate tuples
- Missing tuples
I quickly compared all the tuples I created to the tuples on the main list and verified that they were correct. Once these were verified, I set a break point to see why tuples were missing. As I stepped through the code I noticed that there was a point where the list stopped growing and items were being replaced when they shouldn’t have. Obviously, this means we’ve got a problem with the equals.
Looking at the equals, the error was subtle, they attempted to use an != command on two Integer classes expecting it to compare the integer value of the class and not the hashcode. I made the appropriate change to the equals method and re-ran the test and it passed without problems.
Of course, here I was able to write up what was basically an entire day of work in a few paragraphs… you’d think it’d be easy to spot a poorly written equals or even figure out that is the problem when you begin to see issues in production code. However, the nature of production code and the complexities of the systems often lead you down rat holes in the search for the true problem.