JNI wrapper: testing class(es) (or: how to write a console app in Java)

[wftk-j ] [ xml source ] [ discussion ]

The wrappertest class is actually significant more as a point of departure than anything else, as it's the first code I wrote while putting together the build environment for the wrapper. Essentially, all it's going to do is to create some wftk objects, do things to them, and write some things to stdout. What we do after that, I don't know. It would be logical to look at some existing Java test code, I suppose.

Anyway, down to business. Writing a console app in Java is simple: you just declare a class, and make sure it has a "main" method. Then, you run it with, e.g. "java wrappertest" and you're in business.

In our case, the main method will call a series of individual testing methods, which will be defined below.
 
import org.wftk.*;

class wrappertest {
   public static void main(String[] args) {
      try {
         System.out.println ("test_1 (create, string) - " + test_1() + "\n");
      } catch (Exception e) {
         System.out.println ("Exception in test_1 (create, string): " + e);
      }
      try {
         System.out.println ("test_2 (attributes I) - " + test_2() + "\n");
      } catch (Exception e) {
         System.out.println ("Exception in test_2 (attributes I): " + e);
      }
      try {
         System.out.println ("test_3 (text nodes) - " + test_3() + "\n");
      } catch (Exception e) {
         System.out.println ("Exception in test_3 (text nodes): " + e);
      }
      try {
         System.out.println ("test_4 (append) - " + test_4() + "\n");
      } catch (Exception e) {
         System.out.println ("Exception in test_4 (append): " + e);
      }
      try {
         System.out.println ("test_5 (parsing) - " + test_5() + "\n");
      } catch (Exception e) {
         System.out.println ("Exception in test_5 (parsing): " + e);
      }
      try {
         System.out.println ("test_6 (loc) - " + test_6() + "\n");
      } catch (Exception e) {
         System.out.println ("Exception in test_6 (loc): " + e);
      }
      try {
         System.out.println ("test_7 (copy, replace) - " + test_7() + "\n");
      } catch (Exception e) {
         System.out.println ("Exception in test_7 (copy, replace): " + e);
      }

      try {
         System.out.println ("test_simple_soap_1 - " + test_simple_soap_1());
      } catch (Exception e) {
         System.out.println ("Exception in test_simple_soap_1: " + e);
      }

      try {
         System.out.println ("test_repos_soap_1 - " + test_repos_soap_1());
      } catch (Exception e) {
         System.out.println ("Exception in test_repos_soap_1: " + e);
      }
   }
   public static String test_1() throws Exception {
      See Basic XMLAPI functionality
   }
   public static String test_2() throws Exception {
      See Basic attribute access
   }
   public static String test_3() throws Exception {
      See Basic character data access
   }
   public static String test_4() throws Exception {
      See Basic character data access
   }
   public static String test_5() throws Exception {
      See Parsing
   }
   public static String test_6() throws Exception {
      See Finding pieces of XML with xml_loc
   }
   public static String test_7() throws Exception {
      See More manipulation (copy and replace)
   }
   public static String test_simple_soap_1() throws Exception {
      See Simple SOAP client
   }
   public static String test_repos_soap_1() throws Exception {
      See Repository SOAP client
   }
}


Basic XMLAPI functionality
The first item on the agenda is just to ensure that our wrapper is functioning at all. To this end, we create an xml object, convert it to a string, and make sure that the string we get is the one we expected. That's pretty easy.
 
xml    xml = new xml();
String str = "not called";

xml.create ("element");
str = xml.string ();
xml.close();
if ("".equals(str)) return ("ok");
return ("fail: " + str);
This test first succeeded at 8:45 AM on Sunday, 24 August, 2003, and the next shortly thereafter. The wftk-j project is actually happening.

Basic attribute access
Next, we test setting and getting of attribute values.
 
xml     xml = new xml();
boolean everything_ok = true;
String  problem = "";
String  str;

xml.create ("element");
xml.set ("attr1", "value1");
xml.set ("attr2", "value2");
str = xml.attrval ("attr1");
if (!str.equals("value1")) { everything_ok=false; problem += str + " "; }
str = xml.string ();
if (!str.equals("")) { everything_ok=false; problem += str + " "; }
xml.unset ("attr2");
str = xml.string ();
if (!str.equals("")) { everything_ok=false; problem += str + " "; }

xml.close();
if (everything_ok) return ("ok");
return ("fail: " + str);


Basic character data access
Next, we test creation and accretion of text elements.
 
xml     xml = new xml();
boolean everything_ok = true;
String  problem = "";
String  str;

xml.createtext ("this is a text node");
str = xml.string ();
if (!str.equals("this is a text node")) { everything_ok=false; problem += str + " "; }

