/* * Copyright (c) 2004, Codehaus.org * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is furnished to do * so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ import org.codehaus.modello.OrderedProperties; import org.codehaus.modello.verifier.Verifier; import org.codehaus.modello.verifier.VerifierException; import org.codehaus.modello.test.features.AssociationFeatures; import org.codehaus.modello.test.features.BaseClass; import org.codehaus.modello.test.features.Bidirectional; import org.codehaus.modello.test.features.BidiInList; import org.codehaus.modello.test.features.BidiInSet; import org.codehaus.modello.test.features.InterfacesFeature; import org.codehaus.modello.test.features.JavaAbstractFeature; import org.codehaus.modello.test.features.JavaFeatures; import org.codehaus.modello.test.features.NodeItem; import org.codehaus.modello.test.features.Reference; import org.codehaus.modello.test.features.SimpleInterface; import org.codehaus.modello.test.features.SimpleTypes; import org.codehaus.modello.test.features.SubClassLevel1; import org.codehaus.modello.test.features.SubClassLevel2; import org.codehaus.modello.test.features.SubClassLevel3; import org.codehaus.modello.test.features.SubInterface; import org.codehaus.modello.test.features.Thing; import org.codehaus.modello.test.features.Thingy; import org.codehaus.modello.test.features.XmlAttributes; import org.codehaus.modello.test.features.XmlFeatures; import org.codehaus.modello.test.features.other.SubInterfaceInPackage; import org.codehaus.plexus.util.xml.Xpp3Dom; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import junit.framework.Assert; /** * @author Herve Boutemy */ public class JavaVerifier extends Verifier { public void verify() { try { verifySimpleTypes(); verifyXmlAttributes(); verifyJavaFeatures(); } catch ( NoSuchFieldException nsfe ) { throw new VerifierException( "field not found", nsfe ); } catch ( NoSuchMethodException nsme ) { throw new VerifierException( "method not found", nsme ); } verifyDefaultValues(); verifyInterfaces(); verifyMisc(); verifyClone(); } /** * Check that a field has been propertly declared with public accessors. * * @param clazz the class that should contain the field * @param attributeName the field's attribute name * @param type the field expected type * @param getterName the expected getter method name * @param setterName the expected setter method name * @throws NoSuchFieldException * @throws NoSuchMethodException */ private void checkField( Class clazz, String attributeName, Class type, String getterName, String setterName ) throws NoSuchFieldException, NoSuchMethodException { checkField( clazz, attributeName, type, getterName, setterName, type /* by default, accessors use same type as corresponding field */ ); } /** * Check that a field has been propertly declared with public accessors. * * @param clazz the class that should contain the field * @param attributeName the field's attribute name * @param type the field expected type * @param getterName the expected getter method name * @param setterName the expected setter method name * @param getterAndSetterType the type expected in getter and setter methods * @throws NoSuchFieldException * @throws NoSuchMethodException */ private void checkField( Class clazz, String attributeName, Class type, String getterName, String setterName, Class getterAndSetterType) throws NoSuchFieldException, NoSuchMethodException { Field field = clazz.getDeclaredField( attributeName ); Assert.assertEquals( attributeName + " attribute type", type, field.getType() ); Assert.assertTrue( attributeName + " attribute should be private", Modifier.isPrivate( field.getModifiers() ) ); Method getter = clazz.getMethod( getterName, (Class[]) null ); Assert.assertNotNull( getterName + "() method", getter ); Assert.assertEquals( getterName + "() method return type", getterAndSetterType, getter.getReturnType() ); Assert.assertTrue( getterName + "() method should be public", Modifier.isPublic( getter.getModifiers() ) ); Method setter = clazz.getMethod( setterName, new Class[] { getterAndSetterType } ); Assert.assertNotNull( setterName + "( " + type.getName() + " ) method", setter ); Assert.assertTrue( setterName + "( " + type.getName() + " ) method should be public", Modifier.isPublic( setter.getModifiers() ) ); } /** * Check fields declaration common to SimpleTypes and XmlAttributes classes. * * @param clazz the actuel class to check * @throws NoSuchFieldException * @throws NoSuchMethodException */ private void checkCommonFields( Class clazz ) throws NoSuchFieldException, NoSuchMethodException { checkField( clazz, "primitiveBoolean", Boolean.TYPE , "isPrimitiveBoolean", "setPrimitiveBoolean" ); checkField( clazz, "primitiveByte" , Byte.TYPE , "getPrimitiveByte" , "setPrimitiveByte" ); checkField( clazz, "primitiveChar" , Character.TYPE, "getPrimitiveChar" , "setPrimitiveChar" ); checkField( clazz, "primitiveShort" , Short.TYPE , "getPrimitiveShort" , "setPrimitiveShort" ); checkField( clazz, "primitiveInt" , Integer.TYPE , "getPrimitiveInt" , "setPrimitiveInt" ); checkField( clazz, "primitiveLong" , Long.TYPE , "getPrimitiveLong" , "setPrimitiveLong" ); checkField( clazz, "primitiveFloat" , Float.TYPE , "getPrimitiveFloat" , "setPrimitiveFloat" ); checkField( clazz, "primitiveDouble" , Double.TYPE , "getPrimitiveDouble", "setPrimitiveDouble" ); checkField( clazz, "objectBoolean" , Boolean.class , "isObjectBoolean" , "setObjectBoolean" ); checkField( clazz, "objectString" , String.class , "getObjectString" , "setObjectString" ); checkField( clazz, "objectDate" , Date.class , "getObjectDate" , "setObjectDate" ); } /** * Verify SimpleTypes generated class. * * @throws NoSuchFieldException * @throws NoSuchMethodException */ public void verifySimpleTypes() throws NoSuchFieldException, NoSuchMethodException { checkCommonFields( SimpleTypes.class ); } /** * Verify XmlAttributes generated class. * * @throws NoSuchFieldException * @throws NoSuchMethodException */ public void verifyXmlAttributes() throws NoSuchFieldException, NoSuchMethodException { checkCommonFields( XmlAttributes.class ); } /** * Verify default values. */ public void verifyDefaultValues() { SimpleTypes simple = new SimpleTypes(); Assert.assertEquals( "primitiveBoolean", true , simple.isPrimitiveBoolean() ); Assert.assertEquals( "primitiveByte" , 12 , simple.getPrimitiveByte() ); Assert.assertEquals( "primitiveChar" , 'H' , simple.getPrimitiveChar() ); Assert.assertEquals( "primitiveShort" , (short) 1212 , simple.getPrimitiveShort() ); Assert.assertEquals( "primitiveInt" , 121212 , simple.getPrimitiveInt() ); Assert.assertEquals( "primitiveLong" , 1234567890123L , simple.getPrimitiveLong() ); Assert.assertEquals( "primitiveFloat" , 12.12f , simple.getPrimitiveFloat(), 0f ); Assert.assertEquals( "primitiveDouble" , 12.12 , simple.getPrimitiveDouble(), 0 ); Assert.assertEquals( "objectBoolean" , Boolean.TRUE , simple.isObjectBoolean() ); Assert.assertEquals( "objectByte" , 12 , simple.getObjectByte().byteValue() ); Assert.assertEquals( "objectChar" , 'H' , simple.getObjectCharacter().charValue() ); Assert.assertEquals( "objectShort" , (short) 1212 , simple.getObjectShort().shortValue() ); Assert.assertEquals( "objectInt" , 121212 , simple.getObjectInteger().intValue() ); Assert.assertEquals( "objectLong" , 1234567890123L , simple.getObjectLong().longValue() ); Assert.assertEquals( "objectFloat" , 12.12f , simple.getObjectFloat().floatValue(), 0f ); Assert.assertEquals( "objectDouble" , 12.12 , simple.getObjectDouble().doubleValue(), 0 ); Assert.assertEquals( "objectString" , "default value", simple.getObjectString() ); Assert.assertEquals( "primitiveBoolean", false , simple.isPrimitiveBooleanNoDefault() ); Assert.assertEquals( "primitiveByte" , 0 , simple.getPrimitiveByteNoDefault() ); Assert.assertEquals( "primitiveChar" , '\0' , simple.getPrimitiveCharNoDefault() ); Assert.assertEquals( "primitiveShort" , 0 , simple.getPrimitiveShortNoDefault() ); Assert.assertEquals( "primitiveInt" , 0 , simple.getPrimitiveIntNoDefault() ); Assert.assertEquals( "primitiveLong" , 0 , simple.getPrimitiveLongNoDefault() ); Assert.assertEquals( "primitiveFloat" , 0 , simple.getPrimitiveFloatNoDefault(), 0f ); Assert.assertEquals( "primitiveDouble" , 0 , simple.getPrimitiveDoubleNoDefault(), 0 ); Assert.assertEquals( "objectBoolean" , null , simple.isObjectBooleanNoDefault() ); Assert.assertEquals( "objectByte" , null , simple.getObjectByteNoDefault() ); Assert.assertEquals( "objectChar" , null , simple.getObjectCharacterNoDefault() ); Assert.assertEquals( "objectShort" , null , simple.getObjectShortNoDefault() ); Assert.assertEquals( "objectInt" , null , simple.getObjectIntegerNoDefault() ); Assert.assertEquals( "objectLong" , null , simple.getObjectLongNoDefault() ); Assert.assertEquals( "objectFloat" , null , simple.getObjectFloatNoDefault() ); Assert.assertEquals( "objectDouble" , null , simple.getObjectDoubleNoDefault() ); Assert.assertEquals( "objectString" , null , simple.getObjectStringNoDefault() ); XmlAttributes xmlAttributes = new XmlAttributes(); Assert.assertEquals( "primitiveBoolean", true , xmlAttributes.isPrimitiveBoolean() ); Assert.assertEquals( "primitiveByte" , 12 , xmlAttributes.getPrimitiveByte() ); Assert.assertEquals( "primitiveChar" , 'H' , xmlAttributes.getPrimitiveChar() ); Assert.assertEquals( "primitiveShort" , (short) 1212 , xmlAttributes.getPrimitiveShort() ); Assert.assertEquals( "primitiveInt" , 121212 , xmlAttributes.getPrimitiveInt() ); Assert.assertEquals( "primitiveLong" , 1234567890123L , xmlAttributes.getPrimitiveLong() ); Assert.assertEquals( "primitiveFloat" , 12.12f , xmlAttributes.getPrimitiveFloat(), 0f ); Assert.assertEquals( "primitiveDouble" , 12.12 , xmlAttributes.getPrimitiveDouble(), 0 ); Assert.assertEquals( "objectBoolean" , Boolean.TRUE , xmlAttributes.isObjectBoolean() ); Assert.assertEquals( "objectByte" , 12 , xmlAttributes.getObjectByte().byteValue() ); Assert.assertEquals( "objectChar" , 'H' , xmlAttributes.getObjectCharacter().charValue() ); Assert.assertEquals( "objectShort" , (short) 1212 , xmlAttributes.getObjectShort().shortValue() ); Assert.assertEquals( "objectInt" , 121212 , xmlAttributes.getObjectInteger().intValue() ); Assert.assertEquals( "objectLong" , 1234567890123L , xmlAttributes.getObjectLong().longValue() ); Assert.assertEquals( "objectFloat" , 12.12f , xmlAttributes.getObjectFloat().floatValue(), 0f ); Assert.assertEquals( "objectDouble" , 12.12 , xmlAttributes.getObjectDouble().doubleValue(), 0 ); Assert.assertEquals( "objectString" , "default value", xmlAttributes.getObjectString() ); } public void verifyJavaFeatures() throws NoSuchFieldException, NoSuchMethodException { // java.abstract feature if ( !Modifier.isAbstract( JavaAbstractFeature.class.getModifiers() ) ) { throw new VerifierException( "JavaAbstractFeature should be abstract" ); } // interfaces feature if ( !java.io.Serializable.class.isAssignableFrom( InterfacesFeature.class ) ) { throw new VerifierException( "InterfacesFeature should implement java.io.Serializable" ); } if ( !java.rmi.Remote.class.isAssignableFrom( InterfacesFeature.class ) ) { throw new VerifierException( "InterfacesFeature should implement java.rmi.Remote" ); } if ( !SubInterface.class.isAssignableFrom( InterfacesFeature.class ) ) { throw new VerifierException( "InterfacesFeature should implement SubInterface" ); } if ( !SubInterfaceInPackage.class.isAssignableFrom( InterfacesFeature.class ) ) { throw new VerifierException( "InterfacesFeature should implement SubInterfaceInPackage" ); } // superClass feature if ( !BaseClass.class.isAssignableFrom( SubClassLevel1.class ) ) { throw new VerifierException( "SubClassLevel1 should extend BaseClass" ); } if ( !SubClassLevel1.class.isAssignableFrom( SubClassLevel2.class ) ) { throw new VerifierException( "SubClassLevel2 should extend SubClassLevel1" ); } if ( !SubClassLevel2.class.isAssignableFrom( SubClassLevel3.class ) ) { throw new VerifierException( "SubClassLevel3 should extend SubClassLevel2" ); } // methods for collections AssociationFeatures association = new AssociationFeatures(); // add/remove for List association.setListReferences( new ArrayList() ); List list = association.getListReferences(); association.addListReference( new Reference() ); association.removeListReference( new Reference() ); // add/remove for Set association.setSetReferences( new HashSet() ); Set set = association.getSetReferences(); association.addSetReference( new Reference() ); association.removeSetReference( new Reference() ); // java.adder=false JavaFeatures java = new JavaFeatures(); java.setJavaListNoAdd( new ArrayList() ); list = java.getJavaListNoAdd(); checkNoMethod( JavaFeatures.class, "addJavaListNoAdd", Reference.class ); checkNoMethod( JavaFeatures.class, "removeJavaListNoAdd", Reference.class ); java.setJavaSetNoAdd( new HashSet() ); set = java.getJavaSetNoAdd(); checkNoMethod( JavaFeatures.class, "addJavaSetNoAdd", Reference.class ); checkNoMethod( JavaFeatures.class, "removeJavaSetNoAdd", Reference.class ); // bidi Bidirectional bidi = new Bidirectional(); association.setBidi( bidi ); Assert.assertEquals( "setting bidi in association should set the reverse association", association, bidi.getParent() ); bidi.setParent( null ); Assert.assertNull( "setting parent to null in bidi should remove value in association", association.getBidi() ); BidiInList bidiInList = new BidiInList(); association.addListOfBidi( bidiInList ); Assert.assertEquals( "setting bidi in many association should set the reverse association", association, bidiInList.getParent() ); bidiInList.setParent( null ); Assert.assertEquals( 0, association.getListOfBidis().size() ); bidiInList.setParent( association ); Assert.assertEquals( bidiInList, association.getListOfBidis().get( 0 ) ); association.removeListOfBidi( bidiInList ); Assert.assertEquals( 0, association.getListOfBidis().size() ); BidiInSet bidiInSet = new BidiInSet(); association.addSetOfBidi( bidiInSet ); Assert.assertEquals( "setting bidi in many association should set the reverse association", association, bidiInSet.getParent() ); bidiInSet.setParent( null ); Assert.assertEquals( 0, association.getSetOfBidis().size() ); bidiInSet.setParent( association ); Assert.assertEquals( bidiInSet, association.getSetOfBidis().iterator().next() ); association.removeSetOfBidi( bidiInSet ); Assert.assertEquals( 0, association.getSetOfBidis().size() ); // class with single association to itself, but not bidi! NodeItem parentNode = new NodeItem(); NodeItem childNode = new NodeItem(); parentNode.setChild( childNode ); assertSame( childNode, parentNode.getChild() ); assertNull( childNode.getChild() ); // java.useInterface checkField( JavaFeatures.class, "useInterface", SubClassLevel1.class, "getUseInterface", "setUseInterface", BaseClass.class); } /** * Check that a method doesn't exist. * * @param clazz the class to check * @param method the method name that shouldn't exist * @param attribute the method attribute type */ private void checkNoMethod( Class clazz, String method, Class attribute ) { try { clazz.getMethod( method, new Class[] { attribute } ); throw new VerifierException( clazz.getName() + " should not contain " + method + "( " + attribute.getName() + " ) method." ); } catch ( NoSuchMethodException nsme ) { // ok, that's expected } } public void verifyInterfaces() { Assert.assertTrue( "SimpleInterface should be an interface", SimpleInterface.class.isInterface() ); Assert.assertTrue( "SubInterface should be an interface", SubInterface.class.isInterface() ); Assert.assertTrue( "SubInterfaceInPackage should be an interface", SubInterfaceInPackage.class.isInterface() ); // superInterface feature if ( !SimpleInterface.class.isAssignableFrom( SubInterface.class ) ) { throw new VerifierException( "SubInterface should extend SimpleInterface" ); } if ( !SimpleInterface.class.isAssignableFrom( SubInterfaceInPackage.class ) ) { throw new VerifierException( "SubInterfaceInPackage should extend SimpleInterface" ); } // codeSegments Assert.assertNotNull( "SimpleInterface.CODE_SEGMENT should be here", SimpleInterface.CODE_SEGMENT ); } /** * Verify misc aspects of the generated classes. */ public void verifyMisc() { // <default><key>java.util.Properties</key><value>new org.codehaus.modello.OrderedProperties()</value></default> if (! ( new XmlFeatures().getExplodeProperties() instanceof OrderedProperties ) ) { throw new VerifierException( "java.util.Properties model default value was ignored" ); } } /** * Verify generated clone() methods. */ public void verifyClone() { checkCloneNullSafe(); checkClone(); } private void checkCloneNullSafe() { Thing orig = new Thing(); Thing copy = (Thing) orig.clone(); assertNotNull( copy ); assertNotSame( orig, copy ); } private void checkClone() { Thing orig = new Thing(); orig.setSomeBoolean( true ); orig.setSomeChar( 'X' ); orig.setSomeByte( (byte) 7 ); orig.setSomeShort( (short) 11 ); orig.setSomeInt( 13 ); orig.setSomeLong( 17 ); orig.setSomeFloat( -2.5f ); orig.setSomeDouble( 3.14 ); orig.setSomeString( "test" ); orig.setSomeDate( new Date() ); orig.setSomeDom( new Xpp3Dom( "test" ) ); orig.addSomeStringList( "string" ); orig.addSomeStringSet( "string" ); orig.setDeepThingy( new Thingy() ); orig.addDeepThingyList( new Thingy() ); orig.addDeepThingySet( new Thingy() ); orig.setShallowThingy( new Thingy() ); orig.addShallowThingyList( new Thingy() ); orig.addShallowThingySet( new Thingy() ); orig.addSomeProperty( "key", "value" ); orig.customProperties.setProperty( "key", "value" ); Thing copy = (Thing) orig.clone(); assertNotNull( copy ); assertNotSame( orig, copy ); assertEquals( orig.isSomeBoolean(), copy.isSomeBoolean() ); assertEquals( orig.getSomeChar(), copy.getSomeChar() ); assertEquals( orig.getSomeByte(), copy.getSomeByte() ); assertEquals( orig.getSomeShort(), copy.getSomeShort() ); assertEquals( orig.getSomeInt(), copy.getSomeInt() ); assertEquals( orig.getSomeLong(), copy.getSomeLong() ); assertEquals( orig.getSomeFloat(), copy.getSomeFloat(), 0.1 ); assertEquals( orig.getSomeDouble(), copy.getSomeDouble(), 0.1 ); assertEquals( orig.getSomeString(), copy.getSomeString() ); assertEquals( orig.getSomeDate(), copy.getSomeDate() ); assertNotSame( orig.getSomeDate(), copy.getSomeDate() ); assertEquals( orig.getSomeDom(), copy.getSomeDom() ); assertNotSame( orig.getSomeDom(), copy.getSomeDom() ); assertEquals( orig.getSomeStringList(), copy.getSomeStringList() ); assertNotSame( orig.getSomeStringList(), copy.getSomeStringList() ); assertEquals( orig.getSomeStringSet(), copy.getSomeStringSet() ); assertNotSame( orig.getSomeStringSet(), copy.getSomeStringSet() ); assertNotSame( orig.getDeepThingy(), copy.getDeepThingy() ); assertNotSame( orig.getDeepThingyList(), copy.getDeepThingyList() ); assertNotSame( orig.getDeepThingyList().iterator().next(), copy.getDeepThingyList().iterator().next() ); assertNotSame( orig.getDeepThingySet(), copy.getDeepThingySet() ); assertNotSame( orig.getDeepThingySet().iterator().next(), copy.getDeepThingySet().iterator().next() ); assertSame( orig.getShallowThingy(), copy.getShallowThingy() ); assertNotSame( orig.getShallowThingyList(), copy.getShallowThingyList() ); assertSame( orig.getShallowThingyList().iterator().next(), copy.getShallowThingyList().iterator().next() ); assertNotSame( orig.getShallowThingySet(), copy.getShallowThingySet() ); assertSame( orig.getShallowThingySet().iterator().next(), copy.getShallowThingySet().iterator().next() ); assertEquals( orig.customProperties, copy.customProperties ); assertNotSame( orig.customProperties, copy.customProperties ); Thingy orig2 = new Thingy(); orig2.setSomeContent( "content" ); Thingy copy2 = (Thingy) orig2.clone(); assertNotNull( copy2 ); assertNotSame( orig2, copy2 ); assertEquals( "content", copy2.getSomeContent() ); } }