Debugging Tools

Meta4 has 2 debugging tools to track down errors in regression tests and in model transformation programs and 1 tool to update correct results in regression tests.  The tools are:

RegTest.Utilty.debugViaHTML(String htmlDir, String... cdfiles)

CD.DebugUtilities.pumlDebug(String Trash, String DirName, String i, String o)

RegTest.Utility.saveCorrectOutput(...)


Among the main difficulties in debugging database programs is that you need to have screen real estate to view all of the databases that were input and output, and to compare them.  In NetBeans, this is hard because window management is not great.  Tabbed windows allow you to look at any number of files, but you have to flip between the tabs.  And you can only have so many windows open before you go crazy.

The idea behind the debugging tools is that they both produce a single html page that can display, side-by side, any number of databases per row.
The idea behind the correct-results-update tool deals with the pain of updating "correct" files manually that are used in a regression test and to make this task easy.


debugViaHTML

Suppose A, B, C are files (they don't have to be database files) that you would like to compare, side by side.  These files are produced during the execution of some regression test and you want to examine them.  To do so, you make the following call:

RegTest.Utility.debugViaHTML("trash/myDebugPage", A, B, C);

A web page, "trash/myDebugPage.html" is created.  It will have one row, where the contents of files A,B,C are placed side by side, from left-to-right, for you to compare.  You can view any number of files in a row, but you'll quickly realize that there is a limit, because the width of a file panel is 90%/N, where N = number of files to view in that row.  N=2 and N=3 are reasonable, but not much more.

You can create multiple rows of files, each row having different numbers of files.  The way to express this is in the file list; use "null" to indicate the end of a row of files and the beginning of a new row.  So the call:

RegTest.Utility.debugViaHTML("trash/myDebugPage", A, B, C, null, C, D, null, E);

creates 3 rows:  The first contains files A,B,C; the second contains files C and D; and the third contains only E. Just beware: you must list one file per row, otherwise an error will be tossed.

Follow this link to an example output of debugViaHTML.  See below on examples of this tool's use.  Also, be aware that CD.CDConform (the conformance rules for CD files) is NOT called by debugViaHTML.


pumlDebug

A common model-to-model transformation is to map one CD database to another CD database.  The debugViaHTML is helpful, but sometimes you need more.  Two programs have been added to Meta4 that may help:
M4.CD2Png  x

M4.CD2HTML x
CD2Png converts  a file "x" (whose full pathname is x.cd.pl) and creates a file x.class.png --- a portable graphics file which can be viewed in a browser.
CD2HTML convers a file "x" (whose full pathname is x.cd.pl) and creates an HTML page that presents the database x.cd.pl AND if there is a file x.class.png in the same directory, will display that also. 
CD.CDConform is not called by either CD2Png or CD2HTML -- so beware if your files are ill-formed.

Here is an example output of CD2HTML. 

Here's how pumlDebug comes into the picture.  You provide a  CD databases. pumlDebug produces a png and HTML file for both.  And then calls debugViaHTML to display them. Here is how pumlDebug is called:

    CD.DebugUtilities.pumlDebug("Trash/", "viewMe", "a.cd.pl", "yx/b.cd.pl" );


An HTML file is produced ("Trash/viewme.html").  It contains two panels, one to view a.class "Trash/a.class.pl" and another to view "Trash/b.class.html".  In general, pumlDebug uses debugViaHTML, so you can present any number of CD files (and rows of CD files) in the above manner.

 Here is an example output of pumlDebug.
  See below on examples of this tool's use.



saveCorrectOutput

A common way to perform regression tests on a model-2-model (or database-2-database) transformation is to create an output file (out.pl) and to compare it to a known correct output file (Correct/out.pl):

RegTest.Utilities.validate("out.pl", "Correct/out.pl", false);    // there are several versions of validate
Often, programs change.  And output, while correct, is flagged in error by the above call.  (This can be validated by pumlDebug and debugViaHTML).  So it is tedious to drag "out.pl" to override "Correct/out.pl" so that subsequent executions of the above call will report no errors.  A fast way to do this is to replace "validate" with "saveCorrectOutput" leaving all of the argument of the original call intact, like:

RegTest.Utilities.saveCorrectOutput("out.pl", "Correct/out.pl", false);    // there are several versions of validate

This copies "out.pl" to "Correct/out.pl" for you.  Now be sure to replace saveCorrectOutput with validate (returning to the original call) for subsequent regression tests!


Typical Usage

Here is some code that I used for debugging a composite transformation:
        
String start = Correct + "star.cd.pl";
String end = Trash + "starEnd
.cd.pl";
CD.CDConform.main(start);
CD.CDConform.main(end); // make sure that start and end files are OK

...

MoveAssocVia("yc","CD");
MoveAssocVia("xc","CD");
Merge("C","D","CD");

// save database and convert into yuml specification
SharedBody.db.print(end);

//debugViaHTML(
start, end);
//pumlDebug(
start, end);
RegTest.Utility.validate(end, start, false, elim);

Look at the red lines.  If I uncomment the debugViaHTML (or pumlDebug), I'll get a web page generated for me to look at.  If I don't want these tools, I simply comment out the line.  Usually, I start with debugViaHTML until I'm convinced I can go further visually using pumlDebug.   It works better than typical NetBeans windows. 

Finally, note that the red debugViaHTML(...) and pumlDebug(...) are presently customized in a NetBeans test directory by the following methods.  Generated files are tossed into the Trash/ directory of a NetBeans project.

public class SharedDecls {

public static final String Trash = "trash/";
public static final String yuml = ".yuml.yuml";
public static final String cdEnd = ".cd.pl";
public static final String pngEnd = ".class.png";
public static final String cdspecEnd = CDSpec.cdspecEnd;
public static final String errorCDSpecFile = Trash + "error.cdspec.pl";
public static final String outputCDFile = Trash+"error.cd.pl";
public static final String plantuml = ".class.plantuml";
public static String Allegory = "Allegory/";
public static String slash = "/";
public static String debugHtml = "CDDebug";

/**
* ********************** debugging ***********************
*/
public static void htmlDebug(String... files) {
RegTest.Utility.debugViaHtml(Trash + debugHtml, files);
}

public static void pumlDebug(String... files) {
String s[], name, html, o[];
o = new String[files.length];
int c = 0;
for (String f : files) {
if (f.equals("null")) {
o[c++] = null;
continue;
}
s = MDLUtilities.Utils.parseFileName(f);
name = s[2];
M4.CD2Png.main(f, Trash + name + ".class.png");
html = Trash + name + ".class.html";
M4.CD2HTML.main(f, html);
o[c++] = html;
}
RegTest.Utility.debugViaHtml(Trash + "CDDebug", o);
}
}