You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2022/04/24 15:41:39 UTC

[groovy] branch GROOVY_4_0_X updated (875295e483 -> 53657938bb)

This is an automated email from the ASF dual-hosted git repository.

emilles pushed a change to branch GROOVY_4_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git


    from 875295e483 GROOVY-10587: resolve annotations from module before nested
     new f80662a7db stop writing classes to project basedir
     new 53657938bb add `GroovyShell#withConfig(Closure)` and refactor some unit tests

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../builder/CompilerCustomizationBuilder.groovy    |  36 +-
 ...onditionalInterruptibleASTTransformation.groovy |  23 +-
 src/main/java/groovy/grape/Grape.java              |   6 +-
 src/main/java/groovy/lang/GroovyShell.java         |  23 +-
 .../customizers/builder/CustomizersFactory.java    |  15 +-
 .../typing/TypeCheckingExtensionSpecTest.groovy    |  14 +-
 .../bugs/DirectMethodCallWithVargsTest.groovy      |  93 ++---
 .../transform/ConditionalInterruptTest.groovy      | 259 ++++++------
 src/test/groovy/transform/LazyTest.groovy          | 118 +++---
 src/test/groovy/transform/ReadWriteLockTest.groovy | 293 +++++++-------
 .../groovy/transform/ThreadInterruptTest.groovy    | 430 ++++++++++----------
 .../groovy/transform/TimedInterruptTest.groovy     | 448 ++++++++++-----------
 .../groovy/transform/stc/MethodCallsSTCTest.groovy |  15 +-
 .../ClosureWriterGeneratedAnnotationTest.groovy    |  75 ++--
 .../classgen/asm/sc/BugsStaticCompileTest.groovy   |   3 +-
 ...ticCompileClosureGeneratedAnnotationTest.groovy |  81 ++--
 .../groovy/transform/AutoCloneTransformTest.groovy |   8 +-
 .../groovy/transform/AutoFinalTransformTest.groovy |   7 +-
 .../TransformsAndCustomClassLoadersTest.groovy     |   2 +-
 19 files changed, 941 insertions(+), 1008 deletions(-)


[groovy] 01/02: stop writing classes to project basedir

Posted by em...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch GROOVY_4_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit f80662a7dbc9d470217aa16039655c009481f361
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sat Apr 23 15:17:25 2022 -0500

    stop writing classes to project basedir
---
 ...onditionalInterruptibleASTTransformation.groovy |  23 +-
 .../transform/ConditionalInterruptTest.groovy      | 261 ++++++------
 src/test/groovy/transform/LazyTest.groovy          | 118 +++---
 src/test/groovy/transform/ReadWriteLockTest.groovy | 295 +++++++-------
 .../groovy/transform/ThreadInterruptTest.groovy    | 432 ++++++++++----------
 .../groovy/transform/TimedInterruptTest.groovy     | 450 ++++++++++-----------
 .../ClosureWriterGeneratedAnnotationTest.groovy    |  75 ++--
 .../classgen/asm/sc/BugsStaticCompileTest.groovy   |   3 +-
 ...ticCompileClosureGeneratedAnnotationTest.groovy |  81 ++--
 .../TransformsAndCustomClassLoadersTest.groovy     |   2 +-
 10 files changed, 853 insertions(+), 887 deletions(-)

diff --git a/src/main/groovy/org/codehaus/groovy/transform/ConditionalInterruptibleASTTransformation.groovy b/src/main/groovy/org/codehaus/groovy/transform/ConditionalInterruptibleASTTransformation.groovy
index 90fce9c7c6..594f87b41d 100644
--- a/src/main/groovy/org/codehaus/groovy/transform/ConditionalInterruptibleASTTransformation.groovy
+++ b/src/main/groovy/org/codehaus/groovy/transform/ConditionalInterruptibleASTTransformation.groovy
@@ -28,12 +28,10 @@ import org.codehaus.groovy.ast.FieldNode
 import org.codehaus.groovy.ast.MethodNode
 import org.codehaus.groovy.ast.Parameter
 import org.codehaus.groovy.ast.PropertyNode
-import org.codehaus.groovy.ast.expr.ArgumentListExpression
 import org.codehaus.groovy.ast.expr.ClosureExpression
 import org.codehaus.groovy.ast.expr.Expression
-import org.codehaus.groovy.ast.expr.MethodCallExpression
-import org.codehaus.groovy.ast.expr.VariableExpression
 import org.codehaus.groovy.ast.tools.ClosureUtils
+import org.codehaus.groovy.ast.tools.GeneralUtils
 import org.codehaus.groovy.control.CompilePhase
 
 /**
@@ -48,25 +46,21 @@ import org.codehaus.groovy.control.CompilePhase
 @GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION)
 class ConditionalInterruptibleASTTransformation extends AbstractInterruptibleASTTransformation {
 
-    private static final ClassNode MY_TYPE = ClassHelper.make(ConditionalInterrupt)
-
     private ClosureExpression conditionNode
     private String conditionMethod
-    private MethodCallExpression conditionCallExpression
     private ClassNode currentClass
 
     protected ClassNode type() {
-        MY_TYPE
+        ClassHelper.make(ConditionalInterrupt)
     }
 
-    @SuppressWarnings('Instanceof')
     protected void setupTransform(AnnotationNode node) {
         super.setupTransform(node)
-        ClosureExpression member = (ClosureExpression) node.getMember('value')
-        if (!member || !(member instanceof ClosureExpression)) internalError("Expected closure value for annotation parameter 'value'. Found $member")
-        conditionNode = member
+        def member = node.getMember('value')
+        if (member !instanceof ClosureExpression)
+            internalError("Expected closure value for annotation parameter 'value'. Found $member")
+        conditionNode = (ClosureExpression) member
         conditionMethod = 'conditionalTransform' + node.hashCode() + '$condition'
-        conditionCallExpression = new MethodCallExpression(new VariableExpression('this'), conditionMethod, new ArgumentListExpression())
     }
 
     protected String getErrorMessage() {
@@ -75,15 +69,14 @@ class ConditionalInterruptibleASTTransformation extends AbstractInterruptibleAST
 
     void visitClass(ClassNode type) {
         currentClass = type
-        def method = type.addMethod(conditionMethod, ACC_PRIVATE | ACC_SYNTHETIC, ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, conditionNode.code)
-        method.synthetic = true
+        type.addSyntheticMethod(conditionMethod, ACC_PRIVATE, ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, conditionNode.code)
         if (applyToAllMembers) {
             super.visitClass(type)
         }
     }
 
     protected Expression createCondition() {
-        conditionCallExpression
+        GeneralUtils.callThisX(conditionMethod)
     }
 
     @Override
diff --git a/src/test/groovy/transform/ConditionalInterruptTest.groovy b/src/test/groovy/transform/ConditionalInterruptTest.groovy
index 60b218fdeb..cb86990292 100644
--- a/src/test/groovy/transform/ConditionalInterruptTest.groovy
+++ b/src/test/groovy/transform/ConditionalInterruptTest.groovy
@@ -18,186 +18,193 @@
  */
 package groovy.transform
 
-import groovy.test.GroovyTestCase
+import org.codehaus.groovy.control.CompilerConfiguration
+import org.codehaus.groovy.control.customizers.ImportCustomizer
+import org.junit.Test
+
+import static groovy.test.GroovyAssert.assertScript
 
 /**
- * Test for {@link ConditionalInterrupt} AST Transformation.
+ * Tests for the {@link ConditionalInterrupt} AST transform.
  */
