/*
 * JBoss, Home of Professional Open Source
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */
package org.jboss.cache.marshall;

import junit.framework.TestCase;
import org.jboss.cache.misc.TestingUtil;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Random;

/**
 * Tests the performance of JBoss Serialization
 *
 * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik@jboss.org)</a>
 */
public class JBossSerializationTest extends TestCase
{

   // you can change these variables to change behavior of this testsuite, for debug purposes:

   public static boolean SAVE_FILE = false;
   public static boolean USE_STRING = false;

   protected void setUp()
   {
      // do a GC and wait for it to kick in - useful when running as a part of the test suite.
      System.gc();
      TestingUtil.sleepThread(1000);
   }

   static class DummyObject implements java.io.Serializable
   {
      private static final long serialVersionUID = -1374365296408936578L;
      String stringName;

      public DummyObject()
      {
         stringName = "Hello world, blah blah blah." + (new Random().nextInt());
      }

      public boolean equals(Object obj)
      {
         return stringName.equals(((DummyObject) obj).stringName);
      }
   }

   private static void saveBytes(File fileName, byte[] bytes) throws Exception
   {
      if (SAVE_FILE)
      {
         FileOutputStream fileOut = new FileOutputStream(fileName);
         fileOut.write(bytes);
         fileOut.close();
      }
   }

   public void testSpeedSizeAndDefaults() throws Exception
   {

      assertTrue("JBoss Serialization should be enabled by default", ObjectSerializationFactory.useJBossSerialization);
      assertEquals("Should use JBossObjectStreamFactory", JBossObjectStreamFactory.class, ObjectSerializationFactory.factory.getClass());
      Object dummyObject = null;

      if (USE_STRING)
      {
         dummyObject = "Hello world, blah blah blah.";
      }
      else
      {
         dummyObject = new DummyObject();
      }

      ObjectSerializationFactory.useJBossSerialization = false;
      ObjectSerializationFactory.factory = new JavaObjectStreamFactory();
      assertTrue("Should be false", !ObjectSerializationFactory.useJBossSerialization);


      ByteArrayOutputStream out = new ByteArrayOutputStream();

      long start = 0;

      for (int i = 0; i < 50000; i++)
      {
         out.reset();
         if (i == 1000)
         {
            start = System.currentTimeMillis();
         }
         ObjectOutputStream objectOut = ObjectSerializationFactory.createObjectOutputStream(out);
         objectOut.writeObject(dummyObject);
         objectOut.close();

         ObjectInputStream objectInput = ObjectSerializationFactory.createObjectInputStream(out.toByteArray());
         Object newObject = objectInput.readObject();

         assertEquals(dummyObject, newObject);
         assertNotSame(dummyObject, newObject);
      }


      long javaSerializationTime = System.currentTimeMillis() - start;
      int javaSerializationSize = out.toByteArray().length;

      saveBytes(new File("/tmp/fileJava.bin"), out.toByteArray());

      ObjectSerializationFactory.useJBossSerialization = true;
      ObjectSerializationFactory.factory = new JBossObjectStreamFactory();
      assertTrue("Should be true", ObjectSerializationFactory.useJBossSerialization);

      start = 0;
      for (int i = 0; i < 50000; i++)
      {
         out.reset();
         if (i == 1000)
         {
            start = System.currentTimeMillis();
         }
         ObjectOutputStream objectOut = ObjectSerializationFactory.createObjectOutputStream(out);
         objectOut.writeObject(dummyObject);
         objectOut.close();

         ObjectInputStream objectInput = ObjectSerializationFactory.createObjectInputStream(out.toByteArray());
         Object newObject = objectInput.readObject();

         assertEquals(dummyObject, newObject);
         assertNotSame(dummyObject, newObject);
      }
      long jbossSerializationTime = System.currentTimeMillis() - start;
      int jbossSerializationSize = out.toByteArray().length;

      System.out.println("FinishJBoss:" + System.currentTimeMillis());
      saveBytes(new File("/tmp/fileJBoss.bin"), out.toByteArray());

      System.out.println("JBossSerialization Time:" + jbossSerializationTime);
      System.out.println("JavaSerialization Time:" + javaSerializationTime);

      System.out.println("JBossSerialization Size:" + jbossSerializationSize);
      System.out.println("JavaSerialization Size:" + javaSerializationSize);

      assertTrue("JBoss Serialization should be FASTER than Java Serialization. Java: " + javaSerializationTime + "; jboss: " + jbossSerializationTime, jbossSerializationTime < javaSerializationTime);
      assertTrue("JBoss Serialization output should be SMALLER than Java Serialization. Java: " + javaSerializationSize + "; jboss: " + jbossSerializationSize, jbossSerializationSize < javaSerializationSize);
   }

}
