/** \file
 *
 *  Contains the test cases for the Str class
 *
 *  Copyright (c) 2007,2008,2009 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 */

#ifndef _STR_TEST_H_
#define _STR_TEST_H_

#include "utils/Str.h"

#include <cxxtest/TestSuite.h>

/**
 * %Units tests for class Str
 *
 * \ingroup utils
 */
class Str_Test : public CxxTest::TestSuite
{
public:

    /// %Units tests for Str( const char* str = NULL, size_t length = NO_POS );
    void testConstructorCharStar( void )
    {
        Str str( "1234" );
        TS_ASSERT_EQUALS( str.length(), 4U );
        TS_ASSERT_SAME_DATA( str.cStr(), "1234", 5 );

        Str str3( "1234", 3 );
        TS_ASSERT_EQUALS( str3.length(), 3U );
        TS_ASSERT_SAME_DATA( str3.cStr(), "123", 4 );

        Str str0( "1234", 0 );
        TS_ASSERT_EQUALS( str0.length(), 0U );
        TS_ASSERT_EQUALS( str0, Str::EMPTY_STR );
        TS_ASSERT_SAME_DATA( str0.cStr(), "", 1 );

        Str strEmpty128( ( char* )NULL, 128 );
        TS_ASSERT_EQUALS( strEmpty128.length(), 128U );
        TS_ASSERT_DIFFERS( strEmpty128, Str::EMPTY_STR );
        TS_ASSERT_SAME_DATA( strEmpty128.cStr(), "", 1 );
    }

    /// %Units tests for Str( const Str& str, const size_t offset = 0, size_t count = NO_POS );
    void testCopyConstructor( void )
    {
        Str str( "1234" );

        Str strCopy( str );
        TS_ASSERT_EQUALS( strCopy, str );
        TS_ASSERT_EQUALS( strCopy.length(), 4U );
        TS_ASSERT_SAME_DATA( strCopy.cStr(), "1234", 5 );

        Str strCopy0( str, 0 );
        TS_ASSERT_EQUALS( strCopy0, str );
        TS_ASSERT_EQUALS( strCopy0.length(), 4U );
        TS_ASSERT_SAME_DATA( strCopy0.cStr(), "1234", 5 );

        Str strCopy1( str, 1 );
        TS_ASSERT_EQUALS( strCopy1.length(), 3U );
        TS_ASSERT_SAME_DATA( strCopy1.cStr(), "234", 4 );

        Str strCopyMax( str, Str::MAX_LEN );
        TS_ASSERT_EQUALS( strCopyMax.length(), 0U );
        TS_ASSERT_SAME_DATA( strCopyMax.cStr(), "", 1 );

        Str strCopy04( str, 0, 4 );
        TS_ASSERT_EQUALS( strCopy04, str );
        TS_ASSERT_EQUALS( strCopy04.length(), 4U );
        TS_ASSERT_SAME_DATA( strCopy04.cStr(), "1234", 5 );

        Str strCopy0Max( str, 0, Str::MAX_LEN );
        TS_ASSERT_EQUALS( strCopy0Max, str );
        TS_ASSERT_EQUALS( strCopy0Max.length(), 4U );
        TS_ASSERT_SAME_DATA( strCopy0Max.cStr(), "1234", 5 );

        Str strCopy00( str, 0, 0 );
        TS_ASSERT_EQUALS( strCopy00.length(), 0U );
        TS_ASSERT_SAME_DATA( strCopy00.cStr(), "", 1 );

        Str strCopy02( str, 0, 2 );
        TS_ASSERT_EQUALS( strCopy02.length(), 2U );
        TS_ASSERT_SAME_DATA( strCopy02.cStr(), "12", 3 );

        Str strCopy10( str, 1, 0 );
        TS_ASSERT_EQUALS( strCopy10.length(), 0U );
        TS_ASSERT_SAME_DATA( strCopy10.cStr(), "", 1 );

        Str strCopy12( str, 1, 2 );
        TS_ASSERT_EQUALS( strCopy12.length(), 2U );
        TS_ASSERT_SAME_DATA( strCopy12.cStr(), "23", 3 );

        Str strCopy1Max( str, 1, Str::MAX_LEN );
        TS_ASSERT_EQUALS( strCopy1Max.length(), 3U );
        TS_ASSERT_SAME_DATA( strCopy1Max.cStr(), "234", 4 );

    }

