From 2fe4f9e0bc7bde186df0cf63bb90462f1eb37fcc Mon Sep 17 00:00:00 2001 From: Matthias Otterbach Date: Tue, 15 Apr 2025 21:20:33 +0200 Subject: [PATCH] Add CleanupStaticFieldsStatement --- .../platform/runner/PlatformTestRunner.java | 21 +++++-- .../CleanupStaticFieldsStatement.java | 62 +++++++++++++++++++ 2 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 org.eclipse.scout.rt.platform.test/src/main/java/org/eclipse/scout/rt/testing/platform/runner/statement/CleanupStaticFieldsStatement.java diff --git a/org.eclipse.scout.rt.platform.test/src/main/java/org/eclipse/scout/rt/testing/platform/runner/PlatformTestRunner.java b/org.eclipse.scout.rt.platform.test/src/main/java/org/eclipse/scout/rt/testing/platform/runner/PlatformTestRunner.java index 10f4381e1c6..4034c903ea2 100644 --- a/org.eclipse.scout.rt.platform.test/src/main/java/org/eclipse/scout/rt/testing/platform/runner/PlatformTestRunner.java +++ b/org.eclipse.scout.rt.platform.test/src/main/java/org/eclipse/scout/rt/testing/platform/runner/PlatformTestRunner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023 BSI Business Systems Integration AG + * Copyright (c) 2010, 2025 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -21,6 +21,7 @@ import org.eclipse.scout.rt.testing.platform.runner.statement.AssertNoRunningJobsStatement; import org.eclipse.scout.rt.testing.platform.runner.statement.BeanAnnotationsCleanupStatement; import org.eclipse.scout.rt.testing.platform.runner.statement.BeanAnnotationsInitStatement; +import org.eclipse.scout.rt.testing.platform.runner.statement.CleanupStaticFieldsStatement; import org.eclipse.scout.rt.testing.platform.runner.statement.ClearThreadInterruptionStatusStatement; import org.eclipse.scout.rt.testing.platform.runner.statement.PlatformStatement; import org.eclipse.scout.rt.testing.platform.runner.statement.RegisterBeanStatement; @@ -161,11 +162,18 @@ protected Statement methodBlock(final FrameworkMethod method) { } protected Statement interceptBeforeClassStatement(Statement beforeClassStatement, Class javaClass) { - return interceptClassLevelStatement(beforeClassStatement, javaClass); + final Statement s2 = new SubjectStatement(beforeClassStatement, javaClass.getAnnotation(RunWithSubject.class)); + final Statement s1 = new RegisterBeanStatement(s2, new BeanMetaData(JUnitExceptionHandler.class).withReplace(true).withOrder(-1000)); // exception handler to not silently swallow handled exceptions. + + return s1; } - protected Statement interceptAfterClassStatement(Statement beforeClassStatement, Class javaClass) { - return interceptClassLevelStatement(beforeClassStatement, javaClass); + protected Statement interceptAfterClassStatement(Statement afterClassStatement, Class javaClass) { + final Statement s3 = new CleanupStaticFieldsStatement(afterClassStatement, javaClass); + final Statement s2 = new SubjectStatement(s3, javaClass.getAnnotation(RunWithSubject.class)); + final Statement s1 = new RegisterBeanStatement(s2, new BeanMetaData(JUnitExceptionHandler.class).withReplace(true).withOrder(-1000)); // exception handler to not silently swallow handled exceptions. + + return s1; } protected Statement interceptBeforeStatement(final Statement next, final Class testClass, final Method testMethod) { @@ -208,7 +216,10 @@ protected Statement interceptAfterStatement(final Statement next, final Class * @return the head of the chain to be invoked first. */ protected Statement interceptClassLevelStatement(final Statement next, final Class testClass) { - final Statement s2 = new SubjectStatement(next, testClass.getAnnotation(RunWithSubject.class)); + final List afters = getTestClass().getAnnotatedMethods(AfterClass.class); + + final Statement s3 = afters.isEmpty() ? new CleanupStaticFieldsStatement(next, testClass) : next; + final Statement s2 = new SubjectStatement(s3, testClass.getAnnotation(RunWithSubject.class)); final Statement s1 = new RegisterBeanStatement(s2, new BeanMetaData(JUnitExceptionHandler.class).withReplace(true).withOrder(-1000)); // exception handler to not silently swallow handled exceptions. return s1; diff --git a/org.eclipse.scout.rt.platform.test/src/main/java/org/eclipse/scout/rt/testing/platform/runner/statement/CleanupStaticFieldsStatement.java b/org.eclipse.scout.rt.platform.test/src/main/java/org/eclipse/scout/rt/testing/platform/runner/statement/CleanupStaticFieldsStatement.java new file mode 100644 index 00000000000..4b153740400 --- /dev/null +++ b/org.eclipse.scout.rt.platform.test/src/main/java/org/eclipse/scout/rt/testing/platform/runner/statement/CleanupStaticFieldsStatement.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2010, 2025 BSI Business Systems Integration AG + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.scout.rt.testing.platform.runner.statement; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +import org.junit.runners.model.Statement; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CleanupStaticFieldsStatement extends Statement { + + private static final Logger LOG = LoggerFactory.getLogger(CleanupStaticFieldsStatement.class); + + private final Statement m_next; + private final Class m_testClass; + + public CleanupStaticFieldsStatement(Statement next, Class testClass) { + m_next = next; + m_testClass = testClass; + } + + @Override + public void evaluate() throws Throwable { + try { + m_next.evaluate(); + } + finally { + Class currentClass = m_testClass; + while (currentClass != null) { + for (Field field : currentClass.getDeclaredFields()) { + int modifiers = field.getModifiers(); + boolean staticField = Modifier.isStatic(modifiers); + boolean finalField = Modifier.isFinal(modifiers); + + if (!staticField || finalField) { + continue; + } + + if (field.getType().isPrimitive()) { + continue; + } + + LOG.info("{}#{}: setting static field to null after test is finished", currentClass.getName(), field.getName()); + + field.setAccessible(true); + field.set(null, null); + } + + currentClass = currentClass.getSuperclass(); + } + } + } +}