From 800c4e4c1fb6e52dc6391cc9ef09a68b9697d422 Mon Sep 17 00:00:00 2001 From: Benjamin Bentmann Date: Fri, 3 Oct 2008 19:29:31 +0000 Subject: [PATCH] o Added new IT plugin to inspect the runtime state of the POM and things like by dumping expression values into a properties file git-svn-id: https://svn.apache.org/repos/asf/maven/core-integration-testing/trunk@701503 13f79535-47bb-0310-9956-ffa450edef68 --- .../maven-it-plugin-expression/pom.xml | 54 +++++ .../apache/maven/plugin/coreit/EvalMojo.java | 171 +++++++++++++ .../maven/plugin/coreit/ExpressionUtil.java | 227 ++++++++++++++++++ .../maven/plugin/coreit/PropertyUtil.java | 194 +++++++++++++++ .../plugin/coreit/ExpressionUtilTest.java | 122 ++++++++++ .../maven/plugin/coreit/PropertyUtilTest.java | 130 ++++++++++ its/core-it-support/core-it-plugins/pom.xml | 1 + 7 files changed, 899 insertions(+) create mode 100644 its/core-it-support/core-it-plugins/maven-it-plugin-expression/pom.xml create mode 100644 its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/EvalMojo.java create mode 100644 its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/ExpressionUtil.java create mode 100644 its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/PropertyUtil.java create mode 100644 its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/ExpressionUtilTest.java create mode 100644 its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/PropertyUtilTest.java diff --git a/its/core-it-support/core-it-plugins/maven-it-plugin-expression/pom.xml b/its/core-it-support/core-it-plugins/maven-it-plugin-expression/pom.xml new file mode 100644 index 0000000000..e2e2704776 --- /dev/null +++ b/its/core-it-support/core-it-plugins/maven-it-plugin-expression/pom.xml @@ -0,0 +1,54 @@ + + + + + + 4.0.0 + + + maven-it-plugins + org.apache.maven.its.plugins + 2.1-SNAPSHOT + + + maven-it-plugin-expression + maven-plugin + + Maven Integration Test Plugin :: Expression + + A test plugin that creates a properties file with the effective values of some user-defined expressions. As such it + allows to analyze the runtime state of the POM similar to the Help Plugin. + + 2008 + + + + org.apache.maven + maven-plugin-api + 2.0 + + + junit + junit + 3.8.2 + test + + + diff --git a/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/EvalMojo.java b/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/EvalMojo.java new file mode 100644 index 0000000000..dbfaa9435e --- /dev/null +++ b/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/EvalMojo.java @@ -0,0 +1,171 @@ +package org.apache.maven.plugin.coreit; + +/* + * 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. + */ + +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +/** + * Creates a properties file with the effective values of some user-defined expressions. Unlike Maven's built-in + * expression syntax for interpolation, these expressions use forward slashes to navigate down the object graph and + * support access to individual collection/array elements. Furthermore, the result of an expression need not be a scalar + * value but can also be a collection/array or a bean-like object (from the Maven model). For example, the expression + * "project/dependencies/0" would extract the first project dependency. In more detail, this example expression could + * output the following keys to the properties file: + * + *
+ * project.dependencies.0.groupId = org.apache.maven
+ * project.dependencies.0.artifactId = maven-project
+ * project.dependencies.0.type = jar
+ * project.dependencies.0.version = 2.0
+ * project.dependencies.0.optional = false
+ * project.dependencies.0.exclusions = 2
+ * project.dependencies.0.exclusions.0.groupId = plexus
+ * project.dependencies.0.exclusions.0.artifactId = plexus-utils
+ * project.dependencies.0.exclusions.1.groupId = plexus
+ * project.dependencies.0.exclusions.1.artifactId = plexus-container-default
+ * 
+ * + * Expressions that reference non-existing objects or use invalid collection/array indices silently resolve to + * null. + * + * @goal eval + * @phase initialize + * + * @author Benjamin Bentmann + * @version $Id$ + */ +public class EvalMojo + extends AbstractMojo +{ + + /** + * The path to the output file for the properties with the expression values. For each expression given by the + * parameter {@link #expressions} an similar named properties key will be used to save the expression value. If an + * expression evaluated to null, there will be no corresponding key in the properties file. + * + * @parameter expression="${expression.outputFile}" default-value="${project.build.directory}/expression.properties" + */ + private File outputFile; + + /** + * The set of expressions to evaluate. + * + * @parameter + */ + private String[] expressions; + + /** + * The comma separated set of expressions to evaluate. + * + * @parameter expression="${expression.expressions}" + */ + private String expressionList; + + /** + * The current Maven project against which expressions are evaluated. + * + * @parameter default-value="${project}" + * @readonly + */ + private Object project; + + /** + * The merged user/global settings of the current build against which expressions are evaluated. + * + * @parameter default-value="${settings}" + * @readonly + */ + private Object settings; + + /** + * The session context of the current build against which expressions are evaluated. + * + * @parameter default-value="${session}" + * @readonly + */ + private Object session; + + /** + * The local repository of the current build against which expressions are evaluated. + * + * @parameter default-value="${localRepository}" + * @readonly + */ + private Object localRepository; + + /** + * Runs this mojo. + * + * @throws MojoExecutionException If the output file could not be created. + * @throws MojoFailureException If the output file has not been set. + */ + public void execute() + throws MojoExecutionException, MojoFailureException + { + if ( outputFile == null ) + { + throw new MojoFailureException( "Path name for output file has not been specified" ); + } + + getLog().info( "[MAVEN-CORE-IT-LOG] Creating output file: " + outputFile ); + + Properties expressionProperties = new Properties(); + + if ( expressionList != null && expressionList.length() > 0 ) + { + expressions = expressionList.split( "," ); + } + if ( expressions != null && expressions.length > 0 ) + { + Map contexts = new HashMap(); + contexts.put( "project", project ); + contexts.put( "pom", project ); + contexts.put( "settings", settings ); + contexts.put( "session", session ); + contexts.put( "localRepository", localRepository ); + + for ( int i = 0; i < expressions.length; i++ ) + { + Object value = ExpressionUtil.evaluate( expressions[i], contexts ); + PropertyUtil.store( expressionProperties, expressions[i].replace( '/', '.' ), value ); + } + } + + try + { + PropertyUtil.write( expressionProperties, outputFile ); + } + catch ( IOException e ) + { + throw new MojoExecutionException( "Output file could not be created: " + outputFile, e ); + } + + getLog().info( "[MAVEN-CORE-IT-LOG] Created output file: " + outputFile ); + } + +} diff --git a/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/ExpressionUtil.java b/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/ExpressionUtil.java new file mode 100644 index 0000000000..9f32f8b04e --- /dev/null +++ b/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/ExpressionUtil.java @@ -0,0 +1,227 @@ +package org.apache.maven.plugin.coreit; + +/* + * 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. + */ + +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * Assists in evaluating expressions. + * + * @author Benjamin Bentmann + * @version $Id$ + */ +class ExpressionUtil +{ + + private static final Object[] NO_ARGS = {}; + + private static final Class[] NO_PARAMS = {}; + + private static final Class[] OBJECT_PARAM = { Object.class }; + + private static final Class[] STRING_PARAM = { String.class }; + + /** + * Evaluates the specified expression. Expressions are composed of segments which are separated by a forward slash + * ('/'). Each segment specifies a (public) bean property of the current object and drives the evaluation further + * down the object graph. For lists, arrays and maps segments can additionally specify the index/key of an element. + * The initial segment denotes the root object and the parameter contexts is used to specify which + * root objects are available. For instance, if contexts maps the token "project" to a Maven project + * instance, the expression "project/build/resources/0/directory" specifies the first resource directory of the + * project. + * + * @param expression The expression to evaluate, may be null. + * @param contexts The possible root objects for the expression evaluation, indexed by their identifying token, must + * not be null. + * @return The value of the expression or null if the expression could not be evaluated. + */ + public static Object evaluate( String expression, Map contexts ) + { + Object value = null; + + if ( expression != null && expression.length() > 0 ) + { + List segments = Arrays.asList( expression.split( "/", 0 ) ); + if ( !segments.isEmpty() ) + { + Object context = contexts.get( segments.get( 0 ) ); + if ( context != null ) + { + value = evaluate( context, segments.subList( 1, segments.size() ) ); + } + } + } + + return value; + } + + /** + * Evaluates the given expression segments against the specified object. + * + * @param context The object to evaluate the segments against, may be null. + * @param segments The expression segments to evaluate, must not be null. + * @return The value of the evaluation or null if the segments could not be evaluated. + */ + private static Object evaluate( Object context, List segments ) + { + Object value = null; + + if ( segments.isEmpty() ) + { + value = context; + } + else if ( context != null ) + { + Object target = null; + String segment = (String) segments.get( 0 ); + if ( segment.length() <= 0 ) + { + value = context; + } + else if ( context.getClass().isArray() && Character.isDigit( segment.charAt( 0 ) ) ) + { + try + { + int index = Integer.parseInt( segment ); + target = Array.get( context, index ); + } + catch ( RuntimeException e ) + { + // invalid index, just ignore + } + } + else if ( ( context instanceof List ) && Character.isDigit( segment.charAt( 0 ) ) ) + { + try + { + int index = Integer.parseInt( segment ); + target = ( (List) context ).get( index ); + } + catch ( RuntimeException e ) + { + // invalid index, just ignore + } + } + else + { + target = getProperty( context, segment ); + } + value = evaluate( target, segments.subList( 1, segments.size() ) ); + } + + return value; + } + + /** + * Gets the value of a (public) bean property from the specified object. + * + * @param context The object whose bean property should be retrieved, must not be null. + * @param property The name of the bean property, must not be null. + * @return The value of the bean property or null if the property does not exist. + */ + static Object getProperty( Object context, String property ) + { + Object value; + + Class type = context.getClass(); + if ( context instanceof Collection ) + { + type = Collection.class; + } + else if ( context instanceof Map ) + { + type = Map.class; + } + + try + { + try + { + Method method = type.getMethod( property, NO_PARAMS ); + value = method.invoke( context, NO_ARGS ); + } + catch ( NoSuchMethodException e ) + { + try + { + String name = "get" + Character.toUpperCase( property.charAt( 0 ) ) + property.substring( 1 ); + Method method = type.getMethod( name, NO_PARAMS ); + value = method.invoke( context, NO_ARGS ); + } + catch ( NoSuchMethodException e1 ) + { + try + { + String name = "is" + Character.toUpperCase( property.charAt( 0 ) ) + property.substring( 1 ); + Method method = type.getMethod( name, NO_PARAMS ); + value = method.invoke( context, NO_ARGS ); + } + catch ( NoSuchMethodException e2 ) + { + try + { + Method method; + try + { + method = type.getMethod( "get", STRING_PARAM ); + } + catch ( NoSuchMethodException e3 ) + { + method = type.getMethod( "get", OBJECT_PARAM ); + } + value = method.invoke( context, new Object[] { property } ); + } + catch ( NoSuchMethodException e3 ) + { + try + { + Field field = type.getField( property ); + value = field.get( context ); + } + catch ( NoSuchFieldException e4 ) + { + if ( "length".equals( property ) && type.isArray() ) + { + value = new Integer( Array.getLength( context ) ); + } + else + { + throw e4; + } + } + } + } + } + } + } + catch ( Exception e ) + { + value = null; + } + return value; + } + +} diff --git a/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/PropertyUtil.java b/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/PropertyUtil.java new file mode 100644 index 0000000000..831dc3d223 --- /dev/null +++ b/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/PropertyUtil.java @@ -0,0 +1,194 @@ +package org.apache.maven.plugin.coreit; + +/* + * 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. + */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; + +/** + * Assists in serializing primitives and beans into properties for later inspection/verification. + * + * @author Benjamin Bentmann + * @version $Id$ + */ +class PropertyUtil +{ + + private static final Object[] NO_ARGS = {}; + + /** + * Serializes the specified object into the given properties, using the provided key. The object may be a scalar + * value like a string or some array/collection/map or a bean. + * + * @param props The properties to serialize into, must not be null. + * @param key The key to use for serialization of the object data, must not be null. + * @param obj The object to serialize, may be null. + */ + public static void store( Properties props, String key, Object obj ) + { + store( props, key, obj, new HashSet() ); + } + + /** + * /** Serializes the specified object into the given properties, using the provided key. The object may be a scalar + * value like a string or some array/collection/map or a bean. + * + * @param props The properties to serialize into, must not be null. + * @param key The key to use for serialization of the object data, must not be null. + * @param obj The object to serialize, may be null. + * @param visited The set/stack of already visited objects, used to detect back references in the object graph, must + * not be null. + */ + private static void store( Properties props, String key, Object obj, Collection visited ) + { + if ( obj != null ) + { + if ( ( obj instanceof String ) || ( obj instanceof Number ) || ( obj instanceof Boolean ) + || ( obj instanceof File ) ) + { + props.put( key, obj.toString() ); + } + else if ( obj instanceof Collection ) + { + Collection coll = (Collection) obj; + props.put( key, Integer.toString( coll.size() ) ); + int index = 0; + for ( Iterator it = coll.iterator(); it.hasNext(); index++ ) + { + Object elem = it.next(); + store( props, key + "." + index, elem ); + } + } + else if ( obj instanceof Map ) + { + Map map = (Map) obj; + props.put( key, Integer.toString( map.size() ) ); + int index = 0; + for ( Iterator it = map.entrySet().iterator(); it.hasNext(); index++ ) + { + Map.Entry entry = (Map.Entry) it.next(); + store( props, key + "." + entry.getKey(), entry.getValue() ); + } + } + else if ( obj.getClass().isArray() ) + { + int length = Array.getLength( obj ); + props.put( key, Integer.toString( length ) ); + for ( int index = 0; index < length; index++ ) + { + Object elem = Array.get( obj, index ); + store( props, key + "." + index, elem ); + } + } + else if ( obj != null && !visited.contains( obj ) ) + { + visited.add( obj ); + Class type = obj.getClass(); + Method[] methods = type.getMethods(); + for ( int i = 0; i < methods.length; i++ ) + { + Method method = methods[i]; + if ( Modifier.isStatic( method.getModifiers() ) || method.getParameterTypes().length > 0 + || !method.getName().matches( "(get|is)\\p{Lu}.*" ) || method.getName().endsWith( "AsMap" ) + || Class.class.isAssignableFrom( method.getReturnType() ) + || Object.class.equals( method.getReturnType() ) ) + { + continue; + } + + try + { + Object value = method.invoke( obj, NO_ARGS ); + store( props, key + "." + getPropertyName( method.getName() ), value, visited ); + } + catch ( Exception e ) + { + // just ignore + } + } + visited.remove( obj ); + } + } + } + + /** + * Derives the bean property name from the specified method for its getter. + * + * @param methodName The method name of the property's getter, must not be null. + * @return The property name, never null. + */ + static String getPropertyName( String methodName ) + { + String propertyName = methodName; + if ( methodName.startsWith( "get" ) && methodName.length() > 3 ) + { + propertyName = Character.toLowerCase( methodName.charAt( 3 ) ) + methodName.substring( 4 ); + } + else if ( methodName.startsWith( "is" ) && methodName.length() > 2 ) + { + propertyName = Character.toLowerCase( methodName.charAt( 2 ) ) + methodName.substring( 3 ); + } + return propertyName; + } + + /** + * Writes the specified properties to the given file. + * + * @param props The properties to write, must not be null. + * @param file The output file for the properties, must not be null. + * @throws IOException If the properties could not be written to the file. + */ + public static void write( Properties props, File file ) + throws IOException + { + OutputStream out = null; + try + { + file.getParentFile().mkdirs(); + out = new FileOutputStream( file ); + props.store( out, "MAVEN-CORE-IT-LOG" ); + } + finally + { + if ( out != null ) + { + try + { + out.close(); + } + catch ( IOException e ) + { + // just ignore + } + } + } + } + +} diff --git a/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/ExpressionUtilTest.java b/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/ExpressionUtilTest.java new file mode 100644 index 0000000000..fe797405c0 --- /dev/null +++ b/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/ExpressionUtilTest.java @@ -0,0 +1,122 @@ +package org.apache.maven.plugin.coreit; + +/* + * 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. + */ + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import junit.framework.TestCase; + +/** + * @author Benjamin Bentmann + * @version $Id$ + */ +public class ExpressionUtilTest + extends TestCase +{ + + public void testEvaluate() + { + Object array = new String[] { "one", "two", "three" }; + Object list = Arrays.asList( new String[] { "0", "-1", "-2" } ); + Object map = Collections.singletonMap( "some.key", "value" ); + Object bean = new BeanTwo(); + + Map contexts = new HashMap(); + contexts.put( "array", array ); + contexts.put( "list", list ); + contexts.put( "map", map ); + contexts.put( "bean", bean ); + + assertSame( array, ExpressionUtil.evaluate( "array", contexts ) ); + assertSame( array, ExpressionUtil.evaluate( "array/", contexts ) ); + assertSame( list, ExpressionUtil.evaluate( "list", contexts ) ); + assertSame( map, ExpressionUtil.evaluate( "map", contexts ) ); + assertSame( bean, ExpressionUtil.evaluate( "bean", contexts ) ); + assertNull( ExpressionUtil.evaluate( "no-root", contexts ) ); + + assertEquals( new Integer( 3 ), ExpressionUtil.evaluate( "array/length", contexts ) ); + assertEquals( "three", ExpressionUtil.evaluate( "array/2", contexts ) ); + assertEquals( new Integer( 5 ), ExpressionUtil.evaluate( "array/2/length", contexts ) ); + assertNull( ExpressionUtil.evaluate( "array/invalid", contexts ) ); + assertNull( ExpressionUtil.evaluate( "array/-1", contexts ) ); + assertNull( ExpressionUtil.evaluate( "array/999", contexts ) ); + + assertEquals( new Integer( 3 ), ExpressionUtil.evaluate( "list/size", contexts ) ); + assertEquals( "-2", ExpressionUtil.evaluate( "list/2", contexts ) ); + assertNull( ExpressionUtil.evaluate( "list/invalid", contexts ) ); + assertNull( ExpressionUtil.evaluate( "list/-1", contexts ) ); + assertNull( ExpressionUtil.evaluate( "list/999", contexts ) ); + + assertEquals( new Integer( 1 ), ExpressionUtil.evaluate( "map/size", contexts ) ); + assertEquals( "value", ExpressionUtil.evaluate( "map/some.key", contexts ) ); + assertNull( ExpressionUtil.evaluate( "map/invalid", contexts ) ); + + assertEquals( "field", ExpressionUtil.evaluate( "bean/field", contexts ) ); + assertNull( ExpressionUtil.evaluate( "bean/invalid", contexts ) ); + assertEquals( "prop", ExpressionUtil.evaluate( "bean/bean/prop", contexts ) ); + assertEquals( "flag", ExpressionUtil.evaluate( "bean/bean/flag", contexts ) ); + assertEquals( "arg", ExpressionUtil.evaluate( "bean/bean/arg", contexts ) ); + } + + public void testGetProperty() + { + BeanOne bean1 = new BeanOne(); + BeanTwo bean2 = new BeanTwo(); + + assertEquals( bean1.isFlag(), ExpressionUtil.getProperty( bean1, "flag" ) ); + assertEquals( bean1.getProp(), ExpressionUtil.getProperty( bean1, "prop" ) ); + assertEquals( bean1.get( "get" ), ExpressionUtil.getProperty( bean1, "get" ) ); + + assertNull( ExpressionUtil.getProperty( bean2, "invalid" ) ); + assertEquals( bean2.field, ExpressionUtil.getProperty( bean2, "field" ) ); + assertSame( bean2.bean, ExpressionUtil.getProperty( bean2, "bean" ) ); + + assertEquals( new Integer( 0 ), ExpressionUtil.getProperty( new String[0], "length" ) ); + } + + public static class BeanOne + { + public String isFlag() + { + return "flag"; + } + + public String getProp() + { + return "prop"; + } + + public String get( String arg ) + { + return arg; + } + } + + public static class BeanTwo + { + public String field = "field"; + + public BeanOne bean = new BeanOne(); + + } +} diff --git a/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/PropertyUtilTest.java b/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/PropertyUtilTest.java new file mode 100644 index 0000000000..ac0f5b2e79 --- /dev/null +++ b/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/PropertyUtilTest.java @@ -0,0 +1,130 @@ +package org.apache.maven.plugin.coreit; + +/* + * 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. + */ + +import java.io.File; +import java.util.Arrays; +import java.util.Collections; +import java.util.Properties; + +import junit.framework.TestCase; + +/** + * @author Benjamin Bentmann + * @version $Id$ + */ +public class PropertyUtilTest + extends TestCase +{ + + public void testStoreScalar() + { + Properties props = new Properties(); + PropertyUtil.store( props, "null", null ); + PropertyUtil.store( props, "string", "str" ); + PropertyUtil.store( props, "boolean", Boolean.TRUE ); + PropertyUtil.store( props, "int", new Integer( 7 ) ); + PropertyUtil.store( props, "file", new File( "pom.xml" ) ); + + assertNull( props.get( "null" ) ); + assertEquals( "str", props.get( "string" ) ); + assertEquals( "true", props.get( "boolean" ) ); + assertEquals( "7", props.get( "int" ) ); + assertEquals( "pom.xml", props.get( "file" ) ); + assertEquals( 4, props.size() ); + } + + public void testStoreArray() + { + Properties props = new Properties(); + PropertyUtil.store( props, "arr", new String[] { "one", "two" } ); + + assertEquals( "2", props.get( "arr" ) ); + assertEquals( "one", props.get( "arr.0" ) ); + assertEquals( "two", props.get( "arr.1" ) ); + assertEquals( 3, props.size() ); + } + + public void testStoreList() + { + Properties props = new Properties(); + PropertyUtil.store( props, "arr", Arrays.asList( new String[] { "one", "two" } ) ); + + assertEquals( "2", props.get( "arr" ) ); + assertEquals( "one", props.get( "arr.0" ) ); + assertEquals( "two", props.get( "arr.1" ) ); + assertEquals( 3, props.size() ); + } + + public void testStoreMap() + { + Properties props = new Properties(); + PropertyUtil.store( props, "map", Collections.singletonMap( "key", "value" ) ); + + assertEquals( "1", props.get( "map" ) ); + assertEquals( "value", props.get( "map.key" ) ); + assertEquals( 2, props.size() ); + } + + public void testStoreBean() + { + Properties props = new Properties(); + PropertyUtil.store( props, "bean", new Bean() ); + + assertEquals( "name", props.get( "bean.name" ) ); + assertEquals( "false", props.get( "bean.enabled" ) ); + assertEquals( 2, props.size() ); + } + + public void testGetPropertyName() + { + assertEquals( "name", PropertyUtil.getPropertyName( "getName" ) ); + assertEquals( "enabled", PropertyUtil.getPropertyName( "isEnabled" ) ); + } + + public static class Bean + { + public String getName() + { + return "name"; + } + + public boolean isEnabled() + { + return false; + } + + public String toString() + { + return "excluded"; + } + + public Object getUntypedReturnValue() + { + return "excluded"; + } + + public Bean getCyclicReference() + { + return this; + } + } + +} diff --git a/its/core-it-support/core-it-plugins/pom.xml b/its/core-it-support/core-it-plugins/pom.xml index aa567b35de..bc3a828c00 100644 --- a/its/core-it-support/core-it-plugins/pom.xml +++ b/its/core-it-support/core-it-plugins/pom.xml @@ -39,6 +39,7 @@ under the License. maven-it-plugin-context-passing maven-it-plugin-core-stubs maven-it-plugin-dependency-resolution + maven-it-plugin-expression maven-it-plugin-file maven-it-plugin-fork maven-it-plugin-generate-envar-properties