/*
* 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;
}
}
}