package hirondelle.web4j.model;

import junit.framework.*;
//import junit.ui.TestRunner;
//import junit.textui.TestRunner;
import java.util.*;

/**
 <a href="http://www.junit.org">JUnit</a> test cases for {@link ModelUtil}.

 <P>These tests are rather odd, since the hashCode contract is rather odd: it 
 doesn't specify the precise values to be returned. Hence, these test cases 
 have knowledge of implementation details which are usually ignored by tests.
*/
public final class TESTHashCodeUtil extends TestCase {

  /**
   Run the test cases.
  */
   public static void main(String args[]) {
     String[] testCaseName = { TESTHashCodeUtil.class.getName()};
     //Select one of several types of interfaces.
     junit.textui.TestRunner.main(testCaseName);
     //junit.swingui.TestRunner.main(testCaseName);
     //junit.ui.TestRunner.main(testCaseName);
  }

  /**
   Canonical form of constructor.
  */
  public TESTHashCodeUtil( String aName) {
   super( aName );
  }

  // TEST CASES //

  public void testBoolean(){
    int value = ModelUtil.hash(fSEED, true);
    assertTrue(value == (fODD_PRIME*fSEED + 1));
    
    value = ModelUtil.hash(fSEED, false);
    assertTrue(value == (fODD_PRIME*fSEED + 0));
  }
  
  public void testChar(){
    char val = 'A';
    int value = ModelUtil.hash(fSEED, val);
    assertTrue(value == (fODD_PRIME*fSEED + val));
  }
  
  public void testInt(){
    int val = 1003;
    int value = ModelUtil.hash(fSEED,val);
    assertTrue( value == (fODD_PRIME*fSEED + val));
  }

  public void testNullObject(){
    Object item = null;
    int value = ModelUtil.hash(fSEED, item);
    assertTrue( value == fODD_PRIME*fSEED + 0);
  }
  
  public void testString(){
    String blah = "blah";
    int blahHashCode = blah.hashCode();
    int value = ModelUtil.hash(fSEED, blah);
    assertTrue( value == (fODD_PRIME*fSEED + blahHashCode));
  }
  
  public void testList(){
    List<String> girlfriends = new ArrayList<String>();
    girlfriends.add("Gilberte");
    girlfriends.add("Albertine");
    int girlfriendsHashCode = girlfriends.hashCode();
    
    int value = ModelUtil.hash(fSEED, girlfriends);
    assertTrue(value == (fODD_PRIME*fSEED + girlfriendsHashCode));
  }
  
  public void testNullArray(){
    String[] stuff = null;
    int value = ModelUtil.hash(fSEED, stuff);
    assertTrue(value == fODD_PRIME*fSEED + 0);
  }
  
  public void testStringArray(){
    String gilberte = "Gilberte";
    String albertine = "Albertine";
    String[] names = new String[2];
    names[0] = gilberte;
    names[1] = albertine;
    
    int expectedVal = fODD_PRIME*fSEED + gilberte.hashCode();
    expectedVal = fODD_PRIME*expectedVal + albertine.hashCode();
    
    int value = ModelUtil.hash(fSEED, names);
    assertTrue(value == expectedVal);
  }
  
  public void testIntArray(){
    int[] ages = new int[2];
    ages[0] = 41;
    ages[1] = 57;
    int expectedVal = fODD_PRIME*fSEED + 41;
    expectedVal = fODD_PRIME*expectedVal + 57;
    
    int value = ModelUtil.hash(fSEED, ages);
    assertTrue(value == expectedVal);
  }
  
  public void testArrayOfNulls(){
    Object[] stuff = new Object[2];
    //all elements are now initialized to null
    int expectedVal = fODD_PRIME*fSEED + 0;
    expectedVal = fODD_PRIME*expectedVal + 0;
    
    int value = ModelUtil.hash(fSEED, stuff);
    assertTrue(value == expectedVal);
  }
  
  public void testNestedArray(){
    Object[] stuff = new Object[2];
    Object[] otherStuff = new Object[2];
    
    otherStuff[0] = "otherthing1";
    otherStuff[1] = "otherthing2";
    stuff[0] = "thing";
    stuff[1] = otherStuff;
    //just makes sure it doesn't blow up, or go into a loop
    int value = ModelUtil.hash(fSEED, stuff);
    assertTrue(value == 1757769324);
  }

  // FIXTURE //

  /**
   Build a fixture of test objects. This method is called anew for
   each test, such that the tests will always start with the same
   set of test objects, and the execution of one test will not interfere
   with the execution of another.
  */
   protected void setUp(){
   }

   /**
    Re-set test objects.
   */
   protected void tearDown() {
   }

   // PRIVATE  //
   private int fSEED = ModelUtil.HASH_SEED;
   private static final int fODD_PRIME = 37;
}
