/* * JBoss, Home of Professional Open Source. * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. Some portions may be licensed * to Red Hat, Inc. under one or more contributor license agreements. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA. */ package org.teiid.test.util; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.io.StringWriter; import java.lang.reflect.Method; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.teiid.jdbc.TeiidSQLException; /** * TestResultSetUtil was built in order to override the {@link #printThrowable(Throwable, PrintStream)} method * in order to call out.print instead of out.println * This is because the println adds a line terminator, and when the result file is in turn used for * comparison it fails because of the line terminator. * * @since */ @SuppressWarnings("nls") public class TestResultSetUtil { public static final int DEFAULT_MAX_COL_WIDTH = 29; private static final String SPACER = " "; //$NON-NLS-1$ private static final String NULL = "<null>"; //$NON-NLS-1$ private static final String MORE = "$ "; public static List compareThrowable(Throwable t, String query, File expectedResultsFile, boolean printToConsole) throws IOException { BufferedReader expectedResultsReader = null; if (expectedResultsFile != null && expectedResultsFile.exists() && expectedResultsFile.canRead()) { expectedResultsReader = new BufferedReader(new FileReader(expectedResultsFile)); } PrintStream out = TestResultSetUtil.getPrintStream(null,expectedResultsReader, printToConsole ? System.out : null); printThrowable(t, query, out); return TestResultSetUtil.getUnequalLines(out); } public static void printThrowable(Throwable t, String sql, PrintStream out) { out.println(sql); Throwable answer = t; if (t instanceof TeiidSQLException) { TeiidSQLException sqle = (TeiidSQLException) t; SQLException se = sqle.getNextException(); if (se != null) { SQLException s = null; while( (s = se.getNextException()) != null) { se = s; } answer = se; } } out.print(t.getClass().getName() + " : " + answer.getMessage()); //$NON-NLS-1$ } /** * Gets a PrintStream implementation that uses the input parameters as underlying streams * @param resultsOutput an output file for result data. If null, results will only be written to the defaul stream. * @param expectedResultsInput the reader for expected data. If null, actual data is never compared against expected results. * @param defaultPrintStream if not null, this utility will always write to this stream. Typically this is System.out * @return the single PrintStream that wraps all the input streams for writing and comparison. * @since 4.2 */ public static PrintStream getPrintStream(OutputStream resultsOutput, BufferedReader expectedResultsInput, PrintStream defaultPrintStream) { PrintStream out = null; if (defaultPrintStream == null) { defaultPrintStream = new PrintStream(new OutputStream () { public void write(int b) throws IOException {} }); } if (resultsOutput == null && expectedResultsInput == null) { out = defaultPrintStream; } else if (resultsOutput == null && expectedResultsInput != null) { out = new ComparingPrintStream(defaultPrintStream, expectedResultsInput); } else if (resultsOutput!= null && expectedResultsInput == null) { PrintStream filePrintStream = new PrintStream(resultsOutput); out = new MuxingPrintStream(new PrintStream[] {defaultPrintStream, filePrintStream}); } else { PrintStream filePrintStream = new PrintStream(resultsOutput); out = new ComparingPrintStream(new MuxingPrintStream(new PrintStream[] {defaultPrintStream, filePrintStream}), expectedResultsInput); } return out; } /** * Compares the actual results with the expected results. * @param updateCount the result of the execution * @param resultsFile output file to which the results will be written. Can be null. * @param expectedResultsFile expected results file with which to compare the results. Can be null. * @param printToConsole writes to System.out if true * @return The List of line numbers which differ between the actual and expected results. * @throws IOException * @since 4.3 */ // public static List writeAndCompareUpdateCount(int updateCount, File resultsFile, File expectedResultsFile, boolean printToConsole) throws IOException { // FileOutputStream resultsOutputStream = null; // if (resultsFile != null) { // resultsOutputStream = new FileOutputStream(resultsFile); // } // BufferedReader expectedResultsReader = null; // if (expectedResultsFile != null && expectedResultsFile.exists() && expectedResultsFile.canRead()) { // expectedResultsReader = new BufferedReader(new FileReader(expectedResultsFile)); // } // return writeAndCompareUpdateCount(updateCount, resultsOutputStream, expectedResultsReader, printToConsole ? System.out : null); // } /** * Compares the actual results with the expected results. * @param updateCount the result of the execution * @param resultsOutput OutputStream to which the results will be written. Can be null. * @param expectedResultsInput reader with which the expected results are read. Can be null. * @param defaultPrintStream the default stream to which to write the results. Can be null. * @return The List of line numbers which differ between the actual and expected results. * @since 4.3 */ // public static List writeAndCompareUpdateCount(int updateCount, OutputStream resultsOutput, BufferedReader expectedResultsInput, PrintStream defaultPrintStream) { // PrintStream out = getPrintStream(resultsOutput, expectedResultsInput, defaultPrintStream); // printUpdateCount(updateCount, out); // return getUnequalLines(out); // } /** * Compares the actual results with the expected results. * @param counts the result of the execution * @param resultsFile output file to which the results will be written. Can be null. * @param expectedResultsFile expected results file with which to compare the results. Can be null. * @param printToConsole writes to System.out if true * @return The List of line numbers which differ between the actual and expected results. * @throws IOException * @since 4.3 */ // public static List writeAndCompareBatchedUpdateCounts(int[] counts, File resultsFile, File expectedResultsFile, boolean printToConsole) throws IOException { // FileOutputStream resultsOutputStream = null; // if (resultsFile != null) { // resultsOutputStream = new FileOutputStream(resultsFile); // } // BufferedReader expectedResultsReader = null; // if (expectedResultsFile != null && expectedResultsFile.exists() && expectedResultsFile.canRead()) { // expectedResultsReader = new BufferedReader(new FileReader(expectedResultsFile)); // } // return writeAndCompareBatchedUpdateCounts(counts, resultsOutputStream, expectedResultsReader, printToConsole ? System.out : null); // } /** * Compares the actual results with the expected results. * @param counts the result of the execution * @param resultsOutput OutputStream to which the results will be written. Can be null. * @param expectedResultsInput reader with which the expected results are read. Can be null. * @param defaultPrintStream the default stream to which to write the results. Can be null. * @return The List of line numbers which differ between the actual and expected results. * @since 4.3 */ // public static List writeAndCompareBatchedUpdateCounts(int[] counts, OutputStream resultsOutput, BufferedReader expectedResultsInput, PrintStream defaultPrintStream) { // PrintStream out = getPrintStream(resultsOutput, expectedResultsInput, defaultPrintStream); // printBatchedUpdateCounts(counts, out); // return getUnequalLines(out); // } // /** * Compares the actual results with the expected results. * @param rs the result of the execution * @param maxColWidth the max width a column is allowed to have * @param printMetadata writes the metadata if true * @param resultsFile output file to which the results will be written. Can be null. * @param expectedResultsFile expected results file with which to compare the results. Can be null. * @param printToConsole writes to System.out if true * @return The List of line numbers which differ between the actual and expected results. * @throws IOException * @throws SQLException * @since 4.3 */ public static List writeAndCompareResultSet(ResultSet rs, String query, int maxColWidth, boolean printMetadata, File resultsFile, File expectedResultsFile, boolean printToConsole) throws IOException, SQLException { FileOutputStream resultsOutputStream = null; if (resultsFile != null) { resultsOutputStream = new FileOutputStream(resultsFile); } BufferedReader expectedResultsReader = null; if (expectedResultsFile != null && expectedResultsFile.exists() && expectedResultsFile.canRead()) { expectedResultsReader = new BufferedReader(new FileReader(expectedResultsFile)); } return writeAndCompareResultSet(rs, query, maxColWidth, printMetadata, resultsOutputStream, expectedResultsReader, printToConsole ? System.out : null); } /** * Compares the actual results with the expected results. * @param rs the result of the execution * @param maxColWidth the max width a column is allowed to have * @param printMetadata writes the metadata if true * @param resultsOutput OutputStream to which the results will be written. Can be null. * @param expectedResultsInput reader with which the expected results are read. Can be null. * @param defaultPrintStream the default stream to which to write the results. Can be null. * @return The List of line numbers which differ between the actual and expected results. * @throws SQLException * @since 4.3 */ public static List writeAndCompareResultSet(ResultSet rs, String query, int maxColWidth, boolean printMetadata, OutputStream resultsOutput, BufferedReader expectedResultsInput, PrintStream defaultPrintStream) throws SQLException { PrintStream out = getPrintStream(resultsOutput, expectedResultsInput, defaultPrintStream); printResultSet(rs, query, maxColWidth, printMetadata, out); return getUnequalLines(out); } public static List getUnequalLines(PrintStream out) { if (out instanceof ComparingPrintStream) { return ((ComparingPrintStream)out).getUnequalLines(); } return Collections.EMPTY_LIST; } // public static List writeAndCompareThrowable(Throwable t, File resultsFile, File expectedResultsFile, boolean printToConsole) throws IOException, SQLException { // FileOutputStream resultsOutputStream = null; // if (resultsFile != null) { // resultsOutputStream = new FileOutputStream(resultsFile); // } // BufferedReader expectedResultsReader = null; // if (expectedResultsFile != null && expectedResultsFile.exists() && expectedResultsFile.canRead()) { // expectedResultsReader = new BufferedReader(new FileReader(expectedResultsFile)); // } // return writeAndCompareThrowable(t, resultsOutputStream, expectedResultsReader, printToConsole ? System.out : null); // } // public static List writeAndCompareThrowable(Throwable t, OutputStream resultsOutput, BufferedReader expectedResultsInput, PrintStream defaultPrintStream) throws SQLException { // PrintStream out = getPrintStream(resultsOutput, expectedResultsInput, defaultPrintStream); // printThrowable(t, out); // return getUnequalLines(out); // } // // public static void printThrowable(Throwable t, PrintStream out) { // out.println(t.getClass().getName() + " : " + t.getMessage()); //$NON-NLS-1$ // } public static void printUpdateCount(int updateCount, PrintStream out) { out.println("Update Count : " + updateCount); //$NON-NLS-1$ } public static void printBatchedUpdateCounts(int[] counts, PrintStream out) { out.println("Batched Update Counts :"); //$NON-NLS-1$ for (int i = 0; i < counts.length; i++) { out.println(counts[i]); } out.println("Total Batched Commands : " + counts.length); //$NON-NLS-1$ } /** * Prints the ResultSet (and optionally the ResultSetMetaData) to a stream. If you're using the stream from getPrintStream(), * then you can also compare data with expected results. * @param rs * @param maxColWidth the max width a column is allowed to have. The column will be wider than this value only if the column name is longer. * @param printMetadata * @param out * @throws SQLException * @since 4.2 */ public static void printResultSet(ResultSet rs, String query, int maxColWidth, boolean printMetadata, PrintStream out) throws SQLException { if (maxColWidth < 0) { maxColWidth = DEFAULT_MAX_COL_WIDTH; } out.println(query); ResultSetMetaData rsmd = rs.getMetaData(); int count = rsmd.getColumnCount(); int[] sizes = new int[count]; StringWriter types = new StringWriter(); StringWriter columns = new StringWriter(); for (int i = 1; i <= count; i++) { String columnName = rsmd.getColumnName(i); String typeName = rsmd.getColumnTypeName(i); if (maxColWidth == 0) { // Sets the width of the column to the wider of the column name and the column type name. sizes[i-1] = Math.max(columnName.length(), typeName.length()); } else { // Sets the width of the column to the wider of the column name and the column display size (which cannot exceed maxColWidth). sizes[i-1] = Math.max(Math.max(columnName.length(), typeName.length()), // takes into account the type name width Math.min(rsmd.getColumnDisplaySize(i), maxColWidth)); } types.write(resizeString(typeName, sizes[i-1])); columns.write(resizeString(columnName, sizes[i-1])); if (i != count) { types.write(SPACER); columns.write(SPACER); } } out.println(types.toString()); out.println(columns.toString()); int totalRows = 0; while (rs.next()) { for (int j = 1; j <= count; j++) { if (maxColWidth == 0) { Object obj = rs.getObject(j); out.print(obj == null ? NULL : obj); //$NON-NLS-1$ if (j != count) out.print(SPACER); } else { String resizedString = resizeString(rs.getObject(j), sizes[j-1]); out.print(resizedString); if (j != count && resizedString.length() <= sizes[j-1]) { out.print(SPACER); } } } out.println(); totalRows++; } out.println("Row Count : " + totalRows); //$NON-NLS-1$ if (printMetadata) printResultSetMetadata(rsmd, out); } private static String[] METADATA_METHODS = { "getColumnName", //$NON-NLS-1$ "getColumnType", //$NON-NLS-1$ "getCatalogName", //$NON-NLS-1$ "getColumnClassName", //$NON-NLS-1$ "getColumnLabel", //$NON-NLS-1$ "getColumnTypeName", //$NON-NLS-1$ "getSchemaName", //$NON-NLS-1$ "getTableName", //$NON-NLS-1$ "getColumnDisplaySize", //$NON-NLS-1$ "getPrecision", //$NON-NLS-1$ "getScale", //$NON-NLS-1$ "isAutoIncrement", //$NON-NLS-1$ "isCaseSensitive", //$NON-NLS-1$ "isCurrency", //$NON-NLS-1$ "isDefinitelyWritable", //$NON-NLS-1$ "isNullable", //$NON-NLS-1$ "isReadOnly", //$NON-NLS-1$ "isSearchable", //$NON-NLS-1$ "isSigned", //$NON-NLS-1$ "isWritable", //$NON-NLS-1$ }; /** * Prints the ResultSetMetaData values for each column * @param rsmd * @param out * @throws SQLException * @since 4.2 */ public static void printResultSetMetadata(ResultSetMetaData rsmd, PrintStream out) throws SQLException { int columns = rsmd.getColumnCount(); Class RSMD = ResultSetMetaData.class; Class[] params = {int.class}; int numMethods = METADATA_METHODS.length; String[][] metadataStrings = new String[columns][numMethods]; // Init the widths of the columns int[] maxColWidths = new int[numMethods]; for (int i = 0; i < numMethods; i++) { maxColWidths[i] = METADATA_METHODS[i].length(); } // Buffer the metadata for (int col = 1; col <= columns; col++) { Object [] columnParam = {new Integer(col)}; for (int i = 0; i < numMethods; i++) { try { Method m = RSMD.getMethod(METADATA_METHODS[i], params); Object obj = m.invoke(rsmd, columnParam); String stringVal = (obj == null) ? NULL : obj.toString(); //$NON-NLS-1$ metadataStrings[col - 1][i] = stringVal; if (maxColWidths[i] < stringVal.length()) { maxColWidths[i] = stringVal.length(); } } catch (Throwable t) { } } } // Print the header for (int i = 0; i < numMethods; i++) { out.print(resizeString(METADATA_METHODS[i], maxColWidths[i])); if (i != numMethods) { out.print(SPACER); } } out.println(); // Print the metadata from the buffer for (int col = 0; col < columns; col++) { for (int i = 0; i < numMethods; i++) { out.print(resizeString(metadataStrings[col][i], maxColWidths[i])); if (i != numMethods) { out.print(SPACER); } } out.println(); } } private static String resizeString(Object obj, int size) { if (obj == null) { return resizeString(NULL, size); //$NON-NLS-1$ } String str = obj.toString(); if (str.length() == size) { return str; } else if (str.length() < size) { return pad(str, size - str.length()); } else { return str.substring(0, size) + MORE; } } private static String pad(String str, int padding) { StringBuffer buf = new StringBuffer(str); for (int i = 0; i < padding; i++) { buf.append(' '); } return buf.toString(); } /** * Used to write the same data to more than one output stream. * @since 4.2 */ private static final class MuxingPrintStream extends PrintStream { private PrintStream[] streams; private MuxingPrintStream(PrintStream[] streams) { super(streams[0]); this.streams = new PrintStream[streams.length]; System.arraycopy(streams, 0, this.streams, 0, streams.length); } public void close() { for (int i = 0; i < streams.length; i++) { streams[i].close(); } } public void flush() { for (int i = 0; i < streams.length; i++) { streams[i].close(); } } public void print(boolean b) { for (int i = 0; i < streams.length; i++) { streams[i].print(b); } } public void print(char c) { for (int i = 0; i < streams.length; i++) { streams[i].print(c); } } public void print(char[] s) { for (int i = 0; i < streams.length; i++) { streams[i].print(s); } } public void print(double d) { for (int i = 0; i < streams.length; i++) { streams[i].print(d); } } public void print(float f) { for (int i = 0; i < streams.length; i++) { streams[i].print(f); } } public void print(int b) { for (int i = 0; i < streams.length; i++) { streams[i].print(b); } } public void print(long l) { for (int i = 0; i < streams.length; i++) { streams[i].print(l); } } public void print(Object obj) { for (int i = 0; i < streams.length; i++) { streams[i].print(obj); } } public void print(String s) { for (int i = 0; i < streams.length; i++) { streams[i].print(s); } } public void println() { for (int i = 0; i < streams.length; i++) { streams[i].println(); } } public void println(boolean x) { for (int i = 0; i < streams.length; i++) { streams[i].println(x); } } public void println(char x) { for (int i = 0; i < streams.length; i++) { streams[i].println(x); } } public void println(char[] x) { for (int i = 0; i < streams.length; i++) { streams[i].println(x); } } public void println(double x) { for (int i = 0; i < streams.length; i++) { streams[i].println(x); } } public void println(float x) { for (int i = 0; i < streams.length; i++) { streams[i].println(x); } } public void println(int x) { for (int i = 0; i < streams.length; i++) { streams[i].println(x); } } public void println(long x) { for (int i = 0; i < streams.length; i++) { streams[i].println(x); } } public void println(Object x) { for (int i = 0; i < streams.length; i++) { streams[i].println(x); } } public void println(String x) { for (int i = 0; i < streams.length; i++) { streams[i].println(x); } } public void write(byte[] buf, int off, int len) { for (int i = 0; i < streams.length; i++) { streams[i].write(buf, off, len); } } public void write(int b) { for (int i = 0; i < streams.length; i++) { streams[i].write(b); } } public void write(byte[] b) throws IOException { for (int i = 0; i < streams.length; i++) { streams[i].write(b); } } } /** * Used to compare (per line) the data being written to the output stream with * some expected data read from an input stream * @since 4.2 */ private static final class ComparingPrintStream extends PrintStream { private ByteArrayOutputStream byteStream = new ByteArrayOutputStream(2048); private PrintStream buf = new PrintStream(byteStream); private BufferedReader in; private int line = 0; private ArrayList unequalLines = new ArrayList(); private ComparingPrintStream(OutputStream out, BufferedReader in) { super(out); this.in = in; } public void print(boolean b) { super.print(b); buf.print(b); } public void print(char c) { super.print(c); buf.print(c); } public void print(char[] s) { super.print(s); buf.print(s); } public void print(double d) { super.print(d); buf.print(d); } public void print(float f) { super.print(f); buf.print(f); } public void print(int i) { super.print(i); buf.print(i); } public void print(long l) { super.print(l); buf.print(l); } public void print(Object obj) { super.print(obj); buf.print(obj); } public void print(String s) { super.print(s); buf.print(s); } public void println() { super.println(); compareLines(); } public void println(boolean x) { super.println(x); compareLines(); } public void println(char x) { super.println(x); compareLines(); } public void println(char[] x) { super.println(x); compareLines(); } public void println(double x) { super.println(x); compareLines(); } public void println(float x) { super.println(x); compareLines(); } public void println(int x) { super.println(x); compareLines(); } public void println(long x) { super.println(x); compareLines(); } public void println(Object x) { super.println(x); compareLines(); } public void println(String x) { super.println(x); compareLines(); } private void compareLines() { line++; buf.flush(); String bufferedLine = byteStream.toString(); byteStream.reset(); try { String expectedLine = in.readLine(); if (!bufferedLine.equals(expectedLine)) { unequalLines.add("\n" + new Integer(line) + ":" + bufferedLine ); } } catch (IOException e) { } } public List getUnequalLines() { return unequalLines; } } }