Tuesday, June 19, 2007

One way to test a two dimensional array in Java with JUnit

There is some times when you want to do some unit testing on a multidimensional array with Java and JUnit. I'm posting one solution today to share it, but also because I want you to share your better solutions. I am really not an expert in Java and I had some difficulties trying to unit test one of my class with a 2 dimensional array, so I wrote this simple class:


import junit.framework.Assert;
import java.util.Arrays;

public class Assertx extends Assert {

    /** A private constructor because we don't want any Assertx object */
    private Assertx() {}

    /**
     * This method test two "2 dimensional" arrays to see if they are the same
     * size and if the items inside are the same.
     * @param message The message that will be outputed if the test fail.
     * @param expected The expected 2 dimensional array.
     * @param actual The actual 2 dimensional array.
     */
    static public void assertArrayEquals(String message,
                                         double[][] expected,
                                         double[][] actual) {

        // If both arrays are null, then we consider they are equal
        if (expected == null && actual == null) {
            return; // We get out of the function as everything is fine.
        }

        // We test to see if the first dimension is the same.
        if (expected.length != actual.length) {
            fail(message +
            ". The array lengths of the first dimensions aren't the same.");
        }

        // We test every array inside the 'outer' array.
        for (int i=0; i>expected.length; i++) {
            // Can also use (with JUnit 4.3, but never tried
            // it) assertArrayEquals(actual, expected);
            assertTrue(message + ". Array no." + i +
            " in expected and actual aren't the same.",
                       Arrays.equals(expected[i], actual[i]));
        }
    }

    /**
     * This method test two "2 dimensional" arrays to see if they are the same
     * size and if the items inside are the same.
     * @param expected The expected 2 dimensional array.
     * @param actual The actual 2 dimensional array.
     */
    static public void assertArrayEquals(double[][] expected, double[][] actual) {
        assertArrayEquals(null, expected, actual);
    }   
}



To use this class, simply import it and do your test like this:

double[][] arrAct = {{0.0}, {1.0}, {2.0}, {1}};
double[][] arrExp = {{0.0}, {1.0}, {2.0}, {1}};

assertArrayEquals(arrExp, arrAct);


So, as you can see, it's quite simple to do your test with that kind of class. If you want to test for an 'int', simply change the 'double' for 'int'. As I was saying, I would like to know a better solution to do it. I guess there is a way to do it directly with JUnit, but I didn't come up with a working solution, so please, post your solutions!

Tuesday, May 1, 2007

Natural order String comparison for the Ruby Array class

Sometimes you want to order an array of strings with embedded numbers. But if we use the sort method from the array class we can have some big surprises (some information has been deleted for clarity):

irb>foo = ['foobar', 'a13bb32', 'a10', 'a13bb2c10',
       'a2', 'a3', 'a13bb2c9', 'a13', 'a20', 'a13bb2',
       'a13bb1', 'a13bb10', 'a13bb20', 'a13bb3', 'a13bb01']

irb>puts foo.sort
a10
a13
a13bb01
a13bb1
a13bb10
a13bb2
a13bb20
a13bb2c10
a13bb2c9
a13bb3
a13bb32
a2
a20
a3
foobar


The problem is that the sort method from the Array class cannot "see" the embedded numbers. It only sorts comparing each characters one at a time (usually with the ASCII numbers for the priority), so that 'a13' comes before 'a2' (because '1' comes before '2', the sort method doesn't compare '13' with '2'). Because we can open Ruby classes easily, we can add a new way to sort our strings with embedded numbers:

# --------8<--------
class Array

  # Method which sort an array composed of strings with embedded numbers by
  # the 'natural' representation of numbers inside a string.
  def natcmp
  
    reg_number = /\d+/
  
    # We call the sort method of the Array class.
    self.sort do |str1, str2|
  
      # We try to find an embedded number
      a = str1.match(reg_number)
      b = str2.match(reg_number)
  
      # If there is no number
      if [a,b].include? nil
        str1 <=> str2
      else
        while true
          begin
            # We compare strings before the number. If there
            # are equal, we will have to compare the numbers
            if (comp = a.pre_match <=> b.pre_match) == 0
              # If the numbers are equal
              comp = (a[0] == b[0]) ? comp = a[0] + a.post_match <=> b[0] + b.post_match :
                                      comp = a[0].to_i <=> b[0].to_i
            end
  
            str1, str2 = a.post_match, b.post_match
            a = str1.match(reg_number)
            b = str2.match(reg_number)
          rescue
            break
          end
        end
        comp
      end
    end
  end
  
  # Same as 'natcmp' but replace in place.
  def natcmp!
    self.replace(natcmp)
  end

end
# --------8<--------

So now, if we try our new method, here's the result:

irb>puts foo.natcmp
a2
a3
a10
a13
a13bb1
a13bb01
a13bb2
a13bb2c9
a13bb2c10
a13bb3
a13bb10
a13bb20
a13bb32
a20
foobar


We can even use the 'natcmp!' method if we want to change the array in place. I hope this will help somebody.

Thursday, April 19, 2007

Ruby and the old phone programming challenge

I recently came across an old programming language challenge while I was looking for the new D programming language (http://www.digitalmars.com/d/lisp-java-d.html). The challenge is to write a program which will output all possible combinations of phone numbers with words (like 555-ruby) given a dictionnary and a phone number in input. Lionello Lunesu took 1h15 and 55 lines of D code to achieve the goal. With the links on his site, I then look at this site and this one from Peter Norvig, a Lisp programmer, which took 2h and 45 lines of lisp code to do it. Being a Ruby fan, I tried to solve this challenge with one of my favorite language: Ruby. I was telling everybody how much of a productivity boost I got since I learned this new language, I thought it was time to prove it. And guess what, I was able to achieve it with pretty good results: 20 lines of Ruby code in 50 minutes (not couting blanks and comments like everybody else)! Here is my code:

# Number/letters mapping
map = {'2'=>'a'..'c', '3'=>'d'..'f', '4'=>'g'..'i', '5'=>'j'..'l', '6'=>'m'..'o',
       '7'=>'p'..'s', '8'=>'t'..'v', '9'=>'w'..'z', '0'=>[], '1'=>[]}

if ARGV.length != 2
    puts 'Usage: {dictFile} {phoneNumber}'
else
    # Reading the file in memory (*nix or Windows (or Mac???))
    f = IO.popen("cat #{ARGV[0]}") rescue IO.popen("type #{ARGV[0]}") rescue fail '?'
    content = f.readlines

    # For each word found
    content.each do |word|
        word.chomp!.downcase!
        next if word.empty? or word.size != ARGV[1].size # If the word is not good.

        good_word = true
        ARGV[1].size.times do |i|

            # Comparing each letters
            if not map[ARGV[1][i,1]].include?(word[i,1])
                good_word = false
                break
            end
        end

        # Write it if it's good.
        puts word if good_word
    end
end

That's it! I took a dictionnary from OpenOffice to test my code and it seems to work fine. I know that I could optimize my code, but that's not the point of the challenge. The same thing can be achieved with different languages (Python for instance), but I wanted to share my solution for those of you who are looking at Ruby.