package clearcut; import java.util.Map; import java.util.HashMap; import java.util.List; import java.util.ArrayList; import java.sql.SQLException; import java.lang.reflect.Constructor; import org.junit.Test; import junit.framework.TestCase; import static org.junit.Assert.*; import example.biz.IMember; import example.biz.IMedication; import static clearcut.Injector.INJECTOR; /** To run this, app.ini should contain <code> [injection] realMember=example.biz.Member mockMember=example.biz.MockMember member=mockMember doubleIndirection=member noMember=thisDoesNotExist noParamsMember=example.biz.Member ( ) emptyMember= a_ctor=example.biz.ActorType("Patient") # Test spacing, quotes, booleans, objects... a_member=example.biz.Member('Rod',"David" , "O'Reilly", a_ctor, true) a_drug=example.biz.Medication( "Prozac", 'Useless', 0, 42) # Numbers and primitives number_cast_error = example.biz.Medication( "Zoloft", 'Useless', 2.0, -42 ) should_fail = example.biz.Medication( "Pseudoephedrine", 'Wrong, 1, 42 ) ; Missing quote should_also_fail=example.biz.Medication("wrong","number","and""type" "of","parameters" ) should_fail_too= example.biz.Member( "No closing", 'parenthesis)', a_ctor, true no_commas=example.biz.Member( "Who"'needs' 'commas?', dr_who false ) ) ) dr_who=example.biz.ActorType("Doctor") # Commas, spaces and extra brackets are optional dr_666=example.biz.ActorType("Doctor") num_in_name=example.biz.Member( 'Jim' null 'Catch22' dr_666 true ) too_many_minuses=java.lang.Integer(-42-1 ) too_many_dots=java.lang.Integer( 0.1.2 ) dot_at_end_err=java.lang.Long(42.) ok_number=java.lang.Integer( -42) overflower=java.lang.Byte(42000000) # 2147483648 is MaxInt + 1 - works OK in a long parameter long_higher_than_int=example.biz.Medication( "Paxil" , 'Useless' , 42 , 2147483648 ) </code> */ public class InjectionTest extends TestCase { private Logger logger = Logger.LOGGER(this); public InjectionTest() { } public void testAppIni() throws Exception { String properties = INJECTOR.fessUp(); assertTrue ( "Should contain NO SECTION section", properties.contains( Ini.NO_SECTION )); assertTrue ( "Should have some properties", properties.contains( "=" )); } public void testCreatingMockMemberFromInjection() throws Exception { IMember member = (IMember) INJECTOR.implement( "mockMember" ); assertEquals( "Mock member should have 'Mock Member' as its name", "Mock Member", member.name() ); assertNotNull( "Mock member should have a mock actor type", member.actorType() ); } public void testCreatingRealMemberFromInjection() throws Exception { IMember member = (IMember) INJECTOR.implement( "realMember" ); assertNotSame("A real member should not be called 'Mock Member'", "Mock Member", member.name() ); assertNull( "Real member should have a null actor type 'cos it did not get set yet", member.actorType()); } public void testEmptyMemberCausesException () throws Exception { try { INJECTOR.implement( "emptyMember" ); } catch( InjectionException e ) { return; } throw new Exception( "We should not of gotten here" ); } public void testNonExistentMemberCausesException () throws Exception { try { IMember member = (IMember) INJECTOR.implement( "not.there" ); } catch( InjectionException e ) { /* OK */ return; } throw new Exception( "We should not be here" ); } public void testConstructorInjectionWithObjectParameters () throws Exception { IMember member = (IMember) INJECTOR.implement( "a_member" ); String name = member.name(); assertEquals( "Name should start with 'Rod'", "Rod", name.substring( 0, 3 )); assertFalse( "Name should not be 'Johnson'", name.indexOf( "Johnson") > -1 ); String actorType = member.actorType(); assertEquals( "Should be 'Patient'", "Patient", actorType ); Boolean gender = member.gender(); assertTrue( "Should be male", gender.booleanValue() ); } public void testConstructorWithParenthesesButNoParameters () throws Exception { IMember member = (IMember) INJECTOR.implement( "noParamsMember" ); String name = member.name(); // Uninitialized name might be null, spaces, the word null... assertTrue( "Name is " + name, name == null || name.trim().equals( "" ) || name.indexOf("null") > -1 ); } public void testInjectionIndirection () throws Exception { IMember member = (IMember) INJECTOR.implement( "doubleIndirection" ); String name = member.name(); // doubleIndirection points to member in app.ini, and member can point to realMember or mockMember assertTrue( "Name is " + name, name == null || name.trim().equals( "" ) || name.indexOf("null") > -1 || name.indexOf("Mock") > -1 ); } public void testIndirectionFailure () throws Exception { try { IMember member = (IMember) INJECTOR.implement( "noMember" ); } catch( InjectionException e ) { return; } throw new Exception( "Reference to non-reference failed to throw" ); } public void testConstructingNumbers() throws Exception { Number n = (Number) INJECTOR.implement("ok_number"); assertEquals("Should be minus forty-two", -42, n.intValue() ); } // Found a bug by running on Windows: added IllegalArgumentException check in Injector.implement() // Class is java.lang.Integer, which has two 1-param constructors; parameter is an Integer, -42 public void testIllegalArgument () throws Exception { Class [] classes = new Class[ 1 ]; Class claS$ = Class.forName( "java.lang.Integer" ); Constructor[] constructors = claS$.getConstructors(); boolean found = false; for( Constructor con : constructors ) { try { classes = con.getParameterTypes(); if( classes.length == 1 ) { Object [] parameters = new Object[ 1 ]; parameters[ 0 ] = new Integer( -42 ); con.newInstance( parameters ); found = true; } } catch( IllegalArgumentException u ) { // Try another constructor } } assertTrue( "Didn't succeed in constructing an Integer with -42", found ); } public void testLongParameter() throws Exception { IMedication med = (IMedication) INJECTOR.implement( "long_higher_than_int" ); long outOf = med.outOf(); assertTrue( "Should be higher than "+Integer.MAX_VALUE, ((long) Integer.MAX_VALUE) < outOf ); } public void testTooManyMinusesInNumberFails() throws Exception { Number n = null; try { n = (Number) INJECTOR.implement("too_many_minuses" ); } catch( InjectionException e ) { return; } throw new Exception( "Too many minuses in number didn't fail like one might expect" ); } public void testTooManyDotsInNumberFails() throws Exception { Number n = null; try { n = (Number) INJECTOR.implement("too_many_dots" ); } catch( InjectionException i ) { return; // OK } throw new Exception( "Too many dots in number failed to fail like it should have" ); } public void testDotAtEndOfNumberIsNoGood() throws Exception { try { Long n = (Long) INJECTOR.implement("dot_at_end_err"); } catch( InjectionException e ) { return; } throw new Exception( "Number ending in a dot didn't throw exception - this is not good news" ); } public void testOverflow() throws Exception { try { Byte n = (Byte) INJECTOR.implement("overflower"); } catch( InjectionException e ) { return; } throw new Exception( "Big number didn't throw exception but shoulduv" ); } public void testCommasAreOptionalAndForwardReferencesWork () throws Exception { IMember member = (IMember) INJECTOR.implement( "no_commas" ); String name = member.name(); assertEquals( "Who?", "Who", name.substring( 0, 3 )); } public void testNumberInNameAndReference () throws Exception { IMember member = (IMember) INJECTOR.implement( "num_in_name" ); String name = member.name(); assertTrue( "'Catch22' should be in name, but name is "+name, name.indexOf("Catch22") > -1 ); String actorType = member.actorType(); assertEquals( "Should be 'Doctor'", "Doctor", actorType ); } public void testConstructorInjectionWithNumberParameters () throws Exception { IMedication med = (IMedication) INJECTOR.implement( "a_drug" ); String name = med.name(); assertEquals( "Should be called Prozac", "Prozac", name ); name = med.cla$$(); assertEquals( "Should be called Useless", "Useless", name ); int num = med.rank(); assertEquals( "Rank should be zero", 0, num); long outOf = med.outOf(); assertEquals( "Out-of number should be 42", 42L, outOf); } public void testConstructorInjectionWithDoubleToLongCastFails () throws Exception { IMedication med = null; try { med = (IMedication) INJECTOR.implement( "number_cast_error" ); } catch( InjectionException e ) { return; } throw new Exception( "This should not happen" ); } public void testConstructorInjectionWithFaultyParameterFails () throws Exception { IMedication med = null; try { med = (IMedication) INJECTOR.implement( "should_fail" ); } catch( InjectionException e ) { return; } throw new Exception( "We should so not be here" ); } public void testConstructorInjectionWithWrongNumberOfParametersFails () throws Exception { IMedication med = null; try { med = (IMedication) INJECTOR.implement( "should_also_fail" ); } catch( InjectionException e ) { return; } throw new Exception( "This is not a place we want to be" ); } public void testConstructorInjectionWithNoClosingParenthesisFails () throws Exception { IMember aPerson = null; try { aPerson = (IMember) INJECTOR.implement( "should_fail_too" ); } catch( InjectionException e ) { return; } throw new Exception( "Something has gone very wrong" ); } // Please keep public void testClassCastingWithNumbers () throws Exception { Integer i = new Integer( Integer.MAX_VALUE ); Long l = new Long( Long.MAX_VALUE ); Byte b = new Byte( Byte.MAX_VALUE ); Float f = new Float (Float.MAX_VALUE); Short s = new Short (Short.MAX_VALUE); // Has anyone EVER used a Short in Java before? Double d = new Double( Double.MAX_VALUE ); List<Number> list = new ArrayList<Number> (); list.add(i); list.add(l); list.add(b); list.add(f); list.add(s); list.add(d); Object [] arr = list.toArray(); String c = ""; for( Number n : list ) { for( Object o : arr ) { c = "" + o.getClass().getName()+" into "+n.getClass().getName(); try { n = (Number)(o.getClass().cast(o)); } catch(ClassCastException e ) { System.out.println( "Cast exception " + c ); // continue } } } } // Please keep public void testParsingNumbers () throws Exception { Long.parseLong( "42" ); Long.parseLong( "-42" ); String n = "42.0"; try { Long.parseLong( n ); } catch( NumberFormatException x ) { Double d = Double.parseDouble( n ); assertEquals( 42.0, d.doubleValue() ); } try{ Long.parseLong( "-4-2" ); } catch (NumberFormatException e ) { return; } throw new Exception( "Long.parseLong() with invalid number didn't throw exception" ); } }