| /* |
| * Copyright (c) 2006, 2021 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| // Contributors: |
| // Oracle - initial API and implementation |
| // |
| package org.eclipse.persistence.jpa.tests.jpql; |
| |
| import java.lang.annotation.Annotation; |
| import java.lang.reflect.Constructor; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.Modifier; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.persistence.jpa.jpql.tools.model.AbstractActualJPQLQueryFormatter; |
| import org.eclipse.persistence.jpa.jpql.tools.model.BaseJPQLQueryFormatter; |
| import org.eclipse.persistence.jpa.jpql.tools.model.IJPQLQueryBuilder; |
| import org.eclipse.persistence.jpa.tests.jpql.parser.JPQLGrammarTestHelper; |
| import org.eclipse.persistence.jpa.tests.jpql.tools.model.IJPQLQueryBuilderTestHelper; |
| import org.eclipse.persistence.jpa.tests.jpql.tools.model.IJPQLQueryFormatterTestHelper; |
| import org.junit.internal.builders.AllDefaultPossibilitiesBuilder; |
| import org.junit.internal.runners.ErrorReportingRunner; |
| import org.junit.runner.Description; |
| import org.junit.runner.Runner; |
| import org.junit.runner.notification.RunNotifier; |
| import org.junit.runners.BlockJUnit4ClassRunner; |
| import org.junit.runners.ParentRunner; |
| import org.junit.runners.Suite.SuiteClasses; |
| import org.junit.runners.model.FrameworkMethod; |
| import org.junit.runners.model.InitializationError; |
| import org.junit.runners.model.Statement; |
| |
| /** |
| * This JUnit runner is the sole runner of Hermes unit-tests because it modifies the default |
| * behavior by adding the following support: |
| * <ul> |
| * <li>Adds the ability to inject objects that are instantiated by a test suite into the unit-test |
| * before they are run. |
| * <li>Because one unit-test can be run more than once with different state of any given object, |
| * this cause issues in Eclipse because the IDE uses {@link Object#toString()} and cannot |
| * discriminate between those identical tests. This runner changes the test's description by adding |
| * enough information in order to make each test's description unique. |
| * </ul> |
| * |
| * @version 2.4 |
| * @since 2.4 |
| * @author Pascal Filion |
| */ |
| @SuppressWarnings({ "nls", "restriction" }) |
| public class JPQLTestRunner extends ParentRunner<Runner> { |
| |
| /** |
| * The cached {@link Description} so it's not recreated every time. |
| */ |
| private Description description; |
| |
| /** |
| * This contains the helpers that will be injected into each test. |
| */ |
| private DescriptionHelper descriptionHelper; |
| |
| /** |
| * The display string of this test suite. |
| */ |
| private String name; |
| |
| /** |
| * The {@link Runner runners} for the test classes defined in {@link org.junit.runners.Suite.SuiteClasses |
| * @SuiteClasses}. |
| */ |
| private List<Runner> runners; |
| |
| /** |
| * The parent {@link SuiteHelper} or <code>null</code> if none was defined yet. |
| */ |
| private SuiteHelper suiteHelper; |
| |
| /** |
| * The list of registered helpers that inject values from the test suite into the unit-tests |
| * before they are running. |
| */ |
| private static final Map<Class<? extends Annotation>, DescriptionBuilder> testRunnerHelpers; |
| |
| /** |
| * Registers the supported test runner helpers. |
| */ |
| static { |
| |
| testRunnerHelpers = new HashMap<Class<? extends Annotation>, DescriptionBuilder>(); |
| |
| testRunnerHelpers.put(IJPQLQueryBuilderTestHelper.class, buildJPQLQueryBuilderTestHelperDescriptionBuilder()); |
| testRunnerHelpers.put(IJPQLQueryFormatterTestHelper.class, buildJPQLQueryFormatterTestHelperDescriptionBuilder()); |
| testRunnerHelpers.put(JPQLGrammarTestHelper.class, buildJPQLGrammarTestHelperDescriptionBuilder()); |
| testRunnerHelpers.put(JPQLQueryHelperTestHelper.class, buildJPQLQueryHelperTestHelperDescriptionBuilder()); |
| testRunnerHelpers.put(JPQLQueryTestHelperTestHelper.class, buildJPQLQueryTestHelperTestHelperDescriptionBuilder()); |
| } |
| |
| /** |
| * Creates a new <code>JPQLTestRunner</code>. |
| * |
| * @param testClass The class that is either a test suite or a unit-tests |
| * @throws InitializationError If the given test class is malformed |
| */ |
| public JPQLTestRunner(Class<?> testClass) throws InitializationError { |
| super(testClass); |
| } |
| |
| /** |
| * Creates a new <code>JPQLTestRunner</code>. |
| * |
| * @param testClass The class that is either a test suite or a unit-tests |
| * @param suiteHelper The parent {@link SuiteHelper} or {@code null} if none was defined yet |
| * @throws InitializationError If the given test class is malformed |
| */ |
| public JPQLTestRunner(Class<?> testClass, SuiteHelper suiteHelper) throws InitializationError { |
| this(testClass); |
| this.suiteHelper = suiteHelper; |
| } |
| |
| private static DescriptionBuilder buildJPQLGrammarTestHelperDescriptionBuilder() { |
| return new DescriptionBuilder() { |
| @Override |
| public String toString(Object object) { |
| return object.toString(); |
| } |
| }; |
| } |
| |
| private static DescriptionBuilder buildJPQLQueryBuilderTestHelperDescriptionBuilder() { |
| return new DescriptionBuilder() { |
| @Override |
| public String toString(Object object) { |
| IJPQLQueryBuilder builder = (IJPQLQueryBuilder) object; |
| StringBuilder sb = new StringBuilder(); |
| sb.append(builder.getClass().getSimpleName()); |
| sb.append("["); |
| sb.append(builder.getGrammar().toString()); |
| sb.append("]"); |
| return sb.toString(); |
| } |
| }; |
| } |
| |
| private static DescriptionBuilder buildJPQLQueryFormatterTestHelperDescriptionBuilder() { |
| return new DescriptionBuilder() { |
| @Override |
| public String toString(Object object) { |
| BaseJPQLQueryFormatter formatter = (BaseJPQLQueryFormatter) object; |
| StringBuilder sb = new StringBuilder(); |
| sb.append(formatter.getClass().getSimpleName()); |
| sb.append("["); |
| sb.append(formatter.getIdentifierStyle().name()); |
| if (object instanceof AbstractActualJPQLQueryFormatter) { |
| AbstractActualJPQLQueryFormatter actualFormatter = (AbstractActualJPQLQueryFormatter) object; |
| sb.append("|"); |
| sb.append(actualFormatter.isUsingExactMatch()); |
| } |
| sb.append("]"); |
| return sb.toString(); |
| } |
| }; |
| } |
| |
| private static DescriptionBuilder buildJPQLQueryHelperTestHelperDescriptionBuilder() { |
| return new DescriptionBuilder() { |
| @Override |
| public String toString(Object object) { |
| return object.getClass().getSimpleName(); |
| } |
| }; |
| } |
| |
| private static DescriptionBuilder buildJPQLQueryTestHelperTestHelperDescriptionBuilder() { |
| return new DescriptionBuilder() { |
| @Override |
| public String toString(Object object) { |
| return object.getClass().getSimpleName(); |
| } |
| }; |
| } |
| |
| private List<Runner> buildChildren() { |
| |
| SuiteClasses suiteClasses = findSuiteClasses(getTestClass().getJavaClass()); |
| |
| if (suiteClasses == null) { |
| return Collections.emptyList(); |
| } |
| |
| List<Runner> runners = new ArrayList<Runner>(); |
| |
| for (Class<?> test : suiteClasses.value()) { |
| if (descriptionHelper.helpers.isEmpty()) { |
| Runner runner = buildRunner(test, suiteHelper); |
| runners.add(runner); |
| } |
| else { |
| for (SuiteHelper suiteHelper : buildSuiteHelpers()) { |
| Runner runner = buildRunner(test, suiteHelper); |
| runners.add(runner); |
| } |
| } |
| } |
| |
| Collections.sort(runners, buildRunnerComparator()); |
| return runners; |
| } |
| |
| private String buildDisplayString() { |
| |
| String displayString = super.getName(); |
| |
| if (suiteHelper != null) { |
| StringBuilder writer = new StringBuilder(); |
| writer.append(displayString); |
| suiteHelper.addAdditionalInfo(writer); |
| displayString = writer.toString(); |
| } |
| |
| return displayString; |
| } |
| |
| private Runner buildRunner(Class<?> testClass, SuiteHelper suiteHelper) { |
| |
| try { |
| |
| // Create a runner for multiple unit-tests |
| SuiteClasses suiteClasses = findSuiteClasses(testClass); |
| |
| if (suiteClasses != null) { |
| return new JPQLTestRunner(testClass, suiteHelper); |
| } |
| |
| // Create a runner for a single unit-test |
| if (JPQLBasicTest.class.isAssignableFrom(testClass)) { |
| return new JPQLBasicTestRunner(testClass, suiteHelper); |
| } |
| |
| // Create the default runner |
| return new AllDefaultPossibilitiesBuilder().runnerForClass(testClass); |
| } |
| catch (Throwable e) { |
| return new ErrorReportingRunner(testClass, e); |
| } |
| } |
| |
| private Comparator<Runner> buildRunnerComparator() { |
| return new Comparator<Runner>() { |
| @Override |
| public int compare(Runner runner1, Runner runner2) { |
| String displayName1 = runner1.getDescription().getDisplayName(); |
| String displayName2 = runner1.getDescription().getDisplayName(); |
| return displayName1.compareTo(displayName2); |
| } |
| }; |
| } |
| |
| private List<SuiteHelper> buildSuiteHelpers() { |
| |
| List<SuiteHelper> suiteHelpers = new ArrayList<SuiteHelper>(); |
| Map<Class<? extends Annotation>, Object> singleHelpers = new HashMap<Class<? extends Annotation>, Object>(); |
| Collection<Class<? extends Annotation>> multipleHelpers = retrieveMultipleHelpers(); |
| |
| for (Map.Entry<Class<? extends Annotation>, Object[]> helper : descriptionHelper.helpers.entrySet()) { |
| if (!multipleHelpers.contains(helper.getKey())) { |
| singleHelpers.put(helper.getKey(), helper.getValue()[0]); |
| } |
| } |
| |
| if (multipleHelpers.size() > 1) { |
| for (Class<? extends Annotation> firstHelperKey : multipleHelpers) { |
| for (Class<? extends Annotation> secondHelperKey : multipleHelpers) { |
| if (firstHelperKey != secondHelperKey) { |
| for (Object firstHelper : descriptionHelper.helpers.get(firstHelperKey)) { |
| for (Object secondHelper : descriptionHelper.helpers.get(secondHelperKey)) { |
| Map<Class<? extends Annotation>, Object> copy = new HashMap<Class<? extends Annotation>, Object>(); |
| copy.putAll(singleHelpers); |
| copy.put(firstHelperKey, firstHelper); |
| copy.put(secondHelperKey, secondHelper); |
| |
| List<Class<? extends Annotation>> keys = new ArrayList<Class<? extends Annotation>>(); |
| keys.add(firstHelperKey); |
| keys.add(secondHelperKey); |
| |
| suiteHelpers.add(new SuiteHelper(suiteHelper, copy, keys)); |
| } |
| } |
| } |
| } |
| } |
| } |
| else if (multipleHelpers.size() == 1) { |
| for (Class<? extends Annotation> firstHelperKey : multipleHelpers) { |
| for (Object firstHelper : descriptionHelper.helpers.get(firstHelperKey)) { |
| Map<Class<? extends Annotation>, Object> copy = new HashMap<Class<? extends Annotation>, Object>(); |
| copy.putAll(singleHelpers); |
| copy.put(firstHelperKey, firstHelper); |
| |
| List<Class<? extends Annotation>> keys = new ArrayList<Class<? extends Annotation>>(); |
| keys.add(firstHelperKey); |
| |
| suiteHelpers.add(new SuiteHelper(suiteHelper, copy, keys)); |
| } |
| } |
| } |
| else { |
| suiteHelpers.add(new SuiteHelper(suiteHelper, singleHelpers)); |
| } |
| |
| return suiteHelpers; |
| } |
| |
| @Override |
| protected void collectInitializationErrors(List<Throwable> errors) { |
| super.collectInitializationErrors(errors); |
| initializeDescriptionHelper(errors); |
| } |
| |
| @Override |
| protected Description describeChild(Runner child) { |
| return child.getDescription(); |
| } |
| |
| private SuiteClasses findSuiteClasses(Class<?> testClass) { |
| |
| if (testClass == Object.class) { |
| return null; |
| } |
| |
| SuiteClasses suiteClasses = testClass.getAnnotation(SuiteClasses.class); |
| |
| if (suiteClasses != null) { |
| return suiteClasses; |
| } |
| |
| return findSuiteClasses(testClass.getSuperclass()); |
| } |
| |
| @Override |
| protected List<Runner> getChildren() { |
| // Cache the Description since JUnit always recreate it, this will increase performance |
| if (runners == null) { |
| runners = buildChildren(); |
| } |
| return runners; |
| } |
| |
| @Override |
| public Description getDescription() { |
| // Cache the Description since JUnit always recreate it, this will increase performance |
| if (description == null) { |
| description = super.getDescription(); |
| } |
| return description; |
| } |
| |
| @Override |
| protected String getName() { |
| // Cache the Description since JUnit always recreate it, this will increase performance and |
| // also, add the extra information otherwise Eclipse will not be able to update the status of |
| // the tests, it uses the display string to retrieve the node from the JUnit view, if two |
| // nodes have the same display string, then only the last one is updated |
| if (name == null) { |
| name = buildDisplayString(); |
| } |
| return name; |
| } |
| |
| private void initializeDescriptionHelper(List<Throwable> errors) { |
| |
| descriptionHelper = new DescriptionHelper(); |
| Class<?> unitTest = getTestClass().getJavaClass(); |
| |
| for (Method method : unitTest.getDeclaredMethods()) { |
| |
| if (isHelperMethod(method)) { |
| |
| for (Class<? extends Annotation> annotation : testRunnerHelpers.keySet()) { |
| |
| if (method.isAnnotationPresent(annotation)) { |
| |
| try { |
| method.setAccessible(true); |
| Object value = method.invoke(null); |
| |
| descriptionHelper.helpers.put( |
| annotation, |
| value.getClass().isArray() ? (Object[]) value : new Object[] { value } |
| ); |
| } |
| catch (Exception e) { |
| errors.add(e); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| private boolean isHelperMethod(Method method) { |
| return Modifier.isStatic(method.getModifiers()); |
| } |
| |
| private Collection<Class<? extends Annotation>> retrieveMultipleHelpers() { |
| |
| Collection<Class<? extends Annotation>> keys = new ArrayList<Class<? extends Annotation>>(); |
| |
| for (Map.Entry<Class<? extends Annotation>, Object[]> helper : descriptionHelper.helpers.entrySet()) { |
| if (helper.getValue().length > 1) { |
| keys.add(helper.getKey()); |
| } |
| } |
| |
| return keys; |
| } |
| |
| @Override |
| protected void runChild(Runner child, RunNotifier notifier) { |
| child.run(notifier); |
| } |
| |
| /** |
| * This interface is used to create the description of a unit-tests. |
| */ |
| private static interface DescriptionBuilder { |
| |
| /** |
| * Creates a string representation of the given object. |
| * |
| * @param object The object to convert into a human readable string |
| * @return A unique description for the given object |
| */ |
| String toString(Object object); |
| } |
| |
| private static class DescriptionHelper { |
| |
| private Map<Class<? extends Annotation>, Object[]> helpers; |
| |
| DescriptionHelper() { |
| super(); |
| helpers = new HashMap<Class<? extends Annotation>, Object[]>(); |
| } |
| } |
| |
| private static class JPQLBasicTestRunner extends BlockJUnit4ClassRunner { |
| |
| private Description description; |
| private SuiteHelper suiteHelper; |
| private JPQLBasicTest test; |
| private boolean uniquenessRequired; |
| |
| JPQLBasicTestRunner(Class<?> testClass, SuiteHelper suiteHelper) throws InitializationError { |
| super(testClass); |
| this.suiteHelper = suiteHelper; |
| // Check to see if the signature of the test methods needs to be unique, |
| // this is required when the same test is run more than once and the |
| // generated signature remains identical |
| uniquenessRequired = testClass.isAnnotationPresent(UniqueSignature.class); |
| } |
| |
| private Description buildDescription() { |
| |
| Description description = Description.createSuiteDescription( |
| buildDisplayString(), |
| getTestClass().getAnnotations() |
| ); |
| |
| Description superDescription = super.getDescription(); |
| description.getChildren().addAll(superDescription.getChildren()); |
| |
| return description; |
| } |
| |
| private String buildDisplayString() { |
| if (suiteHelper != null) { |
| StringBuilder writer = new StringBuilder(); |
| writer.append(getName()); |
| suiteHelper.addAdditionalInfo(writer); |
| return writer.toString(); |
| } |
| return getName(); |
| } |
| |
| private Comparator<FrameworkMethod> buildMethodComparator() { |
| return new Comparator<FrameworkMethod>() { |
| @Override |
| public int compare(FrameworkMethod method1, FrameworkMethod method2) { |
| return method1.getName().compareTo(method2.getName()); |
| } |
| }; |
| } |
| |
| @Override |
| protected Statement classBlock(RunNotifier notifier) { |
| Statement statement = new CreateTestStatement(); |
| statement = new SetUpClassStatement(statement); |
| statement = new CompositeStatement(statement, childrenInvoker(notifier)); |
| statement = new TearDownClassStatement(statement); |
| return statement; |
| } |
| |
| @Override |
| protected Object createTest() throws Exception { |
| return test; |
| } |
| |
| @Override |
| protected List<FrameworkMethod> getChildren() { |
| List<FrameworkMethod> methods = new ArrayList<>(super.getChildren()); |
| Collections.sort(methods, buildMethodComparator()); |
| return methods; |
| } |
| |
| @Override |
| public Description getDescription() { |
| if (description == null) { |
| description = buildDescription(); |
| } |
| return description; |
| } |
| |
| private void instantiateTest() throws Throwable { |
| |
| Class<?> testClass = getTestClass().getJavaClass(); |
| Constructor<?> constructor = testClass.getConstructor(); |
| constructor.setAccessible(true); |
| test = (JPQLBasicTest) constructor.newInstance(); |
| |
| // Inject the SuiteHelper' values into the test |
| if (suiteHelper != null) { |
| suiteHelper.injectValues(test); |
| } |
| } |
| |
| @Override |
| protected Statement methodBlock(FrameworkMethod method) { |
| Statement statement = new SetUpStatement(); |
| statement = new CompositeStatement(statement, super.methodBlock(method)); |
| statement = new TearDownStatement(statement); |
| return statement; |
| } |
| |
| @Override |
| protected Statement methodInvoker(FrameworkMethod method, Object test) { |
| this.test = (JPQLBasicTest) test; |
| return super.methodInvoker(method, test); |
| } |
| |
| @Override |
| protected String testName(FrameworkMethod method) { |
| |
| // Create the signature of the method, which will have the helpers' additional information |
| StringBuilder writer = new StringBuilder(); |
| writer.append(method.getName()); |
| |
| if (suiteHelper != null) { |
| suiteHelper.addAdditionalInfo(writer); |
| } |
| |
| // It is possible two signatures maybe be identical, add something unique |
| if (uniquenessRequired) { |
| writer.append(" ("); |
| writer.append(hashCode()); |
| writer.append(")"); |
| } |
| |
| return writer.toString(); |
| } |
| |
| private class CompositeStatement extends Statement { |
| |
| private Statement statement1; |
| private Statement statement2; |
| |
| CompositeStatement(Statement statement1, Statement statement2) { |
| super(); |
| this.statement1 = statement1; |
| this.statement2 = statement2; |
| } |
| |
| |
| @Override |
| public void evaluate() throws Throwable { |
| statement1.evaluate(); |
| statement2.evaluate(); |
| } |
| } |
| |
| /** |
| * This {@link Statement} evaluates the wrapped {@link Statement} and then invoke {@link |
| * JPQLBasicTest#setUpClass()}. |
| */ |
| private class CreateTestStatement extends Statement { |
| @Override |
| public void evaluate() throws Throwable { |
| instantiateTest(); |
| } |
| } |
| |
| /** |
| * This {@link Statement} evaluates the wrapped {@link Statement} and then invoke {@link |
| * JPQLBasicTest#setUpClass()}. |
| */ |
| private class SetUpClassStatement extends Statement { |
| |
| private Statement statement; |
| |
| SetUpClassStatement(Statement statement) { |
| super(); |
| this.statement = statement; |
| } |
| |
| |
| @Override |
| public void evaluate() throws Throwable { |
| statement.evaluate(); |
| test.setUpClass(); |
| } |
| } |
| |
| /** |
| * This {@link Statement} evaluates the wrapped {@link Statement} and then invoke {@link |
| * JPQLBasicTest#setUp()}. |
| */ |
| private class SetUpStatement extends Statement { |
| @Override |
| public void evaluate() throws Throwable { |
| test.setUp(); |
| } |
| } |
| |
| /** |
| * This {@link Statement} evaluates the wrapped {@link Statement} and then invoke {@link |
| * JPQLBasicTest#tearDownClass()}. |
| */ |
| private class TearDownClassStatement extends Statement { |
| |
| private Statement statement; |
| |
| TearDownClassStatement(Statement statement) { |
| super(); |
| this.statement = statement; |
| } |
| |
| |
| @Override |
| public void evaluate() throws Throwable { |
| try { |
| statement.evaluate(); |
| } |
| finally { |
| if (test != null) { |
| test.tearDownClass(); |
| } |
| } |
| } |
| } |
| |
| /** |
| * This {@link Statement} evaluates the wrapped {@link Statement} and then invoke {@link |
| * JPQLBasicTest#tearDown()}. |
| */ |
| private class TearDownStatement extends Statement { |
| |
| private Statement statement; |
| |
| TearDownStatement(Statement statement) { |
| super(); |
| this.statement = statement; |
| } |
| |
| |
| @Override |
| public void evaluate() throws Throwable { |
| try { |
| statement.evaluate(); |
| } |
| finally { |
| if (test != null) { |
| test.tearDown(); |
| } |
| } |
| } |
| } |
| } |
| |
| private static class SuiteHelper { |
| |
| private Map<Class<? extends Annotation>, Object> helpers; |
| private SuiteHelper parent; |
| private List<Class<? extends Annotation>> primaryKeys; |
| |
| SuiteHelper(SuiteHelper parent, |
| Map<Class<? extends Annotation>, Object> helpers) { |
| |
| this(parent, helpers, Collections.<Class<? extends Annotation>>emptyList()); |
| } |
| |
| SuiteHelper(SuiteHelper parent, |
| Map<Class<? extends Annotation>, Object> helpers, |
| List<Class<? extends Annotation>> primaryKeys) { |
| |
| super(); |
| this.parent = parent; |
| this.helpers = helpers; |
| this.primaryKeys = primaryKeys; |
| } |
| |
| void addAdditionalInfo(StringBuilder writer) { |
| |
| for (Class<? extends Annotation> primaryKey : primaryKeys) { |
| writer.append(" - "); |
| Object helper = helpers.get(primaryKey); |
| DescriptionBuilder descriptionBuilder = testRunnerHelpers.get(primaryKey); |
| writer.append(descriptionBuilder.toString(helper)); |
| } |
| |
| if (parent != null) { |
| parent.addAdditionalInfo(writer); |
| } |
| } |
| |
| private void injectValues(Class<?> testClass, JPQLBasicTest test) throws Exception { |
| |
| if (testClass == Object.class) { |
| return; |
| } |
| |
| Field[] fields = testClass.getDeclaredFields(); |
| |
| for (Field field : fields) { |
| for (Map.Entry<Class<? extends Annotation>, Object> helper : helpers.entrySet()) { |
| if (field.isAnnotationPresent(helper.getKey())) { |
| field.setAccessible(true); |
| field.set(test, helper.getValue()); |
| } |
| } |
| } |
| |
| injectValues(testClass.getSuperclass(), test); |
| } |
| |
| void injectValues(JPQLBasicTest test) throws Exception { |
| |
| injectValues(test.getClass(), test); |
| |
| if (parent != null) { |
| parent.injectValues(test); |
| } |
| } |
| } |
| } |