My hobbyist coding updates and releases as the mysterious "Mr. Tines"

Sunday 2 December 2007

Making a hash of it

Wrote one (meta-)test today. Find every class in com.ravnaandtines.crypt.mda, instantiate through the default constructor, and check that putting in a short sequence of bytes one at a time, as an array or as an array-slice all gave the same results.

On the up-side, this ups coverage:

Packagecom.ravnaandtines.crypt.mda
# Classes8
Line Coverage95% 1051/1104
Branch Coverage81% 170/210
Complexity2.369

and found one bug, in BlockCypherHash, where partial blocks were being lost (I wasn't updating the count of pending bytes when I should).

On the down side, while the test driver was easy to write for J#

MD5 prototype = new MD5(); // an arbitrary class in the right assembly
System.Reflection.Assembly algorithms = prototype.GetType().get_Assembly();
System.Type[] types = algorithms.GetTypes();
System.Type mda = algorithms.GetType("com.ravnaandtines.crypt.mda.MDA");

for (int k = 0; k < types.length; ++k )
{
 final System.Type underTest = types[k];
 if (!mda.IsAssignableFrom(underTest))
 {
  continue;
 }
…

but for Java, it requires some magic to do similar blind enumeration of classes. The following fudge (based off this one, with the fix noted below) gets the all loaded classes in a named package (stuck with Java 1.1 for convenience when cross compiling)

    public static java.util.Vector find(final String pckgname) {
        // Translate the package name into an absolute path
        String name = pckgname;
        if (!name.startsWith("/")) {
            name = "/" + name;
        }
        name = name.replace('.', '/');
        // Get a File object for the package
        final java.net.URL url = // get an instance of the current class to hook from
                new CryptTestUtils().getClass().getResource(name);

        // NOTE -- this url will put %20 for spaces in your path 
        // It needs to be cleared up before creating a File object
        final String dirpath = java.net.URLDecoder.decode(// 1.2 class easily stubbed for J#
                url.getFile()); 

        final java.io.File directory = new java.io.File(dirpath);
        final java.util.Vector contents = new java.util.Vector();
        if (directory.exists()) {
            // Get the list of the files contained in the package
            final String[] files = directory.list();
            for (int i = 0; i < files.length; i++) {

                // we are only interested in .class files
                if (files[i].endsWith(".class")) {
                    // removes the .class extension
                    final String classname = 
                            files[i].substring(0, files[i].length() - 6);
                    try {
                        // Try to create an instance of the object
                        final Object obj = 
                                Class.forName(pckgname + "." + classname).newInstance();
                        contents.add(obj.getClass()); // save off the class
                    } catch (ClassNotFoundException cnfex) { 
                    } catch (InstantiationException iex) { 
                    // We try to instantiate an interface
                    // or an object that does not have a 
                    // default constructor
                    } catch (IllegalAccessException iaex) { 
                    // The class is not public
                    }
                }
            }
        }
            return contents;
    }

and then we do

final java.util.Vector classes = 
                com.ravnaandtines.crypt.CryptTestUtils.find(
                "com.ravnaandtines.crypt.mda"
                );       

for (final java.util.Enumeration iter = classes.elements(); iter.hasMoreElements();)
{
      final Class underTest = (Class) iter.nextElement();

      final Object test = underTest.newInstance();
      if(!(test instanceof com.ravnaandtines.crypt.mda.MDA ))
      {
          continue;
      }
…

So, that's all the hash algorithms done. Next is the similarly mindless conversion of the crypto algorithm test vectors (and a similar meta-test). Then turning the JZlib system tests into a set of unit tests, and porting something like the Ruby Bignum unit tests. Maybe by the turn of the year, I shall actually have a platform based on existing work that can be taken forward.

No comments: