You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by fu...@apache.org on 2007/04/19 00:11:28 UTC
svn commit: r530182 -
/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/util/SQLToJUnit.java
Author: fuzzylogic
Date: Wed Apr 18 15:11:27 2007
New Revision: 530182
URL: http://svn.apache.org/viewvc?view=rev&rev=530182
Log:
DERBY-2151: Add utility to aid in converting .sql tests to JUnit.
Patch originally contributed by A B <qo...@gmail.com> with additional
modifications and comments by me.
Added:
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/util/SQLToJUnit.java (with props)
Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/util/SQLToJUnit.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/util/SQLToJUnit.java?view=auto&rev=530182
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/util/SQLToJUnit.java (added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/util/SQLToJUnit.java Wed Apr 18 15:11:27 2007
@@ -0,0 +1,1260 @@
+package org.apache.derbyTesting.functionTests.util;
+
+import java.io.*;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+/**
+ * Convert a SQL script to a JUnit test.
+ *
+ * Usage: java org.apache.derbyTesting.functionTests.util.SQLToJUnit <embedded_sql_out_file>
+ */
+public class SQLToJUnit
+{
+ // Default left margin is 8 spaces.
+ private static final int DEFAULT_LEFT_MARGIN = 8;
+ private static String leftMargin;
+
+ private static final String IJ_COMMENT = "--";
+ private static final String IJ_WARNING = "ij warning";
+ private static final String JAVA_COMMENT = "//";
+ private static final String RS_META_OBJECT_NAME = "rsmd";
+ private static final String RS_OBJECT_NAME = "rs";
+ private static final String CSTMT_OBJECT_NAME = "cSt";
+ private static final String PSTMT_OBJECT_NAME = "pSt";
+ private static final String SQL_WARN_OBJECT_NAME = "sqlWarn";
+
+ private static String IJ_PROMPT = "ij>";
+ private static String CONN_OBJECT_NAME = "conn";
+ private static String STMT_OBJECT_NAME = "st";
+ private static String USER_NAME = "";
+ private static String getWarningLogic;
+
+ // DDL statements for which we will NOT generate row count assertions.
+ private static final String [] DDL_NO_RC_COMMANDS =
+ {
+ "create", "drop", "alter", "insert", "rename", "grant ", "set schema",
+ "revoke", "lock table"
+ };
+
+ // DDL statements for which we WILL generate row count assertions.
+ private static final String [] DDL_RC_COMMANDS =
+ {
+ "update", "delete", "declare"
+ };
+
+ // SQL statements that return a result set.
+ private static final String [] QUERY_COMMANDS =
+ {
+ "select", "values"
+ };
+
+ // IJ-only (non-SQL) commands
+ private static final String [] IJ_COMMANDS =
+ {
+ "show", "describe"
+ };
+
+ /* Positive numbers (and zero) indicate that we need to
+ * generate some kind of JDBC call and (potentially)
+ * assert something (result set, row count, etc.); negative
+ * numbers represent a "result" from executing some
+ * statement--ex. error, warning, row count, etc.
+ */
+ private static int EXEC_QUERY = 0;
+ private static int EXEC_DDL_NO_ROW_COUNT = 1;
+ private static int EXEC_DDL_WITH_ROW_COUNT = 2;
+ private static int PREPARE = 3;
+ private static int P_EXECUTE = 4;
+ private static int CALL_STMT = 5;
+ private static int COMMENT = 6;
+ private static int AUTOCOMMIT = 7;
+ private static int COMMIT = 8;
+ private static int ROLLBACK = 9;
+ private static int SET_SCHEMA = 10;
+ private static int REMOVE = 11;
+ private static int GRANT = 12;
+ private static int GET_CURSOR = 13;
+ private static int CURSOR_NEXT = 14;
+ private static int CURSOR_CLOSE = 15;
+ private static int CONNECT = 16;
+ private static int SET_CONNECTION = 17;
+ private static int REVOKE = 18;
+ private static int IJ_COMMAND = 19;
+
+ private static int ROW_COUNT = -1;
+ private static int BLANK_LINE = -3;
+ private static int SQL_ERROR = -4;
+ private static int SQL_WARNING = -5;
+ private static int IWARNING = -7;
+
+ /* Note that the result set produced by execution of a
+ * QUERY_COMMAND falls into the category of "UNKNOWN
+ * LINE" because there is no fixed "prefix" that matches
+ * the start of all result sets.
+ */
+ private static int UNKNOWN_LINE = -999;
+
+ // Maximum length of a line to print to the JUnit output
+ // (with some exceptions).
+ private static int LINE_LENGTH = 60;
+
+ private int prevLineType;
+ private String jTestName;
+
+ private BufferedReader ijScript;
+ private BufferedWriter junit;
+
+ // tmpBuf is used as a pushback buffer to store lines in case we
+ // go too far reading in result set lines.
+ private StringBuffer tmpBuf;
+
+ // used to skip commands in runtime statistics calls across calls to getNextIjCommand
+ private boolean gotRuntimeStatistics = false;
+
+ private int numIgnored = 0;
+ private int numUnconverted = 0;
+
+ /* This is set if connect .. user .. as statements are found in
+ * the test to decide if we should alter our search patterns to
+ * account for ij's multiple connection behavior. The hashtable
+ * is used to store the user and connection names.
+ */
+ private boolean multipleUserConnections = false;
+ private Properties userConnections = new Properties();
+ private int usersConnected;
+ private int anonymousCount = 0;
+
+ public static void main(String [] args)
+ {
+ try {
+
+ (new SQLToJUnit()).convert(args);
+
+ } catch (Exception e) {
+
+ System.out.println("OOPS, top-level error:");
+ e.printStackTrace();
+
+ }
+ }
+
+ /**
+ * Convert .sql test output to JUnit JDBC code.
+ *
+ * This keeps two lines/blocks of output at a time in currLineType
+ * and nextLineType so that the result of statement executions can be
+ * handled along with the executing statement, for example to generate
+ * the necessary asserts for errors or resultsets.
+ */
+ public void convert(String [] args) throws Exception
+ {
+ if (args.length < 1)
+ {
+ System.out.println("\n Usage: java SQLToJUnit <embedded_sql_out_file>\n");
+ return;
+ }
+
+ if (!loadIJScript(args[0]))
+ return;
+
+ writePrologue();
+ tmpBuf = new StringBuffer();
+
+ try {
+
+ leftMargin = "";
+ for (int i = 0; i < DEFAULT_LEFT_MARGIN; i++)
+ leftMargin += " ";
+
+ writeJUnitEOL();
+
+ int nextLineType;
+ boolean writeCurrLine;
+ boolean done = false;
+ StringBuffer currLine = new StringBuffer();
+ StringBuffer nextLine = new StringBuffer();
+ StringBuffer str = new StringBuffer();
+ while (!done && getNextIjCommand(str))
+ {
+ nextLineType = getLineType(str);
+
+ // if the next line is a set connection, make the switch to
+ // the object names before the next line after is read.
+ //
+ // TODO: not sure this is the exactly right place for this,
+ // some comments are recorded with their ij prompt intact.
+ if (nextLineType == SET_CONNECTION)
+ {
+ CONN_OBJECT_NAME = str.substring(str.indexOf("set connection ") + 15, str.length());
+ STMT_OBJECT_NAME = "st_" + CONN_OBJECT_NAME;
+ IJ_PROMPT = "ij(" + CONN_OBJECT_NAME.toUpperCase()+ ")>";
+ USER_NAME = (String)userConnections.getProperty(CONN_OBJECT_NAME);
+ junit.write("// set connection " + CONN_OBJECT_NAME);
+ writeJUnitEOL();
+ }
+
+ // Ignore IJ-specific warnings for now.
+ while (ignorableLine(nextLineType))
+ {
+ if (nextLineType != BLANK_LINE)
+ {
+ junit.write("[**:: IGNORED ::**] ");
+ junit.write(str.toString().trim());
+ writeJUnitEOL();
+ writeJUnitEOL();
+ numIgnored++;
+ }
+ str.delete(0, str.length());
+ if (!getNextIjCommand(str))
+ {
+ done = true;
+ break;
+ }
+ nextLineType = getLineType(str);
+ }
+
+ writeCurrLine = true;
+
+ // Condense multiple comment lines into uniform
+ // blocks of Java comments.
+ if (nextLineType == COMMENT)
+ {
+ if (prevLineType == COMMENT)
+ {
+ nextLine.append(strip(str, IJ_COMMENT));
+ writeCurrLine = false;
+ }
+ else
+ {
+ nextLine.append(str.toString().trim());
+ writeCurrLine = (currLine.length() > 0);
+ }
+ }
+
+ if (writeCurrLine && ((nextLineType != SQL_ERROR)
+ || (prevLineType != SQL_ERROR)))
+ {
+ if (nextLineType != COMMENT)
+ nextLine.append(str);
+
+ writeJavaLine(currLine, nextLine);
+ if (nextLine.length() == 0)
+ writeJUnitEOL();
+ }
+
+ // Clear out the lines that have been processed and shuffle
+ // the buffers to prepare for the next incoming line.
+ // NOTE: prevLineType should maybe be named currLineType?
+ prevLineType = nextLineType;
+ str.delete(0, str.length());
+ currLine.append(nextLine.toString());
+ nextLine.delete(0, nextLine.length());
+ }
+
+ if (currLine.length() > 0)
+ writeJavaLine(currLine, nextLine);
+
+ // TODO: need cleanup for multiple connections
+ writeJUnitEOL();
+ junit.write("getConnection().rollback();");
+ writeJUnitEOL();
+ junit.write("st.close();");
+ junit.write("\n }\n}");
+
+ System.out.println("\n ==> Ignored " + numIgnored + " lines and left " +
+ numUnconverted + " lines unconverted.\n ==> Output is in '" +
+ jTestName + ".junit'.\n\nDone.\n");
+
+ junit.flush();
+
+ } catch (Exception e) {
+
+ // If something went wrong flush the junit output so that
+ // user can see whereabouts the problem occurred.
+ if (junit != null)
+ junit.flush();
+
+ throw e;
+ }
+ }
+
+ private boolean loadIJScript(String fName)
+ throws Exception
+ {
+ try {
+
+ ijScript = new BufferedReader(
+ new InputStreamReader(
+ new FileInputStream(fName)));
+
+ if (fName.endsWith(".out"))
+ jTestName = fName.substring(0, fName.indexOf("."));
+ else
+ jTestName = fName;
+
+ jTestName = jTestName.replaceAll("[.]", "_");
+ junit = new BufferedWriter(new FileWriter(jTestName + ".junit"));
+
+ } catch (IOException ioe) {
+
+ System.out.println("-=- Could not find IJ master: '" +
+ fName + "'");
+
+ return false;
+
+ }
+
+ return true;
+ }
+
+ private void writeJavaLine(StringBuffer lineToWrite,
+ StringBuffer followupLine) throws Exception
+ {
+ if ((lineToWrite == null) || (lineToWrite.length() == 0))
+ return;
+
+ boolean writeEOL = true;
+ strip(lineToWrite, IJ_PROMPT);
+ if (prevLineType == COMMENT)
+ {
+ strip(lineToWrite, IJ_COMMENT);
+ junit.write(JAVA_COMMENT);
+ writeMaxLenLine(lineToWrite, JAVA_COMMENT + " ", null);
+ writeJUnitEOL();
+ }
+ else if (prevLineType == IJ_COMMAND)
+ {
+ junit.write("[**:: UNCONVERTED ::**] ");
+ junit.write(lineToWrite.toString());
+ writeJUnitEOL();
+ numUnconverted++;
+ }
+ else if (prevLineType >= 0)
+ writeJDBCCode(lineToWrite, followupLine);
+ else if (prevLineType == SQL_WARNING)
+ {
+ writeAssertWarning(lineToWrite);
+ writeJUnitEOL();
+ }
+ else
+ {
+ String str = lineToWrite.toString();
+ if (str.trim().length() > 0)
+ {
+ junit.write("[**:: UNCONVERTED ::**] ");
+ junit.write(str);
+ writeJUnitEOL();
+ numUnconverted++;
+ }
+ else
+ writeEOL = false;
+ }
+
+ if (writeEOL)
+ writeJUnitEOL();
+
+ lineToWrite.delete(0, lineToWrite.length());
+ return;
+ }
+
+ private void writeJDBCCode(StringBuffer stmt,
+ StringBuffer result) throws Exception
+ {
+ int resultType = getLineType(result);
+ boolean success = (resultType != SQL_ERROR);
+
+ String indent = "";
+ if (!success)
+ indent = " ";
+
+ if (prevLineType == EXEC_QUERY)
+ {
+ if (success)
+ {
+ junit.write("rs = ");
+ junit.write(STMT_OBJECT_NAME);
+ junit.write(".executeQuery(");
+ writeJUnitEOL();
+ writeQuotedLine(stmt, indent);
+ writeJUnitEOL();
+ writeAssertResultSet(result);
+ }
+ else
+ writeFailStatement(stmt, null, result, false);
+ }
+ else if ((prevLineType == EXEC_DDL_WITH_ROW_COUNT)
+ || (prevLineType == EXEC_DDL_NO_ROW_COUNT))
+ {
+ if (success)
+ {
+ if ((resultType == ROW_COUNT) &&
+ (prevLineType == EXEC_DDL_WITH_ROW_COUNT))
+ {
+ writeAssertDDLCount(stmt, result, STMT_OBJECT_NAME);
+ }
+ else
+ {
+ junit.write(STMT_OBJECT_NAME);
+ junit.write(".executeUpdate(");
+ writeJUnitEOL();
+ writeQuotedLine(stmt, indent);
+ result.delete(0, result.length());
+ }
+ }
+ else
+ writeFailStatement(stmt, null, result, false);
+ }
+ else if (prevLineType == PREPARE)
+ {
+ stmt.delete(0, stmt.indexOf("'") + 1);
+ stmt.delete(stmt.lastIndexOf("'"), stmt.length());
+ if (success)
+ {
+ junit.write(indent);
+ junit.write(PSTMT_OBJECT_NAME);
+ junit.write(" = ");
+ junit.write("prepareStatement(");
+ writeJUnitEOL();
+ writeQuotedLine(stmt, indent);
+ writeJUnitEOL();
+ }
+ else
+ writeFailStatement(stmt, null, result, true);
+ }
+ else if (prevLineType == P_EXECUTE)
+ {
+ // Bind the parameters.
+ if (stmt.indexOf("'") != -1)
+ {
+ stmt.delete(0, stmt.indexOf("'") + 1);
+ stmt.delete(stmt.lastIndexOf("'"), stmt.length());
+ junit.write(RS_OBJECT_NAME);
+ junit.write(" = ");
+ junit.write(STMT_OBJECT_NAME);
+ junit.write(".executeQuery(");
+ writeJUnitEOL();
+ collapseQuotes(stmt, '\'');
+ writeQuotedLine(stmt, indent);
+ writeJUnitEOL();
+ writeJUnitEOL();
+ junit.write(RS_OBJECT_NAME);
+ junit.write(".next();");
+ writeJUnitEOL();
+ junit.write(RS_META_OBJECT_NAME);
+ junit.write(" = ");
+ junit.write(RS_OBJECT_NAME);
+ junit.write(".getMetaData();");
+ writeJUnitEOL();
+ junit.write("for (int i = 1; i <= ");
+ junit.write(RS_META_OBJECT_NAME);
+ junit.write(".getColumnCount(); i++)");
+ writeJUnitEOL();
+ junit.write(" ");
+ junit.write(PSTMT_OBJECT_NAME);
+ junit.write(".setObject(i, ");
+ junit.write(RS_OBJECT_NAME);
+ junit.write(".getObject(i));");
+ writeJUnitEOL();
+ writeJUnitEOL();
+ }
+
+ // Now execute.
+ if (success)
+ {
+ if (resultType == ROW_COUNT)
+ writeAssertDDLCount(null, result, PSTMT_OBJECT_NAME);
+ else
+ {
+ junit.write("rs = ");
+ junit.write(PSTMT_OBJECT_NAME);
+ junit.write(".executeQuery();");
+ writeAssertResultSet(result);
+ }
+ }
+ else
+ {
+ writeFailStatement(null, PSTMT_OBJECT_NAME,
+ result, false);
+ }
+ }
+ else if (prevLineType == CALL_STMT)
+ {
+ junit.write(CSTMT_OBJECT_NAME);
+ junit.write(" = prepareCall(");
+ writeJUnitEOL();
+ writeQuotedLine(stmt, "");
+
+ if (success) {
+ writeJUnitEOL();
+ writeAssertDDLCount(null, result, CSTMT_OBJECT_NAME);
+ }
+ else
+ {
+ writeJUnitEOL();
+ writeFailStatement(null, CSTMT_OBJECT_NAME,
+ result, false);
+ }
+ }
+ else if (prevLineType == AUTOCOMMIT)
+ {
+ junit.write(CONN_OBJECT_NAME + ".setAutoCommit(");
+ junit.write(stmt.indexOf(" off") == -1 ? "true" : "false");
+ junit.write(");");
+ writeJUnitEOL();
+ }
+ else if (prevLineType == COMMIT)
+ junit.write(CONN_OBJECT_NAME + ".commit();");
+ else if (prevLineType == ROLLBACK)
+ {
+ junit.write(CONN_OBJECT_NAME + ".rollback();");
+ writeJUnitEOL();
+ }
+ else if (prevLineType == GET_CURSOR)
+ writeGetCursor(stmt, indent);
+ else if (prevLineType == CURSOR_NEXT)
+ {
+ junit.write(stmt.substring(stmt.lastIndexOf(" ") + 1));
+ junit.write(".next();");
+ writeJUnitEOL();
+ }
+ else if (prevLineType == CURSOR_CLOSE)
+ {
+ String cName = stmt.substring(stmt.lastIndexOf(" ") + 1).trim();
+ junit.write(cName);
+ junit.write(".close();");
+ writeJUnitEOL();
+ junit.write("ps_");
+ junit.write(cName);
+ junit.write(".close();");
+ writeJUnitEOL();
+ } else if (prevLineType == CONNECT)
+ {
+ multipleUserConnections = true;
+ int userpos = 0;
+ boolean anonymous = false;
+
+ if (stmt.indexOf("user=") > 0) {
+ userpos = stmt.indexOf("user=") + 4;
+ if (stmt.indexOf(" as ") < 0) {
+ anonymous = true;
+ }
+ } else
+ {
+ userpos = stmt.indexOf("'", stmt.indexOf("user") + 1);
+ }
+
+ if (anonymous) {
+ CONN_OBJECT_NAME = "CONNECTION" + anonymousCount;
+ anonymousCount++;
+ } else {
+ int connpos = stmt.indexOf(" as ");
+ CONN_OBJECT_NAME = stmt.substring(connpos + 4, stmt.length());
+ }
+ STMT_OBJECT_NAME = "st_" + CONN_OBJECT_NAME;
+ USER_NAME = stmt.substring(userpos + 1, stmt.indexOf("'", userpos + 1));
+ if (userConnections.get(USER_NAME) == null) {
+ junit.write("Connection ");
+ junit.write(CONN_OBJECT_NAME);
+ junit.write(" = openUserConnection(\"");
+ junit.write(USER_NAME);
+ junit.write("\");");
+ writeJUnitEOL();
+ junit.write("Statement ");
+ junit.write(STMT_OBJECT_NAME);
+ junit.write(" = ");
+ junit.write(CONN_OBJECT_NAME);
+ junit.write(".createStatement();");
+ writeJUnitEOL();
+ }
+ userConnections.setProperty(CONN_OBJECT_NAME, USER_NAME);
+ usersConnected++;
+ if (usersConnected > 1)
+ IJ_PROMPT = "ij(" + CONN_OBJECT_NAME.toUpperCase()+ ")>";
+ }
+ }
+
+ private void writeFailStatement(StringBuffer stmt,
+ String stmtName, StringBuffer result, boolean compileTime)
+ throws Exception
+ {
+ String sqlState = extractSQLState(result);
+ if (compileTime)
+ junit.write("assertCompileError(\"");
+ else
+ junit.write("assertStatementError(\"");
+ junit.write(sqlState);
+ junit.write("\", ");
+ if (stmt != null)
+ {
+ if (!compileTime)
+ {
+ junit.write(STMT_OBJECT_NAME);
+ junit.write(",");
+ }
+ writeJUnitEOL();
+ writeQuotedLine(stmt, "");
+ }
+ else
+ {
+ junit.write(stmtName);
+ junit.write(");");
+ }
+ }
+
+ private void writeAssertDDLCount(StringBuffer stmt,
+ StringBuffer ddlCount, String stmtName)
+ throws Exception
+ {
+ junit.write("assertUpdateCount(");
+ junit.write(stmtName);
+ junit.write(", ");
+ junit.write(extractRowCount(ddlCount));
+ if (stmt != null)
+ {
+ junit.write(",");
+ writeJUnitEOL();
+ writeQuotedLine(stmt, "");
+ }
+ else
+ junit.write(");");
+ }
+
+ private String extractRowCount(StringBuffer sBuf)
+ throws Exception
+ {
+ int lineType = getLineType(sBuf);
+ if (lineType != ROW_COUNT)
+ {
+ System.out.println("OOPS, tried to extract row count from " + sBuf);
+ return "";
+ }
+
+ String rowCount = sBuf.substring(0, sBuf.indexOf(" ")).trim();
+ sBuf.delete(0, sBuf.length());
+ return rowCount;
+ }
+
+ /**
+ * Write JDBC code for an ij statement of the form:
+ *
+ * get cursor c1 as 'select * from t1'
+ */
+ private void writeGetCursor(StringBuffer stmt, String indent)
+ throws Exception
+ {
+ int pos_1 = stmt.indexOf("cursor") + 7;
+ if (pos_1 < 0)
+ pos_1 = stmt.indexOf("CURSOR") + 7;
+
+ int pos_2 = stmt.indexOf(" as ");
+ if (pos_2 < 0)
+ pos_2 = stmt.indexOf(" AS ");
+ String cName = stmt.substring(pos_1, pos_2).trim();
+ junit.write("PreparedStatement ps_");
+ junit.write(cName);
+ junit.write(" = prepareStatement(");
+ writeJUnitEOL();
+
+ stmt.delete(0, stmt.indexOf("'") + 1);
+ stmt.delete(stmt.lastIndexOf("'"), stmt.length());
+ collapseQuotes(stmt, '\'');
+ writeQuotedLine(stmt, indent);
+ writeJUnitEOL();
+ writeJUnitEOL();
+
+ junit.write("ResultSet ");
+ junit.write(cName);
+ junit.write(" = ps_");
+ junit.write(cName);
+ junit.write(".executeQuery();");
+ writeJUnitEOL();
+ }
+
+ private void writeMaxLenLine(StringBuffer aLine,
+ String prefix, String suffix) throws Exception
+ {
+ if (aLine.length() <= LINE_LENGTH)
+ {
+ junit.write(aLine.toString());
+ return;
+ }
+
+ int prefixLen = (prefix == null) ? 0 : prefix.length();
+ int suffixLen = (suffix == null) ? 0 : suffix.length();
+
+ String s;
+ int pos = -1;
+ boolean firstLine = true;
+ while (aLine.length() > 0)
+ {
+ if (!firstLine)
+ {
+ writeJUnitEOL();
+ if (prefixLen > 0)
+ junit.write(prefix);
+ }
+
+ pos = aLine.indexOf("\n");
+ if (pos != -1)
+ {
+ writeMaxLenLine(new StringBuffer(aLine.substring(0, pos)),
+ prefix, suffix);
+ pos++;
+ }
+ else if (aLine.length() <= LINE_LENGTH)
+ {
+ junit.write(aLine.toString());
+ pos = aLine.length();
+ }
+ else
+ {
+ s = aLine.toString().substring(
+ 0, LINE_LENGTH - prefixLen - suffixLen);
+
+ pos = s.lastIndexOf(" ") + 1;
+ if (pos == 0)
+ pos = s.length();
+ junit.write(s.substring(0, pos));
+ }
+
+ aLine.delete(0, pos);
+ if ((suffixLen > 0) && (aLine.length() > 0))
+ junit.write(suffix);
+
+ firstLine = false;
+ }
+
+ return;
+ }
+
+ private void escapeQuotes(StringBuffer aLine)
+ {
+ if ((aLine == null) || (aLine.length() == 0))
+ return;
+
+ int len = aLine.length();
+ for (int i = len - 1; i >= 0; i--)
+ {
+ if (aLine.charAt(i) == '"')
+ aLine.replace(i, i+1, "\\\"");
+ }
+
+ return;
+ }
+
+ private void collapseQuotes(StringBuffer aLine, char quote)
+ {
+ if ((aLine == null) || (aLine.length() == 0))
+ return;
+
+ int len = aLine.length();
+ for (int i = len - 1; i >= 1; i--)
+ {
+ if ((aLine.charAt(i) == quote) &&
+ (aLine.charAt(i-1) == quote))
+ {
+ aLine.deleteCharAt(i);
+ i--;
+ }
+ }
+
+ return;
+ }
+
+ private String strip(String str, String toStrip)
+ {
+ if ((toStrip == null) || (toStrip.length() == 0))
+ return str;
+
+ if (!str.trim().startsWith(toStrip))
+ return str;
+
+ return str.substring(
+ str.indexOf(toStrip) + toStrip.length()).trim();
+ }
+
+ private StringBuffer strip(StringBuffer sBuf, String toStrip)
+ {
+ if ((toStrip == null) || (toStrip.length() == 0))
+ return sBuf;
+
+ if (sBuf.length() == 0)
+ return sBuf;
+
+ // Move past the beginning whitespace, if any.
+ int pos = 0;
+ while (Character.isWhitespace(sBuf.charAt(pos)))
+ pos++;
+
+ int len = toStrip.length();
+ boolean okayToStrip = true;
+ for (int i = 0; (i < len) && okayToStrip; i++)
+ {
+ if (sBuf.charAt(pos+i) != toStrip.charAt(i))
+ okayToStrip = false;
+ }
+
+ if (okayToStrip)
+ sBuf.delete(0, pos + len);
+
+ return sBuf;
+ }
+
+ private int getLineType(StringBuffer sBuf)
+ {
+ return getLineType(sBuf.toString());
+ }
+
+ private int getLineType(String str)
+ {
+ str = strip(str, IJ_PROMPT).toLowerCase().trim();
+ if (str.length() == 0)
+ return BLANK_LINE;
+ else if (str.startsWith(IJ_WARNING))
+ return IWARNING;
+ else if (str.startsWith(IJ_COMMENT))
+ return COMMENT;
+ else if (str.startsWith("error"))
+ return SQL_ERROR;
+ else if (str.startsWith("warning"))
+ return SQL_WARNING;
+ else if (isIjCommand(str))
+ return IJ_COMMAND;
+ else if (isQueryStatement(str))
+ return EXEC_QUERY;
+ else if (isDDLWithRowCount(str))
+ return EXEC_DDL_WITH_ROW_COUNT;
+ else if (isDDLNoRowCount(str))
+ return EXEC_DDL_NO_ROW_COUNT;
+ else if (str.startsWith("prepare"))
+ return PREPARE;
+ else if (str.startsWith("execute"))
+ return P_EXECUTE;
+ else if (str.startsWith("call "))
+ return CALL_STMT;
+ else if (Character.isDigit(str.charAt(0)))
+ {
+ int pos = str.indexOf(" ");
+ if ((pos > 0) && str.substring(pos).trim().startsWith("row"))
+ return ROW_COUNT;
+ return UNKNOWN_LINE;
+ }
+ else if (str.startsWith("autocommit"))
+ return AUTOCOMMIT;
+ else if (str.startsWith("commit"))
+ return COMMIT;
+ else if (str.startsWith("rollback"))
+ return ROLLBACK;
+ else if (str.startsWith("set schema"))
+ return SET_SCHEMA;
+ else if (str.startsWith("grant "))
+ return GRANT;
+ else if (str.startsWith("revoke"))
+ return REVOKE;
+ else if (str.startsWith("remove"))
+ return REMOVE;
+ else if (str.startsWith("get cursor"))
+ return GET_CURSOR;
+ else if (str.startsWith("next "))
+ return CURSOR_NEXT;
+ else if (str.startsWith("close"))
+ return CURSOR_CLOSE;
+ else if (str.startsWith("connect"))
+ return CONNECT;
+ else if (str.startsWith("set connection"))
+ return SET_CONNECTION;
+ else
+ return UNKNOWN_LINE;
+ }
+
+ /* Note: the next four methods could probably be condensed into one
+ * method: e.g. void isMember(String[], String)
+ */
+
+ private boolean isDDLWithRowCount(String str)
+ {
+ for (int i = 0; i < DDL_RC_COMMANDS.length; i++)
+ {
+ if (str.startsWith(DDL_RC_COMMANDS[i]))
+ return true;
+ }
+
+ return false;
+ }
+
+ private boolean isDDLNoRowCount(String str)
+ {
+ for (int i = 0; i < DDL_NO_RC_COMMANDS.length; i++)
+ {
+ if (str.startsWith(DDL_NO_RC_COMMANDS[i]))
+ return true;
+ }
+
+ return false;
+ }
+
+ private boolean isQueryStatement(String str)
+ {
+ for (int i = 0; i < QUERY_COMMANDS.length; i++)
+ {
+ if (str.startsWith(QUERY_COMMANDS[i]))
+ return true;
+ }
+
+ return false;
+ }
+
+ private boolean isIjCommand(String str)
+ {
+ for (int i = 0; i < IJ_COMMANDS.length; i++)
+ {
+ if (str.startsWith(IJ_COMMANDS[i]))
+ return true;
+ }
+
+ return false;
+ }
+
+ private void writeAssertResultSet(StringBuffer rsAsText)
+ throws Exception
+ {
+ while ((rsAsText.length() > 0) &&
+ Character.isWhitespace(rsAsText.charAt(0)))
+ {
+ rsAsText.deleteCharAt(0);
+ }
+
+ BufferedReader rsReader =
+ new BufferedReader(
+ new StringReader(rsAsText.toString()));
+
+ int rowCount = 0;
+ int colCount = 0;
+ boolean wroteDecl = false;
+ StringBuffer sBuf = new StringBuffer();
+ StringTokenizer tkzr = null;
+ for (String row = rsReader.readLine(); row != null;
+ row = rsReader.readLine(), rowCount++)
+ {
+ // Second row is just "underlining" of the column names,
+ // so skip it.
+ if ((rowCount == 1) || (getLineType(row) == ROW_COUNT))
+ continue;
+
+ // First row is column names.
+ if (rowCount == 0)
+ {
+ writeJUnitEOL();
+ junit.write("expColNames = new String [] {");
+ }
+ else if (!wroteDecl)
+ {
+ writeJUnitEOL();
+ junit.write("expRS = new String [][]");
+ writeJUnitEOL();
+ junit.write("{");
+ wroteDecl = true;
+ }
+
+ if (rowCount > 2)
+ junit.write(",");
+
+ colCount = 0;
+ tkzr = new StringTokenizer(row, "|");
+ if (rowCount > 0)
+ {
+ writeJUnitEOL();
+ junit.write(" {");
+ }
+
+ while (tkzr.hasMoreTokens())
+ {
+ sBuf.append(tkzr.nextToken().trim());
+ escapeQuotes(sBuf);
+ if (colCount > 0)
+ junit.write(", ");
+
+ if (sBuf.toString().equals("NULL"))
+ junit.write("null");
+ else
+ {
+ junit.write("\"");
+ writeMaxLenLine(sBuf, " + \"", "\"");
+ junit.write("\"");
+ }
+
+ colCount++;
+ sBuf.delete(0, sBuf.length());
+ }
+
+ junit.write("}");
+ if (rowCount == 0)
+ {
+ junit.write(";");
+ writeJUnitEOL();
+ junit.write("JDBC.assertColumnNames(rs, expColNames);");
+ writeJUnitEOL();
+ }
+ }
+
+ // Row count of 2 means we had an empty result set.
+ if (rowCount == 2)
+ junit.write("JDBC.assertDrainResults(rs, 0);");
+ else
+ {
+ writeJUnitEOL();
+ junit.write("};");
+ writeJUnitEOL();
+ writeJUnitEOL();
+ junit.write("JDBC.assertFullResultSet(rs, expRS, true);");
+ }
+
+ rsAsText.delete(0, rsAsText.length());
+ }
+
+ /**
+ * Extract out the SQLSTATE. Messages are of the
+ * form "ERROR <SQLSTATE>: ..." or "WARNING <SQLSTATE>: ...".
+ * or "ERROR ... SQLSTATE <SQLSTATE>"
+ */
+ private String extractSQLState(StringBuffer errString)
+ throws Exception
+ {
+ String sqlState;
+ if (errString.indexOf("SQLSTATE") > 0)
+ {
+ sqlState = errString.delete(0, errString.indexOf(" ", errString.indexOf("SQLSTATE")) + 1).toString().substring(0,5);
+ errString.delete(0, 6);
+ } else {
+ sqlState =
+ errString.substring(
+ errString.indexOf(" ") + 1, errString.indexOf(":"));
+ errString.delete(0, errString.length());
+ }
+ return sqlState;
+ }
+
+ private void writeAssertSQLState(String sqlState,
+ String objName) throws Exception
+ {
+ junit.write("assertSQLState(\"");
+ junit.write(sqlState);
+ junit.write("\", ");
+ junit.write(objName);
+ junit.write(");");
+
+ return;
+ }
+
+ private void writeAssertWarning(StringBuffer warnString)
+ throws Exception
+ {
+ String indent = " ";
+ if (getWarningLogic == null)
+ {
+ getWarningLogic =
+ "if (usingEmbedded())\n" + leftMargin + "{\n" +
+ leftMargin + indent + "if ((" + SQL_WARN_OBJECT_NAME +
+ " == null) && (" + STMT_OBJECT_NAME + " != null))\n"
+ + leftMargin + indent + indent + SQL_WARN_OBJECT_NAME
+ + " = " + STMT_OBJECT_NAME + ".getWarnings();\n" +
+ leftMargin + indent + "if (" + SQL_WARN_OBJECT_NAME +
+ " == null)\n" + leftMargin + indent + indent +
+ SQL_WARN_OBJECT_NAME + " = " +
+ (multipleUserConnections ? CONN_OBJECT_NAME : "getConnection()")
+ + ".getWarnings();\n" + leftMargin;
+ }
+
+ junit.write(getWarningLogic);
+ junit.write(indent);
+ junit.write("assertNotNull(\"Expected warning but found none\", ");
+ junit.write(SQL_WARN_OBJECT_NAME);
+ junit.write(");");
+ writeJUnitEOL();
+ junit.write(indent);
+ writeAssertSQLState(
+ extractSQLState(warnString), SQL_WARN_OBJECT_NAME);
+ writeJUnitEOL();
+ junit.write(indent);
+ junit.write("sqlWarn = null;");
+ writeJUnitEOL();
+ junit.write("}");
+ }
+
+ private void writeQuotedLine(StringBuffer line, String indent)
+ throws Exception
+ {
+ junit.write(indent);
+ junit.write(" \"");
+ escapeQuotes(line);
+ writeMaxLenLine(line, indent + " + \"", "\"");
+ junit.write("\");");
+ }
+
+ private void writeJUnitEOL()
+ throws IOException
+ {
+ junit.write("\n");
+ junit.write(leftMargin);
+ }
+
+ /**
+ * Return one ij command, or if it's a result set, return the entire result set
+ * in the StringBuffer.
+ */
+ private boolean getNextIjCommand(StringBuffer aLine)
+ throws IOException
+ {
+
+ int c = 0;
+ boolean done = false;
+
+ StringBuffer targetBuf = aLine;
+ String nextline = null;
+ boolean insideRS = false;
+ boolean gotFirstComment = false;
+ boolean gotCommand = false;
+ boolean readFromTmpBuf = false;
+
+ if (tmpBuf.length() > 0)
+ {
+ // get pushed back command
+ nextline = tmpBuf.toString();
+ tmpBuf.delete(0, tmpBuf.length());
+ readFromTmpBuf = true;
+ }
+
+ while(!done)
+ {
+ if (!readFromTmpBuf) {
+ nextline = ijScript.readLine();
+ } else {
+ readFromTmpBuf = false;
+ }
+ int linetype;
+
+ if (nextline == null) {
+ c = -1;
+ break;
+ } else {
+ nextline = nextline.trim();
+ linetype = getLineType(nextline);
+ // multiple lines of SQL comments will be condensed in convert().
+ // If we are inside a result set, allow the first line of a command
+ // to be pushed back, otherwise Once we are accumulating lines for a command,
+ // don't stop until we find a semicolon.
+ if (!insideRS)
+ gotCommand = gotCommand || (linetype > -1 && linetype != COMMENT);
+ }
+
+ if (!insideRS && (nextline.charAt(nextline.length() - 1) == ';'))
+ {
+ // most likely a single-line command, chomp the semicolon and return
+ targetBuf.append(nextline.substring(0, nextline.length() - 1));
+ // if we're getting runtime statistics, skip the next command inside a
+ // result set, it will be the command that we're getting RS for.
+ if (nextline.indexOf("GET_RUNTIMESTATISTICS()") > 0)
+ gotRuntimeStatistics = true;
+ break;
+ } else {
+ // unknown lines are assumed to be a part of a command if we got one previously.
+ // otherwise, must be part of a result set.
+ if (!gotCommand) {
+ // must be part of a result set
+ if (linetype == UNKNOWN_LINE || (linetype == COMMENT && !gotFirstComment && insideRS)) {
+ insideRS = true;
+ if (linetype == COMMENT) gotFirstComment = true;
+ targetBuf.append(nextline);
+ targetBuf.append("\n");
+ continue;
+ }
+ }
+ if (insideRS) {
+ if (linetype > -1) {
+ // got a command, comment or query. Result
+ // set is over and we went one line too far, hold it for
+ // the next call.
+
+ // put the first command found into the resulset if this is a
+ // RuntimeStatistics resultset.
+ if (gotRuntimeStatistics) {
+ gotRuntimeStatistics = false;
+ targetBuf.append(nextline);
+ targetBuf.append("\n");
+ continue;
+ }
+
+ tmpBuf.append(nextline);
+ break;
+ } else {
+ // got a row count or error, return it with the result set.
+ targetBuf.append(nextline);
+ break;
+ }
+ } else {
+ targetBuf.append(nextline);
+ if (gotCommand)
+ // multi-line command or comment, keep going till
+ // we get a semicolon
+ continue;
+ else
+ // single line warning or error, finished
+ break;
+ }
+ }
+ }
+
+ return (c != -1);
+ }
+
+ private boolean haveNonCommand(String aLine)
+ {
+ int lType = getLineType(aLine);
+ return ((lType < 0) || (lType == COMMENT));
+ }
+
+ private boolean ignorableLine(int lineType)
+ {
+ return (lineType == IWARNING)
+ || (lineType == BLANK_LINE);
+ }
+
+ /* TODO: It would be nice to automatically write the prologue to
+ * contain the proper sqlAuthorizationDecorator if we have
+ * multiple connections in the test, but this would require
+ * rethinking how the output is written, since the prologue
+ * could not be constructed until the rest of the output has
+ * been processed.
+ */
+ private void writePrologue() throws IOException
+ {
+ final String prologueText =
+ "\npublic final class IJToJUnitTest extends BaseJDBCTestCase {\n\n" +
+ " /**\n" +
+ " * Public constructor required for running test as standalone JUnit.\n" +
+ " */\n" +
+ " public IJToJUnitTest(String name)\n" +
+ " {\n" +
+ " super(name);\n" +
+ " }\n\n" +
+ " public static Test suite()\n" +
+ " {\n" +
+ " TestSuite suite = new TestSuite(\"IJToJUnitTest Test\");\n" +
+ " suite.addTest(TestConfiguration.defaultSuite(IJToJUnitTest.class));\n" +
+ " return suite;\n" +
+ " }\n\n" +
+ " public void test_IJToJUnitTest() throws Exception\n" +
+ " {\n" +
+ " ResultSet rs = null;\n" +
+ " ResultSetMetaData rsmd;\n" +
+ " SQLWarning sqlWarn = null;\n\n" +
+ " PreparedStatement pSt;\n" +
+ " CallableStatement cSt;\n" +
+ " Statement st = createStatement();\n\n" +
+ " String [][] expRS;\n" +
+ " String [] expColNames;\n\n";
+
+ junit.write(prologueText.replaceAll("IJToJUnitTest", jTestName));
+ }
+}
Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/util/SQLToJUnit.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/util/SQLToJUnit.java
------------------------------------------------------------------------------
svn:executable = *