001 /*
002 * $Id: ComparableTester.java,v 1.2 2011/09/25 19:41:52 oboehm Exp $
003 *
004 * Copyright (c) 2011 by Oliver Boehm
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express orimplied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 *
018 * (c)reated 21.09.2011 by oliver (ob@oasd.de)
019 */
020
021 package patterntesting.runtime.junit;
022
023 import java.util.*;
024
025 import org.junit.Assert;
026 import org.slf4j.*;
027
028 import patterntesting.runtime.monitor.ClasspathMonitor;
029
030 /**
031 * This utility class checks classes which implements the {@link Comparable}
032 * interface. E.g. for two objects which are equals it is expected that the
033 * {@link Comparable#compareTo(Object)} method returns 0.
034 *
035 * @author oliver (ob@aosd.de)
036 * @since 1.2 (21.09.2011)
037 */
038 public final class ComparableTester {
039
040 private static final Logger log = LoggerFactory.getLogger(ComparableTester.class);
041 private static final ClasspathMonitor classpathMonitor = ClasspathMonitor.getInstance();
042
043 /** Utility class - no need to instantiate it. */
044 private ComparableTester() {}
045
046 /**
047 * The {@link Comparable#compareTo(Object)} method should return 0 if the
048 * given objects are eqals. If they are not equals the shouldn't return 0.
049 * This is checked here.
050 *
051 * @param c1 the first Comparable
052 * @param c2 the second Comparable
053 * @throws AssertionError if the check fails
054 */
055 @SuppressWarnings({ "rawtypes", "unchecked" })
056 public static void assertCompareTo(final Comparable c1, final Comparable c2) {
057 int ret1 = c1.compareTo(c2);
058 int ret2 = c2.compareTo(c1);
059 if (c1.equals(c2)) {
060 String msg = c1.getClass() + ": compareTo(..) should return 0 for equals objects";
061 Assert.assertEquals(msg, 0, ret1);
062 Assert.assertEquals(msg, 0, ret2);
063 } else {
064 String msg = c1.getClass()
065 + ": compareTo(..) should return not 0 for not equals objects " + c1 + " and "
066 + c2;
067 Assert.assertTrue(msg, ret1 != 0);
068 Assert.assertTrue(msg, ret2 != 0);
069 msg = c1.getClass() + ": <" + c2 + ">.compareTo(<" + c1 + ">) should return "
070 + (-ret2) + " (not " + ret2 + ")";
071 if (ret1 < 0) {
072 Assert.assertTrue(msg, ret2 > 0);
073 } else {
074 Assert.assertTrue(msg, ret2 < 0);
075 }
076 }
077 log.info("compareTo implementation of " + c1.getClass() + " seems to be ok");
078 }
079
080 /**
081 * This method will create two objects of the given class using the
082 * default constructor and compares them. So two preconditions must be
083 * true:
084 * <ol>
085 * <li>the class must not be abstract</li>
086 * <li>there must be a (public) default constructor</li>
087 * </li>
088 * </ol>
089 *
090 * @param clazz the clazz
091 * @throws AssertionError if the check fails
092 */
093 @SuppressWarnings("rawtypes")
094 public static void assertCompareTo(final Class<? extends Comparable> clazz)
095 throws AssertionError {
096 log.trace("checking {}.compareTo(..)...", clazz);
097 Comparable<?> comp = (Comparable<?>) ObjectTester.newInstanceOf(clazz);
098 Comparable<?> clone = (Comparable<?>) ObjectTester.clone(comp);
099 assertCompareTo(comp, clone);
100 }
101
102 /**
103 * Check for each class in the given collection if the compareTo method
104 * works as expected
105 *
106 * @param classes a collection of classes to be checked
107 */
108 @SuppressWarnings("rawtypes")
109 public static void assertCompareTo(final Collection<Class<Comparable>> classes) {
110 for (Class<Comparable> clazz : classes) {
111 assertCompareTo(clazz);
112 }
113 }
114
115 /**
116 * Check for each {@link Comparable} class in the given package if the
117 * compareTo(..) method works as expected.
118 * <br/>
119 * To get a name of a package call {@link Package#getPackage(String)}.
120 * But be sure that you can't get <em>null</em> as result. In this case
121 * use {@link #assertCompareToOfPackage(String)}.
122 *
123 * @param pkg the package e.g. "patterntesting.runtime"
124 * @see #assertCompareToOfPackage(String)
125 */
126 public static void assertCompareTo(final Package pkg) {
127 assert pkg!= null;
128 assertCompareToOfPackage(pkg.getName());
129 }
130
131 /**
132 * Check for each {@link Comparable} class in the given package if the
133 * compareTo(..) method works as expected.
134 *
135 * @param packageName the package name e.g. "patterntesting.runtime"
136 */
137 @SuppressWarnings("rawtypes")
138 public static void assertCompareToOfPackage(final String packageName) {
139 assert packageName != null;
140 Collection<Class<Comparable>> comparables = getComparableClasses(packageName);
141 assertCompareTo(comparables);
142 }
143
144 /**
145 * Check for each {@link Comparable} class in the given package if the
146 * compareTo(..) method works as expected.
147 *
148 * @param packageName the package name e.g. "patterntesting.runtime"
149 * @param excluded classes which should be excluded from the check
150 * @see #assertCompareToOfPackage(String)
151 */
152 public static void assertCompareToOfPackage(final String packageName,
153 final Class<? extends Comparable<?>>... excluded) {
154 List<Class<? extends Comparable<?>>> excludedList = Arrays.asList(excluded);
155 assertCompareToOfPackage(packageName, excludedList);
156 }
157
158 /**
159 * Check for each {@link Comparable} class in the given package if the
160 * compareTo(..) method works as expected.
161 *
162 * @param packageName the package name e.g. "patterntesting.runtime"
163 * @param excluded classes which should be excluded from the check
164 * @see #assertCompareToOfPackage(String)
165 */
166 @SuppressWarnings("rawtypes")
167 public static void assertCompareToOfPackage(final String packageName,
168 final List<Class<? extends Comparable<?>>> excluded) {
169 Collection<Class<Comparable>> classes = getComparableClasses(packageName);
170 log.debug("{} will be excluded from check", excluded);
171 ObjectTester.removeClasses(classes, excluded);
172 assertCompareTo(classes);
173 }
174
175 @SuppressWarnings( "rawtypes" )
176 private static Collection<Class<Comparable>> getComparableClasses(final String packageName) {
177 Collection<Class<Comparable>> comparables = classpathMonitor.getClassList(packageName,
178 Comparable.class);
179 return comparables;
180 }
181
182 }
183