blob: 2b84924f2481c1d75b32c29af295de65946524c0 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package groovy.util.logging
import groovy.test.GroovyTestCase
import java.lang.reflect.Field
import java.lang.reflect.Modifier
import static groovy.test.GroovyAssert.isAtLeastJdk
/**
* Unit test for the commons logging @Log based annotation.
*/
class CommonsTest extends GroovyTestCase {
PrintStream savedSystemOut
ByteArrayOutputStream redirectedSystemOut
void setUp() {
super.setUp()
savedSystemOut = System.out
redirectedSystemOut = new ByteArrayOutputStream()
System.out = new PrintStream(redirectedSystemOut)
}
void tearDown() {
super.tearDown()
System.out = savedSystemOut
}
void testPrivateFinalStaticLogFieldAppears() {
Class clazz = new GroovyClassLoader().parseClass('''
@groovy.util.logging.Commons
class MyClass {
} ''')
assert clazz.declaredFields.find { Field field ->
field.name == "log" &&
Modifier.isPrivate(field.getModifiers()) &&
Modifier.isStatic(field.getModifiers()) &&
Modifier.isTransient(field.getModifiers()) &&
Modifier.isFinal(field.getModifiers())
}
}
void testExplicitPrivateFinalStaticLogFieldAppears() {
Class clazz = new GroovyClassLoader().parseClass('''
import static groovy.transform.options.Visibility.*
@groovy.transform.VisibilityOptions(value = PRIVATE)
@groovy.util.logging.Commons
class MyClass {
}
''')
assert clazz.declaredFields.find { Field field ->
field.name == "log" &&
Modifier.isPrivate(field.getModifiers()) &&
Modifier.isStatic(field.getModifiers()) &&
Modifier.isTransient(field.getModifiers()) &&
Modifier.isFinal(field.getModifiers())
}
}
void testPackagePrivateFinalStaticLogFieldAppears() {
Class clazz = new GroovyClassLoader().parseClass('''
import static groovy.transform.options.Visibility.*
@groovy.transform.VisibilityOptions(value = PACKAGE_PRIVATE)
@groovy.util.logging.Commons
class MyClass {
}
''')
assert clazz.declaredFields.find { Field field ->
field.name == "log" &&
!Modifier.isPrivate(field.getModifiers()) &&
!Modifier.isProtected(field.getModifiers()) &&
!Modifier.isPublic(field.getModifiers()) &&
Modifier.isStatic(field.getModifiers()) &&
Modifier.isTransient(field.getModifiers()) &&
Modifier.isFinal(field.getModifiers())
}
}
void testProtectedFinalStaticLogFieldAppears() {
Class clazz = new GroovyClassLoader().parseClass('''
import static groovy.transform.options.Visibility.*
@groovy.transform.VisibilityOptions(value = PROTECTED)
@groovy.util.logging.Commons
class MyClass {
}
''')
assert clazz.declaredFields.find { Field field ->
field.name == "log" &&
Modifier.isProtected(field.getModifiers()) &&
Modifier.isStatic(field.getModifiers()) &&
Modifier.isTransient(field.getModifiers()) &&
Modifier.isFinal(field.getModifiers())
}
}
void testPublicFinalStaticLogFieldAppears() {
Class clazz = new GroovyClassLoader().parseClass('''
import static groovy.transform.options.Visibility.*
@groovy.transform.VisibilityOptions(value = PUBLIC)
@groovy.util.logging.Commons
class MyClass {
}
''')
assert clazz.declaredFields.find { Field field ->
field.name == "log" &&
Modifier.isPublic(field.getModifiers()) &&
Modifier.isStatic(field.getModifiers()) &&
Modifier.isTransient(field.getModifiers()) &&
Modifier.isFinal(field.getModifiers())
}
}
void testPrivateFinalStaticNamedLogFieldAppears() {
Class clazz = new GroovyClassLoader().parseClass('''
@groovy.util.logging.Commons('logger')
class MyClass {
} ''')
assert clazz.declaredFields.find { Field field ->
field.name == "logger" &&
Modifier.isPrivate(field.getModifiers()) &&
Modifier.isStatic(field.getModifiers()) &&
Modifier.isTransient(field.getModifiers()) &&
Modifier.isFinal(field.getModifiers())
}
}
void testClassAlreadyHasLogField() {
shouldFail {
Class clazz = new GroovyClassLoader().parseClass('''
@groovy.util.logging.Commons
class MyClass {
String log
} ''')
assert clazz.newInstance()
}
}
void testClassAlreadyHasNamedLogField() {
shouldFail {
Class clazz = new GroovyClassLoader().parseClass('''
@groovy.util.logging.Commons('logger')
class MyClass {
String logger
} ''')
assert clazz.newInstance()
}
}
void testLogLevelDebug() {
Class clazz = new GroovyClassLoader().parseClass('''
@groovy.util.logging.Commons
class MyClass {
def loggingMethod() {
log.error ("error called")
log.warn ("warn called")
log.info ("info called")
log.debug ("debug called")
}
}
new MyClass().loggingMethod() ''')
clazz.newInstance().run()
String log = redirectedSystemOut.toString()
assert log.contains("error called")
assert log.contains("warn called")
assert log.contains("info called")
assert log.contains("debug called")
}
void testLogFromStaticMethods() {
Class clazz = new GroovyClassLoader().parseClass("""
@groovy.util.logging.Commons
class MyClass {
static loggingMethod() {
log.info ("(static) info called")
}
}
MyClass.loggingMethod()""")
clazz.newInstance().run()
String log = redirectedSystemOut.toString()
assert log.contains("(static) info called")
}
void testNamedLogger() {
Class clazz = new GroovyClassLoader().parseClass('''
@groovy.util.logging.Commons('logger')
class MyClass {
def loggingMethod() {
logger.error ("error called")
logger.warn ("warn called")
logger.info ("info called")
logger.debug ("debug called")
}
}
new MyClass().loggingMethod() ''')
clazz.newInstance().run()
String log = redirectedSystemOut.toString()
assert log.contains("error called")
assert log.contains("warn called")
assert log.contains("info called")
assert log.contains("debug called")
}
void testLogGuards() {
// JDK12+ doesn't allow adjusting static final fields even via reflection
// so skip this test on such JDK versions - it is only this test which is affected
// and currently we have coverage from builds with lower JDK versions.
if (isAtLeastJdk('12')) return
Class clazz = new GroovyClassLoader().parseClass('''
class LogDecorator extends groovy.util.Proxy {
boolean isTraceEnabled() { false }
}
@groovy.util.logging.Commons
class MyClass {
boolean traceCalled = false
def loggingMethod() {
overrideLog()
log.trace (traceCalled = true)
}
def overrideLog() {
def field = MyClass.getDeclaredField('log')
field.accessible = true
def modifiersField = java.lang.reflect.Field.getDeclaredField("modifiers")
modifiersField.accessible = true
modifiersField.setInt(field, field.modifiers & ~java.lang.reflect.Modifier.FINAL)
field.set(null, new LogDecorator().wrap(log) as org.apache.commons.logging.Log)
}
}
def o = new MyClass()
o.loggingMethod()
o.traceCalled''')
Script s = (Script) clazz.newInstance()
def result = s.run()
assert !result
}
void testDefaultCategory() {
Class clazz = new GroovyClassLoader().parseClass("""
@groovy.util.logging.Commons
class MyClass {
static loggingMethod() {
log.error("error called")
}
}""")
clazz.newInstance().loggingMethod()
assert redirectedSystemOut.toString().contains('MyClass')
}
void testCustomCategory() {
Class clazz = new GroovyClassLoader().parseClass("""
@groovy.util.logging.Commons(category='customCategory')
class MyClass {
static loggingMethod() {
log.error("error called")
}
}""")
clazz.newInstance().loggingMethod()
assert redirectedSystemOut.toString().contains('customCategory')
}
}