Skip to content

Commit 25780a5

Browse files
committed
Merge pull request #9557 from pjungermann/issue_9952_9953
fix for issue #9952 and #9953
2 parents f149c62 + d911578 commit 25780a5

File tree

4 files changed

+224
-13
lines changed

4 files changed

+224
-13
lines changed

grails-plugin-testing/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ dependencies {
3030
runtime "cglib:cglib:${cglibVersion}"
3131

3232
provided "org.apache.ant:ant:${antVersion}"
33+
34+
testCompile "jline:jline:$jlineVersion"
3335
}
3436

3537
eclipse {

grails-plugin-testing/src/main/groovy/org/codehaus/groovy/grails/compiler/injection/test/IntegrationTestMixinTransformation.groovy

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2013 the original author or authors.
2+
* Copyright 2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,20 +16,19 @@
1616

1717
package org.codehaus.groovy.grails.compiler.injection.test
1818

19+
import grails.test.mixin.integration.Integration
20+
import grails.test.mixin.integration.IntegrationTestMixin
1921
import groovy.transform.CompileStatic
20-
import org.codehaus.groovy.transform.GroovyASTTransformation
21-
import org.codehaus.groovy.control.CompilePhase
22-
import org.codehaus.groovy.transform.ASTTransformation
2322
import org.codehaus.groovy.ast.ASTNode
24-
import org.codehaus.groovy.control.SourceUnit
25-
import org.codehaus.groovy.ast.AnnotationNode
2623
import org.codehaus.groovy.ast.AnnotatedNode
24+
import org.codehaus.groovy.ast.AnnotationNode
2725
import org.codehaus.groovy.ast.ClassNode
28-
import grails.test.mixin.TestMixin
29-
import grails.test.mixin.integration.Integration
30-
import org.codehaus.groovy.ast.expr.ListExpression
3126
import org.codehaus.groovy.ast.expr.ClassExpression
32-
import grails.test.mixin.integration.IntegrationTestMixin
27+
import org.codehaus.groovy.ast.expr.ListExpression
28+
import org.codehaus.groovy.control.CompilePhase
29+
import org.codehaus.groovy.control.SourceUnit
30+
import org.codehaus.groovy.transform.ASTTransformation
31+
import org.codehaus.groovy.transform.GroovyASTTransformation
3332

3433
/**
3534
* An AST transformation that automatically applies the IntegrationTestMixin to integration tests
@@ -39,9 +38,11 @@ import grails.test.mixin.integration.IntegrationTestMixin
3938
*/
4039
@CompileStatic
4140
@GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION)
42-
class IntegrationTestMixinTransformation implements ASTTransformation{
41+
class IntegrationTestMixinTransformation implements ASTTransformation {
42+
4343
public static final String OBJECT_CLASS = "java.lang.Object";
4444
private static final ClassNode MY_TYPE = new ClassNode(Integration);
45+
4546
@Override
4647
void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {
4748
final node = astNodes[0]
@@ -58,11 +59,24 @@ class IntegrationTestMixinTransformation implements ASTTransformation{
5859
ClassNode classNode = (ClassNode) parent;
5960
ListExpression listExpression = new ListExpression()
6061
listExpression.addExpression(new ClassExpression(new ClassNode(IntegrationTestMixin).getPlainNodeReference()))
61-
if(!isSubclassOf(classNode, "grails.test.spock.IntegrationSpec")) {
62+
if (isApplicableTo(classNode)) {
6263
new TestMixinTransformation().weaveMixinsIntoClass(classNode, listExpression)
6364
}
6465
}
6566

67+
private static boolean isApplicableTo(ClassNode classNode) {
68+
// isInterface covers "interface", "trait" and "annotation"
69+
// we could also identify "annotations" among them,
70+
// but there is no special treatment needed here
71+
return !classNode.isInterface() &&
72+
!isInnerClass(classNode) &&
73+
!isSubclassOf(classNode, "grails.test.spock.IntegrationSpec")
74+
}
75+
76+
private static boolean isInnerClass(ClassNode classNode) {
77+
return classNode.getOuterClass() != null
78+
}
79+
6680
private static boolean isSubclassOf(ClassNode classNode, String testType) {
6781
ClassNode currentSuper = classNode.getSuperClass();
6882
while (currentSuper != null && !currentSuper.getName().equals(OBJECT_CLASS)) {
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
/*
2+
* Copyright 2013 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package grails.test.mixin
18+
19+
import org.apache.tools.ant.BuildException
20+
import org.apache.tools.ant.Project
21+
import org.apache.tools.ant.types.Path
22+
import org.codehaus.groovy.grails.test.compiler.GrailsIntegrationTestCompiler
23+
import org.junit.rules.TemporaryFolder
24+
import spock.lang.Specification
25+
import spock.lang.Unroll
26+
27+
import java.lang.reflect.Field
28+
29+
/**
30+
* Tests for {@link org.codehaus.groovy.grails.compiler.injection.test.IntegrationTestMixinTransformation}
31+
* to verify that it only transforms the right classes and ignores the rest.
32+
*
33+
* @author patrick.jungermann
34+
* @since 12/01/16
35+
* @see <a href="https://github.com/grails/grails-core/issues/9552">https://github.com/grails/grails-core/issues/9552</a>
36+
* @see <a href="https://github.com/grails/grails-core/issues/9553">https://github.com/grails/grails-core/issues/9553</a>
37+
*/
38+
@Unroll
39+
class IntegrationTestMixinTransformationSpec extends Specification {
40+
41+
@SuppressWarnings("GroovyPointlessBoolean")
42+
void "IntegrationTestMixin should get applied to #type? #toBeApplied (class: #clazz)"(String type, Class clazz, boolean toBeApplied) {
43+
expect:
44+
clazz != null // class loading failed otherwise
45+
Field field = getDeclaredField(clazz, '$integrationTestMixin')
46+
toBeApplied == (field != null)
47+
48+
where:
49+
type | clazz || toBeApplied
50+
"class" | getJunit4TestClass() || true
51+
"interface" | getInterfaceClass() || false
52+
"trait" | getTraitClass() || false
53+
"annotation" | getAnnotationClass() || false
54+
"inner class" | getInnerClassOfJunit4TestClass() || false
55+
"static inner class" | getStaticInnerClassOfJunit4TestClass() || false
56+
"anonymous class" | getAnonymousClassOfJunit4TestClass() || false
57+
}
58+
59+
Field getDeclaredField(Class clazz, String name) {
60+
try {
61+
return clazz.getDeclaredField(name)
62+
63+
} catch (NoSuchFieldException ignore) {
64+
return null
65+
}
66+
}
67+
68+
Class getJunit4TestClass() {
69+
return compileClass('MyJunit4Test', '''
70+
class MyJunit4Test {
71+
72+
@org.junit.Test
73+
void testSomething() {
74+
grailsApplication != null
75+
applicationContext != null
76+
callMe()
77+
}
78+
}
79+
''')
80+
}
81+
82+
Class getInterfaceClass() {
83+
return compileClass('MyInterface', '''
84+
interface MyInterface {
85+
86+
void something()
87+
}
88+
''')
89+
}
90+
91+
Class getTraitClass() {
92+
return compileClass('MyTrait', '''
93+
trait MyTrait {
94+
95+
void something() {
96+
println "something"
97+
}
98+
}
99+
''')
100+
}
101+
102+
Class getAnnotationClass() {
103+
return compileClass('MyAnnotation', '''
104+
public @interface MyAnnotation {
105+
}
106+
''')
107+
}
108+
109+
Class getInnerClassOfJunit4TestClass() {
110+
return compileClass('MyJunit4Test', '''
111+
class MyJunit4Test {
112+
113+
@org.junit.Test
114+
void testSomething() {
115+
new InnerClass()
116+
}
117+
118+
class InnerClass {}
119+
}
120+
''', 'InnerClass')
121+
}
122+
123+
Class getStaticInnerClassOfJunit4TestClass() {
124+
return compileClass('MyJunit4Test', '''
125+
class MyJunit4Test {
126+
127+
@org.junit.Test
128+
void testSomething() {
129+
new StaticInnerClass()
130+
}
131+
132+
static class StaticInnerClass {}
133+
}
134+
''', 'StaticInnerClass')
135+
}
136+
137+
Class getAnonymousClassOfJunit4TestClass() {
138+
return compileClass('MyJunit4Test', '''
139+
class MyJunit4Test {
140+
141+
Runnable anonymousClassInstance = new Runnable() {
142+
143+
@Override
144+
void run() {
145+
}
146+
}
147+
148+
@org.junit.Test
149+
void testSomething() {
150+
grailsApplication != null
151+
applicationContext != null
152+
callMe()
153+
}
154+
}
155+
''', '1')
156+
}
157+
158+
Class compileClass(String name, String content, String innerClassToLoad = null) {
159+
// @Rule creation happens after the data table creation
160+
TemporaryFolder temp = new TemporaryFolder()
161+
temp.create()
162+
try {
163+
File srcDir = temp.newFolder()
164+
File destDir = temp.newFolder()
165+
File source = new File(srcDir, name + ".groovy")
166+
source.createNewFile()
167+
source.write(content, "UTF-8")
168+
169+
GrailsIntegrationTestCompiler compiler = new GrailsIntegrationTestCompiler()
170+
compiler.setProject(new Project())
171+
Path srcDirPath = new Path(compiler.getProject())
172+
srcDirPath.setLocation(srcDir)
173+
compiler.setSrcdir(srcDirPath)
174+
compiler.setDestdir(destDir)
175+
176+
compiler.execute()
177+
178+
GroovyClassLoader cl = new GroovyClassLoader()
179+
cl.addClasspath(destDir.canonicalPath)
180+
181+
Class clazz = cl.loadClass(name)
182+
if (innerClassToLoad) {
183+
clazz = cl.loadClass(name + '$' + innerClassToLoad)
184+
}
185+
return clazz
186+
187+
} catch (BuildException ignore) {
188+
// usually caused by org.codehaus.groovy.control.MultipleCompilationErrorsException
189+
return null
190+
191+
} finally {
192+
temp.delete()
193+
}
194+
}
195+
}

grails-resources/src/grails/plugin/grails-app/conf/BuildConfig.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ grails.project.dependency.resolution = {
4040
}
4141

4242
plugins {
43-
build(":release:3.1.1",
43+
build(":release:3.1.2",
4444
":rest-client-builder:2.1.1") {
4545
export = false
4646
}

0 commit comments

Comments
 (0)