/** * @(#)Converter * A class that converts ProfessorJ beginner and intermediate files * to files that run in Java 1.5 with the tester package * * @since 5 March 2008 * @author Viera K. Proulx */ import java.io.BufferedReader; import java.io.File; import javax.swing.filechooser.FileFilter; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import javax.swing.JFileChooser; import javax.swing.JFrame; import java.util.*; /** Program that reads in a ProfessorJ file and converts it so * it can run in Java 1.5 using the tester package. */ public class Converter{ /*-------------------------------------------------------- Member data *------------------------------------------------------*/ /** the input reader */ protected BufferedReader buffer; /** the file writer */ protected FileWriter filewriter; /** one line of input at a time */ protected String line; /** an array of all lines in the file */ protected ArrayList lines = new ArrayList(); /** determines whether the general dialog has been closed */ protected boolean closed = true; /** the JFrame that holds the chooser */ protected JFrame parent = new JFrame("File to Convert"); /** the JFrame that holds the chooser */ protected JFrame parent2 = new JFrame("File to Save"); /*-------------------------------------------------------- Constructor *------------------------------------------------------*/ /** * Build a file chooser for the input file, select the input * ProfessorJ file, build a file chooser for the output file * (must end in .java) and open the file for writing; * then read the input ProfessorJ file * and write the converted .java file. */ public Converter() { /* Select the input file, quit if the user canceled the choice */ JFileChooser chooser = new JFileChooser(); JavaFileFilter filter = new JavaFileFilter(); chooser.setApproveButtonText("Select ProfessorJ File"); int returnVal = chooser.showOpenDialog(parent); if(returnVal == JFileChooser.APPROVE_OPTION) { //System.out.println("You chose to open this file: " + // chooser.getSelectedFile().getName()); closed = false; } else { /* see if file was selected - quit if user canceled */ closed = true; return; } try{ buffer = new BufferedReader( new FileReader(chooser.getSelectedFile())); } catch(FileNotFoundException e){ System.out.println("File not found exception: " + e); closed = true; } /* Select the output file, quit if the user canceled the choice */ boolean nofileyet = true; while (nofileyet){ JFileChooser chooser2 = new JFileChooser(); //chooser2.setFileFilter(filter); returnVal = chooser2.showDialog(parent2, "Save as Java 1.5 File"); if(returnVal == JFileChooser.APPROVE_OPTION) { //System.out.println("You chose to write to this file: " + // chooser2.getSelectedFile().getName()); closed = false; } else { /** see if file was selected - quit if user canceled */ closed = true; return; } try{ File outf = chooser2.getSelectedFile(); if (outf.getName().endsWith(".java")){ filewriter = new FileWriter(outf); nofileyet = false; } } catch(FileNotFoundException e){ System.out.println("File not found exception: " + e); closed = true; } catch(IOException e){ System.out.println("File IO exception: " + e); closed = true; } System.out.println("File name must end with .java"); } /** read all input lines from the selected file */ /** convert the lines and write them to the output file */ readLines(); writeLines(); } /** * Read all lines into a buffer --- until the end of the file */ public void readLines() { if (!closed) try{ while (buffer.ready()){ line = new String(buffer.readLine()); if ((line == null)){ buffer.close(); closed = true; } else{ lines.add(line); } } // finished reading the data buffer.close(); closed = true; } catch(Exception e) { System.out.println("Error in reading line exception: " + e); closed = true; } } /** *

Process every line in the list of lines:

*

First look for test case headers and replace them with test * method call with the Tester t argument.

*

Then look for check - expect clauses and replace them with * t.checkExpect( - and place a comma between the * check and expect clauses. */ public void convertTests(){ // converting the test calls for (int i = 0; i < lines.size(); i++){ String oneLine = lines.get(i); if (oneLine.length() > 0 && isTestHeader(oneLine)) lines.set(i, this.convertTestCall(oneLine, i)); } // converting the check-expect expressions for (int i = 0; i < lines.size(); i++){ String oneLine = lines.get(i); if (oneLine.length() > 0) lines.set(i, this.convertCheckExpect(oneLine, i)); } } /** * Is this line a method header for a test method or a * definition of a test case value? * @param aline the line that could be a test method header or * a test case definition * @return true if the line defines a test method or a test case */ public boolean isTestHeader(String aline){ StringTokenizer st = new StringTokenizer(aline, " (),;{}"); if (st.hasMoreTokens()){ String bool = st.nextToken(); if (bool.equals("public")) bool = st.nextToken(); if (!bool.equals("boolean")) return false; String methodName = st.nextToken(); if (methodName.startsWith("test")) return true; else return false; } else return false; } /** *

Convert the method header for a test method by adding the * Tester t argument

*

Convert a test case definition to a method call with the * Testert t argument, add } after the * test case definition (could be several lines later)

* * @param aline the line that is a test method header * or a test case definition * @return modified line with 'Tester t" parameter included * @effect if this is a test case definition, the line that ends * the test case has } addes after the ; */ public String convertTestCall(String aline, int lineNo){ int n = aline.indexOf("()"); // the line starts: public boolean testMethodname() ... if (n > 0){ String newline = aline.substring(0, n). concat("(Tester t)"). concat(aline.substring(n + 2, aline.length())); return newline; } else{ n = aline.indexOf(" ="); if (n > 0){ // the line starts: public boolean testCaseName = ... String newline = aline.substring(0, n). concat("(Tester t){\n return"). concat(aline.substring(n + 2, aline.length())); if (newline.endsWith(";")) newline = newline.concat("}"); else // look for the end of the test case and add '}" after the ';' for (int i = lineNo; i < lines.size(); i++){ if (lines.get(i).endsWith(";")){ lines.set(i, lines.get(i).concat("}")); i = lines.size(); // exit the loop } } return newline; } else return aline; } } /** * Convert any occurrence of '(check' to 'checkExpect(', * any occurrence of ' expect' to ', ' - accounting for the option * of splitting the check-expect clause over two lines * * @param aline the line with possibly 'check' or 'expect' in it * @return new line with either or both clauses replaced */ public String convertCheckExpect(String aline, int index){ if (aline.length() == 0) return aline; int checkIndexP = aline.indexOf("(check "); int checkIndex = aline.indexOf(" check "); int expectIndex = aline.indexOf(" expect "); if (checkIndexP == -1 && checkIndex == -1 && expectIndex == -1) return aline; String newline = ""; // expect starts on a new line - there is no 'check' in this line if ((checkIndexP == -1 && checkIndex == -1) && expectIndex > 0){ newline = aline.substring(0, expectIndex). concat(aline.substring(expectIndex + 7, aline.length())); return newline; } // replace '(check' with 't.checkExpect(' // replace 'expect' keyword with a comma if (checkIndexP > 0 && checkIndex == -1){ newline = aline.substring(0, checkIndexP); if (expectIndex > 0){ newline = newline.concat("t.checkExpect("). concat(aline.substring(checkIndexP + 7, expectIndex)). concat(", "). concat(aline.substring(expectIndex + 7, aline.length())); return newline; } // if no 'expect' clause in this line, just end it with a comma else{ newline = newline.concat("t.checkExpect("). concat(aline.substring(checkIndexP + 7, aline.length())). concat(", "); return newline; } } // replace ' check' with 't.checkExpect(' // replace 'expect' keyword with a comma else // checkIndexP == -1 && checkIndex > 0 if (expectIndex > 0){ int semiIndex = aline.indexOf(";"); newline = aline.substring(0, checkIndex).concat(" t.checkExpect("). concat(aline.substring(checkIndex + 7, expectIndex)). concat(", "). // insert the comma concat(aline.substring(expectIndex + 7, semiIndex)). concat(")"). // add the closing parenthesis concat(aline.substring(semiIndex, aline.length())); return newline; } // if no 'expect' clause in this line, just end it with a comma // but find the end of the expect clause // and add a closing parentheses there. else{ newline = aline.substring(0, checkIndex).concat(" t.checkExpect("). concat(aline.substring(checkIndex + 7, aline.length())). concat(", "); // look for the end of the test case and add ')' before the ';' for (int i = index; i < lines.size(); i++){ int semiIndex = lines.get(i).indexOf(";"); if (semiIndex > 0){ String line = lines.get(i); lines.set(i, line.substring(0, semiIndex). concat(")"). concat(line.substring(semiIndex, line.length()))); i = lines.size(); // exit the loop } } return newline; } } /** * Add the import statement at the beginning * Find the name of the 'Examples' class * * @return the name of the 'Examples' class that defines the tests */ public String findExamples(){ lines.add(0, "import tester.*;"); lines.add(1, " "); String className = ""; for (int i = 0; i < lines.size(); i++){ String oneLine = lines.get(i); if (this.isClassDef(oneLine)) className = this.classDefName(oneLine); if (isTestHeader(oneLine)) return className; } return ""; } /** * Does this line contain a class definition? * @param aline a line of code that could be a class definition * @return true if it is a class definition */ public boolean isClassDef(String aline){ if (aline.length() == 0) return false; StringTokenizer st = new StringTokenizer(aline, " {(),;}"); if (st.hasMoreTokens()){ String first = st.nextToken(); // possibly a visibility modifier (ignore abstract - cannot be Examples) if (first.equals("public") || first.equals("protected") || first.equals("private")) first = st.nextToken(); // now we have a class def if (first.equals("class")) return true; else return false; } else return false; } /** * Produce the name of the class defined on this line * c * @param aline a line of code that contains a class definition * @return the name of the class defined here */ public String classDefName(String aline){ if (aline.length() == 0) return ""; StringTokenizer st = new StringTokenizer(aline, " {"); String first = st.nextToken(); // possibly a visibility modifier (ignore abstract - cannot be Examples) if (first.equals("public") || first.equals("protected") || first.equals("private")) first = st.nextToken(); // now we have a class def if (first.equals("class")){ first = st.nextToken(); return first; } else return ""; } /** * Print all lines in this file */ public void printLines(){ for (String line: lines) System.out.println(line); } /** * Write all lines into a file */ public void writeLines(){ String testClassName = this.findExamples(); this.convertTests(); try{ for (String line: lines) filewriter.write(line + "\n"); filewriter.close(); } catch(IOException e){ System.out.println("Error when writing file: " + e.getMessage()); } } /*-------------------------------------------------------- Run the converter *------------------------------------------------------*/ public static void main(String argv[]){ Converter convert = new Converter(); String testClassName = convert.findExamples(); convert.convertTests(); convert.printLines(); System.out.println("\n\nTest class name: " + testClassName); convert.parent.removeNotify(); convert.parent2.removeNotify(); } } /** * Class used to assure that only file names with the suffix .java are * seen in the FileChooser dialog. * * @author Viera K. Proulx * @since 7 March 2008 * */ class JavaFileFilter extends FileFilter{ public boolean accept(File f){ // accept if file name ends in .java return f.getName().endsWith(".java"); } public String getDescription(){ return "Java files"; } }