blob: 341e68157f4131b8003f0496d623bb0e5b33b4e9 [file]
/*
* 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 gls.invocation
import groovy.test.GroovyTestCase
import groovy.transform.CompileStatic
@CompileStatic
final class DefaultParamTest extends GroovyTestCase {
void testDefaultParameterCausingDoubledMethod() {
//GROOVY-2191
shouldFail '''
def foo(String one, String two = "two") {"$one $two"}
def foo(String one, String two = "two", String three = "three") {"$one $two $three"}
'''
shouldFail '''
def foo(String one, String two = "two", String three = "three") {"$one $two $three"}
def foo(String one, String two = "two") {"$one $two"}
'''
shouldFail '''
def meth(Closure cl = null) {meth([:], cl)}
def meth(Map args = [:], Closure cl = null) {}
'''
}
void testDefaultParameters() {
assertScript '''
def doSomething(a, b = 'defB', c = 'defC') {
return a + "-" + b + "-" + c
}
assert "X-Y-Z" == doSomething("X", "Y", "Z")
assert "X-Y-defC" == doSomething("X", "Y")
assert "X-defB-defC" == doSomething("X")
'''
shouldFail '''
def doSomething(a, b = 'defB', c = 'defC') {
return a + "-" + b + "-" + c
}
doSomething()
'''
}
void testDefaultTypedParameters() {
assertScript '''
String doTypedSomething(String a = 'defA', String b = 'defB', String c = 'defC') {
a + "-" + b + "-" + c
}
assert "X-Y-Z" == doTypedSomething("X", "Y", "Z")
assert "X-Y-defC" == doTypedSomething("X", "Y")
assert "X-defB-defC" == doTypedSomething("X")
assert "defA-defB-defC" == doTypedSomething()
'''
}
void testDefaultTypedParametersAnother() {
assertScript '''
String doTypedSomethingAnother(String a = 'defA', String b = 'defB', String c) {
return a + "-" + b + "-" + c
}
assert "X-Y-Z" == doTypedSomethingAnother("X", "Y", "Z")
assert "X-defB-Z" == doTypedSomethingAnother("X", "Z")
assert "defA-defB-Z" == doTypedSomethingAnother("Z")
'''
shouldFail '''
String doTypedSomethingAnother(String a = 'defA', String b = 'defB', String c) {
return a + "-" + b + "-" + c
}
doTypedSomethingAnother()
'''
}
void testConstructor() {
assertScript '''
class DefaultParamTestTestClass {
def j
DefaultParamTestTestClass(int i = 1){j=i}
}
assert DefaultParamTestTestClass.declaredConstructors.size() == 2
def foo = new DefaultParamTestTestClass()
assert foo.j == 1
foo = new DefaultParamTestTestClass(2)
assert foo.j == 2
'''
}
void testPrecendence() {
// def meth(Closure cl = null) will produce a call meth(null)
// since interfaces are prefered over normal classes and since
// def meth(Map args, Closure cl = null) will produce a method
// meth(Map) a simple call with meth(null) would normally call
// meth(Map). To ensure this will not happen the call has to
// use a cast in the automatically created method.
assertScript '''
def meth(Closure cl = null) {
return '1' +meth([:], cl)
}
def meth(Map args, Closure cl = null) {
if(args==null) return "2"
return '2'+args.size()
}
assert meth() == "120"
assert meth(null) == "2"
assert meth {} == "120"
assert meth(a:1) == "21"
assert meth(a:1) {} == "21"
'''
}
// GROOVY-9151
void testMethodWithAllParametersDefaulted() {
assertScript '''
String greet(Object o = 'world', String s = o.toString()) {
"hello $s"
}
assert greet() == 'hello world'
'''
}
// GROOVY-9151
void testConstructorWithAllParametersDefaulted() {
assertScript '''
class Greeting {
Greeting(Object o = 'world', String s = o) {
this.text = "hello $s"
}
String text
}
assert new Greeting().text == 'hello world'
'''
}
// GROOVY-9151
void testConstructorWithAllParametersDefaulted2() {
def err = shouldFail '''
class Greeting {
Greeting(Object o = 'world', String s = o.toString()) {
this.text = "hello $s"
}
String text
}
assert new Greeting().text == 'hello world'
'''
assert err =~ /The generated constructor "Greeting\(\)" references parameter 'o' which has been replaced by a default value expression./
}
// GROOVY-5632
void testClosureSharedVariableRefersToDefaultParameter1() {
assertScript '''
def f1( int x = 3, fn={ -> x } ) {
return fn()
}
assert 3 == f1()
assert 42 == f1(42)
'''
}
// GROOVY-5632
void testClosureSharedVariableRefersToDefaultParameter2() {
assertScript '''
def f2( int x = 3, fn={ -> def c2 = { -> x }; c2.call() } ) {
return fn()
}
assert 42 == f2(42)
assert 42 == f2(42)
assert 84 == f2(42) { 84 }
'''
}
// GROOVY-5632
void testClosureSharedVariableRefersToDefaultParameter3() {
assertScript '''
def f3(fn={ -> 42 }, fn2={ -> def c2 = { -> fn() }; c2.call() } ) {
return fn2()
}
assert 42 == f3()
assert 84 == f3({ -> 84 })
'''
}
// GROOVY-5632
void testClosureSharedVariableRefersToDefaultParameter4() {
assertScript '''
def f4(def s = [1,2,3], fn = { -> s.size() }) {
fn()
}
assert 3 == f4()
'''
}
// GROOVY-5632
void testClosureSharedVariableRefersToDefaultParameter5() {
assertScript '''
static <T extends Number> Integer f5(List<T> s = [1,2,3], fn = { -> (s*.intValue()).sum() }) {
fn()
}
assert 6 == f5()
assert 6 == f5([1.1, 2.1, 3.1])
'''
}
// GROOVY-5632
void testClosureSharedVariableRefersToDefaultParameter6() {
assertScript '''
def f6(def s = [1,2,3], fn = { -> s.size() }, fn2 = { fn() + s.size() }) {
fn2()
}
assert 6 == f6()
'''
}
// GROOVY-5632
void testClosureSharedVariableRefersToDefaultParameter7() {
assertScript '''
def f7( int x = 3, int y = 39, fn={ -> x + y } ) {
return fn()
}
assert 42 == f7()
'''
}
}