xml.textcat (" - right?");
str = xml.string ();
if (!str.equals("this is a text node - right?")) { everything_ok=false; problem += str + " "; }

xml.close();
if (everything_ok) return ("ok");
return ("fail: " + str);


Basic character data access
Appending of elements is the last thing we need to build a parser.
 
xml     xml1 = new xml();
xml     xml2 = new xml();
boolean everything_ok = true;
String  problem = "";
String  str;

xml1.create ("top");
xml2.create ("child");
xml1.append (xml2);
str = xml1.string ();
if (!str.equals("<top><child/></top>")) { everything_ok=false; problem += str + " "; }

xml2.close ();
xml2.create ("child2");
xml1.prepend (xml2);
str = xml1.string ();
if (!str.equals("<top><child2/><child/></top>")) { everything_ok=false; problem += str + " "; }

str = xml2.string();
if (!str.equals("<child2/>")) { everything_ok=false; problem += str + " "; }

xml2.close();
str = xml1.string ();
if (!str.equals("<top><child2/><child/></top>")) { everything_ok=false; problem += str + " "; }

xml1.close();

if (everything_ok) return ("ok");
return ("fail: " + problem);
This test succeeded at 4:54 PM on August 24, 2003, after a nice walk with the family through Bonn-Endinich and some ice cream. Ice cream always helps the development effort. In this case, it allowed me to see that the way I was closing xml objects was really stupid.

Parsing
Parsing! We'll test parsing in three steps. The first is just putting child elements in the right place. This tests tree traversal and handle housekeeping. And it flushed out some nasty mistakes in those, too. The second test includes text. And the third adds attributes. (I do it in this order, of course, because I implemented in this order, for no discernible reason.)
 
xml     xml = new xml();
boolean everything_ok = true;
String  problem = "";
String  str;
String  test = "";

try {
   xml.parse (test);
   str = xml.string ();
}
catch (Throwable e)
{
   str = "Exception thrown: " + e;
}
if (!str.equals(test)) { everything_ok=false; problem += "[a] " + str + " "; }
xml.close();

test = "some textmore text";
try {
   xml.parse (test);
   str = xml.string ();
}
catch (Throwable e)
{
   str = "Exception thrown: " + e;
}
if (!str.equals(test)) { everything_ok=false; problem += "[b] " + str + " "; }
xml.close();

test = "some textmore text";
try {
   xml.parse (test);
   str = xml.string ();
}
catch (Throwable e)
{
   str = "Exception thrown: " + e;
}
if (!str.equals(test)) { everything_ok=false; problem += "[c] " + str + " "; }
xml.close();

if (everything_ok) return ("ok");
return ("fail: " + problem);


Finding pieces of XML with xml_loc
Sep 7, 2003: To reconstruct complex XML handed off via SOAP, we need xml_loc location. So here we are.
 
xml     xml1 = new xml();
boolean everything_ok = true;
String  problem = "";
String  str = "";
String  test = "";

try {
   xml1.parse (test);
   str = xml1.string ();
}
catch (Throwable e)
{
   str = "Exception thrown: " + e;
}

xml xml2 = xml1.newhandle();
xml2.to_loc (".child");
if (!xml2.string().equals("<child><inner-child/></child>")) { everything_ok=false; problem += str + " "; }

xml2.to_parent();
xml2.to_loc (".child[second]");
if (!xml2.attrval ("child").equals ("child2")) { everything_ok=false; problem += "[b] couldn't find second child (found " + xml2.string() + ") "; }

xml2.to_parent();
xml2.to_loc (".child(1)");
if (!xml2.attrval ("child").equals ("child2")) { everything_ok=false; problem += "[c] couldn't find second child (found " + xml2.string() + ") "; }

xml2.close ();
xml1.close();

if (everything_ok) return ("ok");
return ("fail: " + problem);


More manipulation (copy and replace)
Sep 8, 2003: To reconstruct complex XML handed off via SOAP, we need even more stuff!
 
xml     xml1 = new xml();
xml     xml2 = new xml();
boolean everything_ok = true;
String  problem = "";
String  str = "";
String  test = "";

try {
   xml1.parse (test);
   xml2.parse (test);
}
catch (Throwable e)
{
   str = "Exception thrown: " + e;
}

xml xml3 = xml1.newhandle();
xml3.to_loc (".child");

xml xml4 = xml2.newhandle();
xml4.to_loc (".child[second]");

xml3.replace (xml4);

xml xml5 = xml2.new_copy();

System.out.println (xml1.string());
System.out.println (xml5.string());


xml5.close();
xml4.close();
xml3.close();
xml2.close();
xml1.close();

if (everything_ok) return ("ok");
return ("fail: " + problem);


