blob: 9edf549148e1c624e2ab787d59f3e5a89a659706 [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
import static groovy.API.*
import static groovy.Container5087.*
import static groovy.Foo4964.*
import static groovy.Outer1.*
import static groovy.Outer2.Inner2
import static groovy.Outer2.Inner2 as InnerAlias2
import static groovy.StaticImportChild.*
import static groovy.StaticImportTarget.x
import static groovy.StaticImportTarget.z
import static java.lang.Boolean.FALSE as F
import static java.lang.Math.*
import static java.text.DateFormat.MEDIUM
import static java.text.DateFormat.MEDIUM as M
import static java.util.Calendar.getInstance as now
import static java.util.jar.Attributes.*
import static java.util.jar.Attributes.Name as AttrName
import static java.util.regex.Pattern.*
import static junit.framework.Assert.format
import org.codehaus.groovy.runtime.DefaultGroovyMethods as DGM
final class StaticImportTest extends groovy.test.GroovyTestCase {
void testFieldWithAliasInExpression() {
assert !F
}
void testMethodAndField() {
assert cos(2 * PI) == 1.0
}
static myStaticMethod() {
cos(2 * PI)
}
void testMethodAndFieldInStaticContext() {
assert myStaticMethod() == 1.0
}
void testMethodAndFieldInClosure() {
def closure = { cos(2 * PI) }
assert closure() == 1.0
}
void testFieldAsObjectExpression() {
assert PI.equals(Math.PI)
}
void testFieldAsArgumentList() {
assert ('' + PI.toString()).contains('3.14')
}
void testFieldAliasing() {
assert MEDIUM == M
}
// GROOVY-1809
void testMethodAliasing() {
// making this not possible on one line?
def now = now().time
assert now.class == Date
}
void testWildCardAliasing() {
assert MULTILINE == java.util.regex.Pattern.MULTILINE
}
private format(a, b, c, ignored) { format(a, b, c) }
void testMethodDefCanUseStaticallyImportedMethodWithSameNameButDiffArgs() {
assert format('different', 'abc', 'aBc', 3) == 'different expected:<abc> but was:<aBc>'
}
void testAssertEqualsFromJUnit() {
double[] values = [3.9999, 4.0001, 0.00021, 0.00019]
assertEquals(values[0], values[1], values[2])
shouldFail(junit.framework.AssertionFailedError) {
assertEquals(values[0], values[1], values[3])
}
}
void testStaticImportFromGroovy() {
def nonstaticval = new StaticImportTarget().y('he', 3)
def staticval = x('he', 3)
assert nonstaticval == staticval
}
void testStaticImportWithVarArgs() {
assert noArrayMethod('one', 1) == 'noArrayMethod(one, 1)'
assert API.arrayMethod('two', 1, 2, 3) == 'arrayMethod(two, 1, 2, 3)'
assert arrayMethod('three', 1, 2, 3) == 'arrayMethod(three, 1, 2, 3)'
}
void testStaticImportFromParentClass() {
assert cmethod() == 'hello from child'
assert pmethod() == 'hello from parent'
assert cfield == 21
assert pfield == 42
}
void testStaticImportAndDefaultValue() {
assertScript '''
import static Foo.*
import static Bar.*
class Bar {
static void bar() {
assert foo(10,1000) == 1010
assert foo(10) == 110
}
}
class Foo {
static int foo(int x, int y = 100) {x+y}
}
Bar.bar()
'''
}
// GROOVY-11180
void testStaticImportAndPackageScope() {
assertScript '''import groovy.transform.*
import static Foo.CONST
class Foo {
@PackageScope static final String CONST = "value"
}
assert CONST == "value"
'''
assertScript '''import groovy.transform.*
import static Foo.CONST
@PackageScope(PackageScopeTarget.FIELDS)
class Foo {
static final String CONST = "value"
}
assert CONST == "value"
'''
}
// GROOVY-11323
void testStaticImportAndInterfaceDefaultMethod() {
assertScript '''import static Bar.*
interface Foo {
default m() { 'Foo' }
}
class Bar {
static m() { 'Bar' }
}
class Baz implements Foo {
void test() {
assert m() == 'Foo'
}
}
new Baz().test()
'''
}
void testStaticImportProperty() {
for (imports in ['import static Foo.getX; import static Foo.setX', 'import static Foo.*']) {
assertScript """$imports
class Foo {
static x = 'foo'
}
assert x == 'foo'
x = 'bar'
assert getX() == 'bar'
setX('baz')
assert 'baz' == x
"""
assertScript """$imports
class Foo {
static x = 'foo'
static getX() { x + '_get' }
}
assert x == 'foo_get'
x = 'bar'
assert getX() == 'bar_get'
setX('baz')
assert 'baz_get' == x
"""
assertScript """$imports
class Foo {
static x = 'foo'
static void setX(newx) { x = newx + '_set' }
}
assert x == 'foo'
x = 'bar'
assert getX() == 'bar_set'
setX('baz')
assert 'baz_set' == x
"""
assertScript """$imports
class Foo {
static x = 'foo'
static getX() { x + '_get' }
static void setX(newx) { x = newx + '_set' }
}
assert x == 'foo_get'
x = 'bar'
assert getX() == 'bar_set_get'
setX('baz')
assert 'baz_set_get' == x
"""
}
}
void testStaticImportPropertyBooleanAlternative() {
for (imports in ['import static Foo.isX; import static Foo.setX', 'import static Foo.x', 'import static Foo.*']) {
assertScript """$imports
class Foo {
static x
static boolean isX() { !!x }
}
assert !x
x = true
assert isX()
setX(false)
assert !x
"""
assertScript """$imports
class Foo {
static x
static boolean isX() { !!x }
static void setX(newx) { x = newx }
}
assert !x
x = false
assert !isX()
setX(true)
assert x
"""
}
}
void testStaticImportPropertyWithPublicField() {
for (imports in ['import static Foo.x', 'import static Foo.*']) {
assertScript """$imports
class Foo {
public static x = 'foo'
}
assert x == 'foo'
x = 'bar'
assert x == 'bar'
x = 'baz'
assert x == 'baz'
"""
assertScript """$imports
class Foo {
public static x = 'foo'
static getX() { x + '_get' }
}
assert x == 'foo_get'
x = 'bar'
assert getX() == 'bar_get'
x = 'baz'
assert x == 'baz_get'
"""
assertScript """$imports
class Foo {
public static x = 'foo'
static void setX(newx) { x = newx + '_set' }
}
assert x == 'foo'
x = 'bar'
assert x == 'bar_set'
setX('baz')
assert x == 'baz_set'
"""
assertScript """$imports
class Foo {
public static x = 'foo'
static getX() { x + '_get' }
static void setX(newx) { x = newx + '_set' }
}
assert x == 'foo_get'
x = 'bar'
assert getX() == 'bar_set_get'
setX('baz')
assert x == 'baz_set_get'
"""
}
assertScript '''
import static Foo.getX; import static Foo.setX
class Foo { public static x = 'foo'; static getX() { x + '_get' }; static void setX(newx) { x = newx + '_set' } }
assert getX() == 'foo_get'; setX('bar'); assert getX() == 'bar_set_get'; setX('baz'); assert 'baz_set_get' == getX()
'''
}
void testStaticImportPropertyWithAliases() {
for (imports in ['import static Foo.getX as getZ; import static Foo.setX as setZ', 'import static Foo.x as z']) {
assertScript """$imports
class Foo {
static x = 'foo'
}
assert z == 'foo'
z = 'bar'
assert getZ() == 'bar'
setZ('baz')
assert z == 'baz'
"""
assertScript """$imports
class Foo {
static x = 'foo'
static getX() { x + '_get' }
}
assert z == 'foo_get'
z = 'bar'
assert getZ() == 'bar_get'
setZ('baz')
assert z == 'baz_get'
"""
assertScript """$imports
class Foo {
static x = 'foo'
static void setX(newx) { x = newx + '_set' }
}
assert z == 'foo'
z = 'bar'
assert getZ() == 'bar_set'
setZ('baz')
assert z == 'baz_set'
"""
assertScript """$imports
class Foo {
static x = 'foo'
static getX() { x + '_get' }
static void setX(newx) { x = newx + '_set' }
}
assert z == 'foo_get'
z = 'bar'
assert getZ() == 'bar_set_get'
setZ('baz')
assert z == 'baz_set_get'
"""
}
assertScript '''
import groovy.transform.CompileStatic
import static Pogo.setP as store
class Pogo {
static p
}
assert Pogo.p == null
@CompileStatic test() {
store('')
assert Pogo.p == ''
}
test()
'''
}
// GROOVY-9382, GROOVY-10133
void testStaticImportPropertyWithChoices() {
assertScript '''
import static Foo.isX
import static Foo.getX
class Foo {
static boolean isX() { true }
static boolean getX() { false }
}
assert x
'''
def err = shouldFail '''
import static Foo.isX
class Foo { static isX() {} }
x
'''
assert err =~ /No such property: x for class/
err = shouldFail '''
import static Foo.isX as isY
class Foo { static isX() {} }
y
'''
assert err =~ /No such property: y for class/
}
// GROOVY-8389, GROOVY-10329
void testStaticImportPropertyWithClosure() {
for (imports in ['import static Foo.bar; import static Foo.baz', 'import static Foo.*']) {
for (tag in ['@groovy.transform.CompileDynamic', '@groovy.transform.CompileStatic']) {
assertScript """$imports
class Foo {
static Closure<String> bar = { -> 'property' }
static Closure<String> baz = { -> 'property' }
}
String bar() {
'method'
}
$tag
String test() {
bar() + ':' + baz()
}
String result = test()
assert result == 'method:property'
"""
}
}
}
// GROOVY-8389
void testStaticImportMethodVsLocalMethod() {
assertScript '''
import static Foo.bar
class Foo {
static bar = 'foo'
}
def bar() {
'bar'
}
@groovy.transform.CompileStatic
def test() {
bar()
}
assert test() == 'bar'
'''
assertScript '''
import static Foo.bar
class Foo {
static bar = 'foo'
}
static bar() {
'bar'
}
@groovy.transform.CompileStatic
def test() {
bar()
}
assert test() == 'bar'
'''
assertScript '''
import static Foo.baz
import static Foo.bar
class Foo {
static bar() { 'foobar' }
static baz() { 'foobaz' }
}
def bar() {
'bar'
}
@groovy.transform.CompileStatic
def test() {
"${bar()}${baz()}"
}
assert test() == 'barfoobaz'
'''
assertScript '''
import static Foo.baz
import static Foo.bar
class Foo {
static bar() { 'foobar' }
static baz() { 'foobaz' }
}
static bar() {
'bar'
}
@groovy.transform.CompileStatic
def test() {
"${bar()}${baz()}"
}
assert test() == 'barfoobaz'
'''
}
// GROOVY-8145
void testStaticImportAnyVsGeneratedField() {
for (what in ['*','log']) {
assertScript """
import static Foo.$what
class Foo {
private static log = [info: Closure.IDENTITY]
}
@groovy.util.logging.Log
class Bar {
def test() {
log.info('bar')
}
}
assert new Bar().test() == null // return from logger
"""
}
for (which in ['public','protected','@groovy.transform.PackageScope']) {
assertScript """
import static Foo.*
class Foo {
$which static log = [info: Closure.IDENTITY]
}
@groovy.util.logging.Log
class Bar {
def test() {
log.info('bar')
}
}
assert new Bar().test() == 'bar'
"""
}
}
void testConstructorArgsAliasing() {
// not recommended style to use statics in constructors but supported
assertScript '''
class Foo {
static x
}
import static Foo.x as z
new Foo(z:'hi')
assert z == 'hi'
'''
}
void testMethodCallWithThisTargetIsNotResolvedToStaticallyImportedMethod() {
// not using shouldFail() to avoid closure scope
try {
this.z()
fail()
} catch (MissingMethodException expected) {}
}
void testMethodCallWithSuperTargetIsNotResolvedToStaticallyImportedMethod() {
// not using shouldFail() to avoid closure scope
try {
super.z()
fail()
} catch (MissingMethodException expected) {}
}
// GROOVY-3945, GROOVY-10329, GROOVY-11056
void testStaticImportOfClosureProperty() {
for (imports in ['import static groovy.StaticImportTarget.cl', 'import static groovy.StaticImportTarget.*']) {
assertScript """$imports
String result = cl()
assert result == 'StaticImportTarget#static closure called'
"""
assertScript """$imports
def fn = { -> cl() }
String result = fn()
assert result == 'StaticImportTarget#static closure called'
"""
}
assertScript """import static groovy.StaticImportTarget.cl as fn
String result = fn()
assert result == 'StaticImportTarget#static closure called'
"""
}
// GROOVY-7490, GROOVY-10329, GROOVY-11056
void testStaticImportOfCallableProperty() {
for (imports in ['import static Pogo.callable_property', 'import static Pogo.*']) {
for (use in ['@groovy.transform.CompileStatic caller()', 'def caller()', 'def caller =']) {
assertScript """$imports
class WithCall {
String call(String input) {
return input
}
}
class Pogo {
static final WithCall callable_property = new WithCall()
}
$use {
callable_property('works')
}
String result = caller()
assert result == 'works'
"""
}
}
}
// GROOVY-4145
void testStaticPropertyImportedImplementedAsGetter() {
assertScript '''
import static Groovy4145.foo4145
class Groovy4145 {
static getFoo4145() {
return 3
}
}
assert foo4145 == 3
'''
}
// GROOVY-4228
void testMethodCallExpressionInStaticContextWithInstanceVariableShouldFail() {
def err = shouldFail '''
class B {
def c = new Object()
static main(args) {
c.foo()
}
}
'''
assert err =~ /Apparent variable 'c' was found in a static scope but doesn't refer to a local variable, static field or class/
}
// GROOVY-10396
void testStaticImportVersusThisOrSuperMethod1() {
assertScript '''
import static groovy.Extension10396.*
static void test() {
println 'x'
}
strings.clear()
test()
assert 'x' in strings
'''
}
// GROOVY-10396
void testStaticImportVersusThisOrSuperMethod2() {
assertScript '''
import static groovy.Extension10396.*
def obj = new Object() { // outer class extends Script
String toString() {
println 'AIC::x'
super.toString()
}
}
strings.clear()
obj.toString()
assert 'x' !in strings
'''
}
// GROOVY-10396
void testStaticImportVersusThisOrSuperMethod3() {
assertScript '''
import static groovy.Extension10396.*
static void println(String s) { // static overload
}
static void test() {
println 'x'
}
strings.clear()
test()
assert 'x' !in strings
'''
}
void testStaticStarImportOfStaticInnerClass() {
assert Inner1.class.name == 'groovy.Outer1$Inner1'
}
void testStaticImportOfStaticInnerClass() {
assert Inner2.class.name == 'groovy.Outer2$Inner2'
}
void testStaticImportOfStaticInnerClassWithAlias() {
assert InnerAlias2.class.name == 'groovy.Outer2$Inner2'
}
void testStaticImportOfStaticInnerClassExistingExternalJar() {
assert Name.class.name == 'java.util.jar.Attributes$Name'
}
void testStaticImportOfStaticInnerClassExistingExternalJarWithAlias() {
assert AttrName.class.name == 'java.util.jar.Attributes$Name'
}
void testExplicitStaticMethodCallHasPrecedenceOverStaticImport() {
Bar4964.run()
}
void testMapIndexInLeftExpressionOfEquals() {
holder = 'foo'
def map = [:]
map[holder] = 'bar'
assert map.containsKey('foo')
assert map.foo == 'bar'
}
void testConstructorParamInLeftExpressionOfEquals() {
holder = [:]
new HolderWrapper(holder).foo = 'baz'
assert holder.foo == 'baz'
}
void testMethodParamInLeftExpressionOfEquals() {
holder = [[a:1, b:2], [c:3]]
DGM.find(holder) { it.size() == 2 }.a = 4
assert holder[0].a == 4
dgmFind(holder) { it.size() == 1 }.c = 7
assert holder[1].c == 7
}
private <T> T dgmFind(Collection<T> col, Closure clos) {
DGM.find(col, clos)
}
}
//------------------------------------------------------------------------------
class API {
static noArrayMethod(String s, int value) {
"noArrayMethod(${s}, ${value})"
}
static arrayMethod(String s, int[] values) {
"arrayMethod(${s}, " + values.toList().join(", ") + ")"
}
}
class StaticImportParent {
static pfield = 42
static pmethod() { 'hello from parent' }
}
class StaticImportChild extends StaticImportParent {
static cfield = 21
static cmethod() { 'hello from child' }
}
class Outer1 {
static class Inner1 {}
}
class Outer2 {
static class Inner2 {}
}
class Foo4964 {
static doIt() { [k: 'foo'] }
}
class Bar4964 {
static doIt() { [k: 'bar'] }
/*
The following `run` method is invoked by `testExplicitStaticMethodCallHasPrecedenceOverStaticImport`
As the method name shows, "ExplicitStaticMethodCall Has Precedence Over StaticImport", but the original test code does not conform to the intention
*/
static run() {
// The original test code is commented as follows:
// assert doIt().k == 'foo'
// assert doIt() == [k: 'foo']
assert doIt().k == 'bar'
assert doIt() == [k: 'bar']
assert Bar4964.doIt() == [k: 'bar']
assert Bar4964.doIt().k == 'bar'
}
}
class Container5087 {
static holder
}
class HolderWrapper {
def holder
HolderWrapper(holder) {
this.holder = holder
}
void setProperty(String name, Object value) {
holder[name] = value
}
}
class Extension10396 {
static final List<String> strings = []
static void println(String s) {
strings << s
}
}