    /// %Units tests for Str( const bool var );
    void testBoolConstructor( void )
    {
        Str strTrue( true );
        TS_ASSERT_EQUALS( strTrue.length(), 1U );
        TS_ASSERT_SAME_DATA( strTrue.cStr(), "1", 2 );

        Str strFalse( false );
        TS_ASSERT_EQUALS( strFalse.length(), 1U );
        TS_ASSERT_SAME_DATA( strFalse.cStr(), "0", 2 );
    }

    /// %Units tests for Str( const double var, size_t precision = 10 )
    void testDoubleConstructor( void )
    {
        Str str0( 1234.0, 0 );
        TS_ASSERT_EQUALS( str0.length(), 4U );
        TS_ASSERT_SAME_DATA( str0.cStr(), "1234", 4 );
        Str str1( 1234.0, 1 );
        TS_ASSERT_EQUALS( str1.length(), 6U );
        TS_ASSERT_SAME_DATA( str1.cStr(), "1234.0", 6 );
        Str str2( 1234.0, 4 );
        TS_ASSERT_EQUALS( str2.length(), 9U );
        TS_ASSERT_SAME_DATA( str2.cStr(), "1234.0000", 5 );
        Str str3( 1234.567, 3 );
        TS_ASSERT_EQUALS( str3.length(), 8U );
        TS_ASSERT_SAME_DATA( str3.cStr(), "1234.567", 9 );
        Str str4( -1234.567, 3 );
        TS_ASSERT_EQUALS( str4.length(), 9U );
        TS_ASSERT_SAME_DATA( str4.cStr(), "-1234.567", 10 );
    }

    /// %Units tests for Str( const int var, size_t radix = 10 )
    void testIntConstructor( void )
    {
        Str str0( 1234 );
        TS_ASSERT_EQUALS( str0.length(), 4U );
        TS_ASSERT_SAME_DATA( str0.cStr(), "1234", 5 );
        Str str1( 1234, 16 );
        TS_ASSERT_EQUALS( str1.length(), 3U );
        TS_ASSERT_SAME_DATA( str1.cStr(), "4D2", 4 );
        Str str2( 1234, 8 );
        TS_ASSERT_EQUALS( str2.length(), 4U );
        TS_ASSERT_SAME_DATA( str2.cStr(), "2322", 5 );
        Str str3( 1234, 2 );
        TS_ASSERT_EQUALS( str3.length(), 11U );
        TS_ASSERT_SAME_DATA( str3.cStr(), "10011010010", 12 );
        Str str4( 1234, 0 );
        TS_ASSERT_EQUALS( str4.length(), 4U );
        TS_ASSERT_SAME_DATA( str4.cStr(), "1234", 5 );
        Str str5( 1234, 1 );
        TS_ASSERT_EQUALS( str5.length(), 11U );
        TS_ASSERT_SAME_DATA( str5.cStr(), "10011010010", 12 );
        Str str6( -1234 );
        TS_ASSERT_EQUALS( str6.length(), 5U );
        TS_ASSERT_SAME_DATA( str6.cStr(), "-1234", 6 );
        Str str7( -1234, 2 );
        TS_ASSERT_EQUALS( str7.length(), 12U );
        TS_ASSERT_SAME_DATA( str7.cStr(), "-10011010010", 13 );
    }

    /// %Units tests for Str( const unsigned int var, size_t radix = 16 )
    void testSizeTConstructor( void )
    {
        const size_t val = 1234;
        Str str0( val );
        TS_ASSERT_EQUALS( str0.length(), 3U );
        TS_ASSERT_SAME_DATA( str0.cStr(), "4D2", 4 );
        Str str1( val, 10 );
        TS_ASSERT_EQUALS( str1.length(), 4U );
        TS_ASSERT_SAME_DATA( str1.cStr(), "1234", 4 );
        Str str2( val, 8 );
        TS_ASSERT_EQUALS( str2.length(), 4U );
        TS_ASSERT_SAME_DATA( str2.cStr(), "2322", 5 );
        Str str3( val, 2 );
        TS_ASSERT_EQUALS( str3.length(), 11U );
        TS_ASSERT_SAME_DATA( str3.cStr(), "10011010010", 12 );
        Str str4( val, 0 );
        TS_ASSERT_EQUALS( str4.length(), 4U );
        TS_ASSERT_SAME_DATA( str4.cStr(), "1234", 5 );
        Str str5( val, 1 );
        TS_ASSERT_EQUALS( str5.length(), 11U );
        TS_ASSERT_SAME_DATA( str5.cStr(), "10011010010", 12 );
    }