Simple SOAP client
This isn't part of the wrapper, but it's part of the "Java toolkit" and so here we go, testing it. It will only work, of course, if the SOAP test server is running on the local machine.

August 27, 2003: Rewrote this a little to use the Python SOAP server as a test server. However, since the contents of the test repository determine the responses, comparison with expected values fails. Instead, we just display the returns and check that they're the types we expected. At some point, I've got some nice plans for a standard set of test cases which need to get implemented. So many to-do points, so little time.
 
String problems = "";
boolean everything_ok = true;

// TODO: "full" mode gives an error in xmlapi-j (stringcontenthtml) -- fix it, as this is kinda important.
simple_soap ss = new simple_soap("http://localhost:8000", "get");
ss.add_parm ("list_id", "Archivalienakzession");
ss.add_parm ("key", "wf1");
ss.add_parm ("mode", "edit");
ss.call();
if (ss.return_type !=0) { everything_ok = false; problems += "[a] return_type not 0 but " + ss.return_type; }
System.out.println (ss.simple_value);
System.out.println (ss.XMLResult);

simple_soap ss2 = new simple_soap("http://localhost:8000", "get");
ss2.add_parm ("list_id", "Archivalienakzession");
ss2.add_parm ("key", "1");
ss2.call();
if (ss2.return_type !=2) { everything_ok = false; problems += "[b] return_type not 2 but " + ss2.return_type; }
System.out.println (ss2.XMLResult);

simple_soap ss3 = new simple_soap("http://localhost:8000", "list");
ss3.add_parm ("list_id", "_lists");
ss3.call();
if (ss3.return_type !=1) { everything_ok = false; problems += "[c] return_type not 1 but " + ss3.return_type; }
System.out.println (ss3.XMLResult);

if (everything_ok) return ("ok");
return ("failed: " + problems);


Repository SOAP client
OK, this segment of the test code runs some basic checks against a wftk SOAP server using the RemoteSOAPRepository implementation of Repository. Granted, this kind of makes the name "wrappertest" obsolete, but that's life in the fast lane.
 
String problems = "";
boolean everything_ok = true;

Repository r = new RemoteSOAPRepository("http://localhost:8000");
Entry e = r.get ("Archivalienakzession", "1");
System.out.println (e.values());

List l = r.list ("_lists");
System.out.println (l.keys());
List l2 = r.lists ();
System.out.println (l2.keys() + ", which has " + l2.count() + " elements.");

Entry e2 = new Entry(r, "Archivalienakzession");
System.out.println ("New rec:\n" + e2.html_edit() + "\n\n");

e2.set ("TBNR", "wftest1");
e2.set ("LO", "ha!");
e2.set ("SS", "n");
e2.set ("BEISPIEL", "beispielstext hier");

e2.add ();

System.out.println ("added new obj '" + e2.key() + "'");
System.out.println ("fields: " + e2.value_count() + " and keys " + e2.values() + "!");

System.out.println ("Display of obj:\n" + e2.html_display() + "\n\n");
System.out.println ("Edit of obj:\n" + e2.html_edit() + "\n\n");

e2.set ("LO", "different");
e2.update ();

e2.set ("LO", "something totally else");
System.out.println ("Value of LO: " + e2.get("LO"));
e2.refresh ();
System.out.println ("Value of LO: " + e2.get("LO"));

l = r.tasks();
System.out.println ("By tasks():");
System.out.println (l.keys());

for (int i = 0; i < l.count(); i++) {
   System.out.println ("Task " + i + ": " + l.get_label(l.get_key(i)));
}

Entry e3 = r.get("_tasks", (String) l.keys().get(0));
System.out.println ("is_task(" + e3.key() + ")? " + e3.is_task());
System.out.println ("fields: " + e3.values());

System.out.println ("display: " + e3.html_display() + "\n\n");

System.out.println ("fields: " + e3.values());

//e3.complete();

Entry e4 = new Entry(r, "Archivalienabgabe");
e4.set ("BEISPIEL", "mehr Beispielstext");

e4.add ();

System.out.println ("Key of new record: " + e4.key());

l = e4.tasks();
System.out.println ("Tasks attached to new record:");
for (int i = 0; i < l.count(); i++) {
   System.out.println ("Task " + i + " (" + l.get_key(i) + "): " + l.get_label(l.get_key(i)));
}

Entry e5 = e4.get_task(l.get_key(0));
System.out.println ("fields: " + e5.values());

System.out.println ("key: " + e5.key() + " (list)" + e5.list_id);
e5.complete();

if (everything_ok) return ("ok");
return ("failed: " + problems);

This code and documentation are released under the terms of the GNU license. They are copyright (c) 2001-2003, Vivtek. All rights reserved except those explicitly granted under the terms of the GNU license. This presentation was prepared with LPML. Try literate programming. You'll like it.