/* * ModeShape (http://www.modeshape.org) * * Licensed 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 org.modeshape.sequencer; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.modeshape.jcr.api.JcrConstants.JCR_PRIMARY_TYPE; import static org.modeshape.sequencer.classfile.ClassFileSequencerLexicon.ABSTRACT; import static org.modeshape.sequencer.classfile.ClassFileSequencerLexicon.ANNOTATIONS; import static org.modeshape.sequencer.classfile.ClassFileSequencerLexicon.CONSTRUCTORS; import static org.modeshape.sequencer.classfile.ClassFileSequencerLexicon.ENUM_VALUES; import static org.modeshape.sequencer.classfile.ClassFileSequencerLexicon.FIELD; import static org.modeshape.sequencer.classfile.ClassFileSequencerLexicon.FIELDS; import static org.modeshape.sequencer.classfile.ClassFileSequencerLexicon.FINAL; import static org.modeshape.sequencer.classfile.ClassFileSequencerLexicon.INTERFACE; import static org.modeshape.sequencer.classfile.ClassFileSequencerLexicon.INTERFACES; import static org.modeshape.sequencer.classfile.ClassFileSequencerLexicon.METHOD; import static org.modeshape.sequencer.classfile.ClassFileSequencerLexicon.METHODS; import static org.modeshape.sequencer.classfile.ClassFileSequencerLexicon.METHOD_PARAMETERS; import static org.modeshape.sequencer.classfile.ClassFileSequencerLexicon.NAME; import static org.modeshape.sequencer.classfile.ClassFileSequencerLexicon.NATIVE; import static org.modeshape.sequencer.classfile.ClassFileSequencerLexicon.RETURN_TYPE_CLASS_NAME; import static org.modeshape.sequencer.classfile.ClassFileSequencerLexicon.STATIC; import static org.modeshape.sequencer.classfile.ClassFileSequencerLexicon.STRICT_FP; import static org.modeshape.sequencer.classfile.ClassFileSequencerLexicon.SUPER_CLASS_NAME; import static org.modeshape.sequencer.classfile.ClassFileSequencerLexicon.SYNCHRONIZED; import static org.modeshape.sequencer.classfile.ClassFileSequencerLexicon.TRANSIENT; import static org.modeshape.sequencer.classfile.ClassFileSequencerLexicon.TYPE_CLASS_NAME; import static org.modeshape.sequencer.classfile.ClassFileSequencerLexicon.VALUE; import static org.modeshape.sequencer.classfile.ClassFileSequencerLexicon.VISIBILITY; import static org.modeshape.sequencer.classfile.ClassFileSequencerLexicon.VOLATILE; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.RepositoryException; import javax.jcr.Value; import javax.jcr.nodetype.NodeType; import org.modeshape.sequencer.classfile.ClassFileSequencerLexicon; import org.modeshape.sequencer.testdata.MockClass; import org.modeshape.sequencer.testdata.MockEnum; /** * Helper class, used by both {@link org.modeshape.sequencer.classfile.ClassFileSequencerTest} and * {@link org.modeshape.sequencer.javafile.JavaFileSequencerTest} to assert the expected values from {@link MockClass} and * {@link MockEnum} * * @author Horia Chiorean */ public abstract class JavaSequencerHelper { private static final String STATIC_VOLATILE_STRING_FIELD = "STATIC_VOLATILE_STRING_FIELD"; @SuppressWarnings( "synthetic-access" ) public static final JavaSequencerHelper CLASS_FILE_HELPER = new ClassFile(); @SuppressWarnings( "synthetic-access" ) public static final JavaSequencerHelper JAVA_FILE_HELPER = new JavaFile(); protected JavaSequencerHelper() { } public void assertSequencedMockEnum( Node enumNode ) throws Exception { TreeSet<String> expectedEnumValues = new TreeSet<String>(Arrays.asList(MockEnum.VALUE_A.name(), MockEnum.VALUE_B.name(), MockEnum.VALUE_C.name())); assertNotNull(enumNode); assertEquals(ClassFileSequencerLexicon.ENUM, enumNode.getProperty(JCR_PRIMARY_TYPE).getString()); assertEquals(expectedEnumValues, enumValuesToString(enumNode)); } private Set<String> enumValuesToString( Node sequencedNode ) throws RepositoryException { Value[] enumValues = sequencedNode.getProperty(ENUM_VALUES).getValues(); assertNotNull(enumValues); Set<String> enumValuesSet = new TreeSet<String>(); for (Value value : enumValues) { enumValuesSet.add(value.getString()); } return enumValuesSet; } public void assertSequencedMockClass( Node classNode ) throws Exception { assertClassMetaInfo(classNode); assertConstructors(classNode); assertMethods(classNode); assertFields(classNode); assertPackage(classNode); } private void assertClassMetaInfo( Node classNode ) throws RepositoryException { // class meta-info assertNotNull(classNode); assertEquals(ClassFileSequencerLexicon.CLASS, classNode.getProperty(JCR_PRIMARY_TYPE).getString()); assertEquals(Object.class.getName(), classNode.getProperty(SUPER_CLASS_NAME).getString()); assertEquals("public", classNode.getProperty(VISIBILITY).getString().toLowerCase()); assertFalse(classNode.getProperty(ABSTRACT).getBoolean()); assertFalse(classNode.getProperty(INTERFACE).getBoolean()); assertTrue(classNode.getProperty(FINAL).getBoolean()); assertFalse(classNode.getProperty(STRICT_FP).getBoolean()); List<String> interfaces = valuesToStringList(classNode.getProperty(INTERFACES).getValues()); assertEquals(Arrays.asList(getExpectedTypeName(Serializable.class)), interfaces); assertNoAnnotationsOnNode(classNode); } private void assertConstructors( Node classNode ) throws RepositoryException { // constructors Node constructors = classNode.getNode(CONSTRUCTORS); assertEquals(CONSTRUCTORS, constructors.getProperty(JCR_PRIMARY_TYPE).getString()); NodeIterator constructorMethodsIt = constructors.getNodes(); Node constructorMethod = constructorMethodsIt.nextNode(); assertMethod(constructorMethod, getExpectedTypeName(MockClass.class), "void", "public", false, false, false, false, false, false, Arrays.<String>asList()); constructorMethod = constructorMethodsIt.nextNode(); assertMethod(constructorMethod, getExpectedTypeName(MockClass.class), "void", "public", false, false, false, false, false, false, Arrays.asList("boolean")); constructorMethod = constructorMethodsIt.nextNode(); assertMethod(constructorMethod, getExpectedTypeName(MockClass.class), "void", "public", false, false, false, false, false, false, Arrays.asList(getExpectedTypeName(Boolean.class))); assertFalse(constructorMethodsIt.hasNext()); assertNoAnnotationsOnNode(constructorMethod); } private void assertMethods( Node classNode ) throws RepositoryException { // methods Node methods = classNode.getNode(METHODS); assertEquals(METHODS, methods.getProperty(JCR_PRIMARY_TYPE).getString()); NodeIterator methodsIterator = methods.getNodes(); Node method = methodsIterator.nextNode(); assertMethod(method, "doSomething", "void", "public", false, false, false, false, false, false, Arrays.asList("double")); method = methodsIterator.nextNode(); assertMethod(method, "doSomething", "void", "public", false, false, false, false, false, false, Arrays.asList("float")); method = methodsIterator.nextNode(); assertMethod(method, "setField", "void", "public", false, false, false, false, false, false, new ArrayList<String>()); method = methodsIterator.nextNode(); assertMethod(method, "setField", "void", "public", false, false, false, false, false, false, Arrays.asList(getExpectedTypeName(Boolean.class))); method = methodsIterator.nextNode(); assertMethod(method, "voidMethod", "void", "package", false, false, false, false, false, true, new ArrayList<String>()); assertNodeHasAnnotation(method, Deprecated.class); assertFalse(methodsIterator.hasNext()); } protected Node assertNodeHasAnnotation( Node method, Class<?> annotationClass ) throws RepositoryException { Node annotations = method.getNode(ANNOTATIONS); assertEquals(ANNOTATIONS, annotations.getProperty(JCR_PRIMARY_TYPE).getString()); NodeIterator annotationsIt = annotations.getNodes(); assertEquals(1, annotationsIt.getSize()); Node annotation = annotationsIt.nextNode(); assertEquals(getExpectedTypeName(annotationClass), annotation.getProperty(NAME).getString()); return annotation; } private void assertFields( Node classNode ) throws RepositoryException { // fields Node fields = classNode.getNode(FIELDS); assertEquals(FIELDS, fields.getProperty(JCR_PRIMARY_TYPE).getString()); // not sure about the order, so we load them into a map Map<String, Node> fieldsMap = loadNodesByName(fields); Node booleanField = fieldsMap.remove("booleanField"); assertField(booleanField, "booleanField", getExpectedTypeName(Boolean.class), "protected", false, false, false, false); Node staticFinalIntegerField = fieldsMap.remove("STATIC_FINAL_INTEGER_FIELD"); assertField(staticFinalIntegerField, "STATIC_FINAL_INTEGER_FIELD", getExpectedTypeName(Integer.class), "public", true, true, false, false); Node staticVolatileStringField = fieldsMap.remove(STATIC_VOLATILE_STRING_FIELD); assertField(staticVolatileStringField, "STATIC_VOLATILE_STRING_FIELD", getExpectedTypeName(String.class), "private", true, false, false, true); Node serialVersionUIDField = fieldsMap.remove("serialVersionUID"); assertField(serialVersionUIDField, "serialVersionUID", getExpectedTypeName(Long.TYPE), "private", true, true, false, false); } private void assertPackage( final Node classNode ) throws Exception { // org.acme.MySource Node parent = classNode.getParent(); // acme assertHasPackageMixin(parent); parent = parent.getParent(); // org assertHasPackageMixin(parent); } private void assertHasPackageMixin( final Node node ) throws Exception { for (final NodeType mixin : node.getMixinNodeTypes()) { if (ClassFileSequencerLexicon.PACKAGE.equals(mixin.getName())) { return; } } fail("Node '" + node.getPath() + "' does not have the java package mixin"); } private Map<String, Node> loadNodesByName( Node rootNode ) throws RepositoryException { Map<String, Node> nodesMap = new HashMap<String, Node>(); NodeIterator nodesIt = rootNode.getNodes(); while (nodesIt.hasNext()) { Node node = nodesIt.nextNode(); nodesMap.put(node.getName(), node); } return nodesMap; } private void assertMethod( Node method, String name, String returnTypeClassName, String visibility, boolean isStatic, boolean isFinal, boolean isAbstract, boolean isStrictFP, boolean isNative, boolean isSynchronized, List<String> expectedParameters ) throws RepositoryException { assertEquals(METHOD, method.getProperty(JCR_PRIMARY_TYPE).getString()); assertEquals(name, method.getProperty(NAME).getString()); assertEquals(returnTypeClassName, method.getProperty(RETURN_TYPE_CLASS_NAME).getString()); assertEquals(visibility, method.getProperty(VISIBILITY).getString()); assertEquals(isStatic, method.getProperty(STATIC).getBoolean()); assertEquals(isFinal, method.getProperty(FINAL).getBoolean()); assertEquals(isAbstract, method.getProperty(ABSTRACT).getBoolean()); assertEquals(isStrictFP, method.getProperty(STRICT_FP).getBoolean()); assertEquals(isNative, method.getProperty(NATIVE).getBoolean()); assertEquals(isSynchronized, method.getProperty(SYNCHRONIZED).getBoolean()); if (!expectedParameters.isEmpty()) { Node parameters = method.getNode(METHOD_PARAMETERS); NodeIterator iter = parameters.getNodes(); Iterator<String> expectedNameIter = expectedParameters.iterator(); while (iter.hasNext()) { Node parameter = iter.nextNode(); assertEquals(expectedNameIter.next(), parameter.getProperty(TYPE_CLASS_NAME).getString()); } } } private void assertField( Node field, String name, String typeClassName, String visibility, boolean isStatic, boolean isFinal, boolean isTransient, boolean isVolatile ) throws RepositoryException { assertEquals(FIELD, field.getProperty(JCR_PRIMARY_TYPE).getString()); assertEquals(name, field.getProperty(NAME).getString()); assertEquals(typeClassName, field.getProperty(TYPE_CLASS_NAME).getString()); assertEquals(visibility, field.getProperty(VISIBILITY).getString().toLowerCase()); assertEquals(isStatic, field.getProperty(STATIC).getBoolean()); assertEquals(isFinal, field.getProperty(FINAL).getBoolean()); assertEquals(isTransient, field.getProperty(TRANSIENT).getBoolean()); assertEquals(isVolatile, field.getProperty(VOLATILE).getBoolean()); assertNoAnnotationsOnNode(field); } protected void assertNoAnnotationsOnNode( Node node ) throws RepositoryException { assertFalse(node.getNodes(ANNOTATIONS).hasNext()); } private List<String> valuesToStringList( Value[] values ) throws RepositoryException { List<String> result = new ArrayList<String>(); for (Value value : values) { result.add(value.getString()); } return result; } protected abstract String getExpectedTypeName( Class<?> expectedTypeClass ); /** * Extension of the default helper, with the particularities for java files */ private static class JavaFile extends JavaSequencerHelper { @Override protected String getExpectedTypeName( Class<?> expectedTypeClass ) { return expectedTypeClass.getSimpleName(); } @Override protected void assertNoAnnotationsOnNode( Node node ) throws RepositoryException { // overcome the fact that source annotations are present when parsing java files if (STATIC_VOLATILE_STRING_FIELD.equals(node.getName())) { Node suppressWarnings = assertNodeHasAnnotation(node, SuppressWarnings.class); Node annotationMember = suppressWarnings.getNode("default"); assertEquals("unused", annotationMember.getProperty(VALUE).getString()); } else { super.assertNoAnnotationsOnNode(node); } } } /** * Extension of the default helper, with the particularities for class files */ private static class ClassFile extends JavaSequencerHelper { @Override protected String getExpectedTypeName( Class<?> expectedTypeClass ) { return expectedTypeClass.getName(); } } }