// Copyright © 2015 HSL <https://www.hsl.fi>
// This program is dual-licensed under the EUPL v1.2 and AGPLv3 licenses.
package fi.hsl.parkandride.back;
import fi.hsl.parkandride.core.service.ValidationException;
import org.junit.Test;
import org.junit.experimental.runners.Enclosed;
import org.junit.runner.RunWith;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertThat;
@RunWith(Enclosed.class)
public class LiipiSQLExceptionTranslatorTest {
protected static abstract class Base {
public static final String EX2_MESSAGE = "Exception 2 message 23985398";
SQLException ex1; // produced with stacktrace by throwing the excpetion inside createEx1()
SQLException ex2 = new SQLException(EX2_MESSAGE);
LiipiSQLExceptionTranslator translator = new LiipiSQLExceptionTranslator();
protected void createEx1(String message, String SQLState) {
try {
throw new SQLException(message, SQLState);
} catch (SQLException e) {
ex1 = e;
}
ex1.setNextException(ex2);
}
protected abstract RuntimeException translateUsingTestedMethod(SQLException e);
@Test
public void verify_that_ex2_is_not_visible_in_ex1_stacktrace_by_default() {
// This test verifies that the chained exceptions of SQLException (which are retrieved with
// getNextException) are not visible in stack trace if nothing is done. Other test cases
// verify that adding the chained exceptions as suppressed exceptions makes them visible
// in stack trace (and thus also in logs).
createEx1("Test exception", null);
assertThat(getPrintedStackTrace(ex1), not(containsString(EX2_MESSAGE)));
}
@Test
public void translator_copies_chained_exception_to_suppressed_exception() {
createEx1("Test exception", null);
RuntimeException translatedEx1 = translateUsingTestedMethod(ex1);
final Throwable[] suppressedExceptions = translatedEx1.getCause().getSuppressed();
assertThat(suppressedExceptions.length, is(1));
assertThat(suppressedExceptions[0], equalTo(ex2));
}
@Test
public void chained_exceptions_are_visible_in_toString_output_of_translated_exception() {
createEx1("Test exception", null);
RuntimeException translatedEx1 = translateUsingTestedMethod(ex1);
assertThat(getPrintedStackTrace(translatedEx1), containsString(EX2_MESSAGE));
}
protected String getPrintedStackTrace(Exception e) {
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
e.printStackTrace(printWriter);
printWriter.flush();
return stringWriter.toString();
}
}
public static final class Translate_with_sql_and_binding_parameters extends Base {
private static final List<Object> BINDINGS = new ArrayList<>();
@Override
protected RuntimeException translateUsingTestedMethod(SQLException e) {
return translator.translate("select * from test", BINDINGS, e);
}
@Test
public void chained_exceptions_are_visible_also_in_validation_exception_stack_trace() {
createEx1("Test exception with unique constraint \"abc_def_u\" violated", "23505");
RuntimeException translatedEx1 = translateUsingTestedMethod(ex1);
assertThat(translatedEx1, instanceOf(ValidationException.class));
assertThat(getPrintedStackTrace(translatedEx1), containsString(EX2_MESSAGE));
}
}
public static final class Translate_with_just_exception_parameter extends Base {
@Override
protected RuntimeException translateUsingTestedMethod(SQLException e) {
return translator.translate(e);
}
}
}