/* * Copyright 2015 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jbpm.query; import static org.jbpm.persistence.util.PersistenceUtil.cleanUp; import static org.jbpm.persistence.util.PersistenceUtil.setupWithPoolingDataSource; import static org.junit.Assert.fail; import static org.kie.api.runtime.EnvironmentName.ENTITY_MANAGER_FACTORY; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.sql.DatabaseMetaData; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import javax.persistence.EntityManagerFactory; //import org.hibernate.tool.hbm2ddl.DatabaseMetadata; import org.kie.internal.query.ExtendedParametrizedQueryBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ch.qos.logback.classic.Level; public abstract class QueryBuilderCoverageTestUtil { private static HashMap<String, Object> context; private static EntityManagerFactory emf; private static final Logger logger = LoggerFactory.getLogger(QueryBuilderCoverageTestUtil.class); public static EntityManagerFactory beforeClass(String persistenceUnit) { hackTheDatabaseMetadataLoggerBecauseTheresALogbackXmlInTheClasspath(); context = setupWithPoolingDataSource(persistenceUnit); emf = (EntityManagerFactory) context.get(ENTITY_MANAGER_FACTORY); return emf; } public static void afterClass() { cleanUp(context); } public static void hackTheDatabaseMetadataLoggerBecauseTheresALogbackXmlInTheClasspath() { String [] fieldName = { "LOG", "log", "logger" }; try { Object loggerObj = null; for( int i = 0; i < fieldName.length; ++i ) { Field loggerField; Class objClass = null; if( loggerObj == null ) { objClass = DatabaseMetaData.class; } else { objClass = loggerObj.getClass(); } loggerField = objClass.getDeclaredField(fieldName[i]); loggerField.setAccessible(true); loggerObj = loggerField.get(loggerObj); } ((ch.qos.logback.classic.Logger) loggerObj).setLevel(Level.OFF); } catch( Exception e ) { e.printStackTrace(); // do nothing } } public static void queryBuilderCoverageTest( ExtendedParametrizedQueryBuilder queryBuilder, Class builderClass, ModuleSpecificInputFiller inputFiller, String... skipMethodName) { Set<Method> queryMethodSet = new HashSet<Method>(); while( builderClass != null && ! builderClass.equals(ExtendedParametrizedQueryBuilder.class) ) { queryMethodSet.addAll(Arrays.asList(builderClass.getMethods())); builderClass = builderClass.getInterfaces()[0]; } List<Method> queryMethods = new ArrayList<Method>(queryMethodSet); String [] specialMethodsArr = { "newGroup", "endGroup", "equals", "identity", "intersect", "union", "and", "or", "like", "regex", "equal", "build", "clear", "notify", "notifyAll", "wait" }; Set<String> specialMethods = new HashSet<String>(Arrays.asList(specialMethodsArr)); specialMethods.addAll(Arrays.asList(skipMethodName)); Iterator<Method> iter = queryMethods.iterator(); while( iter.hasNext() ) { Method method = iter.next(); if( specialMethods.contains(method.getName()) ) { iter.remove(); } } Collections.sort(queryMethods, new Comparator<Method>() { @Override public int compare( Method m1, Method m2 ) { if( m1 == m2 ) { return 0; } else if( m1 == null ) { return -1; } else if( m2 == null ) { return 1; } else { return m1.getName().compareTo(m2.getName()); } } }); for( Method methodA : queryMethods ) { for( Method methodB : queryMethods ) { Object [] inputA = fillInput(methodA.getParameterTypes(), inputFiller); Object [] inputB = fillInput(methodB.getParameterTypes(), inputFiller); try { // build query StringBuffer testName = new StringBuffer(methodA.getName()); callMethod(methodA, queryBuilder, inputA); testName.append(" | "); queryBuilder.union(); testName.append(methodB.getName()); callMethod(methodB, queryBuilder, inputB); logger.debug(testName.toString()); // try queryT queryBuilder.build().getResultList(); queryBuilder.clear(); } catch( Throwable t) { t.printStackTrace(); String msg = createTestName(methodA, inputA, methodB, inputB, queryBuilder.getClass()); fail(msg); } } } } private static <T,S> String createTestName(Method methodA, T [] inputA, Method methodB, S [] inputB, Class builderClass) { StringBuffer msg = new StringBuffer(getMethodName(methodA, inputA)); msg.append(" OR "); msg.append(getMethodName(methodB, inputB)); msg.append(": " + builderClass.getSimpleName()); return msg.toString(); } private static void callMethod(Method method, Object obj, Object input) { boolean noArgs = false; Object [] arrInput = null; if( input.getClass().isArray() ) { int length = Array.getLength(input); if( length == 1 ) { input = Array.get(input, 0); } else if( length == 0 ) { noArgs = true; } else { arrInput = (Object[]) input; } } try { if( noArgs ) { method.invoke(obj); } else { if( arrInput != null ) { method.invoke(obj, arrInput); } else { method.invoke(obj, input); } } } catch( Exception e ) { e.printStackTrace(); fail( "Method [" + method.getName() + ".(" + getInputAsString(input) + ")]"); } } private static <T> String getMethodName(Method method, T [] input) { StringBuilder msg = new StringBuilder(method.getName()); msg.append("("); if( input.length > 0 ) { msg.append(getInputAsString(input[0])); for( int j = 1; j < input.length; ++j ) { msg.append(",").append(getInputAsString(input[j])); } } msg.append(")"); return msg.toString(); } private static <T> String getInputAsString(Object input) { if( input.getClass().isArray()) { if( Array.getLength(input) == 0 ) { return ""; } Class compType = input.getClass().getComponentType(); if( int.class.equals(compType) ) { return Arrays.toString((int []) input); } else if( long.class.equals(compType) ) { return Arrays.toString((long []) input); } else { return Arrays.toString((Object []) input); } } else { return input.toString(); } } public static interface ModuleSpecificInputFiller { public Object fillInput(Class type); } private static Object [] fillInput(Type [] types, ModuleSpecificInputFiller inputFiller) { Object [] result = new Object[types.length]; for( int i = 0; i< types.length; ++i ) { Class type = (Class) types[i]; if( type.equals(int.class) ) { result[i] = 23; } else if( type.equals(boolean.class) ) { result[i] = false; } else if( type.equals(Date.class) ) { result[i] = new Date(); } else if( type.equals(long.class) ) { result[i] = 46l; } else if( type.equals(Long.class) ) { result[i] = 96l; } else if( type.equals(String.class) ) { result[i] = "that"; } else if( type.isArray() ) { Class arrayType = type.getComponentType(); if( arrayType.equals(int.class) ) { int [] intArr = { 1,3,5 }; result[i] = intArr; } else if( arrayType.equals(long.class) ) { long [] longArr = { 1,9,25 }; result[i] = longArr; } else if( arrayType.equals(String.class) ) { String [] strArr = { "blu", "red", "gro"}; result[i] = strArr; } else if( arrayType.equals(Date.class) ) { Date [] strArr = { new Date(), new Date() }; result[i] = strArr; } } if( result[i] == null ) { result[i] = inputFiller.fillInput(type); } if( result[i] == null ) { throw new IllegalStateException("Add logic for type: " + types[i].toString()); } } return result; } }