blob: ff447505572132f23e1ef9f4ab868b537627190e [file] [log] [blame]
import groovy.test.GroovyTestCase
/*
* 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.
*/
class CoercionTest extends GroovyTestCase {
void testStringToEnumValue() {
assertScript '''
// tag::state_enum[]
enum State {
up,
down
}
// end::state_enum[]
try {
// tag::enum_coerce_assignment[]
State st = 'up'
assert st == State.up
// end::enum_coerce_assignment[]
} catch (IllegalArgumentException err) {
assert false:'Test should not have failed'
}
try {
// tag::enum_coerce_assignment_wrong[]
State st = 'not an enum value'
// end::enum_coerce_assignment_wrong[]
} catch (IllegalArgumentException err) {
// woot!
}
try {
// tag::enum_coerce_assignment_gstring[]
def val = "up"
State st = "${val}"
assert st == State.up
// end::enum_coerce_assignment_gstring[]
} catch (IllegalArgumentException err) {
assert false:'Test should not have failed'
}
// tag::enum_switch_method[]
State switchState(State st) {
switch (st) {
case 'up':
return State.down // explicit constant
case 'down':
return 'up' // implicit coercion for return types
}
}
// end::enum_switch_method[]
// tag::enum_switch_test[]
assert switchState('up' as State) == State.down
assert switchState(State.down) == State.up
// end::enum_switch_test[]
'''
}
void testCustomCoercion() {
assertScript '''
import groovy.transform.ToString
import static java.lang.Math.*
@ToString(includeNames=true)
// tag::polar_class_header[]
class Polar {
double r
double phi
// end::polar_class_header[]
// tag::polar_class_astype[]
def asType(Class target) {
if (Cartesian==target) {
return new Cartesian(x: r*cos(phi), y: r*sin(phi))
}
}
// end::polar_class_astype[]
// tag::polar_class_footer[]
}
// end::polar_class_footer[]
@ToString(includeNames=true)
// tag::cartesian_class[]
class Cartesian {
double x
double y
}
// end::cartesian_class[]
// tag::polar_astype_assert[]
def sigma = 1E-16
def polar = new Polar(r:1.0,phi:PI/2)
def cartesian = polar as Cartesian
assert abs(cartesian.x-sigma) < sigma
// end::polar_astype_assert[]
'''
}
void testCustomCoercionWithExternalAsType() {
assertScript '''
import groovy.transform.ToString
import static java.lang.Math.*
@ToString(includeNames=true)
class Polar {
double r
double phi
}
@ToString(includeNames=true)
class Cartesian {
double x
double y
}
// tag::polar_metaclass_astype[]
Polar.metaClass.asType = { Class target ->
if (Cartesian==target) {
return new Cartesian(x: r*cos(phi), y: r*sin(phi))
}
}
// end::polar_metaclass_astype[]
def sigma = 1E-16
def polar = new Polar(r:1.0,phi:PI/2)
def cartesian = polar as Cartesian
assert abs(cartesian.x-sigma) < sigma
'''
}
void testExplicitClosureCoercion() {
assertScript '''
// tag::filter_sam_type[]
interface Predicate<T> {
boolean accept(T obj)
}
// end::filter_sam_type[]
// tag::greeter_sam_type[]
abstract class Greeter {
abstract String getName()
void greet() {
println "Hello, $name"
}
}
// end::greeter_sam_type[]
// tag::assertions_explicit_closure_to_sam[]
Predicate filter = { it.contains 'G' } as Predicate
assert filter.accept('Groovy') == true
Greeter greeter = { 'Groovy' } as Greeter
greeter.greet()
// end::assertions_explicit_closure_to_sam[]
'''
}
void testImplicitClosureCoercionWithAssignment() {
assertScript '''
interface Predicate<T> {
boolean accept(T obj)
}
abstract class Greeter {
abstract String getName()
void greet() {
println "Hello, $name"
}
}
// tag::assertions_implicit_closure_to_sam[]
Predicate filter = { it.contains 'G' }
assert filter.accept('Groovy') == true
Greeter greeter = { 'Groovy' }
greeter.greet()
// end::assertions_implicit_closure_to_sam[]
'''
}
void testImplicitClosureCoercionWithAssignmentAndMethodPointer() {
assertScript '''
interface Predicate<T> {
boolean accept(T obj)
}
abstract class Greeter {
abstract String getName()
void greet() {
println "Hello, $name"
}
}
// tag::assertions_implicit_closure_to_sam_and_method_pointer[]
boolean doFilter(String s) { s.contains('G') }
Predicate filter = this.&doFilter
assert filter.accept('Groovy') == true
Greeter greeter = GroovySystem.&getVersion
greeter.greet()
// end::assertions_implicit_closure_to_sam_and_method_pointer[]
'''
}
void testClosureCoercionWithMethodCall() {
assertScript '''
interface Predicate<T> {
boolean accept(T obj)
}
// tag::method_accepting_filter[]
public <T> List<T> filter(List<T> source, Predicate<T> predicate) {
source.findAll { predicate.accept(it) }
}
// end::method_accepting_filter[]
// tag::method_call_with_explicit_coercion[]
assert filter(['Java','Groovy'], { it.contains 'G'} as Predicate) == ['Groovy']
// end::method_call_with_explicit_coercion[]
// tag::method_call_with_implicit_coercion[]
assert filter(['Java','Groovy']) { it.contains 'G'} == ['Groovy']
// end::method_call_with_implicit_coercion[]
'''
}
void testClosureCoercionToInterface() {
assertScript '''
// tag::foobar_interface[]
interface FooBar {
int foo()
void bar()
}
// end::foobar_interface[]
// tag::foobar2closure_coercion[]
def impl = { println 'ok'; 123 } as FooBar
// end::foobar2closure_coercion[]
// tag::foobarintf_assertions[]
assert impl.foo() == 123
impl.bar()
// end::foobarintf_assertions[]
'''
}
void testClosureCoercionToClass() {
assertScript '''
// tag::closure2foobarclass[]
class FooBar {
int foo() { 1 }
void bar() { println 'bar' }
}
def impl = { println 'ok'; 123 } as FooBar
assert impl.foo() == 123
impl.bar()
// end::closure2foobarclass[]
'''
}
void testCoerceMapToIterator() {
assertScript '''
// tag::coerce_map_to_iterator[]
def map
map = [
i: 10,
hasNext: { map.i > 0 },
next: { map.i-- },
]
def iter = map as Iterator
// end::coerce_map_to_iterator[]
// tag::use_coerced_iterator[]
while ( iter.hasNext() )
println iter.next()
assert map.i==0
// end::use_coerced_iterator[]
'''
}
void testCoerceThrowsNPE() {
assertScript '''
// tag::define_x_interface[]
interface X {
void f()
void g(int n)
void h(String s, int n)
}
x = [ f: {println "f called"} ] as X
// end::define_x_interface[]
// tag::call_existing_method[]
x.f() // method exists
// end::call_existing_method[]
try {
// tag::call_non_existing_method[]
x.g() // MissingMethodException here
// end::call_non_existing_method[]
} catch (MissingMethodException e) {
println "Caught exception"
}
try {
// tag::call_notimplemented_method[]
x.g(5) // UnsupportedOperationException here
// end::call_notimplemented_method[]
} catch (UnsupportedOperationException e) {
println "Caught exception"
}
'''
}
void testAsVsAsType() {
assertScript '''
// tag::as_keyword[]
interface Greeter {
void greet()
}
def greeter = { println 'Hello, Groovy!' } as Greeter // Greeter is known statically
greeter.greet()
// end::as_keyword[]
/*
// tag::clazz_greeter_header[]
Class clazz = Class.forName('Greeter')
// end::clazz_greeter_header[]
// tag::incorrect_as_usage[]
greeter = { println 'Hello, Groovy!' } as clazz
// throws:
// unable to resolve class clazz
// @ line 9, column 40.
// greeter = { println 'Hello, Groovy!' } as clazz
// end::incorrect_as_usage[]
*/
Class clazz = Greeter
// tag::fixed_as_usage[]
greeter = { println 'Hello, Groovy!' }.asType(clazz)
greeter.greet()
// end::fixed_as_usage[]
'''
}
}