Skip to content

Commit

Permalink
Compose support of method and field support
Browse files Browse the repository at this point in the history
The ExternalResourceSupport is now composed of the two separately implemented
support classes for method and field support, respectively.
Includes a test to verify the relative order of both cases.

#433
  • Loading branch information
Matthias Merdes authored and Matthias Merdes committed Sep 1, 2016
1 parent 96e2592 commit dc141ea
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,85 +10,25 @@

package org.junit.jupiter.engine.vintage.rulesupport;

import static org.junit.platform.commons.util.ReflectionUtils.MethodSortOrder.HierarchyDown;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Stream;

import org.junit.Rule;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.TestExtensionContext;
import org.junit.platform.commons.util.AnnotationUtils;
import org.junit.rules.ExternalResource;

public class ExternalResourceSupport implements BeforeEachCallback, AfterEachCallback {

private final Class<Rule> annotationType = Rule.class;
private final Class<ExternalResource> ruleType = ExternalResource.class;
private AbstractExternalResourceSupport fieldSupport = new ExternalResourceFieldSupport();
private AbstractExternalResourceSupport methodSupport = new ExternalResourceMethodSupport();

@Override
public void beforeEach(TestExtensionContext context) throws Exception {
this.invokeAppropriateMethodOnRuleAnnotatedFields(context, GenericBeforeAndAfterAdvice::before);
this.invokeAppropriateMethodOnRuleAnnotatedMethods(context, GenericBeforeAndAfterAdvice::before);
this.fieldSupport.beforeEach(context);
this.methodSupport.beforeEach(context);
}

@Override
public void afterEach(TestExtensionContext context) throws Exception {
this.invokeAppropriateMethodOnRuleAnnotatedFields(context, GenericBeforeAndAfterAdvice::after);
this.invokeAppropriateMethodOnRuleAnnotatedMethods(context, GenericBeforeAndAfterAdvice::after);
}

private void invokeAppropriateMethodOnRuleAnnotatedFields(TestExtensionContext context,
Consumer<GenericBeforeAndAfterAdvice> methodCaller) {
// @formatter:off
Stream<AbstractTestRuleAdapter> ruleAdapters = this.findRuleAnnotatedFields(context)
.map(field -> new RuleAnnotatedField(context, field))
.map(annotatedField -> new ExternalResourceAdapter(annotatedField.getTestRuleInstance()));
// @formatter:on

ruleAdapters.forEach(methodCaller::accept);
}

private void invokeAppropriateMethodOnRuleAnnotatedMethods(TestExtensionContext context,
Consumer<GenericBeforeAndAfterAdvice> methodCaller) {
// @formatter:off
Stream<AbstractTestRuleAdapter> ruleAdapters = this.findRuleAnnotatedMethods(context)
.map(method -> new RuleAnnotatedMethod(context, method))
.map(annotatedMethod -> new ExternalResourceAdapter(annotatedMethod.getTestRuleInstance()));
// @formatter:on

ruleAdapters.forEach(methodCaller::accept);
}

private Stream<Field> findRuleAnnotatedFields(TestExtensionContext context) {
Object testInstance = context.getTestInstance();
return findAnnotatedFields(testInstance, this.ruleType, this.annotationType);
}

private Stream<Method> findRuleAnnotatedMethods(TestExtensionContext context) {
Object testInstance = context.getTestInstance();
List<Method> annotatedMethods = AnnotationUtils.findAnnotatedMethods(testInstance.getClass(),
this.annotationType, HierarchyDown);

return annotatedMethods.stream();
}

// TODO: decide whether this should be promoted to AnnotationUtils
private static Stream<Field> findAnnotatedFields(Object instance, Class<?> fieldType,
Class<? extends Annotation> annotationType) {
Field[] declaredFields = instance.getClass().getDeclaredFields();

// @formatter:off
return Arrays.stream(declaredFields)
.filter(field -> fieldType.isAssignableFrom(field.getType()))
.filter(field -> field.isAnnotationPresent(annotationType));
// @formatter:on
this.fieldSupport.afterEach(context);
this.methodSupport.afterEach(context);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* Copyright 2015-2016 the original author or authors.
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/

package org.junit.jupiter.engine.vintage.rulesupport;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.junit.Rule;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.rules.ExternalResource;

@ExtendWith(ExternalResourceSupport.class)
public class ExternalResourceSupportForMixedMethodAndFieldRulesTests {

private static boolean beforeOfRule1WasExecuted = false;
private static boolean beforeOfRule2WasExecuted = false;

private static boolean afterOfRule1WasExecuted = false;
private static boolean afterOfRule2WasExecuted = false;

private List<String> executions = new ArrayList<String>();

@Rule
public ExternalResource resource1 = new ExternalResource() {
@Override
protected void before() throws Throwable {
beforeOfRule1WasExecuted = true;
executions.add("field");
}

@Override
protected void after() {
afterOfRule1WasExecuted = true;
}
};

private ExternalResource resource2 = new ExternalResource() {
@Override
protected void before() throws Throwable {
beforeOfRule2WasExecuted = true;
executions.add("method");
}

@Override
protected void after() {
afterOfRule2WasExecuted = true;
}
};

@Rule
public ExternalResource getResource2() {
return resource2;
}

@Test
void beforeMethodsOfBothRulesWereExecuted() {
assert beforeOfRule1WasExecuted;
assert beforeOfRule2WasExecuted;
}

@Test
void fieldRuleWasExecutedBeforeMethodRule() {
assertEquals(Arrays.asList("field", "method"), this.executions);
}

@AfterAll
static void afterMethodsOfBothRulesWereExecuted() {
if (!afterOfRule1WasExecuted)
fail();
if (!afterOfRule2WasExecuted)
fail();
}

static void fail() {
//hack: use this blacklisted exception to fail the build, all others would be swallowed...
throw new OutOfMemoryError("a postcondition was violated");
}

}

0 comments on commit dc141ea

Please sign in to comment.