package org.molgenis.data.validation;
import org.molgenis.data.Entity;
import org.molgenis.data.EntityManager;
import org.molgenis.data.Query;
import org.molgenis.data.QueryRule;
import org.molgenis.data.meta.AttributeType;
import org.molgenis.data.meta.model.Attribute;
import org.molgenis.data.meta.model.EntityType;
import org.molgenis.data.support.QueryImpl;
import org.molgenis.file.model.FileMeta;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import java.util.*;
import static java.util.Arrays.asList;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.molgenis.data.QueryRule.Operator.*;
import static org.molgenis.data.meta.AttributeType.*;
public class QueryValidatorTest
{
private QueryValidator queryValidator;
@BeforeMethod
public void setUpBeforeMethod()
{
EntityManager entityManager = mock(EntityManager.class);
this.queryValidator = new QueryValidator(entityManager);
}
@Test(expectedExceptions = NullPointerException.class)
public void testQueryValidator()
{
new QueryValidator(null);
}
@DataProvider(name = "validateValidProvider")
public static Iterator<Object[]> validateValidProvider()
{
List<Object[]> queries = new ArrayList<>(256);
EnumSet.of(EQUALS).forEach(operator ->
{
// BOOL
Entity boolEntityType = createEntityType(BOOL);
asList(Boolean.TRUE, Boolean.FALSE, null, "true", "false", "True", "False").forEach(
value -> queries.add(new Object[] { boolEntityType, new QueryImpl<>().eq("attr", value) }));
// CATEGORICAL, XREF, CATEGORICAL_MREF, MREF, ONE_TO_MANY
EnumSet.of(STRING, INT, LONG, EMAIL, HYPERLINK).forEach(
refIdAttrType -> EnumSet.of(CATEGORICAL, XREF, CATEGORICAL_MREF, MREF, ONE_TO_MANY)
.forEach(refAttrType ->
{
Entity refEntityType = createEntityType(refAttrType, refIdAttrType);
asList("1", 1, 1L, null).forEach(idValue -> queries
.add(new Object[] { refEntityType, new QueryImpl<>().eq("attr", idValue) }));
Entity refEntity = when(mock(Entity.class).getIdValue()).thenReturn("1").getMock();
queries.add(new Object[] { refEntityType, new QueryImpl<>().eq("attr", refEntity) });
}));
// DATE
Entity dateEntityType = createEntityType(DATE);
asList(new Date(), "2016-11-25", null).forEach(
value -> queries.add(new Object[] { dateEntityType, new QueryImpl<>().eq("attr", value) }));
// DATE_TIME
Entity dateTimeEntityType = createEntityType(DATE_TIME);
asList(new Date(), "1985-08-12T11:12:13+0500", null).forEach(
value -> queries.add(new Object[] { dateTimeEntityType, new QueryImpl<>().eq("attr", value) }));
// DECIMAL
Entity decimalEntityType = createEntityType(DECIMAL);
asList(1.23, "1.23", 1, 1L, null).forEach(
value -> queries.add(new Object[] { decimalEntityType, new QueryImpl<>().eq("attr", value) }));
// EMAIL, HTML, HYPERLINK, SCRIPT, STRING, TEXT
EnumSet.of(EMAIL, HTML, HYPERLINK, SCRIPT, STRING, TEXT).forEach(attrType ->
{
Entity entityType = createEntityType(attrType);
asList("abc", 1, 1L, 1.23, null).forEach(
value -> queries.add(new Object[] { entityType, new QueryImpl<>().eq("attr", value) }));
});
// INT, LONG
EnumSet.of(INT, LONG).forEach(attrType ->
{
Entity entityType = createEntityType(attrType);
asList(1, 1L, "1", null).forEach(
value -> queries.add(new Object[] { entityType, new QueryImpl<>().eq("attr", value) }));
});
// FILE
Entity fileEntityType = createEntityType(FILE, STRING);
asList("file0", mock(FileMeta.class), null).forEach(
idValue -> queries.add(new Object[] { fileEntityType, new QueryImpl<>().eq("attr", idValue) }));
// ENUM
Entity enumEntityType = createEntityType(ENUM);
asList(TestEnum.ENUM0, TestEnum.ENUM1, "ENUM0", "ENUM1", null).forEach(
value -> queries.add(new Object[] { enumEntityType, new QueryImpl<>().eq("attr", value) }));
});
EnumSet.of(GREATER, GREATER_EQUAL, LESS, LESS_EQUAL).forEach(operator ->
{
Entity entityType = createEntityType(INT);
QueryImpl<Entity> query = new QueryImpl<>();
query.addRule(new QueryRule("attr", operator, 1));
queries.add(new Object[] { entityType, query });
});
EnumSet.of(FUZZY_MATCH, FUZZY_MATCH_NGRAM, LIKE).forEach(operator ->
{
Entity entityType = createEntityType(STRING);
QueryImpl<Entity> query = new QueryImpl<>();
query.addRule(new QueryRule("attr", operator, "abc"));
queries.add(new Object[] { entityType, query });
});
EnumSet.of(IN, RANGE).forEach(operator ->
{
Entity entityType = createEntityType(INT);
QueryImpl<Entity> query = new QueryImpl<>();
query.addRule(new QueryRule("attr", operator, asList(1, 2)));
queries.add(new Object[] { entityType, query });
});
return queries.iterator();
}
private enum TestEnum
{
ENUM0, ENUM1
}
private static Entity createEntityType(AttributeType attrType)
{
return createEntityType(attrType, null);
}
private static Entity createEntityType(AttributeType attrType, AttributeType refAttrType)
{
String attrName = "attr";
Attribute attr = when(mock(Attribute.class).getDataType()).thenReturn(attrType).getMock();
when(attr.getName()).thenReturn(attrName);
if (attrType == ENUM)
{
when(attr.getEnumOptions()).thenReturn(asList("ENUM0", "ENUM1"));
}
EntityType entityType = when(mock(EntityType.class).getAttribute(attrName)).thenReturn(attr).getMock();
when(entityType.toString()).thenReturn(attrType.toString());
if (refAttrType == null && EnumSet.of(CATEGORICAL, CATEGORICAL_MREF, XREF, MREF).contains(attrType))
{
refAttrType = INT;
}
if (refAttrType != null)
{
Attribute refIdAttr = when(mock(Attribute.class).getDataType()).thenReturn(refAttrType).getMock();
EntityType refEntityType = when(mock(EntityType.class).getIdAttribute()).thenReturn(refIdAttr).getMock();
when(attr.getRefEntity()).thenReturn(refEntityType);
}
return entityType;
}
@Test(dataProvider = "validateValidProvider")
public void testValidateValid(EntityType entityType, Query<Entity> query)
{
queryValidator.validate(query, entityType);
// test passes if not exception occurred
}
@DataProvider(name = "validateInvalidProvider")
public static Iterator<Object[]> validateInvalidProvider()
{
List<Object[]> queries = new ArrayList<>(6);
EnumSet.of(BOOL, DECIMAL, INT, LONG, DATE, DATE_TIME, ENUM).forEach(attrType -> queries
.add(new Object[] { new QueryImpl().eq("attr", "invalid"), createEntityType(attrType) }));
EnumSet.of(BOOL, DECIMAL, INT, LONG, DATE, DATE_TIME, ENUM, XREF, MREF, CATEGORICAL, CATEGORICAL_MREF).forEach(
attrType -> queries
.add(new Object[] { new QueryImpl().eq("attr", new Object()), createEntityType(attrType) }));
queries.add(new Object[] { new QueryImpl().eq("unknownAttr", "str"), createEntityType(STRING) });
queries.add(new Object[] { new QueryImpl().eq("attr", "str"), createEntityType(COMPOUND) });
return queries.iterator();
}
@Test(dataProvider = "validateInvalidProvider", expectedExceptions = MolgenisValidationException.class)
public void testValidateInvalid(Query<Entity> query, EntityType entityType)
{
queryValidator.validate(query, entityType);
}
}