All Downloads are FREE. Search and download functionalities are using the official Maven repository.

patterntesting.runtime.junit.CloneableTester Maven / Gradle / Ivy

Go to download

PatternTesting Runtime (patterntesting-rt) is the runtime component for the PatternTesting framework. It provides the annotations and base classes for the PatternTesting testing framework (e.g. patterntesting-check, patterntesting-concurrent or patterntesting-exception) but can be also used standalone for classpath monitoring or profiling. It uses AOP and AspectJ to perform this feat.

There is a newer version: 2.5.1
Show newest version
/*
 * $Id: CloneableTester.java,v 1.20 2016/03/14 22:01:56 oboehm Exp $
 *
 * Copyright (c) 2010 by Oliver Boehm
 *
 * 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 orimplied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * (c)reated 06.08.2010 by oliver ([email protected])
 */

package patterntesting.runtime.junit;

import java.lang.reflect.*;
import java.util.*;
import java.util.regex.Pattern;

import org.slf4j.*;

import patterntesting.runtime.exception.DetailedAssertionError;
import patterntesting.runtime.monitor.ClasspathMonitor;
import patterntesting.runtime.util.Converter;

/**
 * This tester checks class which implements Clonable and has therefore
 * the clone method implemented. According {@link Object#clone()} the
 * following conditions should be true:
 * 
*
 * x.clone() != x
* will be true, and that the expression: *
*
 * x.clone().getClass() == x.getClass()
* will be true, but these are not absolute requirements. * While it is typically the case that: *
*
 * x.clone().equals(x)
* will be true, this is not an absolute requirement. *

* So the equals method will be only checked if it is overwritten. *

*

* NOTE: In the future this class will be perhaps part of the ObjectTester * class. *

*

* Before v1.1 the methods are named "checkCloning". Since 1.1 these * methods will have now an "assert" prefix ("assertCloning"). *

* * @author oliver * @since 1.0.2 (06.08.2010) */ public final class CloneableTester extends AbstractTester { private static final Logger LOG = LoggerFactory.getLogger(CloneableTester.class); private static final ClasspathMonitor classpathMonitor = ClasspathMonitor.getInstance(); /** Utility class - no need to instantiate it. */ private CloneableTester() {} /** * Check cloning. * * @param clazz the clazz * @since 1.1 */ public static void assertCloning(final Class clazz) { try { assertCloning(clazz.newInstance()); } catch (InstantiationException e) { throw new DetailedAssertionError("can't instantiate " + clazz, e); } catch (IllegalAccessException e) { throw new DetailedAssertionError("can't access " + clazz, e); } } /** * We call the clone method of the given orig paramter.Because the * clone method is normally "protected" we use reflection to call it. * Then we compare the orig and cloned object which should be equals. * * @param orig the original object * @since 1.1 */ public static void assertCloning(final Cloneable orig) { Cloneable clone = getCloneOf(orig); if (ObjectTester.hasEqualsDeclared(orig.getClass())) { ObjectTester.assertEquals(orig, clone); } if (!orig.getClass().equals(clone.getClass())) { throw new AssertionError(orig.getClass().getName() + ".clone() creates another type: " + clone.getClass().getSimpleName()); } } /** * Gets the clone of the given Cloneable object. * * @param orig the orig * @return the clone of * @throws AssertionError the assertion error */ public static Cloneable getCloneOf(final Cloneable orig) throws AssertionError { try { Method cloneMethod = getPublicCloneMethod(orig.getClass()); Cloneable clone = (Cloneable) cloneMethod.invoke(orig); if (clone == orig) { throw new AssertionError(clone + " must have another reference as original object"); } return clone; } catch (SecurityException e) { throw new DetailedAssertionError("can't access clone method of " + orig.getClass(), e); } catch (IllegalAccessException e) { throw new DetailedAssertionError("can't access clone method of " + orig.getClass(), e); } catch (InvocationTargetException e) { throw new DetailedAssertionError("clone of " + orig.getClass() + " failed", e); } } private static Method getPublicCloneMethod(final Class cloneClass) throws AssertionError { try { return cloneClass.getMethod("clone"); } catch (NoSuchMethodException nsme) { if (hasCloneMethod(cloneClass)) { throw new DetailedAssertionError("clone() is not public in " + cloneClass, nsme); } throw new DetailedAssertionError("no clone method found in " + cloneClass, nsme); } } private static boolean hasCloneMethod(final Class cloneClass) { try { Method m = cloneClass.getDeclaredMethod("clone"); if (LOG.isTraceEnabled()) { LOG.trace(m + " found in " + cloneClass); } return true; } catch (NoSuchMethodException e) { LOG.trace(cloneClass + " has no clone method:", e); return false; } } /** * Check for each class in the given collection if it can be cloned * correct. * * @param classes a collection of classes to be checked * @since 1.1 */ public static void assertCloning(final Collection> classes) { for (Class clazz : classes) { assertCloning(clazz); } } /** * Check for each class in the given package if it can be cloned * correct. *

* To get a name of a package call {@link Package#getPackage(String)}. * But be sure that you can't get null as result. In this case * use {@link #assertCloningOfPackage(String)}. *

* * @param pkg the package e.g. "patterntesting.runtime" * @see #assertCloningOfPackage(String) * @since 1.1 */ public static void assertCloning(final Package pkg) { assert pkg!= null; assertCloningOfPackage(pkg.getName()); } /** * Check for each class in the given package if it can be cloned * correct. *

* To get a name of a package call {@link Package#getPackage(String)}. * But be sure that you can't get null as result. In this case * use {@link #assertCloningOfPackage(String, Pattern...)}. *

* * @param pkg the package * @param excluded class pattern which should be excluded from the check * @since 1.6 */ public static void assertCloning(final Package pkg, final Pattern... excluded) { assert pkg != null; assertCloningOfPackage(pkg.getName(), excluded); } /** * Check for each class in the given package if it can be cloned * correct. * * @param packageName the package name e.g. "patterntesting.runtime" * @since 1.1 */ public static void assertCloningOfPackage(final String packageName) { assert packageName != null; Collection> cloneables = getCloneableClasses(packageName); assertCloning(cloneables); } /** * Check for each class in the given package if the clone method is * implemented correct. * * @param packageName the package name e.g. "patterntesting.runtime" * @param excluded classes which should be excluded from the check * @see #assertCloningOfPackage(String) * @since 1.1 */ @SuppressWarnings("unchecked") public static void assertCloningOfPackage(final String packageName, final Class... excluded) { List> excludedList = Arrays.asList((Class[]) excluded); assertCloningOfPackage(packageName, excludedList); } /** * Check for each class in the given package if the clone method is * implemented correct. *
*
Note:
*
Since v1.5.1 this method is deprecated to avoid confusion with method * {@link #assertCloningOfPackage(String, Pattern...)}. This method will be * removed in v1.8.
*
* * @param packageName the package name e.g. "patterntesting.runtime" * @param excluded classes which should be excluded from the check * @see #assertCloningOfPackage(String) * @since 1.1 * @deprecated use {@link #assertCloningOfPackage(String, Class...)} instead */ // TODO: remove me in 1.8 @Deprecated public static void assertCloningOfPackage(final String packageName, final List> excluded) { Collection> classes = getCloneableClasses(packageName); LOG.debug(excluded + " will be excluded from check."); removeClasses(classes, excluded); assertCloning(classes); } /** * Check for each class in the given package if the clone method is * implemented correct. * * @param packageName the package name e.g. "patterntesting.runtime" * @param excluded pattern for classes which should be excluded from the check * @see #assertCloningOfPackage(String) * @since 1.6 */ public static void assertCloningOfPackage(final String packageName, final Pattern... excluded) { Collection> classes = getCloneableClasses(packageName); if (LOG.isDebugEnabled()) { LOG.debug("Pattern {} will be excluded from check.", Converter.toShortString(excluded)); } removeClasses(classes, excluded); assertCloning(classes); } private static Collection> getCloneableClasses(final String packageName) { Collection> cloneables = classpathMonitor.getClassList(packageName, Cloneable.class); return cloneables; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy