RSQLUtility { public static <A extends Enum<A> & FieldNameProvider, T> Specification<T> parse(final String rsql, final Class<A> fieldNameProvider, final VirtualPropertyReplacer virtualPropertyReplacer, final Database database) { return new RSQLSpecification<>(rsql.toLowerCase(), fieldNameProvider, virtualPropertyReplacer, database); } private  RSQLUtility(); static Specification<T> parse(final String rsql,
            final Class<A> fieldNameProvider, final VirtualPropertyReplacer virtualPropertyReplacer,
            final Database database); static void isValid(final String rsql);  }
@Test public void wrongRsqlSyntaxThrowSyntaxException() { final String wrongRSQL = "name==abc;d"; try { RSQLUtility.parse(wrongRSQL, SoftwareModuleFields.class, null, testDb) .toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); fail("Missing expected RSQLParameterSyntaxException because of wrong RSQL syntax"); } catch (final RSQLParameterSyntaxException e) { } }
@Test public void wrongFieldThrowUnsupportedFieldException() { final String wrongRSQL = "unknownField==abc"; when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class); try { RSQLUtility.parse(wrongRSQL, SoftwareModuleFields.class, null, testDb) .toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); fail("Missing an expected RSQLParameterUnsupportedFieldException because of unknown RSQL field"); } catch (final RSQLParameterUnsupportedFieldException e) { } }
@Test public void wrongRsqlMapSyntaxThrowSyntaxException() { String wrongRSQL = TargetFields.ATTRIBUTE + "==abc"; try { RSQLUtility.parse(wrongRSQL, TargetFields.class, null, testDb).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); fail("Missing expected RSQLParameterSyntaxException for target attributes map, caused by wrong RSQL syntax (key was not present)"); } catch (final RSQLParameterUnsupportedFieldException e) { } wrongRSQL = TargetFields.ATTRIBUTE + ".unknown.wrong==abc"; try { RSQLUtility.parse(wrongRSQL, TargetFields.class, null, testDb).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); fail("Missing expected RSQLParameterSyntaxException for target attributes map, caused by wrong RSQL syntax (key includes dots)"); } catch (final RSQLParameterUnsupportedFieldException e) { } wrongRSQL = TargetFields.METADATA + ".unknown.wrong==abc"; try { RSQLUtility.parse(wrongRSQL, TargetFields.class, null, testDb).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); fail("Missing expected RSQLParameterSyntaxException for target metadata map, caused by wrong RSQL syntax (key includes dots)"); } catch (final RSQLParameterUnsupportedFieldException e) { } wrongRSQL = DistributionSetFields.METADATA + "==abc"; try { RSQLUtility.parse(wrongRSQL, DistributionSetFields.class, null, testDb) .toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); fail("Missing expected RSQLParameterSyntaxException for distribution set metadata map, caused by wrong RSQL syntax (key was not present)"); } catch (final RSQLParameterUnsupportedFieldException e) { } }
@Test public void wrongRsqlSubEntitySyntaxThrowSyntaxException() { String wrongRSQL = TargetFields.ASSIGNEDDS + "==abc"; try { RSQLUtility.parse(wrongRSQL, TargetFields.class, null, testDb).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); fail("Missing expected RSQLParameterSyntaxException because of wrong RSQL syntax"); } catch (final RSQLParameterUnsupportedFieldException e) { } wrongRSQL = TargetFields.ASSIGNEDDS + ".unknownField==abc"; try { RSQLUtility.parse(wrongRSQL, TargetFields.class, null, testDb).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); fail("Missing expected RSQLParameterSyntaxException because of wrong RSQL syntax"); } catch (final RSQLParameterUnsupportedFieldException e) { } wrongRSQL = TargetFields.ASSIGNEDDS + ".unknownField.ToMuch==abc"; try { RSQLUtility.parse(wrongRSQL, TargetFields.class, null, testDb).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); fail("Missing expected RSQLParameterSyntaxException because of wrong RSQL syntax"); } catch (final RSQLParameterUnsupportedFieldException e) { } }
@Test public <T> void correctRsqlBuildsPredicate() { reset(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); final String correctRsql = "name==abc;version==1.2"; when(baseSoftwareModuleRootMock.get("name")).thenReturn(baseSoftwareModuleRootMock); when(baseSoftwareModuleRootMock.get("version")).thenReturn(baseSoftwareModuleRootMock); when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class); when(criteriaBuilderMock.upper(eq(pathOfString(baseSoftwareModuleRootMock)))) .thenReturn(pathOfString(baseSoftwareModuleRootMock)); when(criteriaBuilderMock.like(any(Expression.class), anyString(), eq('\\'))).thenReturn(mock(Predicate.class)); when(criteriaBuilderMock.<String> greaterThanOrEqualTo(any(Expression.class), any(String.class))) .thenReturn(mock(Predicate.class)); RSQLUtility.parse(correctRsql, SoftwareModuleFields.class, null, testDb).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); verify(criteriaBuilderMock, times(1)).and(any(Predicate.class)); }
@Test public void correctRsqlBuildsSimpleNotLikePredicate() { reset(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); final String correctRsql = "name!=abc"; when(baseSoftwareModuleRootMock.get("name")).thenReturn(baseSoftwareModuleRootMock); when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class); when(criteriaBuilderMock.isNull(any(Expression.class))).thenReturn(mock(Predicate.class)); when(criteriaBuilderMock.notLike(any(Expression.class), anyString(), eq('\\'))) .thenReturn(mock(Predicate.class)); when(criteriaBuilderMock.upper(eq(pathOfString(baseSoftwareModuleRootMock)))) .thenReturn(pathOfString(baseSoftwareModuleRootMock)); RSQLUtility.parse(correctRsql, SoftwareModuleFields.class, null, testDb).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); verify(criteriaBuilderMock, times(1)).or(any(Predicate.class), any(Predicate.class)); verify(criteriaBuilderMock, times(1)).isNull(eq(pathOfString(baseSoftwareModuleRootMock))); verify(criteriaBuilderMock, times(1)).notLike(eq(pathOfString(baseSoftwareModuleRootMock)), eq("abc".toUpperCase()), eq('\\')); }
@Test public void correctRsqlBuildsNotSimpleNotLikePredicate() { reset(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); final String correctRsql = "type!=abc"; when(baseSoftwareModuleRootMock.get(anyString())).thenReturn(baseSoftwareModuleRootMock); when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class); final Path pathMock = mock(Path.class); when(pathMock.get(anyString())).thenReturn(pathMock); when(subqueryRootMock.get(anyString())).thenReturn(pathMock); when(criteriaBuilderMock.and(any(), any())).thenReturn(mock(Predicate.class)); when(criteriaQueryMock.subquery(SoftwareModule.class)).thenReturn(subqueryMock); when(subqueryMock.from(SoftwareModule.class)).thenReturn(subqueryRootMock); when(subqueryMock.select(subqueryRootMock)).thenReturn(subqueryMock); RSQLUtility.parse(correctRsql, SoftwareModuleFields.class, null, testDb).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); verify(criteriaBuilderMock, times(1)).not(criteriaBuilderMock.exists(eq(subqueryMock))); }
@Test public void correctRsqlBuildsLikePredicateWithPercentage() { reset(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); final String correctRsql = "name==a%"; when(baseSoftwareModuleRootMock.get("name")).thenReturn(baseSoftwareModuleRootMock); when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class); when(criteriaBuilderMock.like(any(Expression.class), anyString(), eq('\\'))).thenReturn(mock(Predicate.class)); when(criteriaBuilderMock.<String> greaterThanOrEqualTo(any(Expression.class), any(String.class))) .thenReturn(mock(Predicate.class)); when(criteriaBuilderMock.upper(eq(pathOfString(baseSoftwareModuleRootMock)))) .thenReturn(pathOfString(baseSoftwareModuleRootMock)); RSQLUtility.parse(correctRsql, SoftwareModuleFields.class, null, Database.H2) .toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); verify(criteriaBuilderMock, times(1)).and(any(Predicate.class)); verify(criteriaBuilderMock, times(1)).like(eq(pathOfString(baseSoftwareModuleRootMock)), eq("a\\%".toUpperCase()), eq('\\')); }
@Test public void correctRsqlBuildsLikePredicateWithPercentageSQLServer() { reset(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); final String correctRsql = "name==a%"; when(baseSoftwareModuleRootMock.get("name")).thenReturn(baseSoftwareModuleRootMock); when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class); when(criteriaBuilderMock.upper(eq(pathOfString(baseSoftwareModuleRootMock)))) .thenReturn(pathOfString(baseSoftwareModuleRootMock)); when(criteriaBuilderMock.like(any(Expression.class), anyString(), eq('\\'))).thenReturn(mock(Predicate.class)); when(criteriaBuilderMock.<String> greaterThanOrEqualTo(any(Expression.class), any(String.class))) .thenReturn(mock(Predicate.class)); RSQLUtility.parse(correctRsql, SoftwareModuleFields.class, null, Database.SQL_SERVER) .toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); verify(criteriaBuilderMock, times(1)).and(any(Predicate.class)); verify(criteriaBuilderMock, times(1)).like(eq(pathOfString(baseSoftwareModuleRootMock)), eq("a[%]".toUpperCase()), eq('\\')); }
@Test public void correctRsqlBuildsLessThanPredicate() { reset(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); final String correctRsql = "name=lt=abc"; when(baseSoftwareModuleRootMock.get("name")).thenReturn(baseSoftwareModuleRootMock); when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class); when(criteriaBuilderMock.lessThan(any(Expression.class), anyString())).thenReturn(mock(Predicate.class)); when(criteriaBuilderMock.<String> greaterThanOrEqualTo(any(Expression.class), any(String.class))) .thenReturn(mock(Predicate.class)); RSQLUtility.parse(correctRsql, SoftwareModuleFields.class, null, testDb).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); verify(criteriaBuilderMock, times(1)).and(any(Predicate.class)); verify(criteriaBuilderMock, times(1)).lessThan(eq(pathOfString(baseSoftwareModuleRootMock)), eq("abc")); }
@Test public void correctRsqlWithEnumValue() { reset(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); final String correctRsql = "testfield==bumlux"; when(baseSoftwareModuleRootMock.get("testfield")).thenReturn(baseSoftwareModuleRootMock); when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) TestValueEnum.class); when(criteriaBuilderMock.equal(any(Root.class), any(TestValueEnum.class))).thenReturn(mock(Predicate.class)); RSQLUtility.parse(correctRsql, TestFieldEnum.class, null, testDb).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); verify(criteriaBuilderMock, times(1)).and(any(Predicate.class)); verify(criteriaBuilderMock, times(1)).equal(eq(baseSoftwareModuleRootMock), eq(TestValueEnum.BUMLUX)); }
@Test public void wrongRsqlWithWrongEnumValue() { reset(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); final String correctRsql = "testfield==unknownValue"; when(baseSoftwareModuleRootMock.get("testfield")).thenReturn(baseSoftwareModuleRootMock); when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) TestValueEnum.class); when(criteriaBuilderMock.equal(any(Root.class), anyString())).thenReturn(mock(Predicate.class)); try { RSQLUtility.parse(correctRsql, TestFieldEnum.class, null, testDb).toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); fail("missing RSQLParameterUnsupportedFieldException for wrong enum value"); } catch (final RSQLParameterUnsupportedFieldException e) { } }
@Test @Description("Tests the resolution of overdue_ts placeholder in context of a RSQL expression.") public void correctRsqlWithOverdueMacro() { reset(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); final String overdueProp = "overdue_ts"; final String overduePropPlaceholder = "${" + overdueProp + "}"; final String correctRsql = "testfield=le=" + overduePropPlaceholder; when(baseSoftwareModuleRootMock.get("testfield")).thenReturn(baseSoftwareModuleRootMock); when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) String.class); when(criteriaBuilderMock.upper(eq(pathOfString(baseSoftwareModuleRootMock)))) .thenReturn(pathOfString(baseSoftwareModuleRootMock)); when(criteriaBuilderMock.like(any(Expression.class), anyString(), eq('\\'))).thenReturn(mock(Predicate.class)); when(criteriaBuilderMock.<String> lessThanOrEqualTo(any(Expression.class), eq(overduePropPlaceholder))) .thenReturn(mock(Predicate.class)); RSQLUtility.parse(correctRsql, TestFieldEnum.class, setupMacroLookup(), testDb) .toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); verify(macroResolver).lookup(overdueProp); verify(criteriaBuilderMock, never()).lessThanOrEqualTo(eq(pathOfString(baseSoftwareModuleRootMock)), eq(overduePropPlaceholder)); }
@Test @Description("Tests RSQL expression with an unknown placeholder.") public void correctRsqlWithUnknownMacro() { reset(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); final String overdueProp = "unknown"; final String overduePropPlaceholder = "${" + overdueProp + "}"; final String correctRsql = "testfield=le=" + overduePropPlaceholder; when(baseSoftwareModuleRootMock.get("testfield")).thenReturn(baseSoftwareModuleRootMock); when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) String.class); when(criteriaBuilderMock.equal(any(Root.class), anyString())).thenReturn(mock(Predicate.class)); when(criteriaBuilderMock.<String> lessThanOrEqualTo(any(Expression.class), eq(overduePropPlaceholder))) .thenReturn(mock(Predicate.class)); RSQLUtility.parse(correctRsql, TestFieldEnum.class, setupMacroLookup(), testDb) .toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); verify(macroResolver).lookup(overdueProp); verify(criteriaBuilderMock).lessThanOrEqualTo(eq(pathOfString(baseSoftwareModuleRootMock)), eq(overduePropPlaceholder)); }