    /// Str::IntToAscii %Unit Tests
    void testIntToAscii( void )
    {
        int i, len;
        char buffer[34];
        i = 0;
        len = Str::IntToAscii( i, buffer, 10, 34 );
        TS_ASSERT_SAME_DATA( buffer, "0", len + 1 );
        i = 5;
        len = Str::IntToAscii( i, buffer, 10, 34 );
        TS_ASSERT_SAME_DATA( buffer, "5", len + 1 );
        i = 10;
        len = Str::IntToAscii( i, buffer, 10, 34 );
        TS_ASSERT_SAME_DATA( buffer, "10", len + 1 );
        i = -10;
        len = Str::IntToAscii( i, buffer, 10, 34 );
        TS_ASSERT_SAME_DATA( buffer, "-10", len + 1 );
        i = 100;
        len = Str::IntToAscii( i, buffer, 10, 34 );
        TS_ASSERT_SAME_DATA( buffer, "100", len + 1 );
        i = -100;
        len = Str::IntToAscii( i, buffer, 10, 34 );
        TS_ASSERT_SAME_DATA( buffer, "-100", len + 1 );
        i = 0x7FFFFFFF;
        len = Str::IntToAscii( i, buffer, 10, 34 );
        TS_ASSERT_SAME_DATA( buffer, "2147483647", len + 1 );
        i = -0x80000000;
        len = Str::IntToAscii( i, buffer, 10, 34 );
        TS_ASSERT_SAME_DATA( buffer, "-2147483648", len + 1 );
        i = 0x7FFFFFFF;
        len = Str::IntToAscii( i, buffer, 2, 34 );
        TS_ASSERT_SAME_DATA( buffer, "1111111111111111111111111111111", len + 1 );
        i = -0x80000000;
        len = Str::IntToAscii( i, buffer, 2, 34 );
        TS_ASSERT_SAME_DATA( buffer, "-10000000000000000000000000000000", len + 1 );
        i = -0x7FFFFFFF;
        len = Str::IntToAscii( i, buffer, 2, 34 );
        TS_ASSERT_SAME_DATA( buffer, "-1111111111111111111111111111111", len + 1 );
        i = 1;
        len = Str::IntToAscii( i, buffer, 2, 34 );
        TS_ASSERT_SAME_DATA( buffer, "1", len + 1 );
        i = 0x7FFFFFFF;
        len = Str::IntToAscii( i, buffer, 16, 34 );
        TS_ASSERT_SAME_DATA( buffer, "7FFFFFFF", len + 1 );
        i = -0x80000000;
        len = Str::IntToAscii( i, buffer, 16, 34 );
        TS_ASSERT_SAME_DATA( buffer, "-80000000", len + 1 );
        i = -0x7FFFFFFF;
        len = Str::IntToAscii( i, buffer, 16, 34 );
        TS_ASSERT_SAME_DATA( buffer, "-7FFFFFFF", len + 1 );
        i = 0xF;
        len = Str::IntToAscii( i, buffer, 16, 34 );
        TS_ASSERT_SAME_DATA( buffer, "F", len + 1 );
    }

