blob: ab2241ad9a51967c18713bd21e4bc1f83e218c3e [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
import groovy.test.GroovyTestCase
/**
* Testing BuilderSupport and reveal how calling methods on it result in implementation callbacks.
* Using the SpoofBuilder (see below) to call it in various ways and analyze the "spoofed" logs.
* This is especially useful when designing subclasses of BuilderSupport.
*/
class BuilderSupportTest extends GroovyTestCase{
void testSimpleNode() {
def b = new SpoofBuilder()
assert b.log == []
def node = b.foo()
assert b.log == [ 'create_with_name','foo',
'node_completed',null, node,
'post_node_completion',null, node
]
}
void testSimpleNodeWithValue() {
def b = new SpoofBuilder()
def node = b.foo('value')
assert b.log == [ 'create_with_name_and_value','foo',
'value', 'node_completed',null,node,
'post_node_completion',null, node
]
}
void testSimpleNodeWithOneAttribute() {
def b = new SpoofBuilder()
def node = b.foo(name:'value')
assert b.log == [
'create_with_name_and_map','foo',
'name','value',
'node_completed',null,'x',
'post_node_completion',null, 'x'
]
}
void testSimpleNodeWithClosure() {
def b = new SpoofBuilder()
b.foo(){
b.bar()
}
assert b.log == [
'create_with_name','foo',
'create_with_name','bar',
'set_parent', 'x', 'x',
'node_completed','x','x',
'post_node_completion', 'x', 'x',
'node_completed',null,'x',
'post_node_completion',null, 'x'
]
}
void testSimpleNodeWithOneAttributeAndValue() {
def b = new SpoofBuilder()
def node = b.foo(bar:'baz', 'value')
assert b.log == [
'create_with_name_map_and_value', 'foo', 'bar', 'baz','value',
'node_completed',null,node,
'post_node_completion',null, node
]
}
void testSimpleNodeWithValueAndOneAttribute() {
def b = new SpoofBuilder()
def node = b.foo('value', bar:'baz')
assert b.log == [
'create_with_name_map_and_value', 'foo', 'bar', 'baz','value',
'node_completed',null,node,
'post_node_completion',null, node
]
}
void testSimpleNodeWithOneAttributeAndValueAndClosure() {
def b = new SpoofBuilder()
def node = b.foo(bar:'baz', 'value') { 1 }
assert b.log == [
'create_with_name_map_and_value', 'foo', 'bar', 'baz','value',
'node_completed',null,node,
'post_node_completion',null, node
]
}
void testSimpleNodeWithValueAndOneAttributeAndClosure() {
def b = new SpoofBuilder()
def node = b.foo('value', bar:'baz') { 1 }
assert b.log == [
'create_with_name_map_and_value', 'foo', 'bar', 'baz','value',
'node_completed',null,node,
'post_node_completion',null, node
]
}
void testSimpleNodeTwoValues() {
def b = new SpoofBuilder()
shouldFail(MissingMethodException, {def node = b.foo('arg1', 'arg2')})
}
void testSimpleNodeTwoValuesClosure() {
def b = new SpoofBuilder()
shouldFail(MissingMethodException, {def node = b.foo('arg1', 'arg2') { 1 } })
}
void testSimpleNodeThreeValues() {
def b = new SpoofBuilder()
shouldFail(MissingMethodException, {def node = b.foo('arg1', 'arg2', 'arg3') })
}
void testSimpleNodeFourValues() {
def b = new SpoofBuilder()
shouldFail(MissingMethodException, {def node = b.foo('arg1', 'arg2', 'arg3', 'arg4') })
}
void testNestedMethodCallsResolution() {
def b = new SpoofBuilder()
b.outest {
b.outer {
nestedBuilderCall(b)
}
}
assert b.log.contains('inner')
}
void nestedBuilderCall(builder) {
builder.inner()
}
// GROOVY-3341
void testSimpleNodeWithClosureThatThrowsAMissingMethodException() {
def builder = new SpoofBuilder()
String errorMessage = shouldFail(MissingMethodException, {
builder.a {
b {
error('xy'.foo())
}
}
})
assert errorMessage.contains('No signature of method: java.lang.String.foo()')
}
}
/**
The SpoofBuilder is a sample instance of the abstract BuilderSupport class
that does nothing but logging how it was called, returning 'x' for each node.
**/
class SpoofBuilder extends BuilderSupport{
def log = []
protected void setParent(Object parent, Object child){
log << "set_parent"
log << parent
log << child
}
protected Object createNode(Object name){
log << 'create_with_name'
log << name
return 'x'
}
protected Object createNode(Object name, Object value){
log << 'create_with_name_and_value'
log << name
log << value
return 'x'
}
protected Object createNode(Object name, Map attributes){
log << 'create_with_name_and_map'
log << name
attributes.each{entry -> log << entry.key; log << entry.value}
return 'x'
}
protected Object createNode(Object name, Map attributes, Object value){
log << 'create_with_name_map_and_value'
log << name
attributes.each{entry -> log << entry.key; log << entry.value}
log << value
return 'x'
}
protected void nodeCompleted(Object parent, Object node) {
log << 'node_completed'
log << parent
log << node
}
protected Object postNodeCompletion(Object parent, Object node) {
log << 'post_node_completion'
log << parent
log << node
node
}
}