#ifndef __STATEFILE_MODULESTEST_H
#define __STATEFILE_MODULESTEST_H

#include <cxxtest/TestSuite.h>
#include <string>
#include <memory.h>
#include "Modules.hxx"


class ModulesTest : public CxxTest::TestSuite {
 public:
  void test_Construction() {
    StateFile::Module *m1;
    TS_ASSERT( m1 = new StateFile::Module( 1 ) );
    delete m1;
    TS_ASSERT( m1 = new StateFile::Module( 1123123, false ) );
    delete m1;
    TS_ASSERT( m1 = new StateFile::Module( 9384345, true ) );
    delete m1;
  }

  void test_Skipping() {
    StateFile::Module *m1;
    TS_ASSERT( m1 = new StateFile::Module( 256 ) );
    TS_ASSERT( ! m1->getSkip() );
    m1->setSkip( false );
    TS_ASSERT( ! m1->getSkip() );
    m1->setSkip( true );
    TS_ASSERT( m1->getSkip() );

    // demonstrate default
    m1->setSkip( false );
    TS_ASSERT( ! m1->getSkip() );
    m1->setSkip();
    TS_ASSERT( m1->getSkip() );
    delete m1;
  }

  void test_ContentEntry() {
    StateFile::Module *m1;
    StateFile::ByteData32 *a32 = new StateFile::ByteData32();

    std::string *str = new std::string( "this is my special string" ); 

    a32->setData( str ); 
    
    TS_ASSERT( m1 = new StateFile::Module( 1231234343 ) );
    TS_ASSERT( m1 );
    TS_ASSERT( ! m1->getContent() );

    m1->setContent( a32 );

    TS_ASSERT( m1->getContent() == a32 );

    m1->setContent( NULL );
    
    TS_ASSERT( ! m1->getContent() );
    delete m1;
    delete a32;
    delete str;
  }
};


class fileModuleTest : public CxxTest::TestSuite {
    std::fstream fi;
      
    char *testFileName;
    char *removeTestFile;

    StateFile::Module *m1, *m2, *m3;
    std::string *name, *fields, *field_names;

    uint32 version;

 public:
    fileModuleTest()  {}

    virtual ~fileModuleTest() { 
      if (m1) delete m1;
      if (m2) delete m2;
      if (m3) delete m3;
    }

    static fileModuleTest *createSuite() { return new fileModuleTest(); }
    static void destroySuite( fileModuleTest *suite ) { delete suite; }

    void setUp() {

      testFileName = ".mod.test";
      removeTestFile = "/bin/rm .mod.test";

      name        = new std::string("Read Write");
      fields      = new std::string("dddd");
      field_names = new std::string("x:y:z:a");

      uint8 data[7] = { 3, 1, 2, 5, 8, 9, 6 };
      
      uint8 special[3] = { 132, 22, 14 };

      TS_ASSERT_EQUALS( special[0], 132 );
      TS_ASSERT_EQUALS( special[2], 14 );
      TS_ASSERT_EQUALS( data[2], 2 );

      version = 123123;

      m1 = new StateFile::Module( version );
      m2 = new StateFile::Module( version );
      m3 = new StateFile::Module( version );

      m1->setName( new std::string("Write Only") );
      m3->setName( new std::string("Skipped") );
      m2->setName( name );

      m2->setContentProfile( fields );      

      m2->setContentNames( field_names );

      StateFile::ByteData8 bd8 = StateFile::ByteData8();
      bd8.setData( special, 3 );

      m2->setExtra( &bd8 );

      StateFile::ByteData32 bd32 = StateFile::ByteData32();
      bd32.setData( data, 7 );
      
      m1->setContent( &bd32 );
      m2->setContent( &bd32 );
      m3->setContent( &bd32 );

      m3->setSkip( true );

      // Write a file (in binary):
      //
      // (10:1, "Write Only", 123123:4, 0:1, "", 0:1, "", 0:1, "")
      //   [7:4, 3, 1, 2, 5, 8, 9, 6]
      // (10, "Read Write", 123123, 4, "dddd", 7, "x:y:z:a", 3, 132, 22, 14)
      //   [7:4, 3, 1, 2, 5, 8, 9, 6]
      //
      fi.open( testFileName, std::ios::out | std::ios::binary );  
      TS_ASSERT( fi );

      TS_ASSERT( m1->fileWrite_Header( &fi ) );
      TS_ASSERT( m1->fileWrite_Content( &fi ) );
      TS_ASSERT( m3->fileWrite_Header( &fi ) );
      TS_ASSERT( m3->fileWrite_Content( &fi ) );
      TS_ASSERT( m2->fileWrite_Header( &fi ) );
      TS_ASSERT( m2->fileWrite_Content( &fi ) );

      fi.close();
      delete m1; m1 = NULL;
      delete m2; m2 = NULL;
      delete m3; m3 = NULL;

    }

    void tearDown() {
      system( removeTestFile );
    }

    void test_ConstructionFromFile() {

      fi.open( testFileName, std::ios::in | std::ios::binary );
      TS_ASSERT( fi );

      TS_ASSERT( m1 = new StateFile::Module( &fi ) );
      TS_ASSERT_EQUALS( strncmp("Write Only",m1->getName()->c_str(), 10), 0 );
      
      TS_ASSERT( m1->getSkip() ); // default behavior.
      m1->setSkip( false );
	
      TS_ASSERT( m1->fileRead( &fi ) );

      TS_ASSERT_EQUALS( (m1->getContent()->getData())[0], 3 );
      TS_ASSERT_EQUALS( (m1->getContent()->getData())[1], 1 );
      TS_ASSERT_EQUALS( (m1->getContent()->getData())[2], 2 );
      TS_ASSERT_EQUALS( (m1->getContent()->getData())[3], 5 );
      TS_ASSERT_EQUALS( (m1->getContent()->getData())[4], 8 );
      TS_ASSERT_EQUALS( (m1->getContent()->getData())[5], 9 );
      TS_ASSERT_EQUALS( (m1->getContent()->getData())[6], 6 );
      TS_ASSERT_EQUALS( m1->getVersion(), version );
      fi.close();
      delete m1;
      m1 = NULL;
    }

    void test_SkipConstruction() {
      fi.open( testFileName, std::ios::in | std::ios::binary );
      TS_ASSERT( fi );
      
      TS_ASSERT( m1 = new StateFile::Module( &fi ) );
      TS_ASSERT_EQUALS( strncmp("Write Only", m1->getName()->c_str(), 10), 0 );

      TS_ASSERT( m1->getSkip() );

      TS_ASSERT( m1->fileRead( &fi ) );

      TS_ASSERT_EQUALS( m1->getContent()->getSize(), 0 );

      delete m1;
      m1 = NULL;
      
    }

};

#endif /* __STATEFILE_MODULESTEST_H */