    /// Str::IntToAscii %Unit Tests
    void testIntToAsciiWithOffset( void )
    {
        int i, len;
        char buffer[34];
        i = 0;
        len = Str::IntToAscii( i, buffer, 10, 34, 10 );
        TS_ASSERT_SAME_DATA( buffer, "A", len + 1 );
        i = 5;
        len = Str::IntToAscii( i, buffer, 26, 34, 10 );
        TS_ASSERT_SAME_DATA( buffer, "F", len + 1 );
        i = 10;
        len = Str::IntToAscii( i, buffer, 26, 34, 10 );
        TS_ASSERT_SAME_DATA( buffer, "K", len + 1 );
        i = -10;
        len = Str::IntToAscii( i, buffer, 26, 34, 10 );
        TS_ASSERT_SAME_DATA( buffer, "-K", len + 1 );
        i = 100;
        len = Str::IntToAscii( i, buffer, 26, 34, 10 );
        TS_ASSERT_SAME_DATA( buffer, "DV", len + 1 );
        i = -100;
        len = Str::IntToAscii( i, buffer, 26, 34, 10 );
        TS_ASSERT_SAME_DATA( buffer, "-DV", len + 1 );
    }

    void testFindLastOf()
    {
        Str testStr = "0123456789";
        TS_ASSERT_EQUALS( testStr.findLastOf( '8' ), ( size_t )8 );
        TS_ASSERT_EQUALS( testStr.findLastOf( "67" ), ( size_t )6 );
        TS_ASSERT_EQUALS( testStr.findLastOf( "679" ), Str::NO_POS );
    }

    void testSplit()
    {
        Str testStr = "1++22+333";
        int num;
        Str* split = testStr.split( num, "+" );
        TS_ASSERT_EQUALS( num, 4 );
        TS_ASSERT_SAME_DATA( split[0].cStr(), "1", 2 );
        TS_ASSERT_SAME_DATA( split[1].cStr(), "", 1 );
        TS_ASSERT_SAME_DATA( split[2].cStr(), "22", 3 );
        TS_ASSERT_SAME_DATA( split[3].cStr(), "333", 4 );
        delete[] split;
    }

    void testAsHex()
    {
        const char chars1[] = { 0x00, 0x79 };
        Str str1( chars1, sizeof( chars1 ) );
        Str strHex1 = str1.asHex();
        TS_ASSERT_EQUALS( strHex1.length(), 4U );
        TS_ASSERT_SAME_DATA( strHex1.cStr(), "0079", 5 );
    }

    void testSetInsideSetChar()
    {
        size_t length = 6;

        Str str;
        str.set( NULL, length );

        TS_ASSERT_EQUALS( str.length(), length );

        TS_ASSERT_SAME_DATA( str.cStr(), "", 1 );

        str.setInside( "123", 0 );
        TS_ASSERT_SAME_DATA( str.cStr(), "123", 4 );

        str.setInside( "321", 0, 3 );
        TS_ASSERT_SAME_DATA( str.cStr(), "321", 4 );

        str.setInside( "123", 2, 3 );
        TS_ASSERT_SAME_DATA( str.cStr(), "32123", 6 );

        str.setChar( 2, 'x' );
        TS_ASSERT_SAME_DATA( str.cStr(), "32x23", 6 );
    }

    // test conversion
    void testStrToDouble( void )
    {
        TS_ASSERT_EQUALS( Str( "5.0" ).toDouble(), 5.0 );
        TS_ASSERT_EQUALS( Str( "5.1e1" ).toDouble(), 51 );
    }

