001/* 002 * #%L 003 * Netarchivesuite - common - test 004 * %% 005 * Copyright (C) 2005 - 2014 The Royal Danish Library, the Danish State and University Library, 006 * the National Library of France and the Austrian National Library. 007 * %% 008 * This program is free software: you can redistribute it and/or modify 009 * it under the terms of the GNU Lesser General Public License as 010 * published by the Free Software Foundation, either version 2.1 of the 011 * License, or (at your option) any later version. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Lesser Public License for more details. 017 * 018 * You should have received a copy of the GNU General Lesser Public 019 * License along with this program. If not, see 020 * <http://www.gnu.org/licenses/lgpl-2.1.html>. 021 * #L% 022 */ 023 024package dk.netarkivet.testutils; 025 026import java.lang.reflect.Field; 027import java.lang.reflect.Method; 028import java.lang.reflect.Modifier; 029import java.util.HashMap; 030import java.util.List; 031import java.util.Map; 032 033import dk.netarkivet.common.exceptions.PermissionDenied; 034import dk.netarkivet.common.utils.CleanupIF; 035import junit.framework.TestCase; 036 037/** 038 * Utility class containing various method for making assertions on Class objects. 039 */ 040@SuppressWarnings({"unchecked"}) 041public class ClassAsserts { 042 043 /** 044 * Tests the class has a static factory method getInstance() 045 * 046 * @param c the class to test 047 */ 048 @SuppressWarnings({"rawtypes"}) 049 public static void assertHasFactoryMethod(Class c) { 050 Method m = null; 051 try { 052 m = c.getDeclaredMethod("getInstance", (Class[]) null); 053 } catch (NoSuchMethodException e) { 054 TestCase.fail("Expect to find getInstance() method in class " + c.getName()); 055 } 056 TestCase.assertEquals("getInstance() method should return " + "an object of the same class: ", c, 057 m.getReturnType()); 058 TestCase.assertTrue("getInstance() method should be static:", Modifier.isStatic(m.getModifiers())); 059 } 060 061 /** 062 * Tests that a class has a static factory method getInstance() and that it acts as a singleton. NB This method will 063 * create an instance of the class. It is your responsibility to clean up after yourself. 064 * 065 * @param c the class to test 066 * @return the singleton 067 */ 068 public static <T> T assertSingleton(Class<T> c) { 069 assertHasFactoryMethod(c); 070 assertPrivateConstructor(c); 071 T o1 = null; 072 T o2 = null; 073 try { 074 Method m = c.getDeclaredMethod("getInstance"); 075 o1 = (T) m.invoke(null); 076 o2 = (T) m.invoke(null); 077 } catch (Exception e) { 078 throw new PermissionDenied("Unexpected error in unit test ", e); 079 } 080 TestCase.assertSame("Expect to find only one distinct instance of " + "class " + c.getName(), o1, o2); 081 if (o1 instanceof CleanupIF) { 082 ((CleanupIF) o1).cleanup(); 083 } 084 return o1; 085 } 086 087 /** 088 * Tests if there are any public constructors. Will fail on any public constructor, and simply return otherwise. 089 * 090 * @param c A class to test. 091 */ 092 public static <T> void assertPrivateConstructor(Class<T> c) { 093 TestCase.assertEquals("Expect to find no public constructors for " + "class " + c.getName(), 0, 094 c.getConstructors().length); 095 } 096 097 /** 098 * Tests that a class' equals method notice changed fields. Also performs some testing of the hashCode method, but 099 * not as comprehensive. 100 * 101 * @param o1 An object to test on. 102 * @param o2 Another object with all fields to be tested set to different values from o1 103 * @param excludedFields A list of field names of fields that should not be included in the test. 104 * @throws IllegalAccessException 105 */ 106 @SuppressWarnings("rawtypes") 107 public static void assertEqualsValid(Object o1, Object o2, List excludedFields) throws IllegalAccessException { 108 TestCase.fail("Unsafe to use with final fields - pending rethought"); 109 Class c = o1.getClass(); 110 TestCase.assertSame("Class must be the same for both objects", c, o2.getClass()); 111 Map<String, Object> fieldValues1 = new HashMap<String, Object>(); 112 Map<String, Object> fieldValues2 = new HashMap<String, Object>(); 113 Field[] fields = c.getDeclaredFields(); 114 for (final Field field : fields) { 115 if (!excludedFields.contains(field.getName()) && !Modifier.isStatic(field.getModifiers())) { 116 field.setAccessible(true); 117 Object fieldValue1 = field.get(o1); 118 fieldValues1.put(field.getName(), fieldValue1); 119 final Object fieldValue2 = field.get(o2); 120 fieldValues2.put(field.getName(), fieldValue2); 121 TestCase.assertNotSame("Values for field " + field + " should not be the same", fieldValue1, 122 fieldValue2); 123 field.set(o2, fieldValue1); 124 } 125 } 126 for (final Field field : fields) { 127 if (!excludedFields.contains(field.getName()) && !Modifier.isStatic(field.getModifiers())) { 128 TestCase.assertEquals("Objects must be same with all fields equals", o1, o2); 129 field.set(o2, fieldValues2.get(field.getName())); 130 TestCase.assertFalse("Changing field " + field + " should cause non-equals", o1.equals(o2)); 131 field.set(o2, fieldValues1.get(field.getName())); 132 TestCase.assertEquals("Objects must have same hashcode with all fields equals", o1.hashCode(), 133 o2.hashCode()); 134 } 135 } 136 } 137}