|
Groovy example source code file (AstBuilderFromSpecificationTest.groovy)
The Groovy AstBuilderFromSpecificationTest.groovy source code
package org.codehaus.groovy.ast.builder
import org.codehaus.groovy.syntax.Token
import org.codehaus.groovy.syntax.Types
import org.codehaus.groovy.ast.*
import org.codehaus.groovy.ast.expr.*
import org.codehaus.groovy.ast.stmt.*
import static org.objectweb.asm.Opcodes.ACC_PUBLIC
import static org.objectweb.asm.Opcodes.ACC_STATIC
/**
* Unit test for the AST from Psuedo-specification feature.
* @author Hamlet D'Arcy
*/
public class AstBuilderFromSpecificationTest extends GroovyTestCase {
public void testSimpleMethodCall() {
def result = new AstBuilder().buildFromSpec {
methodCall {
variable "this"
constant "println"
argumentList {
constant "Hello"
}
}
}
def expected = new MethodCallExpression(
new VariableExpression("this"),
new ConstantExpression("println"),
new ArgumentListExpression(
[new ConstantExpression("Hello")]
)
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testErrorHandling_TooManyArguments() {
def message = shouldFail(IllegalArgumentException) {
new AstBuilder().buildFromSpec {
methodCall {
constant "four arguments"
constant "is too"
constant "many for"
constant "this method"
}
}
}
assertTrue("Unhelpful error message: $message", message.contains('methodCall could not be invoked'))
assertTrue("Unhelpful error message: $message", message.contains('Expected to receive'))
assertTrue("Unhelpful error message: $message", message.contains('but found'))
}
public void testErrorHandling_WrongArgumentTypes() {
def message = shouldFail(IllegalArgumentException) {
new AstBuilder().buildFromSpec {
methodCall {
returnStatement {
constant 1
}
constant "ignored"
empty()
}
}
}
assertTrue("Unhelpful error message: $message", message.contains('methodCall could not be invoked'))
assertTrue("Unhelpful error message: $message", message.contains('Expected to receive'))
assertTrue("Unhelpful error message: $message", message.contains('but found'))
}
public void testAnnotationConstantExpression() {
def result = new AstBuilder().buildFromSpec {
annotationConstant {
annotation Override
}
}
def expected = new AnnotationConstantExpression(
new AnnotationNode(
ClassHelper.make(Override.class, false)
)
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testArgumentListExpression_NoArgs() {
def result = new AstBuilder().buildFromSpec {
argumentList()
}
def expected = new ArgumentListExpression()
AstAssert.assertSyntaxTree([expected], result)
}
public void testArgumentListExpression_OneListArg() {
def result = new AstBuilder().buildFromSpec {
argumentList {
constant "constant1"
constant "constant2"
constant "constant3"
constant "constant4"
}
}
def expected = new ArgumentListExpression(
[new ConstantExpression("constant1"),
new ConstantExpression("constant2"),
new ConstantExpression("constant3"),
new ConstantExpression("constant4"),
]
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testAttributeExpression() {
// represents foo.bar attribute invocation
def result = new AstBuilder().buildFromSpec {
attribute {
variable "foo"
constant "bar"
}
}
def expected = new AttributeExpression(
new VariableExpression("foo"),
new ConstantExpression("bar")
)
AstAssert.assertSyntaxTree([expected], result)
}
/**
* Test for code:
* if (foo == bar) println "Hello" else println "World"
*/
public void testIfStatement() {
// if (foo == bar) println "Hello" else println "World"
def result = new AstBuilder().buildFromSpec {
ifStatement {
booleanExpression {
binary {
variable "foo"
token "=="
variable "bar"
}
}
//if block
expression { // NOTE: if block and else block are order dependent and same type
methodCall {
variable "this"
constant "println"
argumentList {
constant "Hello"
}
}
}
//else block
expression {
methodCall {
variable "this"
constant "println"
argumentList {
constant "World"
}
}
}
}
}
def expected = new IfStatement(
new BooleanExpression(
new BinaryExpression(
new VariableExpression("foo"),
new Token(Types.COMPARE_EQUAL, "==", -1, -1),
new VariableExpression("bar")
)
),
new ExpressionStatement(
new MethodCallExpression(
new VariableExpression("this"),
new ConstantExpression("println"),
new ArgumentListExpression(
[new ConstantExpression("Hello")]
)
)
),
new ExpressionStatement(
new MethodCallExpression(
new VariableExpression("this"),
new ConstantExpression("println"),
new ArgumentListExpression(
[new ConstantExpression("World")]
)
)
)
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testDeclarationAndListExpression() {
// represents def foo = [1, 2, 3]
def result = new AstBuilder().buildFromSpec {
declaration {
variable "foo"
token "="
list {
constant 1
constant 2
constant 3
}
}
}
def expected = new DeclarationExpression(
new VariableExpression("foo"),
new Token(Types.EQUALS, "=", -1, -1),
new ListExpression(
[new ConstantExpression(1),
new ConstantExpression(2),
new ConstantExpression(3),]
)
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testArrayExpression() {
// new Integer[]{1, 2, 3}
def result = new AstBuilder().buildFromSpec {
array(Integer) {
constant 1
constant 2
constant 3
}
}
def expected = new ArrayExpression(
ClassHelper.make(Integer, false),
[
new ConstantExpression(1),
new ConstantExpression(2),
new ConstantExpression(3),]
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testBitwiseNegationExpression() {
def result = new AstBuilder().buildFromSpec {
bitwiseNegation {
constant 1
}
}
def expected = new BitwiseNegationExpression(
new ConstantExpression(1)
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testCastExpression() {
def result = new AstBuilder().buildFromSpec {
cast(Integer) {
constant ""
}
}
def expected = new CastExpression(
ClassHelper.make(Integer, false),
new ConstantExpression("")
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testClosureExpression() {
// { parm -> println parm }
def result = new AstBuilder().buildFromSpec {
closure {
parameters {
parameter 'parm': Object.class
}
block {
expression {
methodCall {
variable "this"
constant "println"
argumentList {
variable "parm"
}
}
}
}
}
}
def expected = new ClosureExpression(
[new Parameter(
ClassHelper.make(Object, false), "parm"
)] as Parameter[],
new BlockStatement(
[new ExpressionStatement(
new MethodCallExpression(
new VariableExpression("this"),
new ConstantExpression("println"),
new ArgumentListExpression(
new VariableExpression("parm")
)
)
)],
new VariableScope()
)
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testClosureExpression_MultipleParameters() {
// { x,y,z -> println z }
def result = new AstBuilder().buildFromSpec {
closure {
parameters {
parameter 'x': Object.class
parameter 'y': Object.class
parameter 'z': Object.class
}
block {
expression {
methodCall {
variable "this"
constant "println"
argumentList {
variable "z"
}
}
}
}
}
}
def expected = new ClosureExpression(
[
new Parameter(ClassHelper.make(Object, false), "x"),
new Parameter(ClassHelper.make(Object, false), "y"),
new Parameter(ClassHelper.make(Object, false), "z")] as Parameter[],
new BlockStatement(
[new ExpressionStatement(
new MethodCallExpression(
new VariableExpression("this"),
new ConstantExpression("println"),
new ArgumentListExpression(
new VariableExpression("z")
)
)
)],
new VariableScope()
)
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testConstructorCallExpression() {
// new Integer(4)
def result = new AstBuilder().buildFromSpec {
constructorCall(Integer) {
argumentList {
constant 4
}
}
}
def expected = new ConstructorCallExpression(
ClassHelper.make(Integer, false),
new ArgumentListExpression(
new ConstantExpression(4)
)
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testNotExpression() {
// !true
def result = new AstBuilder().buildFromSpec {
not {
constant true
}
}
def expected = new NotExpression(
new ConstantExpression(true)
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testPostfixExpression() {
// 1++
def result = new AstBuilder().buildFromSpec {
postfix {
constant 1
token "++"
}
}
def expected = new PostfixExpression(
new ConstantExpression(1),
new Token(Types.PLUS_PLUS, "++", -1, -1)
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testPrefixExpression() {
// ++1
def result = new AstBuilder().buildFromSpec {
prefix {
token "++"
constant 1
}
}
def expected = new PrefixExpression(
new Token(Types.PLUS_PLUS, "++", -1, -1),
new ConstantExpression(1)
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testUnaryMinusExpression() {
// (-foo)
def result = new AstBuilder().buildFromSpec {
unaryMinus {
variable "foo"
}
}
def expected = new UnaryMinusExpression(
new VariableExpression("foo")
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testUnaryPlusExpression() {
// (+foo)
def result = new AstBuilder().buildFromSpec {
unaryPlus {
variable "foo"
}
}
def expected = new UnaryPlusExpression(
new VariableExpression("foo")
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testClassExpression() {
// def foo = String
def result = new AstBuilder().buildFromSpec {
declaration {
variable "foo"
token "="
classExpression String
}
}
def expected = new DeclarationExpression(
new VariableExpression("foo"),
new Token(Types.EQUALS, "=", -1, -1),
new ClassExpression(ClassHelper.make(String, false))
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testFieldExpression() {
// public static String foo = "a value"
def result = new AstBuilder().buildFromSpec {
field {
fieldNode "foo", ACC_PUBLIC & ACC_STATIC, String, this.class, {
constant "a value"
}
}
}
def expected = new FieldExpression(
new FieldNode(
"foo",
ACC_PUBLIC & ACC_STATIC,
ClassHelper.make(String, false),
ClassHelper.make(this.class, false),
new ConstantExpression("a value")
)
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testMapAndMapEntryExpression() {
// [foo: 'bar', baz: 'buz']
def result = new AstBuilder().buildFromSpec {
map {
mapEntry {
constant 'foo'
constant 'bar'
}
mapEntry {
constant 'baz'
constant 'buz'
}
}
}
def expected = new MapExpression(
[
new MapEntryExpression(
new ConstantExpression('foo'),
new ConstantExpression('bar')
),
new MapEntryExpression(
new ConstantExpression('baz'),
new ConstantExpression('buz')
),
]
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testMapAndMapEntryExpression_SimpleCase() {
// [foo: 'bar', baz: 'buz']
def result = new AstBuilder().buildFromSpec {
map {
mapEntry 'foo': 'bar' // NOTE: this really only works for constants.
mapEntry 'baz': 'buz'
mapEntry 'qux': 'quux', 'corge': 'grault'
}
}
def expected = new MapExpression(
[
new MapEntryExpression(
new ConstantExpression('foo'),
new ConstantExpression('bar')
),
new MapEntryExpression(
new ConstantExpression('baz'),
new ConstantExpression('buz')
),
new MapEntryExpression(
new ConstantExpression('qux'),
new ConstantExpression('quux')
),
new MapEntryExpression(
new ConstantExpression('corge'),
new ConstantExpression('grault')
),
]
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testGStringExpression() {
// "$foo"
def result = new AstBuilder().buildFromSpec {
gString '$foo astring $bar', {
strings {
constant ''
constant ' astring '
constant ''
}
values {
variable 'foo'
variable 'bar'
}
}
}
def expected = new GStringExpression('$foo astring $bar',
[new ConstantExpression(''), new ConstantExpression(' astring '), new ConstantExpression('')],
[new VariableExpression('foo'), new VariableExpression('bar')])
AstAssert.assertSyntaxTree([expected], result)
}
public void testMethodPointerExpression() {
// Integer.&toString
def result = new AstBuilder().buildFromSpec {
methodPointer {
classExpression Integer
constant "toString"
}
}
def expected = new MethodPointerExpression(
new ClassExpression(ClassHelper.make(Integer, false)),
new ConstantExpression("toString")
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testRangeExpression() {
// (0..10)
def result = new AstBuilder().buildFromSpec {
range {
constant 0
constant 10
inclusive true
}
}
def expected = new RangeExpression(
new ConstantExpression(0),
new ConstantExpression(10),
true
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testRangeExpression_Exclusive() {
// (0..10)
def result = new AstBuilder().buildFromSpec {
range {
constant 0
constant 10
inclusive false
}
}
def expected = new RangeExpression(
new ConstantExpression(0),
new ConstantExpression(10),
false
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testRangeExpression_SimpleForm() {
// (0..10)
def result = new AstBuilder().buildFromSpec {
range(0..10)
}
def expected = new RangeExpression(
new ConstantExpression(0),
new ConstantExpression(10),
true
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testPropertyExpression() {
// foo.bar
def result = new AstBuilder().buildFromSpec {
property { // this name conflicts with PropertyNode.
variable "foo"
constant "bar"
}
}
def expected = new PropertyExpression(
new VariableExpression("foo"),
new ConstantExpression("bar")
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testSwitchAndCaseAndBreakStatements() {
/*
switch (foo) {
case 0: break "some label"
case 1:
case 2:
println "<3"
break;
default:
println ">2"
}
*/
def result = new AstBuilder().buildFromSpec {
switchStatement { //NOTE: switchStatement is abnormal pattern
variable "foo"
defaultCase { // NOTE: this creates a block statement
expression { //NOTE: default branch is problematic b/c it is order dependent
methodCall {
variable "this"
constant "println"
argumentList {
constant ">2"
}
}
}
}
caseStatement {
constant 0
breakStatement "some label" // label parameter is optional
}
caseStatement {
constant 1
empty()
}
caseStatement {
constant 2
block {
expression {
methodCall {
variable "this"
constant "println"
argumentList {
constant "<3"
}
}
}
breakStatement()
}
}
}
}
def expected = new SwitchStatement(
new VariableExpression("foo"),
[
new CaseStatement(
new ConstantExpression(0),
new BreakStatement("some label")
),
new CaseStatement(
new ConstantExpression(1),
new EmptyStatement()
),
new CaseStatement(
new ConstantExpression(2),
new BlockStatement(
[
new ExpressionStatement(
new MethodCallExpression(
new VariableExpression("this"),
new ConstantExpression("println"),
new ArgumentListExpression(
[new ConstantExpression("<3")]
)
)
),
new BreakStatement()
], new VariableScope()
)
)
],
new BlockStatement(
[new ExpressionStatement(
new MethodCallExpression(
new VariableExpression("this"),
new ConstantExpression("println"),
new ArgumentListExpression(
[new ConstantExpression(">2")]
)
)
)],
new VariableScope()
)
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testAssertStatement() {
/*
assert true : "should always be true"
assert 1 == 2
*/
def result = new AstBuilder().buildFromSpec {
block {
assertStatement {
booleanExpression {
constant true
}
constant "should always be true"
}
assertStatement {
booleanExpression {
binary {
constant 1
token "=="
constant 2
}
}
}
}
}
def expected = new BlockStatement(
[
new AssertStatement(
new BooleanExpression(
new ConstantExpression(true)
),
new ConstantExpression("should always be true")
),
new AssertStatement(
new BooleanExpression(
new BinaryExpression(
new ConstantExpression(1),
new Token(Types.COMPARE_EQUAL, "==", -1, -1),
new ConstantExpression(2)
)
)
),
],
new VariableScope()
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testReturnAndSynchronizedStatement() {
/*
synchronized (this) {
return 1
}
*/
def result = new AstBuilder().buildFromSpec {
synchronizedStatement {
variable "this"
block {
returnStatement {
constant 1
}
}
}
}
def expected = new SynchronizedStatement(
new VariableExpression("this"),
new BlockStatement(
[new ReturnStatement(
new ConstantExpression(1)
)],
new VariableScope()
)
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testTryCatchAndCatchAndThrowStatements() {
/*
try {
return 1
} catch (Exception e) {
throw e
}
*/
def result = new AstBuilder().buildFromSpec {
tryCatch {
block {
returnStatement {
constant 1
}
}
empty() //finally block must be specified?
catchStatement {
parameter 'e': Exception.class
block {
throwStatement {
variable "e"
}
}
}
}
}
TryCatchStatement expected = new TryCatchStatement(
new BlockStatement(
[new ReturnStatement(
new ConstantExpression(1)
)],
new VariableScope()
),
new EmptyStatement()
)
expected.addCatch(
new CatchStatement(
new Parameter(
ClassHelper.make(Exception, false), "e"
),
new BlockStatement(
[new ThrowStatement(
new VariableExpression("e")
)],
new VariableScope()
)
)
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testFinallyStatement() {
/*
try {
return 1
} finally {
x.close()
}
*/
def result = new AstBuilder().buildFromSpec {
tryCatch {
block {
returnStatement {
constant 1
}
}
block {
block {
expression {
methodCall {
variable 'x'
constant 'close'
argumentList()
}
}
}
}
}
}
TryCatchStatement expected = new TryCatchStatement(
new BlockStatement(
[new ReturnStatement(
new ConstantExpression(1)
)],
new VariableScope()
),
new BlockStatement(
[
new BlockStatement(
[
new ExpressionStatement(
new MethodCallExpression(
new VariableExpression('x'),
'close',
new ArgumentListExpression()
)
)
],
new VariableScope())
],
new VariableScope()
)
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testForStatementAndClosureListExpression() {
/*
for (int x = 0; x < 10; x++) {
println x
}
*/
def result = new AstBuilder().buildFromSpec {
forStatement {
parameter 'forLoopDummyParameter': Object.class
closureList {
declaration {
variable 'x'
token '='
constant 0
}
binary {
variable 'x'
token '<'
constant 10
}
postfix {
variable 'x'
token '++'
}
}
block {
expression {
methodCall {
variable 'this'
constant 'println'
argumentList {
variable 'x'
}
}
}
}
}
}
def expected = new ForStatement(
new Parameter(ClassHelper.make(Object, false), "forLoopDummyParameter"),
new ClosureListExpression(
[
new DeclarationExpression(
new VariableExpression("x"),
new Token(Types.EQUALS, "=", -1, -1),
new ConstantExpression(0)
),
new BinaryExpression(
new VariableExpression("x"),
new Token(Types.COMPARE_LESS_THAN, "<", -1, -1),
new ConstantExpression(10)
),
new PostfixExpression(
new VariableExpression("x"),
new Token(Types.PLUS_PLUS, "++", -1, -1)
)
]
),
new BlockStatement(
[
new ExpressionStatement(
new MethodCallExpression(
new VariableExpression("this"),
new ConstantExpression("println"),
new ArgumentListExpression(
new VariableExpression("x"),
)
)
)
],
new VariableScope()
)
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testStaticMethodCallExpression_MethodAsString() {
// Math.min(1,2)
def result = new AstBuilder().buildFromSpec {
staticMethodCall(Math, "min") {
argumentList {
constant 1
constant 2
}
}
}
def expected = new StaticMethodCallExpression(
ClassHelper.make(Math, false),
"min",
new ArgumentListExpression(
new ConstantExpression(1),
new ConstantExpression(2)
)
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testStaticMethodCallExpression_PassingMethodPointer() {
// Math.min(1,2)
def result = new AstBuilder().buildFromSpec {
staticMethodCall(Math.&min) { // more terse way to call existing methods
argumentList {
constant 1
constant 2
}
}
}
def expected = new StaticMethodCallExpression(
ClassHelper.make(Math, false),
"min",
new ArgumentListExpression(
new ConstantExpression(1),
new ConstantExpression(2)
)
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testSpreadExpression() {
// todo: what source code generates this node type?
def result = new AstBuilder().buildFromSpec {
spread {
list {
constant 'foo'
constant 'bar'
}
}
}
def expected = new SpreadExpression(
new ListExpression([
new ConstantExpression('foo'),
new ConstantExpression('bar'),
])
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testSpreadMapExpression() {
// func (*:m)
def result = new AstBuilder().buildFromSpec {
methodCall {
variable 'this'
constant 'func'
mapEntry {
spreadMap {
variable 'm'
}
variable 'm'
}
}
}
def expected = new MethodCallExpression(
new VariableExpression('this', ClassHelper.make(Object, false)),
'func',
new MapEntryExpression(
new SpreadMapExpression(
new VariableExpression('m', ClassHelper.make(Object, false))
),
new VariableExpression('m', ClassHelper.make(Object, false))
)
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testTernaryExpression() {
// true ? "male" : "female"
def result = new AstBuilder().buildFromSpec {
ternary {
booleanExpression {
constant true
}
constant 'male'
constant 'female'
}
}
def expected = new TernaryExpression(
new BooleanExpression(
new ConstantExpression(true)
),
new ConstantExpression('male'),
new ConstantExpression('female')
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testDoWhileStatement() {
// DoWhileStatement doesn't seemed to be used, and the do/while source doesn't compile either
}
public void testStatement() {
// Statement is used as an abstract class within the groovy source and is never instantiated
}
public void testWhileStatementAndContinueStatement() {
/*
while (true) {
x++
continue
}
*/
def result = new AstBuilder().buildFromSpec {
whileStatement {
booleanExpression {
constant true
}
block {
expression {
postfix {
variable 'x'
token '++'
}
}
continueStatement()
}
}
}
def expected = new WhileStatement(
new BooleanExpression(
new ConstantExpression(true)
),
new BlockStatement(
[
new ExpressionStatement(
new PostfixExpression(
new VariableExpression("x"),
new Token(Types.PLUS_PLUS, "++", -1, -1),
)
),
new ContinueStatement()
],
new VariableScope()
)
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testWhileStatementAndContinueToLabelStatement() {
/*
while (true) {
x++
continue "some label"
}
*/
def result = new AstBuilder().buildFromSpec {
whileStatement {
booleanExpression {
constant true
}
block {
expression {
postfix {
variable 'x'
token '++'
}
}
continueStatement {
label "some label"
}
}
}
}
def expected = new WhileStatement(
new BooleanExpression(
new ConstantExpression(true)
),
new BlockStatement(
[
new ExpressionStatement(
new PostfixExpression(
new VariableExpression("x"),
new Token(Types.PLUS_PLUS, "++", -1, -1),
)
),
new ContinueStatement("some label")
],
new VariableScope()
)
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testElvisOperatorExpression() {
// name ?: 'Anonymous'
def result = new AstBuilder().buildFromSpec {
elvisOperator {
booleanExpression {
variable 'name'
}
constant 'Anonymous'
}
}
def expected = new ElvisOperatorExpression(
new BooleanExpression(
new VariableExpression('name')
),
new ConstantExpression('Anonymous')
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testNamedArgumentListExpression() {
// new String(foo: 'bar')
def result = new AstBuilder().buildFromSpec {
constructorCall(String) {
tuple {
namedArgumentList {
mapEntry {
constant 'foo'
constant 'bar'
}
}
}
}
}
def expected = new ConstructorCallExpression(
ClassHelper.make(String),
new TupleExpression(
new NamedArgumentListExpression(
[
new MapEntryExpression(
new ConstantExpression('foo'),
new ConstantExpression('bar'),
)
]
)
)
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testParameters_DefaultValues() {
/*
public String myMethod(String parameter = null) {
'some result'
}
*/
def result = new AstBuilder().buildFromSpec {
method('myMethod', ACC_PUBLIC, String) {
parameters {
parameter 'parameter': String.class, {
constant null
}
}
exceptions {}
block {
returnStatement {
constant 'some result'
}
}
annotations {}
}
}
def expected = new MethodNode(
"myMethod",
ACC_PUBLIC,
ClassHelper.make(String.class, false),
[new Parameter(ClassHelper.make(String, false), "parameter", new ConstantExpression(null))] as Parameter[],
[] as ClassNode[],
new BlockStatement(
[new ReturnStatement(
new ConstantExpression('some result')
)],
new VariableScope()
))
AstAssert.assertSyntaxTree([expected], result)
}
public void testParameters_VarArgs() {
/*
public String myMethod(String... parameters) {
'some result'
}
*/
// vararg methods are just array methods.
def result = new AstBuilder().buildFromSpec {
method('myMethod', ACC_PUBLIC, String) {
parameters {
parameter 'parameters': String[].class
}
exceptions {}
block {
returnStatement {
constant 'some result'
}
}
}
}
def expected = new MethodNode(
"myMethod",
ACC_PUBLIC,
ClassHelper.make(String.class, false),
[new Parameter(ClassHelper.make(String[], false), "parameters")] as Parameter[],
[] as ClassNode[],
new BlockStatement(
[new ReturnStatement(
new ConstantExpression('some result')
)],
new VariableScope()
))
AstAssert.assertSyntaxTree([expected], result)
}
public void testInnerClassNode() {
/*
class Foo {
static class Bar {
}
}
*/
def result = new AstBuilder().buildFromSpec {
innerClass 'Foo$Bar', ACC_PUBLIC, {
//outer class
classNode 'Foo', ACC_PUBLIC, {
classNode Object //superclass
interfaces {
classNode GroovyObject
}
mixins {}
}
classNode Object //superclass
interfaces {
classNode GroovyObject
}
mixins {}
}
}
def expected = new InnerClassNode(
new ClassNode(
"Foo",
ACC_PUBLIC,
ClassHelper.make(Object, false),
[ClassHelper.make(GroovyObject, false)] as ClassNode[],
[] as MixinNode[]
),
'Foo$Bar',
ACC_PUBLIC,
ClassHelper.make(Object, false),
[ClassHelper.make(GroovyObject, false)] as ClassNode[],
[] as MixinNode[]
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testAnnotatedNode() {
// this class is never instantiated. It is used as an abstract class but not marked as such.
}
public void testConstructorNode() {
// public <init>(String foo, Integer bar) throws IOException, Exception {}
def result = new AstBuilder().buildFromSpec {
constructor(ACC_PUBLIC) {
parameters {
parameter 'foo': String.class
parameter 'bar': Integer.class
}
exceptions {
classNode Exception
classNode IOException
}
block {
}
}
}
def expected = new ConstructorNode(
ACC_PUBLIC,
[
new Parameter(ClassHelper.make(String, false), "foo"),
new Parameter(ClassHelper.make(Integer, false), "bar")
] as Parameter[],
[
ClassHelper.make(Exception, false),
ClassHelper.make(IOException, false)
] as ClassNode[],
new BlockStatement()
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testGenericsType() {
// class MyClass<T, U extends Number> {}
def result = new AstBuilder().buildFromSpec {
classNode 'MyClass', ACC_PUBLIC, {
classNode Object //superclass
interfaces {
classNode GroovyObject
}
mixins {}
genericsTypes {
genericsType Object
genericsType Number, {
upperBound {
classNode Number
}
}
}
}
}
def expected = new ClassNode(
"MyClass", ACC_PUBLIC, ClassHelper.make(Object, false)
)
expected.setGenericsTypes(
[
new GenericsType(ClassHelper.make(Object, false)),
new GenericsType(ClassHelper.make(Number, false), [ClassHelper.make(Number, false)] as ClassNode[], null),
] as GenericsType[]
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testGenericsType_WithLowerBounds() {
// class MyClass<T, U extends Number> {}
def result = new AstBuilder().buildFromSpec {
classNode 'MyClass', ACC_PUBLIC, {
classNode Object //superclass
interfaces {
classNode GroovyObject
}
mixins {}
genericsTypes {
genericsType Object
genericsType Number, {
upperBound {
classNode Number //upper bound 1
classNode Comparable //upper bound 2
}
lowerBound Integer
}
}
}
}
def expected = new ClassNode(
"MyClass", ACC_PUBLIC, ClassHelper.make(Object, false)
)
expected.setGenericsTypes(
[
new GenericsType(ClassHelper.make(Object, false)),
new GenericsType(
ClassHelper.make(Number, false),
[ClassHelper.make(Number, false), ClassHelper.make(Comparable, false)] as ClassNode[],
ClassHelper.make(Integer, false)),
] as GenericsType[]
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testImportNode() {
// what source will trigger this node?
def result = new AstBuilder().buildFromSpec {
importNode String, "string"
importNode Integer
}
def expected = [
new ImportNode(ClassHelper.make(String, false), "string"),
new ImportNode(ClassHelper.make(Integer, false), null)
]
AstAssert.assertSyntaxTree(expected, result)
}
public void testMethodNode() {
/*
@Override
public String myMethod(String parameter) throws Exception, IOException {
'some result'
}
}
*/
def result = new AstBuilder().buildFromSpec {
method('myMethod', ACC_PUBLIC, String) {
parameters {
parameter 'parameter': String.class
}
exceptions {
classNode Exception
classNode IOException
}
block {
returnStatement {
constant 'some result'
}
}
annotations {
annotation Override
}
}
}
def expected = new MethodNode(
"myMethod",
ACC_PUBLIC,
ClassHelper.make(String, false),
[new Parameter(ClassHelper.make(String, false), "parameter")] as Parameter[],
[ClassHelper.make(Exception, false), ClassHelper.make(IOException, false)] as ClassNode[],
new BlockStatement(
[new ReturnStatement(
new ConstantExpression('some result')
)],
new VariableScope()
))
expected.addAnnotation(new AnnotationNode(ClassHelper.make(Override, false)))
AstAssert.assertSyntaxTree([expected], result)
}
public void testAnnotation_WithParameter() {
// @org.junit.Test(timeout=50L) def myMethod() {}
def result = new AstBuilder().buildFromSpec {
method 'myMethod', ACC_PUBLIC, Object, {
parameters {}
exceptions {}
block { }
annotations {
annotation(Override) {
member 'timeout', {
constant 50L
}
}
}
}
}
def expected = new MethodNode(
"myMethod",
ACC_PUBLIC,
ClassHelper.make(Object, false),
[] as Parameter[],
[] as ClassNode[],
new BlockStatement([], new VariableScope()))
def annotation = new AnnotationNode(ClassHelper.make(Override, false))
annotation.setMember('timeout', new ConstantExpression(50L))
expected.addAnnotation(annotation)
AstAssert.assertSyntaxTree([expected], result)
}
public void testMixinNode() {
// todo: what source code will generate a MixinNode?
def result = new AstBuilder().buildFromSpec {
classNode 'MyClass', ACC_PUBLIC, {
classNode Object //superclass
interfaces {
classNode GroovyObject
}
mixins {
mixin "ClassA", ACC_PUBLIC, {
classNode String
}
mixin "ClassB", ACC_PUBLIC, {
classNode String
interfaces {
classNode GroovyObject
}
}
}
}
}
def expected = new ClassNode(
"MyClass", ACC_PUBLIC,
ClassHelper.make(Object, false),
[ClassHelper.make(GroovyObject, false)] as ClassNode[],
[
new MixinNode("ClassA", ACC_PUBLIC, ClassHelper.make(String, false)),
new MixinNode(
"ClassB",
ACC_PUBLIC,
ClassHelper.make(String, false),
[ClassHelper.make(GroovyObject, false)] as ClassNode[]), // interfaces
] as MixinNode[]
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testModuleNode() {
// todo: what source code creates a ModuleNode? ModuleNode has a ton of setters that aren't currently being tested. Should this even be part of the DSL?
}
public void testPropertyNode() {
// def myField = "foo"
def result = new AstBuilder().buildFromSpec {
propertyNode "MY_VALUE", ACC_PUBLIC, String, this.class, {
constant "foo"
}
}
def expected = new PropertyNode(
"MY_VALUE",
ACC_PUBLIC,
ClassHelper.make(String, false),
ClassHelper.make(this.class, false),
new ConstantExpression("foo"),
null,
null //todo: do we need to support getter and setter blocks?
)
AstAssert.assertSyntaxTree([expected], result)
}
public void testMethodCallContract_TooManyArguments() {
def msg = shouldFail(IllegalArgumentException) {
new AstBuilder().buildFromSpec {
methodCall {
variable "this"
constant "println"
argumentList {
constant "Hello"
}
constant "illegal value"
}
}
}
assertEquals("Wrong exception message",
"methodCall could not be invoked. Expected to receive parameters [class org.codehaus.groovy.ast.expr.Expression, class org.codehaus.groovy.ast.expr.Expression, class org.codehaus.groovy.ast.expr.Expression] but found [class org.codehaus.groovy.ast.expr.VariableExpression, class org.codehaus.groovy.ast.expr.ConstantExpression, class org.codehaus.groovy.ast.expr.ArgumentListExpression, class org.codehaus.groovy.ast.expr.ConstantExpression]",
msg)
}
public void testMethodCallContract_TooFewArguments() {
def msg = shouldFail(IllegalArgumentException) {
new AstBuilder().buildFromSpec {
methodCall {
variable "this"
constant "println"
// missing argument list!
}
}
}
assertEquals("Wrong exception message",
"methodCall could not be invoked. Expected to receive parameters [class org.codehaus.groovy.ast.expr.Expression, class org.codehaus.groovy.ast.expr.Expression, class org.codehaus.groovy.ast.expr.Expression] but found [class org.codehaus.groovy.ast.expr.VariableExpression, class org.codehaus.groovy.ast.expr.ConstantExpression]",
msg)
}
public void testAnnotationConstantExpressionContract_TooFewArguments() {
shouldFail(IllegalArgumentException) {
new AstBuilder().buildFromSpec {
annotationConstant {
// missing argument
}
}
}
}
public void testAnnotationConstantExpressionContract_TooManyArguments() {
shouldFail(IllegalArgumentException) {
new AstBuilder().buildFromSpec {
annotationConstant {
annotation Override
constant 'illegal parameter'
}
}
}
}
public void testConstructorCallExpressionContract_TooFewParameters() {
shouldFail(IllegalArgumentException) {
new AstBuilder().buildFromSpec {
constructorCall(Integer) {
// missing argument list
}
}
}
}
public void testConstructorCallExpressionContract_TooManyParameters() {
shouldFail(IllegalArgumentException) {
new AstBuilder().buildFromSpec {
constructorCall(Integer) {
argumentList {
constant 4
}
constant 'illegal argument'
}
}
}
}
}
Other Groovy examples (source code examples)Here is a short list of links related to this Groovy AstBuilderFromSpecificationTest.groovy source code file: |
Other websites by Alvin Alexander:
Life/living in Alaska (OneMansAlaska.com)
How I Sold My Business (HowISoldMyBusiness.com)
Copyright 1998-2011 Alvin Alexander, devdaily.com
All Rights Reserved.