-class ConditionalInterruptTest extends GroovyTestCase {
+final class ConditionalInterruptTest {
 
-    void testMethodIsVisited_AndExceptionMessage() {
+    private final GroovyShell shell = new GroovyShell(new CompilerConfiguration().addCompilationCustomizers(
+        new ImportCustomizer().tap {
+            addStarImports('groovy.transform')
+            addStaticImport('groovy.test.GroovyAssert', 'shouldFail')
+        }
+    ))
 
-        def c = new GroovyClassLoader().parseClass('''
-            import groovy.transform.ConditionalInterrupt
-            @ConditionalInterrupt({ visited = true })
-            class MyClass {
-              boolean visited = false
-              def myMethod() { }
+    @Test
+    void testMethodIsVisited_AndExceptionMessage() {
+        assertScript shell, '''
+            @ConditionalInterrupt(applyToAllClasses=false, value={ visited = true })
+            class C {
+                protected boolean visited
+                def m() { }
             }
-        ''')
 
-        def instance = c.newInstance()
-        def message = shouldFail(InterruptedException) {
-            instance.myMethod()
-        }
-        assert message == 'Execution interrupted. The following condition failed: { visited = true }'
-        assert instance.visited
+            def obj = new C()
+            def err = shouldFail(InterruptedException) {
+                obj.m()
+            }
+            assert obj.visited
+            assert err.message == 'Execution interrupted. The following condition failed: { visited = true }'
+        '''
     }
 
+    @Test
     void testMethodIsVisitedCompileStatic() {
-        def c = new GroovyClassLoader().parseClass('''
-            import groovy.transform.*
+        assertScript shell, '''
             @CompileStatic
-            @ConditionalInterrupt({ visited = true })
-            class MyClass {
-              boolean visited = false
-              def myMethod() { }
-            }
-        ''')
-        def instance = c.newInstance()
-        def message = shouldFail(InterruptedException) {
-            instance.myMethod()
-        }
-        assert message == 'Execution interrupted. The following condition failed: { visited = true }'
-        assert instance.visited
+            @ConditionalInterrupt(applyToAllClasses=false, value={ visited = true })
+            class C {
+                protected boolean visited
+                def m() { }
+            }
+
+            def obj = new C()
+            def err = shouldFail(InterruptedException) {
+                obj.m()
+            }
+            assert obj.visited
+            assert err.message == 'Execution interrupted. The following condition failed: { visited = true }'
+        '''
     }
 
+    @Test
     void testMethodIsVisited_AndCustomExceptionMessage() {
-
-        def c = new GroovyClassLoader(this.class.classLoader).parseClass('''
-            import groovy.transform.ConditionalInterrupt
-            @ConditionalInterrupt(thrown=groovy.transform.CustomException, value={ visited = true })
-            class MyClass {
-              boolean visited = false
-              def myMethod() { }
+        assertScript shell, '''
+            @ConditionalInterrupt(applyToAllClasses=false, thrown=CustomException, value={ visited = true })
+            class C {
+                protected boolean visited
+                def m() { }
             }
-        ''')
 
-        def instance = c.newInstance()
-        def message = shouldFail(CustomException) {
-            instance.myMethod()
-        }
-        assert message == 'Execution interrupted. The following condition failed: { visited = true }'
-        assert instance.visited
+            def obj = new C()
+            def err = shouldFail(CustomException) {
+                obj.m()
+            }
+            assert obj.visited
+            assert err.message == 'Execution interrupted. The following condition failed: { visited = true }'
+        '''
     }
 
+    @Test
     void testStaticMethodIsNotVisited() {
-         def c = new GroovyClassLoader().parseClass('''
-            import groovy.transform.ConditionalInterrupt
-            @ConditionalInterrupt({ visited = true })
-            class MyClass {
-              boolean visited = false
-              static def myMethod() { }
-            }
-        ''')
-
-        def instance = c.newInstance()
-        instance.myMethod()
-        assert !instance.visited
+        assertScript shell, '''
+            @ConditionalInterrupt(applyToAllClasses=false, value={ visited = true })
+            class C {
+                protected boolean visited
+                static m() { }
+            }
+
+            def obj = new C()
+            obj.m()
+
+            assert !obj.visited
+        '''
     }
 
+    @Test
     void testClosureFieldIsVisited() {
-
-        def c = new GroovyClassLoader().parseClass('''
-            import groovy.transform.ConditionalInterrupt
-            @ConditionalInterrupt({ visited = true })
-            class MyClass {
-              boolean visited = false
-              def myMethod = { }
+        assertScript shell, '''
+            @ConditionalInterrupt(applyToAllClasses=false, value={ visited = true })
+            class C {
+                protected boolean visited
+                def m = { -> }
             }
-        ''')
 
-        def instance = c.newInstance()
-        shouldFail(InterruptedException) {
-            instance.myMethod()
-        }
-        assert instance.visited
+            def obj = new C()
+            shouldFail(InterruptedException) {
+                obj.m()
+            }
+            assert obj.visited
+        '''
     }
 
+    @Test
     void testWhileLoopVisited() {
-        def c = new GroovyClassLoader().parseClass('''
-            import groovy.transform.ConditionalInterrupt
-            @ConditionalInterrupt({ count > 5 })
-            class MyClass {
-                int count = 0
-                def myMethod = {
+        assertScript shell, '''
+            @ConditionalInterrupt(applyToAllClasses=false, value={ count > 5 })
+            class C {
+                protected int count
+                def m = { ->
                     while (count < 10) {
-                        count++
+                        count += 1
                     }
                 }
             }
-        ''')
 
-        def instance = c.newInstance()
-        shouldFail(InterruptedException) {
-            instance.myMethod()
-        }
-        assert 6 == instance.count
+            def obj = new C()
+            shouldFail(InterruptedException) {
+                obj.m()
+            }
+            assert obj.count == 6
+        '''
     }
 
+    @Test
     void testForLoopVisited() {
-
-        def c = new GroovyClassLoader().parseClass('''
-            import groovy.transform.ConditionalInterrupt
-            @ConditionalInterrupt({ count > 5 })
-            class MyClass {
-                int count = 0
-                def myMethod = {
-                    for (int x = 0; x < 10; x++) {
-                        count++
+        assertScript shell, '''
+            @ConditionalInterrupt(applyToAllClasses=false, value={ count > 5 })
+            class C {
+                protected int count
+                def m = {
+                    for (int i = 0; i < 10; i += 1) {
+                        count += 1
                     }
                 }
             }
-        ''')
 
-        def instance = c.newInstance()
-        shouldFail(InterruptedException) {
-            instance.myMethod()
-        }
-        assert 6 == instance.count
+            def obj = new C()
+            shouldFail(InterruptedException) {
+                obj.m()
+            }
+            assert obj.count == 6
+        '''
     }
 
+    @Test
     void testStaticClosureFieldNotVisited() {
-
-        def c = new GroovyClassLoader().parseClass('''
-            import groovy.transform.ConditionalInterrupt
-            @ConditionalInterrupt({ visited = true })
-            class MyClass {
-                boolean visited = false
-                static def myMethod = { }
+        assertScript shell, '''
+            @ConditionalInterrupt(applyToAllClasses=false, value={ visited = true })
+            class C {
+                protected boolean visited
+                static m = { -> }
             }
-        ''')
 
-        def instance = c.newInstance()
-        instance.myMethod()
-        assert !instance.visited
+            def obj = new C()
+            obj.m()
+
+            assert !obj.visited
+        '''
     }
 
+    @Test
     void testSharedContext() {
-        def shell = new GroovyShell()
-
-        def script = shell.parse('''
-            import groovy.transform.ConditionalInterrupt
-
+        assertScript shell, '''
             class Helper {
-                static int i=0
-                static def shouldInterrupt() { i++>1 }
+                static int i
+                static def shouldInterrupt() { ++i > 1 }
             }
 
-            @ConditionalInterrupt({ Helper.shouldInterrupt() })
-            class MyClass {
-                def myMethod() { }
+            @ConditionalInterrupt(applyToAllClasses=false, value={ Helper.shouldInterrupt() })
+            class C {
+                def m = { -> }
             }
 
-            @ConditionalInterrupt({ Helper.shouldInterrupt() })
-            class MyOtherClass {
-                def myOtherMethod() { new MyClass().myMethod() }
+            @ConditionalInterrupt(applyToAllClasses=false, value={ Helper.shouldInterrupt() })
+            class D {
+                def m() {
+                    new C().m()
+                }
             }
 
-            new MyOtherClass().myOtherMethod()
-        ''', 'myScript')
-        shouldFail(InterruptedException) {
-            script.run()
-        }
+            shouldFail(InterruptedException) {
+                new D().m()
+            }
+        '''
     }
 }
diff --git a/src/test/groovy/transform/LazyTest.groovy b/src/test/groovy/transform/LazyTest.groovy
index 1e22cd1a45..bdfc19e059 100644
--- a/src/test/groovy/transform/LazyTest.groovy
+++ b/src/test/groovy/transform/LazyTest.groovy
@@ -18,72 +18,82 @@
  */
 package groovy.transform
 
-import groovy.test.GroovyTestCase
+import org.codehaus.groovy.control.CompilerConfiguration
+import org.codehaus.groovy.control.customizers.ImportCustomizer
+import org.junit.Test
 
-import java.lang.ref.SoftReference
-import java.lang.reflect.Modifier
+import static groovy.test.GroovyAssert.assertScript
 
 /**
- * Unit tests for the Lazy annotation
+ * Tests for the {@link Lazy} AST transform.
  */
-class LazyTest extends GroovyTestCase {
+final class LazyTest {
+
+    private final GroovyShell shell = new GroovyShell(new CompilerConfiguration().addCompilationCustomizers(
+        new ImportCustomizer().tap { addStaticStars('java.lang.reflect.Modifier') }
+    ))
+
+    @Test
     void testLazyPrimitiveWrapping() {
-        def tester = new GroovyClassLoader().parseClass(
-          '''class MyClass {
-            |    @Lazy int index = { ->
-            |        1
-            |    }
-            |}'''.stripMargin() )
-        // Should be a private non-volatile Integer
-        def field = tester.getDeclaredField( '$index' )
-        assert field
-        assert Modifier.isPrivate(field.modifiers)
-        assert !Modifier.isVolatile(field.modifiers)
-        assert field.type == Integer
+        assertScript shell, '''
+            class C {
+                @Lazy int index = { -> 1 }
+            }
+
+            def field = C.getDeclaredField('$index')
+            assert field
+            assert field.type == Integer
+            assert isPrivate(field.modifiers)
+            assert !isVolatile(field.modifiers)
+        '''
     }
 
+    @Test
     void testLazyVolatilePrimitiveWrapping() {
-        def tester = new GroovyClassLoader().parseClass(
-          '''class MyClass {
-            |    @Lazy volatile int index = { ->
-            |        1
-            |    }
-            |}'''.stripMargin() )
-        // Should be a private volatile Integer
-        def field = tester.getDeclaredField( '$index' )
-        assert field
-        assert Modifier.isPrivate(field.modifiers)
-        assert Modifier.isVolatile(field.modifiers)
-        assert field.type == Integer
+        assertScript shell, '''
+            class C {
+                @Lazy volatile int index = { -> 1 }
+            }
+
+            def field = C.getDeclaredField('$index')
+            assert field
+            assert field.type == Integer
+            assert isPrivate(field.modifiers)
+            assert isVolatile(field.modifiers)
+        '''
     }
 
+    @Test
     void testLazySoftPrimitiveWrapping() {
-        def tester = new GroovyClassLoader().parseClass(
-          '''class MyClass {
-            |    @Lazy(soft=true) int index = { ->
-            |        1
-            |    }
-            |}'''.stripMargin() )
-        // Should be a private non-volatile SoftReference
-        def field = tester.getDeclaredField( '$index' )
-        assert field
-        assert Modifier.isPrivate(field.modifiers)
-        assert !Modifier.isVolatile(field.modifiers)
-        assert field.type == SoftReference
+        assertScript shell, '''
+            import java.lang.ref.SoftReference as SoftRef
+
+            class C {
+                @Lazy(soft=true) int index = { -> 1 }
+            }
+
+            def field = C.getDeclaredField('$index')
+            assert field
+            assert field.type == SoftRef
+            assert isPrivate(field.modifiers)
+            assert !isVolatile(field.modifiers)
+        '''
     }
 
+    @Test
     void testLazyVolatileSoftPrimitiveWrapping() {
-        def tester = new GroovyClassLoader().parseClass(
-          '''class MyClass {
-            |    @Lazy(soft=true) volatile int index = { ->
-            |        1
-            |    }
-            |}'''.stripMargin() )
-        // Should be a private volatile SoftReference
-        def field = tester.getDeclaredField( '$index' )
-        assert field
-        assert Modifier.isPrivate(field.modifiers)
-        assert Modifier.isVolatile(field.modifiers)
-        assert field.type == SoftReference
+        assertScript shell, '''
+            import java.lang.ref.SoftReference as SoftRef
+
+            class C {
+                @Lazy(soft=true) volatile int index = { -> 1 }
+            }
+
+            def field = C.getDeclaredField('$index')
+            assert field
+            assert field.type == SoftRef
+            assert isPrivate(field.modifiers)
+            assert isVolatile(field.modifiers)
+        '''
     }
-}
\ No newline at end of file
+}
diff --git a/src/test/groovy/transform/ReadWriteLockTest.groovy b/src/test/groovy/transform/ReadWriteLockTest.groovy
index a36fcbae27..7a77bb05a9 100644
--- a/src/test/groovy/transform/ReadWriteLockTest.groovy
+++ b/src/test/groovy/transform/ReadWriteLockTest.groovy
@@ -18,82 +18,92 @@
  */
 package groovy.transform
 
-import groovy.test.GroovyTestCase
+import org.codehaus.groovy.control.CompilerConfiguration
+import org.codehaus.groovy.control.customizers.ImportCustomizer
+import org.junit.Test
 
-import java.util.concurrent.locks.ReentrantReadWriteLock
-import java.lang.reflect.Modifier
+import static groovy.test.GroovyAssert.assertScript
+import static groovy.test.GroovyAssert.shouldFail
 
 /**
- * Unit test for WithReadLock and WithWriteLock annotations.
+ * Tests for the {@link WithReadLock} and {@link WithWriteLock} AST transforms.
  */
-class ReadWriteLockTest extends GroovyTestCase {
+final class ReadWriteLockTest {
 
-    void testLockFieldDefaultsForReadLock() {
-        def tester = new GroovyClassLoader().parseClass('''
-        class MyClass {
-            @groovy.transform.WithReadLock
-            public void readerMethod1() { }
+    private final GroovyShell shell = new GroovyShell(new CompilerConfiguration().addCompilationCustomizers(
+        new ImportCustomizer().tap {
+            addStarImports('groovy.transform')
+            addStaticStars('java.lang.reflect.Modifier')
+            addImport('java.util.concurrent.locks.ReentrantReadWriteLock')
         }
-''')
-        def field = tester.getDeclaredField('$reentrantlock')
-        assert Modifier.isPrivate(field.modifiers)
-        assert !Modifier.isTransient(field.modifiers)
-        assert Modifier.isFinal(field.modifiers)
-        assert !Modifier.isStatic(field.modifiers)
-
-        assert field.type == ReentrantReadWriteLock
+    ))
+
+    @Test
+    void testLockFieldDefaultsForReadLock() {
+        assertScript shell, '''
+            class C {
+                @WithReadLock void m() { }
+            }
+
+            def field = C.getDeclaredField('$reentrantlock')
+            assert field.type == ReentrantReadWriteLock
+            assert !isTransient(field.modifiers)
+            assert isPrivate(field.modifiers)
+            assert !isStatic(field.modifiers)
+            assert isFinal(field.modifiers)
+        '''
     }
 
+    @Test
     void testLockFieldDefaultsForWriteLock() {
-        def tester = new GroovyClassLoader().parseClass('''
-        class MyClass {
-            @groovy.transform.WithWriteLock
-            public void readerMethod1() { }
-        }
-''')
-        def field = tester.getDeclaredField('$reentrantlock')
-        assert Modifier.isPrivate(field.modifiers)
-        assert !Modifier.isTransient(field.modifiers)
-        assert Modifier.isFinal(field.modifiers)
-        assert !Modifier.isStatic(field.modifiers)
-
-        assert field.type == ReentrantReadWriteLock
+        assertScript shell, '''
+            class C {
+                @WithWriteLock void m() { }
+            }
+
+            def field = C.getDeclaredField('$reentrantlock')
+            assert field.type == ReentrantReadWriteLock
+            assert !isTransient(field.modifiers)
+            assert isPrivate(field.modifiers)
+            assert !isStatic(field.modifiers)
+            assert isFinal(field.modifiers)
+        '''
     }
 
+    @Test
     void testLockFieldDefaultsForStaticReadLock() {
-        def tester = new GroovyClassLoader().parseClass('''
-        class MyClass {
-            @groovy.transform.WithReadLock
-            public static void readerMethod1() { }
-        }
-''')
-        def field = tester.getDeclaredField('$REENTRANTLOCK')
-        assert Modifier.isPrivate(field.modifiers)
-        assert !Modifier.isTransient(field.modifiers)
-        assert Modifier.isFinal(field.modifiers)
-        assert Modifier.isStatic(field.modifiers)
-
-        assert field.type == ReentrantReadWriteLock
+        assertScript shell, '''
+            class C {
+                @WithReadLock static void m() { }
+            }
+
+            def field = C.getDeclaredField('$REENTRANTLOCK')
+            assert field.type == ReentrantReadWriteLock
+            assert !isTransient(field.modifiers)
+            assert isPrivate(field.modifiers)
+            assert isStatic(field.modifiers)
+            assert isFinal(field.modifiers)
+        '''
     }
 
+    @Test
     void testLockFieldDefaultsForStaticWriteLock() {
-        def tester = new GroovyClassLoader().parseClass('''
-        class MyClass {
-            @groovy.transform.WithWriteLock
-            public static void readerMethod1() { }
-        }
-''')
-        def field = tester.getDeclaredField('$REENTRANTLOCK')
-        assert Modifier.isPrivate(field.modifiers)
-        assert !Modifier.isTransient(field.modifiers)
-        assert Modifier.isFinal(field.modifiers)
-        assert Modifier.isStatic(field.modifiers)
-
-        assert field.type == ReentrantReadWriteLock
+        assertScript shell, '''
+            class C {
+                @WithWriteLock static void m() { }
+            }
+
+            def field = C.getDeclaredField('$REENTRANTLOCK')
+            assert field.type == ReentrantReadWriteLock
+            assert !isTransient(field.modifiers)
+            assert isPrivate(field.modifiers)
+            assert isStatic(field.modifiers)
+            assert isFinal(field.modifiers)
+        '''
     }
 
+    @Test
     void testLocking() {
-
         def tester = new MyClass()
         tester.readerMethod1()
         tester.readerMethod2()
@@ -111,8 +121,8 @@ class ReadWriteLockTest extends GroovyTestCase {
         tester.readerMethod1()
     }
 
+    @Test
     void testStaticLocking() {
-
         def tester = new MyClass()
         tester.staticReaderMethod1()
         tester.staticReaderMethod2()
@@ -130,10 +140,11 @@ class ReadWriteLockTest extends GroovyTestCase {
         tester.staticReaderMethod1()
     }
 
+    @Test
     void testDeadlockingDoesNotOccur() {
         def tester = new MyClass()
 
-        // this tests for deadlocks from not releaseing in finally block 
+        // this tests for deadlocks from not releaseing in finally block
         shouldFail { tester.namedReaderMethod1() }
         shouldFail { tester.namedReaderMethod2() }
         shouldFail { tester.namedWriterMethod1() }
@@ -145,41 +156,40 @@ class ReadWriteLockTest extends GroovyTestCase {
         shouldFail { tester.namedReaderMethod1() }
     }
 
+    @Test
     void testCompileError_NamingConflict() {
-        shouldFail("lock field with name 'unknown' not found") {
-            '''
+        def err = shouldFail shell, '''
             class MyClass {
                 @groovy.transform.WithWriteLock('unknown')
                 public static void readerMethod1() { }
-            } '''
-        }
+            }
+        '''
+        assert err =~ /lock field with name 'unknown' not found/
 
-        shouldFail("lock field with name 'myLock' should be static") {
-            '''
+        err = shouldFail shell, '''
             class MyClass {
-                def myLock = new java.util.concurrent.locks.ReentrantReadWriteLock()
+                def myLock = new ReentrantReadWriteLock()
 
                 @groovy.transform.WithWriteLock('myLock')
                 public static void readerMethod1() { }
-            } '''
-        }
+            }
+        '''
+        assert err =~ /lock field with name 'myLock' should be static/
 
-        shouldFail("lock field with name 'myLock' should not be static") {
-            '''
+        err = shouldFail shell, '''
             class MyClass {
-                static def myLock = new java.util.concurrent.locks.ReentrantReadWriteLock()
+                static def myLock = new ReentrantReadWriteLock()
 
                 @groovy.transform.WithWriteLock('myLock')
                 public void readerMethod1() { }
-            } '''
-        }
+            }
+        '''
+        assert err =~ /lock field with name 'myLock' should not be static/
     }
 
-    // GROOVY-8758
+    @Test // GROOVY-8758
     void testShouldBeAllowedInInnerClassWithCompileStatic() {
-        assertScript '''
-            import groovy.transform.*
-
+        assertScript shell, '''
             @CompileStatic
             class A {
                 private class B {
@@ -198,77 +208,68 @@ class ReadWriteLockTest extends GroovyTestCase {
         '''
     }
 
-    def shouldFail(String expectedText, Closure c) {
-        String script = c()
-        try {
-            new GroovyClassLoader().parseClass(script)
-            fail('Failure Expected')
-        } catch (Exception e) {
-            assert e.getMessage().contains(expectedText)
+    //--------------------------------------------------------------------------
+
+    static class MyClass {
+        def readerMethod1Called = false
+        def readerMethod2Called = false
+        def writerMethod1Called = false
+        def writerMethod2Called = false
+        def staticReaderMethod1Called = false
+        def staticReaderMethod2Called = false
+        def staticWriterMethod1Called = false
+        def staticWriterMethod2Called = false
+        def myLock = new java.util.concurrent.locks.ReentrantReadWriteLock()
+
+        @WithReadLock
+        void readerMethod1() {
+            readerMethod1Called = true
+        }
+        @WithReadLock
+        void readerMethod2() {
+            readerMethod2Called = true
+        }
+        @WithWriteLock
+        void writerMethod1() {
+            writerMethod1Called = true
+        }
+        @WithWriteLock
+        void writerMethod2() {
+            writerMethod2Called = true
         }
-    }
-}
-
-class MyClass {
-
-    def readerMethod1Called = false
-    def readerMethod2Called = false
-    def writerMethod1Called = false
-    def writerMethod2Called = false
-    def staticReaderMethod1Called = false
-    def staticReaderMethod2Called = false
-    def staticWriterMethod1Called = false
-    def staticWriterMethod2Called = false
-    def myLock = new ReentrantReadWriteLock()
-
-    @WithReadLock
-    void readerMethod1() {
-        readerMethod1Called = true
-    }
-    @WithReadLock
-    void readerMethod2() {
-        readerMethod2Called = true
-    }
-    @WithWriteLock
-    void writerMethod1() {
-        writerMethod1Called = true
-    }
-    @WithWriteLock
-    void writerMethod2() {
-        writerMethod2Called = true
-    }
 
-    @WithReadLock('myLock')
-    void namedReaderMethod1() {
-        throw new Exception()
-    }
-    @WithReadLock('myLock')
-    void namedReaderMethod2() {
-        throw new Exception()
-    }
-    @WithWriteLock('myLock')
-    void namedWriterMethod1() {
-        throw new Exception()
-    }
-    @WithWriteLock('myLock')
-    void namedWriterMethod2() {
-        throw new Exception()
-    }
+        @WithReadLock('myLock')
+        void namedReaderMethod1() {
+            throw new Exception()
+        }
+        @WithReadLock('myLock')
+        void namedReaderMethod2() {
+            throw new Exception()
+        }
+        @WithWriteLock('myLock')
+        void namedWriterMethod1() {
+            throw new Exception()
+        }
+        @WithWriteLock('myLock')
+        void namedWriterMethod2() {
+            throw new Exception()
+        }
 
-    @WithReadLock
-    void staticReaderMethod1() {
-        staticReaderMethod1Called = true
-    }
-    @WithReadLock
-    void staticReaderMethod2() {
-        staticReaderMethod2Called = true
-    }
-    @WithWriteLock
-    void staticWriterMethod1() {
-        staticWriterMethod1Called = true
-    }
-    @WithWriteLock
-    void staticWriterMethod2() {
-        staticWriterMethod2Called = true
+        @WithReadLock
+        void staticReaderMethod1() {
+            staticReaderMethod1Called = true
+        }
+        @WithReadLock
+        void staticReaderMethod2() {
+            staticReaderMethod2Called = true
+        }
+        @WithWriteLock
+        void staticWriterMethod1() {
+            staticWriterMethod1Called = true
+        }
+        @WithWriteLock
+        void staticWriterMethod2() {
+            staticWriterMethod2Called = true
+        }
     }
 }
diff --git a/src/test/groovy/transform/ThreadInterruptTest.groovy b/src/test/groovy/transform/ThreadInterruptTest.groovy
index 4747d2d3c1..bc7f3a2b22 100644
--- a/src/test/groovy/transform/ThreadInterruptTest.groovy
+++ b/src/test/groovy/transform/ThreadInterruptTest.groovy
@@ -20,6 +20,8 @@ package groovy.transform
 
 import groovy.mock.interceptor.StubFor
 import org.codehaus.groovy.ast.MethodNode
+import org.codehaus.groovy.control.CompilerConfiguration
+import org.codehaus.groovy.control.customizers.ImportCustomizer
 import org.codehaus.groovy.transform.ThreadInterruptibleASTTransformation
 import org.junit.After
 import org.junit.Before
@@ -27,14 +29,22 @@ import org.junit.Test
 
 import java.lang.reflect.Modifier
 
+import static groovy.test.GroovyAssert.assertScript
 import static groovy.test.GroovyAssert.isAtLeastJdk
 import static groovy.test.GroovyAssert.shouldFail
 import static org.junit.Assume.assumeTrue
 
 /**
- * Test for @ThreadInterrupt.
+ * Tests for the {@link ThreadInterrupt} AST transform.
  */
-class ThreadInterruptTest {
+final class ThreadInterruptTest {
+
+    private final GroovyShell shell = new GroovyShell(new CompilerConfiguration().addCompilationCustomizers(
+        new ImportCustomizer().tap {
+            addStarImports('groovy.transform')
+            addImport('groovy.mock.interceptor.StubFor')
+        }
+    ))
     private static final boolean jdk12plus = isAtLeastJdk('12.0')
     private Map<String, MethodNode> oldValues = [:]
 
@@ -44,7 +54,7 @@ class ThreadInterruptTest {
         Thread.metaClass = null
         ['CURRENTTHREAD_METHOD', 'ISINTERRUPTED_METHOD'].each {
             def ov = ThreadInterruptibleASTTransformation.getDeclaredField(it)
-            def modifiersField = ov.class.getDeclaredField("modifiers")
+            def modifiersField = ov.class.getDeclaredField('modifiers')
             modifiersField.accessible = true
             modifiersField.setInt(ov, ov.modifiers & ~Modifier.FINAL)
             ov.accessible = true
@@ -53,15 +63,15 @@ class ThreadInterruptTest {
     }
 
     @Before
-    void setUp() throws Exception {
+    void setUp() {
         // JDK12+ doesn't allow adjusting static final fields even via reflection, so
         // skip all tests on such JDK versions - it is only test code that's affected
         // and currently we have coverage from builds with lower JDK versions.
-        assumeTrue !jdk12plus
+        assumeTrue(!jdk12plus)
 
         ['CURRENTTHREAD_METHOD', 'ISINTERRUPTED_METHOD'].each {
             def ov = ThreadInterruptibleASTTransformation.getDeclaredField(it)
-            def modifiersField = ov.class.getDeclaredField("modifiers")
+            def modifiersField = ov.class.getDeclaredField('modifiers')
             modifiersField.accessible = true
             modifiersField.setInt(ov, ov.modifiers & ~Modifier.FINAL)
             ov.accessible = true
@@ -72,365 +82,343 @@ class ThreadInterruptTest {
 
     @Test
     void testDefaultParameters_Method() {
-
-        def c = new GroovyClassLoader().parseClass("""
-            @groovy.transform.ThreadInterrupt
-            class MyClass {
-              def myMethod() { }
+        assertScript shell, '''
+            @ThreadInterrupt(applyToAllClasses=false)
+            class C {
+                def m() { }
             }
-        """)
 
-        def counter = new CountingThread()
-        def mocker = new StubFor(Thread.class)
-        mocker.demand.currentThread(1..Integer.MAX_VALUE) { counter }
-        mocker.use {
-            c.newInstance().myMethod()
-        }
-        assert 1 == counter.interruptedCheckCount
+            def mocker = new StubFor(Thread)
+            def counter = new CountingThread()
+            mocker.demand.currentThread(1..Integer.MAX_VALUE) { counter }
+            mocker.use {
+                new C().m()
+            }
+            assert 1 == counter.interruptedCheckCount
+        '''
     }
 
     @Test
     void testNoMethodCheck_Method() {
-
-        def c = new GroovyClassLoader().parseClass("""
-            @groovy.transform.ThreadInterrupt(checkOnMethodStart = false)
-            class MyClass {
-              def myMethod() { }
+        assertScript shell, '''
+            @ThreadInterrupt(applyToAllClasses=false, checkOnMethodStart=false)
+            class C {
+                def m() { }
             }
-        """)
 
-        def mocker = new StubFor(Thread.class)
-        mocker.demand.currentThread(1..Integer.MAX_VALUE) { new InterruptingThread() }
-        mocker.use {
-            c.newInstance().myMethod()
-        }
-        // no exception means success
+            def mocker = new StubFor(Thread)
+            mocker.demand.currentThread(1..Integer.MAX_VALUE) { new InterruptingThread() }
+            mocker.use {
+                new C().m()
+            }
+            // no exception means success
+        '''
     }
 
     @Test
     void testDefaultParameters_ForLoop() {
-
-        def c = new GroovyClassLoader().parseClass("""
-            @groovy.transform.ThreadInterrupt
-            class MyClass {
-              def myMethod() {
-                  for (int i in (1..99)) {
-                      // do something
-                  }
-              }
+        assertScript shell, '''
+            @ThreadInterrupt(applyToAllClasses=false)
+            class C {
+                def m() {
+                    for (int i in (1..99)) {
+                        // do something
+                    }
+                }
             }
-        """)
 
-        def counter = new CountingThread()
-        def mocker = new StubFor(Thread.class)
-        mocker.demand.currentThread(1..Integer.MAX_VALUE) { counter }
-        mocker.use {
-            c.newInstance().myMethod()
-        }
-        assert 100 == counter.interruptedCheckCount
+            def mocker = new StubFor(Thread)
+            def counter = new CountingThread()
+            mocker.demand.currentThread(1..Integer.MAX_VALUE) { counter }
+            mocker.use {
+                new C().m()
+            }
+            assert 100 == counter.interruptedCheckCount
+        '''
     }
 
     @Test
     void testDefaultParameters_WhileLoop() {
-
-        def c = new GroovyClassLoader().parseClass("""
-            @groovy.transform.ThreadInterrupt
-            class MyClass {
-              def myMethod() {
-                  int x = 99
-                  while (x > 0) {
-                      x--
-                  }
-              }
+        assertScript shell, '''
+            @ThreadInterrupt(applyToAllClasses=false)
+            class C {
+                def m() {
+                    int x = 99
+                    while (x > 0) {
+                        x--
+                    }
+                }
             }
-        """)
 
-        def counter = new CountingThread()
-        def mocker = new StubFor(Thread.class)
-        mocker.demand.currentThread(1..Integer.MAX_VALUE) { counter }
-        mocker.use {
-            c.newInstance().myMethod()
-        }
-        assert 100 == counter.interruptedCheckCount
+            def mocker = new StubFor(Thread)
+            def counter = new CountingThread()
+            mocker.demand.currentThread(1..Integer.MAX_VALUE) { counter }
+            mocker.use {
+                new C().m()
+            }
+            assert 100 == counter.interruptedCheckCount
+        '''
     }
 
     @Test
     void testDefaultParameters_Closure() {
-
-        def c = new GroovyClassLoader().parseClass("""
-            @groovy.transform.ThreadInterrupt
-            class MyClass {
-              def myMethod() {
-                  99.times {
-                    // do something
-                  }
-              }
+        assertScript shell, '''
+            @ThreadInterrupt(applyToAllClasses=false)
+            class C {
+                def m() {
+                    99.times {
+                        // do something
+                    }
+                }
             }
-        """)
 
-        def counter = new CountingThread()
-        def mocker = new StubFor(Thread.class)
-        mocker.demand.currentThread(1..Integer.MAX_VALUE) { counter }
-        mocker.use {
-            c.newInstance().myMethod()
-        }
-        assert 100 == counter.interruptedCheckCount
+            def mocker = new StubFor(Thread)
+            def counter = new CountingThread()
+            mocker.demand.currentThread(1..Integer.MAX_VALUE) { counter }
+            mocker.use {
+                new C().m()
+            }
+            assert 100 == counter.interruptedCheckCount
+        '''
     }
 
     @Test
     void testInterrupt_Method_AndTestExceptionMessage() {
-
-        def c = new GroovyClassLoader().parseClass("""
-            @groovy.transform.ThreadInterrupt
-            class MyClass {
-              def myMethod() { }
+        def err = shouldFail shell, InterruptedException, '''
+            @ThreadInterrupt(applyToAllClasses=false)
+            class C {
+                def m() { }
             }
-        """)
 
-        def mocker = new StubFor(Thread.class)
-        mocker.demand.currentThread(1..Integer.MAX_VALUE) { new InterruptingThread() }
-        mocker.use {
-            def ex = shouldFail(InterruptedException) { c.newInstance().myMethod() }
-            assert ex.message == 'Execution interrupted. The current thread has been interrupted.'
-        }
+            def mocker = new StubFor(Thread)
+            mocker.demand.currentThread(1..Integer.MAX_VALUE) { new InterruptingThread() }
+            mocker.use {
+                new C().m()
+            }
+        '''
+        assert err.message == 'Execution interrupted. The current thread has been interrupted.'
     }
 
     @Test
     void testInterrupt_ForLoop() {
-
-        def c = new GroovyClassLoader().parseClass("""
-            @groovy.transform.ThreadInterrupt
-            class MyClass {
-              def myMethod() {
-                  for (int i in (1..99)) {
-                      // do something
-                  }
-              }
+        shouldFail shell, InterruptedException, '''
+            @ThreadInterrupt(applyToAllClasses=false)
+            class C {
+                def m() {
+                    for (int i in (1..99)) {
+                        // do something
+                    }
+                }
             }
-        """)
 
-        def mocker = new StubFor(Thread.class)
-        mocker.demand.currentThread(1..Integer.MAX_VALUE) { new InterruptingThread() }
-        mocker.use {
-            shouldFail(InterruptedException) { c.newInstance().myMethod() }
-        }
+            def mocker = new StubFor(Thread)
+            mocker.demand.currentThread(1..Integer.MAX_VALUE) { new InterruptingThread() }
+            mocker.use {
+                new C().m()
+            }
+        '''
     }
 
     @Test
     void testInterrupt_WhileLoop() {
-
-        def c = new GroovyClassLoader().parseClass("""
-            @groovy.transform.ThreadInterrupt
-            class MyClass {
-              def myMethod() {
-                  int x = 99
-                  while (x > 0) {
-                      x--
-                  }
-              }
+        shouldFail shell, InterruptedException, '''
+            @ThreadInterrupt(applyToAllClasses=false)
+            class C {
+                def m() {
+                    int x = 99
+                    while (x > 0) {
+                        x--
+                    }
+                }
             }
-        """)
 
-        def mocker = new StubFor(Thread.class)
-        mocker.demand.currentThread(1..Integer.MAX_VALUE) { new InterruptingThread() }
-        mocker.use {
-            shouldFail(InterruptedException) { c.newInstance().myMethod() }
-        }
+            def mocker = new StubFor(Thread)
+            mocker.demand.currentThread(1..Integer.MAX_VALUE) { new InterruptingThread() }
+            mocker.use {
+                new C().m()
+            }
+        '''
     }
 
     @Test
     void testInterrupt_Closure() {
-
-        def c = new GroovyClassLoader().parseClass("""
-            @groovy.transform.ThreadInterrupt
-            class MyClass {
-              def myMethod() {
-                  99.times {
-                    // do something
-                  }
-              }
+        shouldFail shell, InterruptedException, '''
+            @ThreadInterrupt(applyToAllClasses=false)
+            class C {
+                def m() {
+                    99.times {
+                      // do something
+                    }
+                }
             }
-        """)
 
-        def mocker = new StubFor(Thread.class)
-        mocker.demand.currentThread(1..Integer.MAX_VALUE) { new InterruptingThread() }
-        mocker.use {
-            shouldFail(InterruptedException) { c.newInstance().myMethod() }
-        }
+            def mocker = new StubFor(Thread)
+            mocker.demand.currentThread(1..Integer.MAX_VALUE) { new InterruptingThread() }
+            mocker.use {
+                new C().m()
+            }
+        '''
     }
 
     @Test
     void testInterrupt_ClosureWithCustomExceptionType() {
-
-        def c = new GroovyClassLoader(this.class.classLoader).parseClass("""
-            @groovy.transform.ThreadInterrupt(thrown=groovy.transform.CustomException)
-            class MyClass {
-              def myMethod() {
-                  99.times {
-                    // do something
-                  }
-              }
+        shouldFail shell, CustomException, '''
+            @ThreadInterrupt(applyToAllClasses=false, thrown=CustomException)
+            class C {
+                def m() {
+                    99.times {
+                      // do something
+                    }
+                }
             }
-        """)
 
-        def mocker = new StubFor(Thread.class)
-        mocker.demand.currentThread(1..Integer.MAX_VALUE) { new InterruptingThread() }
-        mocker.use {
-            shouldFail(CustomException) { c.newInstance().myMethod() }
-        }
+            def mocker = new StubFor(Thread)
+            mocker.demand.currentThread(1..Integer.MAX_VALUE) { new InterruptingThread() }
+            mocker.use {
+                new C().m()
+            }
+        '''
     }
 
     @Test
     void testEntireCompileUnitIsAffected() {
-
         def script = '''
             def scriptMethod() {
                 // this method should inherit the checks from the annotation defined later
             }
 
-            @groovy.transform.ThreadInterrupt
-            class MyClass {
-
-              def myMethod() {
-                // this method should also be guarded
-              }
+            @ThreadInterrupt
+            class C {
+                def m() {
+                    // this method should also be guarded
+                }
             }
+
             scriptMethod()
-            new MyClass().myMethod()
-            '''
+            new C().m()
+        '''
+        def mocker = new StubFor(Thread)
         def counter = new CountingThread()
-        def mocker = new StubFor(Thread.class)
         mocker.demand.currentThread(1..Integer.MAX_VALUE) { counter }
         mocker.use {
-            new GroovyShell().evaluate(script)
+            shell.evaluate(script)
         }
-        // 3 is once for run(), once for scriptMethod() and once for myMethod()
-        assert 3 == counter.interruptedCheckCount
+        assert counter.interruptedCheckCount == 3 // once for run(), once for scriptMethod() and once for m()
     }
 
     @Test
     void testOnlyScriptAffected() {
-
         def script = '''
-            @groovy.transform.ThreadInterrupt(applyToAllClasses = false)
+            @ThreadInterrupt(applyToAllClasses=false)
             def scriptMethod() {
                 // should be affected
             }
 
-            class MyClass {
-              def myMethod() {
-                // should not be affected
-              }
+            class C {
+                def m() {
+                    // should not be affected
+                }
             }
             scriptMethod()
-            new MyClass().myMethod()
-            '''
+            new C().m()
+        '''
+        def mocker = new StubFor(Thread)
         def counter = new CountingThread()
-        def mocker = new StubFor(Thread.class)
         mocker.demand.currentThread(1..Integer.MAX_VALUE) { counter }
         mocker.use {
-            new GroovyShell().evaluate(script)
+            shell.evaluate(script)
         }
-        // 2 is once for run() and once for scriptMethod()
-        assert 2 == counter.interruptedCheckCount
+        assert counter.interruptedCheckCount == 2 // once for run() and once for scriptMethod()
     }
 
     @Test
     void testAnnotationOnImport() {
-
         def script = '''
-            @groovy.transform.ThreadInterrupt
+            @ThreadInterrupt
             import java.lang.String
 
             3.times {
                 // should be affected
             }
-            '''
+        '''
+        def mocker = new StubFor(Thread)
         def counter = new CountingThread()
-        def mocker = new StubFor(Thread.class)
         mocker.demand.currentThread(1..Integer.MAX_VALUE) { counter }
         mocker.use {
-            new GroovyShell().evaluate(script)
+            shell.evaluate(script)
         }
-        // 4 is once for run() plus 3 for times loop
-        assert 4 == counter.interruptedCheckCount
+        assert counter.interruptedCheckCount == 4 // once for run() plus 3 for times loop
     }
 
     @Test
     void testOnlyClassAffected() {
-
         def script = '''
             def scriptMethod() {
                 // this should not be affected
             }
 
-            @groovy.transform.ThreadInterrupt(applyToAllClasses = false)
-            class MyClass {
-              def myMethod() {
-                // this should be affected
-              }
+            @ThreadInterrupt(applyToAllClasses=false)
+            class C {
+                def m() {
+                    // this should be affected
+                }
             }
             scriptMethod()
-            new MyClass().myMethod()
-            '''
+            new C().m()
+        '''
+        def mocker = new StubFor(Thread)
         def counter = new CountingThread()
-        def mocker = new StubFor(Thread.class)
         mocker.demand.currentThread(1..Integer.MAX_VALUE) { counter }
         mocker.use {
-            new GroovyShell(ThreadInterruptibleASTTransformation.getClassLoader()).evaluate(script)
+            shell.evaluate(script)
         }
-        // 1 is once for myMethod()
-        assert 1 == counter.interruptedCheckCount
+        assert counter.interruptedCheckCount == 1 // once for m()
     }
 
     @Test
     void testThreadInterruptOnAbstractClass() {
         def script = '''
-            @groovy.transform.ThreadInterrupt
-            abstract class MyAbstractClass {
-                abstract void myMethod()
+            @ThreadInterrupt
+            abstract class A {
+                abstract void m()
             }
 
-            class Concrete extends MyAbstractClass {
-                void myMethod() {
+            class C extends A {
+                void m() {
                     99.times {
                         // do something
                     }
                 }
             }
 
-            new Concrete().myMethod()
+            new C().m()
         '''
-        def mocker = new StubFor(Thread.class)
+        def mocker = new StubFor(Thread)
         mocker.demand.currentThread(1..Integer.MAX_VALUE) { new InterruptingThread() }
         mocker.use {
-            shouldFail(InterruptedException) {
-                new GroovyShell(ThreadInterruptibleASTTransformation.getClassLoader()).evaluate(script)
-            }
+            shouldFail(shell, InterruptedException, script)
         }
-
     }
 }
 
-class InterruptingThread extends Thread {
+//--------------------------------------------------------------------------
+
+class CountingThread extends Thread {
+    int interruptedCheckCount = 0
     @Override
     boolean isInterrupted() {
-        true
+        interruptedCheckCount += 1
+        false
     }
 }
 
-class CountingThread extends Thread {
-    def interruptedCheckCount = 0
-
+class InterruptingThread extends Thread {
     @Override
     boolean isInterrupted() {
-        interruptedCheckCount++
-        false
+        true
     }
 }
 
+@groovy.transform.InheritConstructors
 class CustomException extends Exception {
-    CustomException(final String message) {
-        super(message)
-    }
-}
\ No newline at end of file
+}
diff --git a/src/test/groovy/transform/TimedInterruptTest.groovy b/src/test/groovy/transform/TimedInterruptTest.groovy
index adbc74a02b..b4aadbde3e 100644
--- a/src/test/groovy/transform/TimedInterruptTest.groovy
+++ b/src/test/groovy/transform/TimedInterruptTest.groovy
@@ -19,271 +19,249 @@
 package groovy.transform
 
 import groovy.mock.interceptor.StubFor
-import groovy.test.GroovyTestCase
+import org.codehaus.groovy.control.CompilerConfiguration
+import org.codehaus.groovy.control.MultipleCompilationErrorsException
+import org.codehaus.groovy.control.customizers.ImportCustomizer
+import org.junit.Test
 
-import java.util.concurrent.TimeUnit
 import java.util.concurrent.TimeoutException
-import org.codehaus.groovy.control.MultipleCompilationErrorsException
-import org.codehaus.groovy.transform.TimedInterruptibleASTTransformation
+
+import static groovy.test.GroovyAssert.assertScript
+import static groovy.test.GroovyAssert.shouldFail
 
 /**
- * Test for TimedInterrupt.
+ * Tests for the {@link TimedInterrupt} AST transform.
  */
-class TimedInterruptTest extends GroovyTestCase {
-
-  void testClassMethodIsVisited() {
-    def c = new GroovyClassLoader().parseClass('''
-      import groovy.transform.TimedInterrupt
-
-      @TimedInterrupt(value = 1L)
-      class MyClass {
-        def myMethod() { }
-      }
-    ''')
-    assertPassesNormalFailsSlowExecution(c)
-  }
-
-  void testClassMethodIsVisitedAndCustomExceptionThrown() {
-    def c = new GroovyClassLoader(this.class.classLoader).parseClass('''
-      import groovy.transform.TimedInterrupt
-
-      @TimedInterrupt(thrown=groovy.transform.CustomException,value = 1L)
-      class MyClass {
-        def myMethod() { }
-      }
-    ''')
-    assertPassesNormalFailsSlowExecution(c, 1000000666L, '1', 'myMethod', CustomException)
-  }
-
-  void testScriptMethodIsVisited() {
-    def c = new GroovyClassLoader().parseClass('''
-      import groovy.transform.TimedInterrupt
-
-      @TimedInterrupt(value = 1L)
-      def myMethod() { }
-    ''')
-    assertPassesNormalFailsSlowExecution(c)
-  }
-
-  void testStaticMethodIsNotVisited() {
-    def c = new GroovyClassLoader().parseClass('''
-      import groovy.transform.TimedInterrupt
-
-      @TimedInterrupt(value = 1L)
-      class MyClass {
-        static def myMethod() { }
-      }
-    ''')
-    assertPassesSlowExecution(c)
-  }
-
-  void testClosureFieldIsVisited() {
-    def c = new GroovyClassLoader().parseClass('''
-      import groovy.transform.TimedInterrupt
-
-      @TimedInterrupt(value = 1L)
-      class MyClass {
-        def myMethod = { }
-      }
-    ''')
-    assertPassesNormalFailsSlowExecution(c)
-  }
-
-  void testClosureInScriptIsVisited_CheckOnMethodStartIsFalse() {
-    def c = new GroovyClassLoader().parseClass('''
-      import groovy.transform.TimedInterrupt
-
-      @TimedInterrupt(checkOnMethodStart = false, value = 1L)
-      def myMethod = { }
-      myMethod()
-    ''')
-    assertPassesNormalFailsSlowExecution(c, 1000000666L, '1', 'run')
-  }
-
-  void testWhileInScriptIsVisited_CheckOnMethodStartIsFalse() {
-    def c = new GroovyClassLoader().parseClass('''
-      @TimedInterrupt(checkOnMethodStart = false, value = 1L)
-      import groovy.transform.TimedInterrupt
-      import java.util.concurrent.TimeUnit
-
-      int x = 1
-      while (x < 2) { x = 2 }
-    ''')
-    assertPassesNormalFailsSlowExecution(c, 1000000666L, '1', 'run')
-  }
-
-  void testForInScriptIsVisited_CheckOnMethodStartIsFalse() {
-    def c = new GroovyClassLoader().parseClass('''
-      @TimedInterrupt(checkOnMethodStart = false, value = 1L)
-      import groovy.transform.TimedInterrupt
-
-      def x = [1]
-      for (def o : x) { o++ }
-    ''')
-    assertPassesNormalFailsSlowExecution(c, 1000000666L, '1', 'run')
-  }
-
-  void testStaticClosureFieldNotVisited() {
-    def c = new GroovyClassLoader().parseClass('''
-      import groovy.transform.TimedInterrupt
-
-      @TimedInterrupt(value = 1L)
-      class MyClass {
-        static def myMethod = { }
-      }
-    ''')
-    assertPassesSlowExecution(c)
-  }
-
-  void testAnnotationParameters() {
-    def c = new GroovyClassLoader().parseClass('''
-      import groovy.transform.TimedInterrupt
-      import java.util.concurrent.TimeUnit
-
-      @TimedInterrupt(value = 18000000L, unit = TimeUnit.MILLISECONDS)
-      def myMethod() { }
-    ''')
-    assertPassesNormalFailsSlowExecution(c, 18000000000666, '18000000', 'myMethod', TimeoutException, 'milliseconds') //5 hours in future
-  }
-
-  // TODO not sure all these tests are pulling their weight - testing Groovy annotation type handing not subject
-  void testErrorHandling() {
-    shouldFail(MultipleCompilationErrorsException) {
-      new GroovyClassLoader().parseClass('''
-        import groovy.transform.TimedInterrupt
-        @TimedInterrupt(value = "5")
-        def myMethod() { }
-      ''')
+final class TimedInterruptTest {
+
+    private final GroovyShell shell = new GroovyShell(new CompilerConfiguration().addCompilationCustomizers(
+        new ImportCustomizer().tap {
+            addStarImports('groovy.transform')
+            addStaticStars(TimedInterruptTest.name)
+            addImport('groovy.mock.interceptor.StubFor')
+        }
+    ))
+
+    @Test
+    void testClassMethodIsVisited() {
+        assertScript shell, '''
+            @TimedInterrupt(applyToAllClasses=false, value=1L)
+            class C {
+                def m() { }
+            }
+            assertPassesNormalFailsSlowExecution(C, methodName: 'm')
+        '''
     }
 
-    shouldFail(MultipleCompilationErrorsException) {
-      new GroovyClassLoader().parseClass('''
-        import groovy.transform.TimedInterrupt
-        @TimedInterrupt(value = foo())
-        def myMethod() { }
-      ''')
+    @Test
+    void testClassMethodIsVisitedAndCustomExceptionThrown() {
+        assertScript shell, '''
+            @TimedInterrupt(applyToAllClasses=false, thrown=CustomException, value=1L)
+            class C {
+                def m() { }
+            }
+            assertPassesNormalFailsSlowExecution(C, methodName: 'm', exception: CustomException)
+        '''
     }
 
-    shouldFail(MultipleCompilationErrorsException) {
-      new GroovyClassLoader().parseClass('''
-        import groovy.transform.TimedInterrupt
-        @TimedInterrupt(value = 5L, applyToAllClasses = 5)
-        def myMethod() { }
-      ''')
+    @Test
+    void testScriptMethodIsVisited() {
+        assertScript shell, '''
+            @TimedInterrupt(applyToAllClasses=false, value=1L) def m() { }
+            assertPassesNormalFailsSlowExecution(this.class, methodName: 'm')
+        '''
     }
 
-    shouldFail(MultipleCompilationErrorsException) {
-      new GroovyClassLoader().parseClass('''
-        import groovy.transform.TimedInterrupt
-        @TimedInterrupt(value = 5L, applyToAllClasses = foo())
-        def myMethod() { }
-      ''')
+    @Test
+    void testStaticMethodIsNotVisited() {
+        assertScript shell, '''
+            @TimedInterrupt(applyToAllClasses=false, value=1L)
+            class C {
+                static myMethod() { }
+            }
+            assertPassesSlowExecution(C)
+        '''
     }
 
-    shouldFail(MultipleCompilationErrorsException) {
-      new GroovyClassLoader().parseClass('''
-        import groovy.transform.TimedInterrupt
-        @TimedInterrupt(value = 5L, checkOnMethodStart = 5)
-        def myMethod() { }
-      ''')
+    @Test
+    void testClosureFieldIsVisited() {
+        assertScript shell, '''
+            @TimedInterrupt(applyToAllClasses=false, value=1L)
+            class C {
+                def m = { -> }
+            }
+            assertPassesNormalFailsSlowExecution(C, methodName: 'm')
+        '''
     }
 
-    shouldFail(MultipleCompilationErrorsException) {
-      new GroovyClassLoader().parseClass('''
-        import groovy.transform.TimedInterrupt
-        @TimedInterrupt(value = 5L, checkOnMethodStart = foo())
-        def myMethod() { }
-      ''')
+    @Test
+    void testClosureInScriptIsVisited_CheckOnMethodStartIsFalse() {
+        def script = shell.parse '''
+            @TimedInterrupt(applyToAllClasses=false, applyToAllMembers=false, checkOnMethodStart=false, value=1L)
+            def m = { -> }
+            m()
+        '''
+        assertPassesNormalFailsSlowExecution(script.class, methodName: 'run')
     }
 
-    shouldFail(MultipleCompilationErrorsException) {
-      new GroovyClassLoader().parseClass('''
-        import groovy.transform.TimedInterrupt
-        @TimedInterrupt(value = 5L, unit = 5)
-        def myMethod() { }
-      ''')
+    @Test
+    void testWhileInScriptIsVisited_CheckOnMethodStartIsFalse() {
+        def script = shell.parse '''
+            @TimedInterrupt(applyToAllClasses=false, checkOnMethodStart=false, value=1L)
+            int x = 1
+            while (x < 2) { x = 2 }
+        '''
+        assertPassesNormalFailsSlowExecution(script.class, methodName: 'run')
     }
 
-    shouldFail(MultipleCompilationErrorsException) {
-      new GroovyClassLoader().parseClass('''
-        import groovy.transform.TimedInterrupt
-        @TimedInterrupt(value = 5L, unit = foo())
-        def myMethod() { }
-      ''')
+    @Test
+    void testForInScriptIsVisited_CheckOnMethodStartIsFalse() {
+        def script = shell.parse '''
+            @TimedInterrupt(applyToAllClasses=false, checkOnMethodStart=false, value=1L)
+            def x = [1]
+            for (def o : x) { o++ }
+        '''
+        assertPassesNormalFailsSlowExecution(script.class, methodName: 'run')
     }
-  }
-
-  void testTimedInterruptOnAbstractClass() {
-    def script = '''
-      @groovy.transform.TimedInterrupt(value = 1L)
-      abstract class MyAbstractClass {
-        abstract void myMethod()
-      }
-
-      class Concrete extends MyAbstractClass {
-        void myMethod() {
-          99.times {
-            // do something
-          }
-        }
-      }
-      new Concrete()
-    '''
 
-    def system = new StubFor(System)
+    @Test
+    void testStaticClosureFieldNotVisited() {
+        assertScript shell, '''
+            @TimedInterrupt(applyToAllClasses=false, value=1L)
+            class C {
+                static myMethod = { -> }
+            }
+            assertPassesSlowExecution(C)
+        '''
+    }
 
-    // start time initialized to the Long of the Beast
-    system.demand.nanoTime(4) { 666L } // 2 times to cover full instantiation
-    system.demand.nanoTime() { 1000000667L }
+    @Test
+    void testAnnotationParameters() {
+        assertScript shell, '''
+            import static java.util.concurrent.TimeUnit.*
 
-    system.use {
-      def instance = new GroovyShell(TimedInterruptibleASTTransformation.getClassLoader()).evaluate(script)
-      // may get false positives if multiple annotations with the same expireTime defined in test script
-      assert instance.dump().matches('.*timedInterrupt\\S+\\$expireTime=1000000666 .*')
+            @TimedInterrupt(applyToAllClasses=false, value=18000000L, unit=MILLISECONDS)
+            def myMethod() { }
 
-      shouldFail(TimeoutException) {
-        instance.myMethod()
-      }
+            assertPassesNormalFailsSlowExecution(this.class, expireTime: 18000000000666L, units: '18000000', timeUnitName: 'milliseconds') // 5 hours in future
+        '''
     }
-  }
-
-  private void assertPassesNormalFailsSlowExecution(c, long expireTime=1000000666L, units='1', methodName='myMethod', exception=TimeoutException, timeUnitName='seconds') {
-    def system = new StubFor(System)
-    // start time initialized to the Long of the Beast
-    system.demand.nanoTime() { 666L }
-    def instance
-    system.use {
-      instance = c.newInstance()
-    }
-    // may get false positives if multiple annotations with the same expireTime defined in test script
-    assert instance.dump().matches('.*timedInterrupt\\S+\\$expireTime=' + expireTime + ' .*')
 
-    system.demand.nanoTime() { expireTime }
-    system.use {
-      instance."$methodName"()
+    @Test // TODO: not sure all these tests are pulling their weight - testing Groovy annotation type handing not subject
+    void testErrorHandling() {
+        shouldFail shell, MultipleCompilationErrorsException, '''
+            @TimedInterrupt(value = "5")
+            def myMethod() { }
+        '''
+
+        shouldFail shell, MultipleCompilationErrorsException, '''
+            @TimedInterrupt(value = foo())
+            def myMethod() { }
+        '''
+
+        shouldFail shell, MultipleCompilationErrorsException, '''
+            @TimedInterrupt(value = 5L, applyToAllClasses = 5)
+            def myMethod() { }
+        '''
+
+        shouldFail shell, MultipleCompilationErrorsException, '''
+            @TimedInterrupt(value = 5L, applyToAllClasses = foo())
+            def myMethod() { }
+        '''
+
+        shouldFail shell, MultipleCompilationErrorsException, '''
+            @TimedInterrupt(value = 5L, checkOnMethodStart = 5)
+            def myMethod() { }
+        '''
+
+        shouldFail shell, MultipleCompilationErrorsException, '''
+            @TimedInterrupt(value = 5L, checkOnMethodStart = foo())
+            def myMethod() { }
+        '''
+
+        shouldFail shell, MultipleCompilationErrorsException, '''
+            @TimedInterrupt(value = 5L, unit = 5)
+            def myMethod() { }
+        '''
+
+        shouldFail shell, MultipleCompilationErrorsException, '''
+            @TimedInterrupt(value = 5L, unit = foo())
+            def myMethod() { }
+        '''
     }
 
-    // one nanosecond too slow
-    system.demand.nanoTime() { expireTime + 1 }
-    system.use {
-      def e = shouldFail(exception) {
-        instance."$methodName"()
-      }
-      assert e.contains('Execution timed out after ' + units + ' ' + timeUnitName)
+    @Test
+    void testTimedInterruptOnAbstractClass() {
+        def script = '''
+            @TimedInterrupt(value = 1L)
+            abstract class A {
+                abstract void m()
+            }
+            class C extends A {
+                void m() {
+                    99.times {
+                        // do something
+                    }
+                }
+            }
+            new C()
+        '''
+        def system = new StubFor(System)
+        // start time initialized to the Long of the Beast
+        system.demand.nanoTime(4) { 666L } // 2 times to cover full instantiation
+        system.demand.nanoTime() { 1000000667L }
+        system.use {
+            def instance = shell.evaluate(script)
+            // may get false positives if multiple annotations with the same expireTime defined in test script
+            assert instance.dump().matches('.*timedInterrupt\\S+\\$expireTime=1000000666 .*')
+
+            shouldFail(TimeoutException) {
+                instance.m()
+            }
+        }
     }
-  }
-
-  private void assertPassesSlowExecution(c) {
-    def system = new StubFor(System)
-    // start time initialized to the Long of the Beast
-    system.demand.nanoTime() { 666L }
-    def instance
-    system.use {
-      instance = c.newInstance()
+
+    //--------------------------------------------------------------------------
+
+    static void assertPassesNormalFailsSlowExecution(Map<String,?> args, Class type) {
+        def system = new StubFor(System)
+        // start time initialized to ...
+        system.demand.nanoTime() { 666L }
+        def instance
+        system.use {
+            instance = type.newInstance()
+        }
+        long expireTime = args.getOrDefault('expireTime', 1000000666L)
+        String methodName = args.getOrDefault('methodName', 'myMethod')
+        // may get false positives if multiple annotations with the same expireTime defined
+        assert instance.dump().matches('.*timedInterrupt\\S+\\$expireTime=' + expireTime + ' .*')
+
+        system.demand.nanoTime() { expireTime }
+        system.use {
+            instance.(methodName)()
+        }
+
+        // one nanosecond too slow
+        system.demand.nanoTime() { expireTime + 1 }
+        system.use {
+            def err = shouldFail(args.getOrDefault('exception', java.util.concurrent.TimeoutException)) {
+                instance.(methodName)()
+            }
+            assert err.message.contains('Execution timed out after ' + args.getOrDefault('units', '1') + ' ' + args.getOrDefault('timeUnitName', 'seconds'))
+        }
     }
-    system.demand.nanoTime() { 1000000667L }
-    system.use {
-      instance.myMethod()
+
+    static void assertPassesSlowExecution(Class c) {
+        def system = new StubFor(System)
+        // start time initialized to the Long of the Beast
+        system.demand.nanoTime() { 666L }
+        def instance
+        system.use {
+            instance = c.newInstance()
+        }
+        system.demand.nanoTime() { 1000000667L }
+        system.use {
+            instance.myMethod()
+        }
     }
-  }
 }
diff --git a/src/test/org/codehaus/groovy/classgen/asm/ClosureWriterGeneratedAnnotationTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/ClosureWriterGeneratedAnnotationTest.groovy
index dba3b22467..9fbcabe848 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/ClosureWriterGeneratedAnnotationTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/ClosureWriterGeneratedAnnotationTest.groovy
@@ -19,7 +19,6 @@
 package org.codehaus.groovy.classgen.asm
 
 import groovy.transform.Generated
-import junit.framework.TestCase
 import org.codehaus.groovy.control.CompilationUnit
 import org.codehaus.groovy.control.Phases
 import org.junit.Test
@@ -27,22 +26,21 @@ import org.junit.Test
 /**
  * Verifies if {@link Generated} annotations are added on {@code call} methods of generated closure classes.
  */
-class ClosureWriterGeneratedAnnotationTest extends TestCase {
-    private CompilationUnit compileScript(String scriptText) {
-        CompilationUnit compilationUnit = new CompilationUnit()
-        compilationUnit.addSource("script", scriptText)
-        compilationUnit.compile(Phases.ALL)
+final class ClosureWriterGeneratedAnnotationTest {
 
-        compilationUnit
+    private CompilationUnit compileScript(String script) {
+        new CompilationUnit().tap {
+            addSource('script', script)
+            compile(Phases.CLASS_GENERATION)
+        }
     }
 
     private Collection<Class> findGeneratedClosureClasses(String outerClassName, CompilationUnit compilationUnit) {
-        Collection<Class> generatedClosureClasses = []
+        List<Class> generatedClosureClasses = []
         compilationUnit.classes.each {
             generatedClosureClasses.add(compilationUnit.classLoader.defineClass(it.name, it.bytes))
         }
-
-        return generatedClosureClasses.findAll({ it.name.matches(/.*${ outerClassName }\$\_.*\_closure.*/) })
+        generatedClosureClasses.findAll { it.name =~ /${outerClassName}\$\_.*\_closure/ }
     }
 
     /**
@@ -50,19 +48,18 @@ class ClosureWriterGeneratedAnnotationTest extends TestCase {
      */
     @Test
     void testClosureWithNoParameters() {
-        String scriptText = """    
-        class MyClass {
-            void myMethod() {
-                [1..3].each {
-                    println it
+        String scriptText = '''
+            class MyClass {
+                void myMethod() {
+                    [1..3].each {
+                        println it
+                    }
                 }
             }
-        }
-        """
-
+        '''
         CompilationUnit compilationUnit = compileScript(scriptText)
-        Class myClosureClassCompiled = findGeneratedClosureClasses("MyClass", compilationUnit)[0]
-        Collection callMethods = myClosureClassCompiled.declaredMethods.findAll { it.name == "call" }
+        Class myClosureClassCompiled = findGeneratedClosureClasses('MyClass', compilationUnit)[0]
+        Collection callMethods = myClosureClassCompiled.declaredMethods.findAll { it.name == 'call' }
 
         assert callMethods.size() == 0
     }
@@ -72,19 +69,18 @@ class ClosureWriterGeneratedAnnotationTest extends TestCase {
      */
     @Test
     void testClosureWithSingleParameter() {
-        String scriptText = """    
-        class MyClass {
-            void myMethod() {
-                [1..3].each { Integer myInt ->
-                    println myInt
+        String scriptText = '''
+            class MyClass {
+                void myMethod() {
+                    [1..3].each { Integer myInt ->
+                        println myInt
+                    }
                 }
             }
-        }
-        """
-
+        '''
         CompilationUnit compilationUnit = compileScript(scriptText)
-        Class myClosureClassCompiled = findGeneratedClosureClasses("MyClass", compilationUnit)[0]
-        Collection callMethodCollection = myClosureClassCompiled.declaredMethods.findAll { it.name == "call" }
+        Class myClosureClassCompiled = findGeneratedClosureClasses('MyClass', compilationUnit)[0]
+        Collection callMethodCollection = myClosureClassCompiled.declaredMethods.findAll { it.name == 'call' }
 
         assert callMethodCollection.size() == 1
         assert callMethodCollection[0].getAnnotation(Generated)
@@ -96,19 +92,18 @@ class ClosureWriterGeneratedAnnotationTest extends TestCase {
      */
     @Test
     void testClosureWithMultipleParameters() {
-        String scriptText = """    
-        class MyClass {
-            void myMethod() {
-                [1..3].eachWithIndex { IntRange entry, Integer i ->
-                    println entry[i]
+        String scriptText = '''
+            class MyClass {
+                void myMethod() {
+                    [1..3].eachWithIndex { IntRange entry, Integer i ->
+                        println entry[i]
+                    }
                 }
             }
-        }
-        """
-
+        '''
         CompilationUnit compilationUnit = compileScript(scriptText)
-        Class myClosureClassCompiled = findGeneratedClosureClasses("MyClass", compilationUnit)[0]
-        Collection callMethodCollection = myClosureClassCompiled.declaredMethods.findAll { it.name == "call" }
+        Class myClosureClassCompiled = findGeneratedClosureClasses('MyClass', compilationUnit)[0]
+        Collection callMethodCollection = myClosureClassCompiled.declaredMethods.findAll { it.name == 'call' }
 
         assert callMethodCollection.size() == 1
         assert callMethodCollection[0].getAnnotation(Generated)
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
index 5576b16354..68181ad0c7 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
@@ -931,8 +931,7 @@ import groovy.transform.TypeCheckingMode
 
     // GROOVY-6095
     void testServletError() {
-        def shell = new GroovyShell()
-        shell.evaluate '''
+        assertScript '''
             @Grab('javax.servlet:javax.servlet-api:3.0.1')
             import groovy.transform.CompileStatic
 
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileClosureGeneratedAnnotationTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileClosureGeneratedAnnotationTest.groovy
index e9641a5c0f..634a6b10dc 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileClosureGeneratedAnnotationTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileClosureGeneratedAnnotationTest.groovy
@@ -19,7 +19,6 @@
 package org.codehaus.groovy.classgen.asm.sc
 
 import groovy.transform.Generated
-import junit.framework.TestCase
 import org.codehaus.groovy.control.CompilationUnit
 import org.codehaus.groovy.control.Phases
 import org.junit.Test
@@ -29,22 +28,21 @@ import java.lang.reflect.Method
 /**
  * Verifies if {@link Generated} annotations are added on {@code call} methods of generated closure classes when static compilation is used.
  */
-class StaticCompileClosureGeneratedAnnotationTest extends TestCase {
-    private CompilationUnit compileScript(String scriptText) {
-        CompilationUnit compilationUnit = new CompilationUnit()
-        compilationUnit.addSource("script", scriptText)
-        compilationUnit.compile(Phases.ALL)
+final class StaticCompileClosureGeneratedAnnotationTest {
 
-        compilationUnit
+    private CompilationUnit compileScript(String script) {
+        new CompilationUnit().tap {
+            addSource('script', script)
+            compile(Phases.CLASS_GENERATION)
+        }
     }
 
     private Collection<Class> findGeneratedClosureClasses(String outerClassName, CompilationUnit compilationUnit) {
-        Collection<Class> generatedClosureClasses = []
+        List<Class> generatedClosureClasses = []
         compilationUnit.classes.each {
             generatedClosureClasses.add(compilationUnit.classLoader.defineClass(it.name, it.bytes))
         }
-
-        return generatedClosureClasses.findAll({ it.name.matches(/.*${ outerClassName }\$\_.*\_closure.*/) })
+        generatedClosureClasses.findAll { it.name =~ /${outerClassName}\$\_.*\_closure/ }
     }
 
     /**
@@ -52,20 +50,19 @@ class StaticCompileClosureGeneratedAnnotationTest extends TestCase {
      */
     @Test
     void testClosureWithNoParameters() {
-        String scriptText = """
-        @groovy.transform.CompileStatic
-        class MyClass {
-            void myMethod() {
-                [1..3].each {
-                    println it
+        String scriptText = '''
+            @groovy.transform.CompileStatic
+            class MyClass {
+                void myMethod() {
+                    [1..3].each {
+                        println it
+                    }
                 }
             }
-        }
-        """
-
+        '''
         CompilationUnit compilationUnit = compileScript(scriptText)
-        Class myClosureClassCompiled = findGeneratedClosureClasses("MyClass", compilationUnit)[0]
-        Collection callMethodCollection = myClosureClassCompiled.declaredMethods.findAll { it.name == "call" }
+        Class myClosureClassCompiled = findGeneratedClosureClasses('MyClass', compilationUnit)[0]
+        Collection callMethodCollection = myClosureClassCompiled.declaredMethods.findAll { it.name == 'call' }
 
         assert callMethodCollection.size() == 2
         callMethodCollection.each { Method method ->
@@ -80,20 +77,19 @@ class StaticCompileClosureGeneratedAnnotationTest extends TestCase {
      */
     @Test
     void testClosureWithSingleParameter() {
-        String scriptText = """
-        @groovy.transform.CompileStatic
-        class MyClass {
-            void myMethod() {
-                [1..3].each { IntRange myIntRange ->
-                  println myIntRange
+        String scriptText = '''
+            @groovy.transform.CompileStatic
+            class MyClass {
+                void myMethod() {
+                    [1..3].each { IntRange myIntRange ->
+                      println myIntRange
+                    }
                 }
             }
-        }
-        """
-
+        '''
         CompilationUnit compilationUnit = compileScript(scriptText)
-        Class myClosureClassCompiled = findGeneratedClosureClasses("MyClass", compilationUnit)[0]
-        Collection callMethodCollection = myClosureClassCompiled.declaredMethods.findAll { it.name == "call" }
+        Class myClosureClassCompiled = findGeneratedClosureClasses('MyClass', compilationUnit)[0]
+        Collection callMethodCollection = myClosureClassCompiled.declaredMethods.findAll { it.name == 'call' }
 
         assert callMethodCollection.size() == 1
         assert callMethodCollection[0].getAnnotation(Generated)
@@ -105,20 +101,19 @@ class StaticCompileClosureGeneratedAnnotationTest extends TestCase {
      */
     @Test
     void testClosureWithMultipleParameters() {
-        String scriptText = """
-        @groovy.transform.CompileStatic
-        class MyClass {
-            void myMethod() {
-                [1..3].eachWithIndex { IntRange entry, Integer i ->
-                    println entry[i]
+        String scriptText = '''
+            @groovy.transform.CompileStatic
+            class MyClass {
+                void myMethod() {
+                    [1..3].eachWithIndex { IntRange entry, Integer i ->
+                        println entry[i]
+                    }
                 }
             }
-        }
-        """
-
+        '''
         CompilationUnit compilationUnit = compileScript(scriptText)
-        Class myClosureClassCompiled = findGeneratedClosureClasses("MyClass", compilationUnit)[0]
-        Collection callMethodCollection = myClosureClassCompiled.declaredMethods.findAll { it.name == "call" }
+        Class myClosureClassCompiled = findGeneratedClosureClasses('MyClass', compilationUnit)[0]
+        Collection callMethodCollection = myClosureClassCompiled.declaredMethods.findAll { it.name == 'call' }
 
         assert callMethodCollection.size() == 1
         assert callMethodCollection[0].getAnnotation(Generated)
diff --git a/src/test/org/codehaus/groovy/transform/classloading/TransformsAndCustomClassLoadersTest.groovy b/src/test/org/codehaus/groovy/transform/classloading/TransformsAndCustomClassLoadersTest.groovy
index e1884bbae1..bc8a0b66c0 100644
--- a/src/test/org/codehaus/groovy/transform/classloading/TransformsAndCustomClassLoadersTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/classloading/TransformsAndCustomClassLoadersTest.groovy
@@ -113,7 +113,7 @@ final class TransformsAndCustomClassLoadersTest {
         try (def loader = new GroovyClassLoader(this.class.classLoader)) {
             def unit = new CompilationUnit(null, null, dependencyLoader, transformLoader)
             unit.addSource('Foo.groovy', source)
-            unit.compile()
+            unit.compile(CompilePhase.CLASS_GENERATION.phaseNumber)
 
             assert unit.classes.size() == 1
             def classInfo = unit.classes[0]


[groovy] 02/02: add `GroovyShell#withConfig(Closure)` and refactor some unit tests

Posted by em...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch GROOVY_4_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 53657938bb19b2685e859df9d691a7cc1d8f659e
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sun Apr 24 10:30:25 2022 -0500

    add `GroovyShell#withConfig(Closure)` and refactor some unit tests
---
 .../builder/CompilerCustomizationBuilder.groovy    | 36 ++++-----
 src/main/java/groovy/grape/Grape.java              |  6 +-
 src/main/java/groovy/lang/GroovyShell.java         | 23 +++++-
 .../customizers/builder/CustomizersFactory.java    | 15 ++--
 .../typing/TypeCheckingExtensionSpecTest.groovy    | 14 ++--
 .../bugs/DirectMethodCallWithVargsTest.groovy      | 93 ++++++++--------------
 .../transform/ConditionalInterruptTest.groovy      | 12 ++-
 src/test/groovy/transform/LazyTest.groovy          | 10 +--
 src/test/groovy/transform/ReadWriteLockTest.groovy | 14 ++--
 .../groovy/transform/ThreadInterruptTest.groovy    | 12 ++-
 .../groovy/transform/TimedInterruptTest.groovy     | 14 ++--
 .../groovy/transform/stc/MethodCallsSTCTest.groovy | 15 ++--
 .../groovy/transform/AutoCloneTransformTest.groovy |  8 +-
 .../groovy/transform/AutoFinalTransformTest.groovy |  7 +-
 14 files changed, 123 insertions(+), 156 deletions(-)

diff --git a/src/main/groovy/org/codehaus/groovy/control/customizers/builder/CompilerCustomizationBuilder.groovy b/src/main/groovy/org/codehaus/groovy/control/customizers/builder/CompilerCustomizationBuilder.groovy
index 2ed466d315..c300c50d55 100644
--- a/src/main/groovy/org/codehaus/groovy/control/customizers/builder/CompilerCustomizationBuilder.groovy
+++ b/src/main/groovy/org/codehaus/groovy/control/customizers/builder/CompilerCustomizationBuilder.groovy
@@ -19,6 +19,7 @@
 
 package org.codehaus.groovy.control.customizers.builder
 
+import groovy.transform.AutoFinal
 import groovy.transform.CompileStatic
 import org.codehaus.groovy.control.CompilerConfiguration
 
@@ -27,22 +28,28 @@ import org.codehaus.groovy.control.CompilerConfiguration
  * various compilation customizers by hand, you may use this builder instead, which provides a
  * shorter syntax and removes most of the verbosity.
  */
-@CompileStatic
+@AutoFinal @CompileStatic
 class CompilerCustomizationBuilder extends FactoryBuilderSupport {
-    CompilerCustomizationBuilder() {
-        registerFactories()
-    }
 
-    static CompilerConfiguration withConfig(CompilerConfiguration config,
-                                            @DelegatesTo(type = 'org.codehaus.groovy.control.customizers.builder.CompilerCustomizationBuilder') Closure code) {
-        CompilerCustomizationBuilder builder = new CompilerCustomizationBuilder()
-        config.invokeMethod('addCompilationCustomizers', builder.invokeMethod('customizers', code))
+    static CompilerConfiguration withConfig(CompilerConfiguration config, @DelegatesTo(type='org.codehaus.groovy.control.customizers.builder.CompilerCustomizationBuilder') Closure spec) {
+        config.invokeMethod('addCompilationCustomizers', new CompilerCustomizationBuilder().invokeMethod('customizers', spec))
         config
     }
 
+    //--------------------------------------------------------------------------
+
+    CompilerCustomizationBuilder() {
+        registerFactory('customizers', new CustomizersFactory()) // root
+
+        registerFactory('ast', new ASTTransformationCustomizerFactory())
+        registerFactory('imports', new ImportCustomizerFactory())
+        registerFactory('inline', new InlinedASTCustomizerFactory())
+        registerFactory('secureAst', new SecureASTCustomizerFactory())
+        registerFactory('source', new SourceAwareCustomizerFactory())
+    }
+
     @Override
-    @SuppressWarnings('Instanceof')
-    protected Object postNodeCompletion(final Object parent, final Object node) {
+    protected Object postNodeCompletion(Object parent, Object node) {
         Object value = super.postNodeCompletion(parent, node)
         Object factory = getContextAttribute(CURRENT_FACTORY)
         if (factory instanceof PostCompletionFactory) {
@@ -51,13 +58,4 @@ class CompilerCustomizationBuilder extends FactoryBuilderSupport {
         }
         value
     }
-
-    private void registerFactories() {
-        registerFactory('ast', new ASTTransformationCustomizerFactory())
-        registerFactory('customizers', new CustomizersFactory())
-        registerFactory('imports', new ImportCustomizerFactory())
-        registerFactory('inline', new InlinedASTCustomizerFactory())
-        registerFactory('secureAst', new SecureASTCustomizerFactory())
-        registerFactory('source', new SourceAwareCustomizerFactory())
-    }
 }
diff --git a/src/main/java/groovy/grape/Grape.java b/src/main/java/groovy/grape/Grape.java
index 78e346ba43..5e71bf3b76 100644
--- a/src/main/java/groovy/grape/Grape.java
+++ b/src/main/java/groovy/grape/Grape.java
@@ -18,7 +18,6 @@
  */
 package groovy.grape;
 
-import java.lang.reflect.InvocationTargetException;
 import java.net.URI;
 import java.security.PrivilegedAction;
 import java.util.Collections;
@@ -121,10 +120,9 @@ public class Grape {
         if (instance == null) {
             try {
                 // by default use GrapeIvy
-                //TODO META-INF/services resolver?
+                // TODO: META-INF/services resolver?
                 instance = (GrapeEngine) Class.forName("groovy.grape.GrapeIvy").getDeclaredConstructor().newInstance();
-            } catch (InstantiationException | ClassNotFoundException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
-                //LOGME
+            } catch (ReflectiveOperationException ignore) {
             }
         }
         return instance;
diff --git a/src/main/java/groovy/lang/GroovyShell.java b/src/main/java/groovy/lang/GroovyShell.java
index 6630356cc6..e167823d04 100644
--- a/src/main/java/groovy/lang/GroovyShell.java
+++ b/src/main/java/groovy/lang/GroovyShell.java
@@ -39,6 +39,7 @@ import java.security.PrivilegedExceptionAction;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import static org.codehaus.groovy.control.ResolveVisitor.EMPTY_STRING_ARRAY;
 import static org.codehaus.groovy.runtime.InvokerHelper.MAIN_METHOD_NAME;
 
 /**
@@ -47,17 +48,35 @@ import static org.codehaus.groovy.runtime.InvokerHelper.MAIN_METHOD_NAME;
 public class GroovyShell extends GroovyObjectSupport {
 
     public static final String DEFAULT_CODE_BASE = "/groovy/shell";
-    private static final String[] EMPTY_STRING_ARRAY = new String[0];
+    private static final String CONFIGURATION_CUSTOMIZER = "org.codehaus.groovy.control.customizers.builder.CompilerCustomizationBuilder";
 
     private final Binding context;
     private final AtomicInteger counter = new AtomicInteger(0);
     private final CompilerConfiguration config;
     private final GroovyClassLoader loader;
 
-    public static void main(String[] args) {
+    public static void main(final String[] args) {
         GroovyMain.main(args);
     }
 
+    /**
+     * @since 4.0.3
+     */
+    public static GroovyShell withConfig(@DelegatesTo(type = CONFIGURATION_CUSTOMIZER) final Closure<Void> spec) {
+        //TODO return new GroovyShell(CompilerCustomizationBuilder.withConfig(new CompilerConfiguration(), spec));
+        CompilerConfiguration config = new CompilerConfiguration();
+        try {
+            Class.forName(CONFIGURATION_CUSTOMIZER)
+                .getDeclaredMethod("withConfig", CompilerConfiguration.class, Closure.class)
+                .invoke(null, config, spec);
+        } catch (ReflectiveOperationException e) {
+            throw new GroovyRuntimeException(e);
+        }
+        return new GroovyShell(config);
+    }
+
+    //--------------------------------------------------------------------------
+
     public GroovyShell() {
         this(null, new Binding());
     }
diff --git a/src/main/java/org/codehaus/groovy/control/customizers/builder/CustomizersFactory.java b/src/main/java/org/codehaus/groovy/control/customizers/builder/CustomizersFactory.java
index 4f86a90156..c9b512acd4 100644
--- a/src/main/java/org/codehaus/groovy/control/customizers/builder/CustomizersFactory.java
+++ b/src/main/java/org/codehaus/groovy/control/customizers/builder/CustomizersFactory.java
@@ -22,9 +22,8 @@ import groovy.util.AbstractFactory;
 import groovy.util.FactoryBuilderSupport;
 import org.codehaus.groovy.control.customizers.CompilationCustomizer;
 
+import java.util.ArrayList;
 import java.util.Collection;
-import java.util.LinkedList;
-import java.util.List;
 import java.util.Map;
 
 /**
@@ -32,29 +31,25 @@ import java.util.Map;
  *
  * @since 2.1.0
  */
+@SuppressWarnings({"unchecked","rawtypes"})
 public class CustomizersFactory extends AbstractFactory implements PostCompletionFactory {
-    private static final CompilationCustomizer[] EMPTY_COMPILATIONCUSTOMIZER_ARRAY = new CompilationCustomizer[0];
 
     @Override
     public Object newInstance(final FactoryBuilderSupport builder, final Object name, final Object value, final Map attributes) throws InstantiationException, IllegalAccessException {
-        return new LinkedList();
+        return new ArrayList();
     }
 
     @Override
-    @SuppressWarnings("unchecked")
     public void setChild(final FactoryBuilderSupport builder, final Object parent, final Object child) {
         if (parent instanceof Collection && child instanceof CompilationCustomizer) {
             ((Collection) parent).add(child);
         }
     }
 
-
     @Override
-    @SuppressWarnings("unchecked")
     public Object postCompleteNode(final FactoryBuilderSupport factory, final Object parent, final Object node) {
-        if (node instanceof List) {
-            List col = (List) node;
-            return col.toArray(EMPTY_COMPILATIONCUSTOMIZER_ARRAY);
+        if (node instanceof Collection) {
+            return ((Collection) node).toArray(new CompilationCustomizer[0]);
         }
         return node;
     }
diff --git a/src/spec/test/typing/TypeCheckingExtensionSpecTest.groovy b/src/spec/test/typing/TypeCheckingExtensionSpecTest.groovy
index 56e19d3262..7da5b6ff7f 100644
--- a/src/spec/test/typing/TypeCheckingExtensionSpecTest.groovy
+++ b/src/spec/test/typing/TypeCheckingExtensionSpecTest.groovy
@@ -22,13 +22,11 @@ import groovy.test.GroovyAssert
 import groovy.test.GroovyTestCase
 import groovy.transform.TypeChecked
 import groovy.xml.MarkupBuilder
-import org.codehaus.groovy.control.CompilerConfiguration
 import org.codehaus.groovy.control.MultipleCompilationErrorsException
-import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
 
 import static asciidoctor.Utils.stripAsciidocMarkup
 
-class TypeCheckingExtensionSpecTest extends GroovyTestCase {
+final class TypeCheckingExtensionSpecTest extends GroovyTestCase {
 
     void testIntro() {
         def out = new PrintWriter(new ByteArrayOutputStream())
@@ -613,13 +611,11 @@ new DelegateTest().delegate()
     }
 
     private def assertScriptWithExtension(String extensionName, String code, Closure<Void> configurator=null) {
-        def config = new CompilerConfiguration()
-        config.addCompilationCustomizers(
-                new ASTTransformationCustomizer(TypeChecked, extensions:[extensionName]))
-        def binding = new Binding()
-        def shell = new GroovyShell(binding,config)
+        def shell = GroovyShell.withConfig {
+            ast(TypeChecked, extensions: [extensionName])
+        }
         if (configurator) {
-            configurator.call(binding)
+            configurator.call(shell.context)
         }
         shell.evaluate(code)
     }
diff --git a/src/test/groovy/bugs/DirectMethodCallWithVargsTest.groovy b/src/test/groovy/bugs/DirectMethodCallWithVargsTest.groovy
index bbdd658c97..1abd390f12 100644
--- a/src/test/groovy/bugs/DirectMethodCallWithVargsTest.groovy
+++ b/src/test/groovy/bugs/DirectMethodCallWithVargsTest.groovy
@@ -18,29 +18,23 @@
  */
 package groovy.bugs
 
-import groovy.test.GroovyTestCase
 import org.codehaus.groovy.ast.ClassCodeVisitorSupport
-import org.codehaus.groovy.control.SourceUnit
-import org.codehaus.groovy.ast.expr.MethodCallExpression
 import org.codehaus.groovy.ast.MethodNode
-import org.codehaus.groovy.control.CompilerConfiguration
-import org.codehaus.groovy.control.customizers.CompilationCustomizer
-import org.codehaus.groovy.control.CompilePhase
-import org.codehaus.groovy.classgen.GeneratorContext
-import org.codehaus.groovy.ast.ClassNode
+import org.codehaus.groovy.ast.expr.MethodCallExpression
+import org.codehaus.groovy.control.SourceUnit
+import org.junit.Test
+
+import static groovy.test.GroovyAssert.assertScript
 
-class DirectMethodCallWithVargsTest extends GroovyTestCase {
+final class DirectMethodCallWithVargsTest {
 
+    @Test
     void testDirectMethodCallWithVargs() {
-        def config = new CompilerConfiguration()
-        config.addCompilationCustomizers(
-                new MyCustomizer()
-        )
-        GroovyShell shell = new GroovyShell(config)
-        shell.evaluate '''
+        assertScript shell, '''
             def foo(String... args) {
                 (args as List).join(',')
             }
+
             assert foo() == ''
             assert foo('1') == '1'
             assert foo('1','2','3') == '1,2,3'
@@ -50,20 +44,16 @@ class DirectMethodCallWithVargsTest extends GroovyTestCase {
             def b = '2'
             def c = '3'
             assert foo(a,b,c) == '1,2,3'
-
         '''
     }
 
+    @Test
     void testDirectMethodCallWithPrimitiveVargs() {
-        def config = new CompilerConfiguration()
-        config.addCompilationCustomizers(
-                new MyCustomizer()
-        )
-        GroovyShell shell = new GroovyShell(config)
-        shell.evaluate '''
+        assertScript shell, '''
             def foo(int... args) {
                 (args as List).join(',')
             }
+
             assert foo() == ''
             assert foo(1) == '1'
             assert foo(1,2,3) == '1,2,3'
@@ -71,16 +61,13 @@ class DirectMethodCallWithVargsTest extends GroovyTestCase {
         '''
     }
 
-    void testDirectMethodCallWithArgPlusVargs() {
-        def config = new CompilerConfiguration()
-        config.addCompilationCustomizers(
-                new MyCustomizer()
-        )
-        GroovyShell shell = new GroovyShell(config)
-        shell.evaluate '''
+    @Test
+    void testDirectMethodCallWithArgumentAndVargs() {
+        assertScript shell, '''
             def foo(String prefix, String... args) {
                 prefix+(args as List).join(',')
             }
+
             assert foo('A') == 'A'
             assert foo('A','1') == 'A1'
             assert foo('A','1','2','3') == 'A1,2,3'
@@ -90,20 +77,16 @@ class DirectMethodCallWithVargsTest extends GroovyTestCase {
             def b = '2'
             def c = '3'
             assert foo('A',a,b,c) == 'A1,2,3'
-
         '''
     }
 
-    void testDirectMethodCallWithPrefixAndPrimitiveVargs() {
-        def config = new CompilerConfiguration()
-        config.addCompilationCustomizers(
-                new MyCustomizer()
-        )
-        GroovyShell shell = new GroovyShell(config)
-        shell.evaluate '''
+    @Test
+    void testDirectMethodCallWithArgumentAndPrimitiveVargs() {
+        assertScript shell, '''
             def foo(int prefix, int... args) {
                 "$prefix"+(args as List).join(',')
             }
+
             assert foo(1) == '1'
             assert foo(1,1) == '11'
             assert foo(1,1,2,3) == '11,2,3'
@@ -111,50 +94,36 @@ class DirectMethodCallWithVargsTest extends GroovyTestCase {
         '''
     }
 
-    private static class MyCustomizer extends CompilationCustomizer {
+    //--------------------------------------------------------------------------
 
-        MyCustomizer() {
-            super(CompilePhase.CANONICALIZATION)
-        }
-
-        @Override
-        void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) {
-            def visitor = new MethodCallVisitor(source)
-            classNode.methods.each { visitor.visitMethod(it) }
+    private final GroovyShell shell = GroovyShell.withConfig {
+        inline(phase: 'CANONICALIZATION') { sourceUnit, x, classNode ->
+            def visitor = new MethodCallVisitor(sourceUnit)
+            classNode.methods.each(visitor.&acceptMethod)
             visitor.visitClass(classNode)
         }
     }
 
     private static class MethodCallVisitor extends ClassCodeVisitorSupport {
-        private final SourceUnit unit
         private MethodNode fooMethod
+        final SourceUnit sourceUnit
 
-        MethodCallVisitor(SourceUnit source) {
-            unit = source
-        }
-
-        @Override
-        protected SourceUnit getSourceUnit() {
-            return unit
+        MethodCallVisitor(final SourceUnit unit) {
+            sourceUnit = unit
         }
 
-        @Override
-        void visitMethod(final MethodNode node) {
-            super.visitMethod(node)
-            if (node.name=='foo') {
+        void acceptMethod(final MethodNode node) {
+            if (node.name == 'foo') {
                 fooMethod = node
             }
         }
 
-
         @Override
         void visitMethodCallExpression(final MethodCallExpression call) {
             super.visitMethodCallExpression(call)
-            if (call.methodAsString=='foo') {
+            if (call.methodAsString == 'foo') {
                 call.methodTarget = fooMethod
             }
         }
-
-
     }
 }
diff --git a/src/test/groovy/transform/ConditionalInterruptTest.groovy b/src/test/groovy/transform/ConditionalInterruptTest.groovy
index cb86990292..330c9914a0 100644
--- a/src/test/groovy/transform/ConditionalInterruptTest.groovy
+++ b/src/test/groovy/transform/ConditionalInterruptTest.groovy
@@ -18,8 +18,6 @@
  */
 package groovy.transform
 
-import org.codehaus.groovy.control.CompilerConfiguration
-import org.codehaus.groovy.control.customizers.ImportCustomizer
 import org.junit.Test
 
 import static groovy.test.GroovyAssert.assertScript
@@ -29,12 +27,12 @@ import static groovy.test.GroovyAssert.assertScript
  */
 final class ConditionalInterruptTest {
 
-    private final GroovyShell shell = new GroovyShell(new CompilerConfiguration().addCompilationCustomizers(
-        new ImportCustomizer().tap {
-            addStarImports('groovy.transform')
-            addStaticImport('groovy.test.GroovyAssert', 'shouldFail')
+    private final GroovyShell shell = GroovyShell.withConfig {
+        imports {
+            star 'groovy.transform'
+            staticMember 'groovy.test.GroovyAssert', 'shouldFail'
         }
-    ))
+    }
 
     @Test
     void testMethodIsVisited_AndExceptionMessage() {
diff --git a/src/test/groovy/transform/LazyTest.groovy b/src/test/groovy/transform/LazyTest.groovy
index bdfc19e059..c16d54f595 100644
--- a/src/test/groovy/transform/LazyTest.groovy
+++ b/src/test/groovy/transform/LazyTest.groovy
@@ -18,8 +18,6 @@
  */
 package groovy.transform
 
-import org.codehaus.groovy.control.CompilerConfiguration
-import org.codehaus.groovy.control.customizers.ImportCustomizer
 import org.junit.Test
 
 import static groovy.test.GroovyAssert.assertScript
@@ -29,9 +27,11 @@ import static groovy.test.GroovyAssert.assertScript
  */
 final class LazyTest {
 
-    private final GroovyShell shell = new GroovyShell(new CompilerConfiguration().addCompilationCustomizers(
-        new ImportCustomizer().tap { addStaticStars('java.lang.reflect.Modifier') }
-    ))
+    private final GroovyShell shell = GroovyShell.withConfig {
+        imports {
+            staticStar 'java.lang.reflect.Modifier'
+        }
+    }
 
     @Test
     void testLazyPrimitiveWrapping() {
diff --git a/src/test/groovy/transform/ReadWriteLockTest.groovy b/src/test/groovy/transform/ReadWriteLockTest.groovy
index 7a77bb05a9..91e7de5f4e 100644
--- a/src/test/groovy/transform/ReadWriteLockTest.groovy
+++ b/src/test/groovy/transform/ReadWriteLockTest.groovy
@@ -18,8 +18,6 @@
  */
 package groovy.transform
 
-import org.codehaus.groovy.control.CompilerConfiguration
-import org.codehaus.groovy.control.customizers.ImportCustomizer
 import org.junit.Test
 
 import static groovy.test.GroovyAssert.assertScript
@@ -30,13 +28,13 @@ import static groovy.test.GroovyAssert.shouldFail
  */
 final class ReadWriteLockTest {
 
-    private final GroovyShell shell = new GroovyShell(new CompilerConfiguration().addCompilationCustomizers(
-        new ImportCustomizer().tap {
-            addStarImports('groovy.transform')
-            addStaticStars('java.lang.reflect.Modifier')
-            addImport('java.util.concurrent.locks.ReentrantReadWriteLock')
+    private final GroovyShell shell = GroovyShell.withConfig {
+        imports {
+            star 'groovy.transform'
+            staticStar 'java.lang.reflect.Modifier'
+            normal 'java.util.concurrent.locks.ReentrantReadWriteLock'
         }
-    ))
+    }
 
     @Test
     void testLockFieldDefaultsForReadLock() {
diff --git a/src/test/groovy/transform/ThreadInterruptTest.groovy b/src/test/groovy/transform/ThreadInterruptTest.groovy
index bc7f3a2b22..95cd0242ec 100644
--- a/src/test/groovy/transform/ThreadInterruptTest.groovy
+++ b/src/test/groovy/transform/ThreadInterruptTest.groovy
@@ -20,8 +20,6 @@ package groovy.transform
 
 import groovy.mock.interceptor.StubFor
 import org.codehaus.groovy.ast.MethodNode
-import org.codehaus.groovy.control.CompilerConfiguration
-import org.codehaus.groovy.control.customizers.ImportCustomizer
 import org.codehaus.groovy.transform.ThreadInterruptibleASTTransformation
 import org.junit.After
 import org.junit.Before
@@ -39,12 +37,12 @@ import static org.junit.Assume.assumeTrue
  */
 final class ThreadInterruptTest {
 
-    private final GroovyShell shell = new GroovyShell(new CompilerConfiguration().addCompilationCustomizers(
-        new ImportCustomizer().tap {
-            addStarImports('groovy.transform')
-            addImport('groovy.mock.interceptor.StubFor')
+    private final GroovyShell shell = GroovyShell.withConfig {
+        imports {
+            star 'groovy.transform'
+            normal 'groovy.mock.interceptor.StubFor'
         }
-    ))
+    }
     private static final boolean jdk12plus = isAtLeastJdk('12.0')
     private Map<String, MethodNode> oldValues = [:]
 
diff --git a/src/test/groovy/transform/TimedInterruptTest.groovy b/src/test/groovy/transform/TimedInterruptTest.groovy
index b4aadbde3e..2108c83a26 100644
--- a/src/test/groovy/transform/TimedInterruptTest.groovy
+++ b/src/test/groovy/transform/TimedInterruptTest.groovy
@@ -19,9 +19,7 @@
 package groovy.transform
 
 import groovy.mock.interceptor.StubFor
-import org.codehaus.groovy.control.CompilerConfiguration
 import org.codehaus.groovy.control.MultipleCompilationErrorsException
-import org.codehaus.groovy.control.customizers.ImportCustomizer
 import org.junit.Test
 
 import java.util.concurrent.TimeoutException
@@ -34,13 +32,13 @@ import static groovy.test.GroovyAssert.shouldFail
  */
 final class TimedInterruptTest {
 
-    private final GroovyShell shell = new GroovyShell(new CompilerConfiguration().addCompilationCustomizers(
-        new ImportCustomizer().tap {
-            addStarImports('groovy.transform')
-            addStaticStars(TimedInterruptTest.name)
-            addImport('groovy.mock.interceptor.StubFor')
+    private final GroovyShell shell = GroovyShell.withConfig {
+        imports {
+            star 'groovy.transform'
+            staticStar TimedInterruptTest.name
+            normal 'groovy.mock.interceptor.StubFor'
         }
-    ))
+    }
 
     @Test
     void testClassMethodIsVisited() {
diff --git a/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy b/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
index 779c84f4f8..3b11fc9e83 100644
--- a/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
@@ -20,7 +20,8 @@ package groovy.transform.stc
 
 import org.codehaus.groovy.control.MultipleCompilationErrorsException
 import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
-import org.codehaus.groovy.control.customizers.ImportCustomizer
+
+import static org.codehaus.groovy.control.customizers.builder.CompilerCustomizationBuilder.withConfig
 
 /**
  * Unit tests for static type checking : method calls.
@@ -29,11 +30,13 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase {
 
     @Override
     protected void configure() {
-        config.addCompilationCustomizers(new ImportCustomizer().tap {
-            addImport('A', 'groovy.transform.stc.MethodCallsSTCTest.MyMethodCallTestClass' )
-            addImport('B', 'groovy.transform.stc.MethodCallsSTCTest.MyMethodCallTestClass2')
-            addImport('C', 'groovy.transform.stc.MethodCallsSTCTest.MyMethodCallTestClass3')
-        })
+        withConfig(config) {
+            imports {
+                alias 'A', 'groovy.transform.stc.MethodCallsSTCTest.MyMethodCallTestClass'
+                alias 'B', 'groovy.transform.stc.MethodCallsSTCTest.MyMethodCallTestClass2'
+                alias 'C', 'groovy.transform.stc.MethodCallsSTCTest.MyMethodCallTestClass3'
+            }
+        }
     }
 
     void testMethodCallOnInstance() {
diff --git a/src/test/org/codehaus/groovy/transform/AutoCloneTransformTest.groovy b/src/test/org/codehaus/groovy/transform/AutoCloneTransformTest.groovy
index c0d2674863..81b3d60613 100644
--- a/src/test/org/codehaus/groovy/transform/AutoCloneTransformTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/AutoCloneTransformTest.groovy
@@ -18,8 +18,6 @@
  */
 package org.codehaus.groovy.transform
 
-import org.codehaus.groovy.control.CompilerConfiguration
-import org.codehaus.groovy.control.customizers.ImportCustomizer
 import org.junit.Test
 
 import static groovy.test.GroovyAssert.assertScript
@@ -30,9 +28,9 @@ import static groovy.test.GroovyAssert.shouldFail
  */
 final class AutoCloneTransformTest {
 
-    private final GroovyShell shell = new GroovyShell(new CompilerConfiguration().
-        addCompilationCustomizers(new ImportCustomizer().tap { addImports('groovy.transform.AutoClone') })
-    )
+    private final GroovyShell shell = GroovyShell.withConfig {
+        imports { normal 'groovy.transform.AutoClone' }
+    }
 
     @Test
     void testBasics() {
diff --git a/src/test/org/codehaus/groovy/transform/AutoFinalTransformTest.groovy b/src/test/org/codehaus/groovy/transform/AutoFinalTransformTest.groovy
index 854b788e6e..99422ffa13 100644
--- a/src/test/org/codehaus/groovy/transform/AutoFinalTransformTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/AutoFinalTransformTest.groovy
@@ -18,7 +18,6 @@
  */
 package org.codehaus.groovy.transform
 
-import org.codehaus.groovy.control.CompilerConfiguration
 import org.codehaus.groovy.control.customizers.*
 import org.junit.Test
 
@@ -30,9 +29,9 @@ import static groovy.test.GroovyAssert.shouldFail
  */
 final class AutoFinalTransformTest {
 
-    private final GroovyShell shell = new GroovyShell(new CompilerConfiguration().
-        addCompilationCustomizers(new ImportCustomizer().tap { addImports('groovy.transform.AutoFinal', 'groovy.transform.ASTTest') })
-    )
+    private final GroovyShell shell = GroovyShell.withConfig {
+        imports { normal 'groovy.transform.AutoFinal', 'groovy.transform.ASTTest' }
+    }
 
     @Test
     void testAutoFinalOnClass() {