    // test conversion
    void testStrToDoubleArray( void )
    {
        int rank, m, n, o = 99;
        Str str( "5.0" );
        double* arr = str.toDoubleArray( rank, m, n, o );
        TS_ASSERT( arr );
        TS_ASSERT_EQUALS( rank, 0 );
        TS_ASSERT_EQUALS( m, 0 );
        TS_ASSERT_EQUALS( *arr, 5.0 );
        delete[] arr;

        str = "[5.1e1]";
        arr = str.toDoubleArray( rank, m, n, o );
        TS_ASSERT( arr );
        TS_ASSERT_EQUALS( rank, 1 );
        TS_ASSERT_EQUALS( m, 1 );
        TS_ASSERT_EQUALS( *arr, 51 );
        delete[] arr;

        str = "5.0,5.1e1";
        arr = str.toDoubleArray( rank, m, n, o );
        TS_ASSERT( arr );
        TS_ASSERT_EQUALS( rank, 1 );
        TS_ASSERT_EQUALS( m, 2 );
        TS_ASSERT_EQUALS( arr[0], 5.0 );
        TS_ASSERT_EQUALS( arr[1], 51 );
        delete[] arr;

        str = "[5.0,5.1e1]";
        arr = str.toDoubleArray( rank, m, n, o );
        TS_ASSERT( arr );
        TS_ASSERT_EQUALS( rank, 1 );
        TS_ASSERT_EQUALS( m, 2 );
        TS_ASSERT_EQUALS( arr[0], 5.0 );
        TS_ASSERT_EQUALS( arr[1], 51 );
        delete[] arr;

        str = "[[5.0,5.1e1],[6.0,6.1e1],[7.0,7.1e1]]";
        arr = str.toDoubleArray( rank, m, n, o );
        TS_ASSERT( arr );
        TS_ASSERT_EQUALS( rank, 2 );
        TS_ASSERT_EQUALS( m, 3 );
        TS_ASSERT_EQUALS( n, 2 );
        TS_ASSERT_EQUALS( arr[0], 5.0 );
        TS_ASSERT_EQUALS( arr[1], 51 );
        TS_ASSERT_EQUALS( arr[2], 6.0 );
        TS_ASSERT_EQUALS( arr[3], 61 );
        TS_ASSERT_EQUALS( arr[4], 7.0 );
        TS_ASSERT_EQUALS( arr[5], 71 );
        delete[] arr;

        str = "[[5.0],[6.0,6.1e1],[7.0]]";
        arr = str.toDoubleArray( rank, m, n, o );
        TS_ASSERT( arr );
        TS_ASSERT_EQUALS( rank, 2 );
        TS_ASSERT_EQUALS( m, 3 );
        TS_ASSERT_EQUALS( n, 2 );
        TS_ASSERT_EQUALS( arr[0], 5.0 );
        TS_ASSERT( isnan( arr[1] ) );
        TS_ASSERT_EQUALS( arr[2], 6.0 );
        TS_ASSERT_EQUALS( arr[3], 61 );
        TS_ASSERT_EQUALS( arr[4], 7.0 );
        TS_ASSERT( isnan( arr[5] ) );
        delete[] arr;

        str = "[[5.0,5.1e1],[6.0,6.1e1],[7.0,7.1e1]]";
        arr = str.toDoubleArray( rank, m, n, o );
        TS_ASSERT( arr );
        TS_ASSERT_EQUALS( rank, 2 );
        TS_ASSERT_EQUALS( m, 3 );
        TS_ASSERT_EQUALS( n, 2 );
        TS_ASSERT_EQUALS( arr[0], 5.0 );
        TS_ASSERT_EQUALS( arr[1], 51 );
        TS_ASSERT_EQUALS( arr[2], 6.0 );
        TS_ASSERT_EQUALS( arr[3], 61 );
        TS_ASSERT_EQUALS( arr[4], 7.0 );
        TS_ASSERT_EQUALS( arr[5], 71 );
        delete[] arr;

        str = "[[[5.0],[6.0,6.1e1],[7.0]],[[8.0],[9.0,9.1e1,9.2e2,9.3e3]]]";
        arr = str.toDoubleArray( rank, m, n, o );
        TS_ASSERT( arr );
        TS_ASSERT_EQUALS( rank, 3 );
        TS_ASSERT_EQUALS( m, 2 );
        TS_ASSERT_EQUALS( n, 3 );
        TS_ASSERT_EQUALS( o, 4 );
        TS_ASSERT_EQUALS( arr[0], 5.0 );
        TS_ASSERT( isnan( arr[1] ) );
        TS_ASSERT_EQUALS( arr[4], 6.0 );
        TS_ASSERT_EQUALS( arr[5], 61 );
        TS_ASSERT_EQUALS( arr[8], 7.0 );
        TS_ASSERT( isnan( arr[9] ) );
        TS_ASSERT_EQUALS( arr[12], 8.0 );
        TS_ASSERT( isnan( arr[13] ) );
        TS_ASSERT_EQUALS( arr[16], 9.0 );
        TS_ASSERT_EQUALS( arr[17], 91 );
        TS_ASSERT_EQUALS( arr[18], 920 );
        TS_ASSERT_EQUALS( arr[19], 9300 );
        TS_ASSERT( isnan( arr[20] ) );
        TS_ASSERT( isnan( arr[23] ) );
        delete[] arr;
    }

};

#endif // _STR_TEST_H
