package annis.sqlgen;
import static annis.sqlgen.TableAccessStrategy.NODE_TABLE;
import static annis.test.TestUtils.createJdbcArray;
import static annis.test.TestUtils.uniqueInt;
import static annis.test.TestUtils.uniqueString;
import java.sql.Array;
import java.sql.ResultSet;
import java.sql.SQLException;
import static java.util.Arrays.asList;
import java.util.List;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;
import org.junit.Before;
import org.junit.Test;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.anyString;
import org.mockito.Mock;
import static org.mockito.MockitoAnnotations.initMocks;
public class PostgreSqlArraySolutionKeyTest
{
// class under test
private PostgreSqlArraySolutionKey<String> key = new PostgreSqlArraySolutionKey<>();
// test data
@Mock private TableAccessStrategy tableAccessStrategy;
@Mock private ResultSet resultSet;
// the column that identifies a node
private static String idColumnName = uniqueString(3);
// the name of the key column in the outer query
private static String keyColumnName = uniqueString(3);
@Before
public void setup()
{
initMocks(this);
key.setIdColumnName(idColumnName);
key.setKeyColumnName(keyColumnName);
}
/**
* ANNOTATE requires columns identifying each node of a matching solution
* in the inner query.
*/
@Test
public void shouldGenerateColumnsForInnerQuery()
{
// given
String nameAlias = uniqueString(3);
given(tableAccessStrategy.aliasedColumn(NODE_TABLE, idColumnName)).willReturn(nameAlias);
int index = uniqueInt(1, 10);
// when
List<String> actual = key.generateInnerQueryColumns(tableAccessStrategy, index);
// then
List<String> expected = asList(nameAlias + " AS " + idColumnName + index);
assertThat(actual, is(expected));
}
/**
* The key for an annotation graph is an array containing the IDs and/or
* names of the matched nodes in a solution.
*/
@Test
public void shouldGenerateColumnsForOuterQuery()
{
// given
String nameAlias = uniqueString(3);
given(tableAccessStrategy.aliasedColumn("solutions", idColumnName)).willReturn(nameAlias);
int size = 3;
// when
List<String> actual = key.generateOuterQueryColumns(tableAccessStrategy, size);
// then
List<String> expected = asList(
"ARRAY[" + nameAlias + "1" + ", " + nameAlias + "2" + ", " + nameAlias + "3" + "] AS " + keyColumnName);
assertThat(actual, is(expected));
}
/**
* The key should be retrieved from a key ARRAY in one column.
*/
@Test
public void shouldRetreiveKeyFromResultSet() throws SQLException
{
// given
String key1 = uniqueString(3);
String key2 = uniqueString(3);
String key3 = uniqueString(3);
Array array = createJdbcArray(key1, key2, key3);
given(resultSet.getArray(keyColumnName)).willReturn(array);
// when
List<String> actual = key.retrieveKey(resultSet);
// then
List<String> expected = asList(key1, key2, key3);
assertThat(actual, is(expected));
}
/**
* Signal illegal state if there is an SQL error.
*/
@Test(expected=IllegalStateException.class)
public void errorIfResultSetThrowsSqlExceptionInRetrieveKey() throws SQLException
{
// given
given(resultSet.getArray(anyString())).willThrow(new SQLException());
// when
key.retrieveKey(resultSet);
}
/**
* Signal illegal state if the key is NULL.
*/
@Test(expected=IllegalStateException.class)
public void errorIfKeyIsNull() throws SQLException
{
// given
given(resultSet.wasNull()).willReturn(true);
// when
key.retrieveKey(resultSet);
}
/**
* Signal if the key changes from one row to the next.
*/
@Test
public void shouldSignalNewKey() throws SQLException
{
// given
String key1 = uniqueString(3);
String key2 = uniqueString(3);
Array array1 = createJdbcArray(key1);
Array array2 = createJdbcArray(key2);
given(resultSet.getArray(keyColumnName)).willReturn(array1, array2);
// when
key.retrieveKey(resultSet);
resultSet.next();
key.retrieveKey(resultSet);
// then
assertThat(key.isNewKey(), is(true));
}
/**
* Don't signal new key if the same key is used in two consecutive rows.
*/
@Test
public void shouldRecognizeOldKey() throws SQLException
{
// given
String key1 = uniqueString(3);
Array array1 = createJdbcArray(key1);
Array array2 = createJdbcArray(key1);
given(resultSet.getArray(keyColumnName)).willReturn(array1, array2);
// when
key.retrieveKey(resultSet);
resultSet.next();
key.retrieveKey(resultSet);
// then
assertThat(key.isNewKey(), is(false));
}
/**
* A node is a match of a search term in the query if its name is part of
* the key.
*/
@Test
public void shouldSignalMatchedNodes() throws SQLException
{
// given
String[] keys = { uniqueString(3), uniqueString(3), uniqueString(3) };
Array array = createJdbcArray(keys);
given(resultSet.getArray(keyColumnName)).willReturn(array);
// when
key.retrieveKey(resultSet);
// then
for (int i = 0; i < keys.length; ++i) {
assertThat(key.getMatchedNodeIndex(keys[i]), is(i + 1));
}
}
/**
* Return {@code null} for unmatched nodes.
*/
@Test
public void shouldReturnNullForUnmatchedNodes() throws SQLException
{
// given
Array array = createJdbcArray(uniqueString());
given(resultSet.getArray(keyColumnName)).willReturn(array);
// when
key.retrieveKey(resultSet);
// then
assertThat(key.getMatchedNodeIndex(uniqueString()), is(nullValue()));
}
/**
* The string representation is the node names concatenated with ","
*/
@Test
public void shouldCreateStringRepresentationOfKey() throws SQLException
{
// given
String key1 = uniqueString(3);
String key2 = uniqueString(3);
String key3 = uniqueString(3);
Array array = createJdbcArray(key1, key2, key3);
given(resultSet.getArray(keyColumnName)).willReturn(array);
// when
key.retrieveKey(resultSet);
String actual = key.getCurrentKeyAsString();
// then
String expected = key1 + "," + key2 + "," + key3;
assertThat(actual, is(expected));
}
/**
* Return the name of the key array as key column.
*/
@Test
public void shouldReturnKeyArrayNameAsKeyColumn()
{
// when
List<String> keyColumns = key.getKeyColumns(0);
// then
assertThat(keyColumns, is(asList(keyColumnName)));
}
}