/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/




// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sal.hxx"
// autogenerated file with codegen.pl

#include <math.h>
#include <stdio.h>

#include <algorithm> // STL

#include "gtest/gtest.h"
#include "stringhelper.hxx"
#include "valueequal.hxx"

inline void printOUString( ::rtl::OUString const & _suStr )
{
    rtl::OString aString;

    printf( "OUString: " );
    aString = ::rtl::OUStringToOString( _suStr, RTL_TEXTENCODING_ASCII_US );
    printf( "'%s'\n", aString.getStr( ) );
}

namespace rtl_OUString
{

    class ctors_rtl_uString : public ::testing::Test
    {
    public:
    };

    /// test of OUString(rtl_uString*)
    TEST_F(ctors_rtl_uString, ctors_001)
    {
        rtl::OUString *pStr = new rtl::OUString( rtl::OUString::createFromAscii("a String") );

        rtl::OUString aStrToTest(pStr->pData);
        delete pStr;

        // maybe here should we do something with current memory
        char* pBuffer = (char*) malloc(2 * 8);
        memset(pBuffer, 0, 2 * 8);
        free(pBuffer);

        sal_Bool bResult = aStrToTest.equals(rtl::OUString::createFromAscii("a String"));
        ASSERT_TRUE(bResult == sal_True) << "String must not be empty";
    }

// -----------------------------------------------------------------------------
class valueOf : public ::testing::Test
{
protected:
    void valueOf_float_test_impl(float _nValue)
        {
            rtl::OUString suValue;
            suValue = rtl::OUString::valueOf( _nValue );
            rtl::OString sValue;
            sValue <<= suValue;
            printf("nFloat := %.9f  sValue := %s\n", _nValue, sValue.getStr());

            float nValueATOF = static_cast<float>(atof( sValue.getStr() ));

            bool bEqualResult = is_float_equal(_nValue, nValueATOF);
            ASSERT_TRUE(bEqualResult == true) << "Values are not equal.";
        }

    void valueOf_float_test(float _nValue)
        {
            valueOf_float_test_impl(_nValue);

            // test also the negative part.
            float nNegativeValue = -_nValue;
            valueOf_float_test_impl(nNegativeValue);
        }

protected:

    void valueOf_double_test_impl(double _nValue)
        {
            rtl::OUString suValue;
            suValue = rtl::OUString::valueOf( _nValue );
            rtl::OString sValue;
            sValue <<= suValue;
            printf("nDouble := %.20f  sValue := %s\n", _nValue, sValue.getStr());

            double nValueATOF = atof( sValue.getStr() );

            bool bEqualResult = is_double_equal(_nValue, nValueATOF);
            ASSERT_TRUE(bEqualResult == true) << "Values are not equal.";
        }

    void valueOf_double_test(double _nValue)
        {
            valueOf_double_test_impl(_nValue);

            // test also the negative part.
            double nNegativeValue = -_nValue;
            valueOf_double_test_impl(nNegativeValue);
        }
}; // class valueOf

    TEST_F(valueOf, valueOf_float_test_001)
    {
        // this is demonstration code
        // ASSERT_TRUE(1 == 1) << "a message";
        float nValue = 3.0f;
        valueOf_float_test(nValue);
    }

    TEST_F(valueOf, valueOf_float_test_002)
    {
        float nValue = 3.5f;
        valueOf_float_test(nValue);
    }

    TEST_F(valueOf, valueOf_float_test_003)
    {
        float nValue = 3.0625f;
        valueOf_float_test(nValue);
    }

    TEST_F(valueOf, valueOf_float_test_004)
    {
        float nValue = 3.502525f;
        valueOf_float_test(nValue);
    }

    TEST_F(valueOf, valueOf_float_test_005)
    {
        float nValue = 3.141592f;
        valueOf_float_test(nValue);
    }

    TEST_F(valueOf, valueOf_float_test_006)
    {
        float nValue = 3.5025255f;
        valueOf_float_test(nValue);
    }

    TEST_F(valueOf, valueOf_float_test_007)
    {
        float nValue = 3.0039062f;
        valueOf_float_test(nValue);
    }

    // valueOf double
    TEST_F(valueOf, valueOf_double_test_001)
    {
        double nValue = 3.0;
        valueOf_double_test(nValue);
    }
    TEST_F(valueOf, valueOf_double_test_002)
    {
        double nValue = 3.5;
        valueOf_double_test(nValue);
    }
    TEST_F(valueOf, valueOf_double_test_003)
    {
        double nValue = 3.0625;
        valueOf_double_test(nValue);
    }
    TEST_F(valueOf, valueOf_double_test_004)
    {
        double nValue = 3.1415926535;
        valueOf_double_test(nValue);
    }
    TEST_F(valueOf, valueOf_double_test_005)
    {
        double nValue = 3.141592653589793;
        valueOf_double_test(nValue);
    }
    TEST_F(valueOf, valueOf_double_test_006)
    {
        double nValue = 3.1415926535897932;
        valueOf_double_test(nValue);
    }
    TEST_F(valueOf, valueOf_double_test_007)
    {
        double nValue = 3.14159265358979323;
        valueOf_double_test(nValue);
    }
    TEST_F(valueOf, valueOf_double_test_008)
    {
        double nValue = 3.141592653589793238462643;
        valueOf_double_test(nValue);
    }

//------------------------------------------------------------------------
// testing the method toDouble()
//------------------------------------------------------------------------
template<class T>
sal_Int16 SAL_CALL checkPrecisionSize()
{
	// sal_Int16 nSize = sizeof(T);
	volatile T nCalcValue = 1.0;


	// (i + 1) is the current precision
    // numerical series
    // 1.1
    // 10.1
    // 100.1
    // ...
    // 1000...0.1

	sal_Int16 i = 0;
	for (i=0;i<50;i++)
	{
		nCalcValue *= 10;
		volatile T nValue = nCalcValue + static_cast<T>(0.1);
		volatile T dSub = nValue - nCalcValue;
		// ----- 0.11 ---- 0.1 ---- 0.09 -----
		if (0.11 > dSub && dSub < 0.09)
		{
			// due to the fact, that the value is break down we sub 1 from the precision value
			// but to suppress this, we start at zero, precision is i+1 till here --i;
			break;
		}
	}

	sal_Int16 j= 0;
	nCalcValue = 1.0;

    // numerical series
    // 1.1
    // 1.01
    // 1.001
    // ...
    // 1.000...001

	for (j=0;j<50;j++)
	{
		nCalcValue /= 10;
		volatile T nValue = nCalcValue + static_cast<T>(1.0);
		volatile T dSub = nValue - static_cast<T>(1.0);
		// ---- 0.02 ----- 0.01 ---- 0 --- -0.99 ---- -0.98 ----
		// volatile T dSubAbsolut = fabs(dSub);
		// ---- 0.02 ----- 0.01 ---- 0 (cut)
		if ( dSub == 0)
			break;
	}
	if (i != j)
	{
            // hmmm....
            // imho i +- 1 == j is a good value
            int n = i - j;
            if (n < 0) n = -n;
            if (n <= 1)
            {
                return std::min(i,j);
            }
            else
            {
                printf("warning: presision differs more than 1!\n");
            }
        }

	return i;
}

// -----------------------------------------------------------------------------

    class testPrecision
    {
    public:
        testPrecision()
            {
                sal_Int16 nPrecision;
                nPrecision = checkPrecisionSize<float>();
                printf("precision of float: %d sizeof()=%lu \n", nPrecision, sizeof(float));

                nPrecision = checkPrecisionSize<double>();
                printf("precision of double: %d sizeof()=%lu \n", nPrecision, sizeof(double));

                nPrecision = checkPrecisionSize<long double>();
                printf("precision of long double: %d sizeof()=%lu \n", nPrecision, sizeof(long double));

            }

    };

    class toInt: public ::testing::Test {
    public:
    };

    TEST_F(toInt, test) {
        ASSERT_EQ(
            static_cast< sal_Int32 >(-0x76543210),
            (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("-76543210")).
            toInt32(16)));
        ASSERT_EQ(
            static_cast< sal_Int32 >(0xFEDCBA98),
            (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("+FEDCBA98")).
            toInt32(16)));
        ASSERT_EQ(
            static_cast< sal_Int64 >(-SAL_CONST_INT64(0x76543210FEDCBA98)),
            (rtl::OUString(
            RTL_CONSTASCII_USTRINGPARAM("-76543210FEDCBA98")).
            toInt64(16)));
        ASSERT_EQ(
            static_cast< sal_Int64 >(SAL_CONST_INT64(0xFEDCBA9876543210)),
            (rtl::OUString(
            RTL_CONSTASCII_USTRINGPARAM("+FEDCBA9876543210")).
            toInt64(16)));
    }

// -----------------------------------------------------------------------------
// - toDouble (tests)
// -----------------------------------------------------------------------------
    class toDouble : public ::testing::Test
    {
    public:
        void toDouble_test_impl(rtl::OString const& _sValue)
            {
            	//printf("the original str is %s\n", _sValue.getStr());
                double nValueATOF = atof( _sValue.getStr() );
		//printf("original data is %e\n", nValueATOF);
                rtl::OUString suValue = rtl::OUString::createFromAscii( _sValue.getStr() );
                double nValueToDouble = suValue.toDouble();
                //printf("result data is %e\n", nValueToDouble);

                bool bEqualResult = is_double_equal(nValueToDouble, nValueATOF);
                ASSERT_TRUE(bEqualResult == true) << "Values are not equal.";
            }

        void toDouble_test(rtl::OString const& _sValue)
            {
                toDouble_test_impl(_sValue);

                // test also the negativ part.
                rtl::OString sNegativValue("-");
                sNegativValue += _sValue;
                toDouble_test_impl(sNegativValue);
            }
    }; // class toDouble

    TEST_F(toDouble, toDouble_selftest)
    {
        printf("Start selftest:\n");
        ASSERT_TRUE (is_double_equal(1.0, 1.01) == false);
        ASSERT_TRUE (is_double_equal(1.0, 1.001) == false);
        ASSERT_TRUE (is_double_equal(1.0, 1.0001) == false);
        ASSERT_TRUE (is_double_equal(1.0, 1.00001) == false);
        ASSERT_TRUE (is_double_equal(1.0, 1.000001) == false);
        ASSERT_TRUE (is_double_equal(1.0, 1.0000001) == false);
        ASSERT_TRUE (is_double_equal(1.0, 1.00000001) == false);
        ASSERT_TRUE (is_double_equal(1.0, 1.000000001) == false);
        ASSERT_TRUE (is_double_equal(1.0, 1.0000000001) == false);
        ASSERT_TRUE (is_double_equal(1.0, 1.00000000001) == false);
        ASSERT_TRUE (is_double_equal(1.0, 1.000000000001) == false);
        ASSERT_TRUE (is_double_equal(1.0, 1.0000000000001) == false);
        // we check til 15 values after comma
        ASSERT_TRUE (is_double_equal(1.0, 1.00000000000001) == true);
        ASSERT_TRUE (is_double_equal(1.0, 1.000000000000001) == true);
        ASSERT_TRUE (is_double_equal(1.0, 1.0000000000000001) == true);
        printf("Selftest done.\n");
    }

    TEST_F(toDouble, toDouble_test_3)
    {
        rtl::OString sValue("3");
        toDouble_test(sValue);
    }
    TEST_F(toDouble, toDouble_test_3_5)
    {
        rtl::OString sValue("3.5");
        toDouble_test(sValue);
    }
    TEST_F(toDouble, toDouble_test_3_0625)
    {
        rtl::OString sValue("3.0625");
        toDouble_test(sValue);
    }
    TEST_F(toDouble, toDouble_test_pi)
    {
        // value from http://www.angio.net/pi/digits/50.txt
        rtl::OString sValue("3.141592653589793238462643383279502884197169399375");
        toDouble_test(sValue);
    }

    TEST_F(toDouble, toDouble_test_1)
    {
        rtl::OString sValue("1");
        toDouble_test(sValue);
    }
    TEST_F(toDouble, toDouble_test_10)
    {
        rtl::OString sValue("10");
        toDouble_test(sValue);
    }
    TEST_F(toDouble, toDouble_test_100)
    {
        rtl::OString sValue("100");
        toDouble_test(sValue);
    }
    TEST_F(toDouble, toDouble_test_1000)
    {
        rtl::OString sValue("1000");
        toDouble_test(sValue);
    }
    TEST_F(toDouble, toDouble_test_10000)
    {
        rtl::OString sValue("10000");
        toDouble_test(sValue);
    }
    TEST_F(toDouble, toDouble_test_1e99)
    {
        rtl::OString sValue("1e99");
        toDouble_test(sValue);
    }
    TEST_F(toDouble, toDouble_test_1e_n99)
    {
        rtl::OString sValue("1e-99");
        toDouble_test(sValue);
    }
    TEST_F(toDouble, toDouble_test_1e308)
    {
        rtl::OString sValue("1e308");
        toDouble_test(sValue);
    }

// -----------------------------------------------------------------------------
// - toFloat (tests)
// -----------------------------------------------------------------------------
    class toFloat : public ::testing::Test
    {
    public:
        void toFloat_test_impl(rtl::OString const& _sValue)
            {
            	//printf("the original str is %s\n", _sValue.getStr());
                float nValueATOF = static_cast<float>(atof( _sValue.getStr() ));
		//printf("the original str is %.10f\n", nValueATOF);
                rtl::OUString suValue = rtl::OUString::createFromAscii( _sValue.getStr() );
                float nValueToFloat = suValue.toFloat();
                //printf("the result str is %.10f\n", nValueToFloat);

                bool bEqualResult = is_float_equal(nValueToFloat, nValueATOF);
                ASSERT_TRUE(bEqualResult == true) << "Values are not equal.";
            }

        void toFloat_test(rtl::OString const& _sValue)
            {
                toFloat_test_impl(_sValue);

                // test also the negativ part.
                rtl::OString sNegativValue("-");
                sNegativValue += _sValue;
                toFloat_test_impl(sNegativValue);
            }
    }; // class toFloat

    TEST_F(toFloat, toFloat_selftest)
    {
        printf("Start selftest:\n");
        ASSERT_TRUE (is_float_equal(1.0f, 1.01f) == false);
        ASSERT_TRUE (is_float_equal(1.0f, 1.001f) == false);
        ASSERT_TRUE (is_float_equal(1.0f, 1.0001f) == false);
        ASSERT_TRUE (is_float_equal(1.0f, 1.00001f) == false);
        ASSERT_TRUE (is_float_equal(1.0f, 1.000002f) == false);
        ASSERT_TRUE (is_float_equal(1.0f, 1.0000001f) == true);
        ASSERT_TRUE (is_float_equal(1.0f, 1.00000001f) == true);
        ASSERT_TRUE (is_float_equal(1.0f, 1.000000001f) == true);

        printf("Selftest done.\n");
    }

    TEST_F(toFloat, toFloat_test_3)
    {
        rtl::OString sValue("3");
        toFloat_test(sValue);
    }
    TEST_F(toFloat, toFloat_test_3_5)
    {
        rtl::OString sValue("3.5");
        toFloat_test(sValue);
    }
    TEST_F(toFloat, toFloat_test_3_0625)
    {
        rtl::OString sValue("3.0625");
        toFloat_test(sValue);
    }
    TEST_F(toFloat, toFloat_test_3_0625_e)
    {
        rtl::OString sValue("3.0625e-4");
        toFloat_test(sValue);
    }
    TEST_F(toFloat, toFloat_test_pi)
    {
        // value from http://www.angio.net/pi/digits/50.txt
        rtl::OString sValue("3.141592653589793238462643383279502884197169399375");
        toFloat_test(sValue);
    }

    TEST_F(toFloat, toFloat_test_1)
    {
        rtl::OString sValue("1");
        toFloat_test(sValue);
    }
    TEST_F(toFloat, toFloat_test_10)
    {
        rtl::OString sValue("10");
        toFloat_test(sValue);
    }
    TEST_F(toFloat, toFloat_test_100)
    {
        rtl::OString sValue("100");
        toFloat_test(sValue);
    }
    TEST_F(toFloat, toFloat_test_1000)
    {
        rtl::OString sValue("1000");
        toFloat_test(sValue);
    }
    TEST_F(toFloat, toFloat_test_10000)
    {
        rtl::OString sValue("10000");
        toFloat_test(sValue);
    }
    TEST_F(toFloat, toFloat_test_mix)
    {
        rtl::OString sValue("456789321455.123456789012");
        toFloat_test(sValue);
    }
    TEST_F(toFloat, toFloat_test_1e99)
    {
        rtl::OString sValue("1e99");
        toFloat_test(sValue);
    }
    TEST_F(toFloat, toFloat_test_1e_n99)
    {
        rtl::OString sValue("1e-9");
        toFloat_test(sValue);
    }
    TEST_F(toFloat, toFloat_test_1e308)
    {
        rtl::OString sValue("1e308");
        toFloat_test(sValue);
    }

// -----------------------------------------------------------------------------
// - lastIndexOf (tests)
// -----------------------------------------------------------------------------
class lastIndexOf : public ::testing::Test
{
public:
    void lastIndexOf_oustring(rtl::OUString const& _suStr, rtl::OUString const& _suSearchStr, sal_Int32 _nExpectedResultPos)
        {
            // Algorithm
            // search the string _suSearchStr (rtl::OUString) in the string _suStr.
            // check if the _nExpectedResultPos occurs.

            sal_Int32 nPos = _suStr.lastIndexOf(_suSearchStr);
            ASSERT_TRUE(nPos == _nExpectedResultPos) << "expected position is wrong";
        }

    void lastIndexOf_salunicode(rtl::OUString const& _suStr, sal_Unicode _cuSearchChar, sal_Int32 _nExpectedResultPos)
        {
            // Algorithm
            // search the unicode char _suSearchChar (sal_Unicode) in the string _suStr.
            // check if the _nExpectedResultPos occurs.

            sal_Int32 nPos = _suStr.lastIndexOf(_cuSearchChar);
            ASSERT_TRUE(nPos == _nExpectedResultPos) << "expected position is wrong";
        }

    void lastIndexOf_oustring_offset(rtl::OUString const& _suStr, rtl::OUString const& _suSearchStr, sal_Int32 _nExpectedResultPos, sal_Int32 _nStartOffset)
        {
            sal_Int32 nPos = _suStr.lastIndexOf(_suSearchStr, _nStartOffset);
            ASSERT_TRUE(nPos == _nExpectedResultPos) << "expected position is wrong";
        }

    void lastIndexOf_salunicode_offset(rtl::OUString const& _suStr, sal_Unicode _cuSearchChar, sal_Int32 _nExpectedResultPos, sal_Int32 _nStartOffset)
        {
            sal_Int32 nPos = _suStr.lastIndexOf(_cuSearchChar, _nStartOffset);
            ASSERT_TRUE(nPos == _nExpectedResultPos) << "expected position is wrong";
        }
}; // class lastIndexOf

    TEST_F(lastIndexOf, lastIndexOf_test_oustring_offset_001)
    {
        // search for sun, start at the end, found (pos==0)
        rtl::OUString aStr = rtl::OUString::createFromAscii("sun java system");
        rtl::OUString aSearchStr = rtl::OUString::createFromAscii("sun");
        lastIndexOf_oustring_offset(aStr, aSearchStr, 0, aStr.getLength());
    }

    TEST_F(lastIndexOf, lastIndexOf_test_oustring_offset_002)
    {
        // search for sun, start at pos = 3, found (pos==0)
        rtl::OUString aStr = rtl::OUString::createFromAscii("sun java system");
        rtl::OUString aSearchStr = rtl::OUString::createFromAscii("sun");
        lastIndexOf_oustring_offset(aStr, aSearchStr, 0, 3);
    }

    TEST_F(lastIndexOf, lastIndexOf_test_oustring_offset_003)
    {
        // search for sun, start at pos = 2, found (pos==-1)
        rtl::OUString aStr = rtl::OUString::createFromAscii("sun java system");
        rtl::OUString aSearchStr = rtl::OUString::createFromAscii("sun");
        lastIndexOf_oustring_offset(aStr, aSearchStr, -1, 2);
    }

    TEST_F(lastIndexOf, lastIndexOf_test_oustring_offset_004)
    {
        // search for sun, start at the end, found (pos==0)
        rtl::OUString aStr = rtl::OUString::createFromAscii("sun java system");
        rtl::OUString aSearchStr = rtl::OUString::createFromAscii("sun");
        lastIndexOf_oustring_offset(aStr, aSearchStr, -1, -1);
    }

    TEST_F(lastIndexOf, lastIndexOf_test_oustring_001)
    {
        // search for sun, found (pos==0)
        rtl::OUString aStr = rtl::OUString::createFromAscii("sun java system");
        rtl::OUString aSearchStr = rtl::OUString::createFromAscii("sun");
        lastIndexOf_oustring(aStr, aSearchStr, 0);
    }

    TEST_F(lastIndexOf, lastIndexOf_test_oustring_002)
    {
        // search for sun, found (pos==4)
        rtl::OUString aStr = rtl::OUString::createFromAscii("the sun java system");
        rtl::OUString aSearchStr = rtl::OUString::createFromAscii("sun");
        lastIndexOf_oustring(aStr, aSearchStr, 4);
    }

    TEST_F(lastIndexOf, lastIndexOf_test_oustring_003)
    {
        // search for sun, found (pos==8)
        rtl::OUString aStr = rtl::OUString::createFromAscii("the sun sun java system");
        rtl::OUString aSearchStr = rtl::OUString::createFromAscii("sun");
        lastIndexOf_oustring(aStr, aSearchStr, 8);
    }

    TEST_F(lastIndexOf, lastIndexOf_test_oustring_004)
    {
        // search for sun, found (pos==8)
        rtl::OUString aStr = rtl::OUString::createFromAscii("the sun sun");
        rtl::OUString aSearchStr = rtl::OUString::createFromAscii("sun");
        lastIndexOf_oustring(aStr, aSearchStr, 8);
    }

    TEST_F(lastIndexOf, lastIndexOf_test_oustring_005)
    {
        // search for sun, found (pos==4)
        rtl::OUString aStr = rtl::OUString::createFromAscii("the sun su");
        rtl::OUString aSearchStr = rtl::OUString::createFromAscii("sun");
        lastIndexOf_oustring(aStr, aSearchStr, 4);
    }

    TEST_F(lastIndexOf, lastIndexOf_test_oustring_006)
    {
        // search for sun, found (pos==-1)
        rtl::OUString aStr = rtl::OUString::createFromAscii("the su su");
        rtl::OUString aSearchStr = rtl::OUString::createFromAscii("sun");
        lastIndexOf_oustring(aStr, aSearchStr, -1);
    }

    TEST_F(lastIndexOf, lastIndexOf_test_oustring_007)
    {
        // search for earth, not found (-1)
        rtl::OUString aStr = rtl::OUString::createFromAscii("the su su");
        rtl::OUString aSearchStr = rtl::OUString::createFromAscii("earth");
        lastIndexOf_oustring(aStr, aSearchStr, -1);
    }

    TEST_F(lastIndexOf, lastIndexOf_test_oustring_008)
    {
        // search for earth, not found (-1)
        rtl::OUString aStr = rtl::OUString();
        rtl::OUString aSearchStr = rtl::OUString::createFromAscii("earth");
        lastIndexOf_oustring(aStr, aSearchStr, -1);
    }

    TEST_F(lastIndexOf, lastIndexOf_test_oustring_009)
    {
        // search for earth, not found (-1)
        rtl::OUString aStr = rtl::OUString();
        rtl::OUString aSearchStr = rtl::OUString();
        lastIndexOf_oustring(aStr, aSearchStr, -1);

    }

    TEST_F(lastIndexOf, lastIndexOf_test_salunicode_001)
    {
        // search for 's', found (19)
        rtl::OUString aStr = rtl::OUString::createFromAscii("the sun sun java system");
        sal_Unicode suChar = L's';
        lastIndexOf_salunicode(aStr, suChar, 19);
    }

    TEST_F(lastIndexOf, lastIndexOf_test_salunicode_002)
    {
        // search for 'x', not found (-1)
        rtl::OUString aStr = rtl::OUString::createFromAscii("the sun sun java system");
        sal_Unicode suChar = L'x';
        lastIndexOf_salunicode(aStr, suChar, -1);
    }

    TEST_F(lastIndexOf, lastIndexOf_test_salunicode_offset_001)
    {
        // search for 's', start from pos last char, found (19)
        rtl::OUString aStr = rtl::OUString::createFromAscii("the sun sun java system");
        sal_Unicode cuChar = L's';
        lastIndexOf_salunicode_offset(aStr, cuChar, 19, aStr.getLength());
    }
    TEST_F(lastIndexOf, lastIndexOf_test_salunicode_offset_002)
    {
        // search for 's', start pos is last occur from search behind, found (17)
        rtl::OUString aStr = rtl::OUString::createFromAscii("the sun sun java system");
        sal_Unicode cuChar = L's';
        lastIndexOf_salunicode_offset(aStr, cuChar, 17, 19);
    }
    TEST_F(lastIndexOf, lastIndexOf_test_salunicode_offset_003)
    {
        // search for 't', start pos is 1, found (0)
        rtl::OUString aStr = rtl::OUString::createFromAscii("the sun sun java system");
        sal_Unicode cuChar = L't';
        lastIndexOf_salunicode_offset(aStr, cuChar, 0, 1);
    }

// -----------------------------------------------------------------------------
// - getToken (tests)
// -----------------------------------------------------------------------------
class getToken : public ::testing::Test
{
public:
}; // class getToken

    TEST_F(getToken, getToken_000)
    {
        rtl::OUString suTokenStr;

        sal_Int32 nIndex = 0;
        do
        {
            rtl::OUString suToken = suTokenStr.getToken( 0, ';', nIndex );
        }
        while ( nIndex >= 0 );
        printf("Index %d\n", nIndex);
        // should not GPF
    }

    TEST_F(getToken, getToken_001)
    {
        rtl::OUString suTokenStr = rtl::OUString::createFromAscii("a;b");

        sal_Int32 nIndex = 0;

        rtl::OUString suToken = suTokenStr.getToken( 0, ';', nIndex );
        ASSERT_TRUE(suToken.equals(rtl::OUString::createFromAscii("a")) == sal_True) << "Token should be a 'a'";

        /* rtl::OUString */ suToken = suTokenStr.getToken( 0, ';', nIndex );
        ASSERT_TRUE(suToken.equals(rtl::OUString::createFromAscii("b")) == sal_True) << "Token should be a 'b'";
        ASSERT_TRUE(nIndex == -1) << "index should be negative";
    }

    TEST_F(getToken, getToken_002)
    {
        rtl::OUString suTokenStr = rtl::OUString::createFromAscii("a;b.c");

        sal_Int32 nIndex = 0;

        rtl::OUString suToken = suTokenStr.getToken( 0, ';', nIndex );
        ASSERT_TRUE(suToken.equals(rtl::OUString::createFromAscii("a")) == sal_True) << "Token should be a 'a'";

        /* rtl::OUString */ suToken = suTokenStr.getToken( 0, '.', nIndex );
        ASSERT_TRUE(suToken.equals(rtl::OUString::createFromAscii("b")) == sal_True) << "Token should be a 'b'";

        /* rtl::OUString */ suToken = suTokenStr.getToken( 0, '.', nIndex );
        ASSERT_TRUE(suToken.equals(rtl::OUString::createFromAscii("c")) == sal_True) << "Token should be a 'c'";
        ASSERT_TRUE(nIndex == -1) << "index should be negative";
    }

    TEST_F(getToken, getToken_003)
    {
        rtl::OUString suTokenStr = rtl::OUString::createFromAscii("a;;b");

        sal_Int32 nIndex = 0;

        rtl::OUString suToken = suTokenStr.getToken( 0, ';', nIndex );
        ASSERT_TRUE(suToken.equals(rtl::OUString::createFromAscii("a")) == sal_True) << "Token should be a 'a'";

        /* rtl::OUString */ suToken = suTokenStr.getToken( 0, ';', nIndex );
        ASSERT_TRUE(suToken.getLength() == 0) << "Token should be empty";

        /* rtl::OUString */ suToken = suTokenStr.getToken( 0, ';', nIndex );
        ASSERT_TRUE(suToken.equals(rtl::OUString::createFromAscii("b")) == sal_True) << "Token should be a 'b'";
        ASSERT_TRUE(nIndex == -1) << "index should be negative";
    }

    TEST_F(getToken, getToken_004)
    {
        rtl::OUString suTokenStr = rtl::OUString::createFromAscii("longer.then.ever.");

        sal_Int32 nIndex = 0;

        rtl::OUString suToken = suTokenStr.getToken( 0, '.', nIndex );
        ASSERT_TRUE(suToken.equals(rtl::OUString::createFromAscii("longer")) == sal_True) << "Token should be 'longer'";

        /* rtl::OUString */ suToken = suTokenStr.getToken( 0, '.', nIndex );
        ASSERT_TRUE(suToken.equals(rtl::OUString::createFromAscii("then")) == sal_True) << "Token should be 'then'";

        /* rtl::OUString */ suToken = suTokenStr.getToken( 0, '.', nIndex );
        ASSERT_TRUE(suToken.equals(rtl::OUString::createFromAscii("ever")) == sal_True) << "Token should be 'ever'";

        /* rtl::OUString */ suToken = suTokenStr.getToken( 0, '.', nIndex );
        ASSERT_TRUE(suToken.getLength() == 0) << "Token should be empty";

        ASSERT_TRUE(nIndex == -1) << "index should be negative";
    }

    TEST_F(getToken, getToken_005) {
        rtl::OUString ab(RTL_CONSTASCII_USTRINGPARAM("ab"));
        sal_Int32 n = 0;
        ASSERT_TRUE(ab.getToken(0, '-', n) == ab) << "token should be 'ab'";
        ASSERT_TRUE(n == -1) << "n should be -1";
        ASSERT_TRUE(ab.getToken(0, '-', n).getLength() == 0) << "token should be empty";
    }

class convertToString: public ::testing::Test {
public:
};

TEST_F(convertToString, test) {
    static sal_Unicode const utf16[] = { 0x0041, 0x00E4, 0x0061 };
    rtl::OString s;
    ASSERT_TRUE(
        rtl::OUString(utf16, sizeof utf16 / sizeof utf16[0]).convertToString(
            &s, RTL_TEXTENCODING_UTF7,
            (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
             RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)));
    ASSERT_EQ(
        rtl::OString(RTL_CONSTASCII_STRINGPARAM("A+AOQ-a")), s);
}

// -----------------------------------------------------------------------------
// - string construction & interning (tests)
// -----------------------------------------------------------------------------
class construction : public ::testing::Test
{
public:
};

    TEST_F(construction, construct)
    {
#ifdef RTL_INLINE_STRINGS
        ::rtl::OUString aFoo( RTL_CONSTASCII_USTRINGPARAM("foo") );
        ASSERT_TRUE(aFoo[0] == 'f') << "string contents";
        ASSERT_TRUE(aFoo[1] == 'o') << "string contents";
        ASSERT_TRUE(aFoo[2] == 'o') << "string contents";
        ASSERT_TRUE(aFoo.getLength() == 3) << "string length";

        ::rtl::OUString aBaa( RTL_CONSTASCII_USTRINGPARAM("this is a very long string with a lot of long things inside it and it goes on and on and on forever etc.") );
        ASSERT_TRUE(aBaa.getLength() == 104) << "string length";
        // Dig at the internals ... FIXME: should we have the bit-flag defines public ?
        ASSERT_TRUE((aBaa.pData->refCount & 1<<30) != 0) << "string static flags";
#endif
    }

    TEST_F(construction, intern)
    {
        // The empty string is 'static' a special case ...
        rtl::OUString aEmpty = rtl::OUString().intern();
        rtl::OUString aEmpty2 = rtl::OUString::intern( RTL_CONSTASCII_USTRINGPARAM( "" ) );

        ::rtl::OUString aFoo( RTL_CONSTASCII_USTRINGPARAM("foo") );
        ::rtl::OUString aFooIntern = aFoo.intern();
        ASSERT_TRUE(aFooIntern.equalsAscii("foo")) << "string contents";
        ASSERT_TRUE(aFooIntern.getLength() == 3) << "string length";
        // We have to dup due to no atomic 'intern' bit-set operation
        ASSERT_TRUE(aFoo.pData != aFooIntern.pData) << "intern dups";

        // Test interning lots of things
        int i;
        static const int nSequence = 4096;
        rtl::OUString *pStrs;
        sal_uIntPtr   *pValues;

        pStrs = new rtl::OUString[nSequence];
        pValues = new sal_uIntPtr[nSequence];
        for (i = 0; i < nSequence; i++)
        {
            pStrs[i] = rtl::OUString::valueOf( sqrt( static_cast<double>(i) ) ).intern();
            pValues[i] = reinterpret_cast<sal_uIntPtr>( pStrs[i].pData );
        }
        for (i = 0; i < nSequence; i++)
        {
            rtl::OUString aNew = rtl::OUString::valueOf( sqrt( static_cast<double>(i) ) ).intern();
            ASSERT_TRUE(aNew.pData == pStrs[i].pData) << "double intern failed";
        }

        // Free strings to check for leaks
        for (i = 0; i < nSequence; i++)
        {
            // Overwrite - hopefully this re-uses the memory
            pStrs[i] = rtl::OUString();
            pStrs[i] = rtl::OUString::valueOf( sqrt( static_cast<double>(i) ) );
        }

        for (i = 0; i < nSequence; i++)
        {
            rtl::OUString aIntern;
            sal_uIntPtr nValue;
            aIntern = rtl::OUString::valueOf( sqrt( static_cast<double>(i) ) ).intern();

            nValue = reinterpret_cast<sal_uIntPtr>( aIntern.pData );
            // This may not be 100% reliable: memory may
            // have been re-used, but it's worth checking.
            ASSERT_TRUE(nValue != pValues[i]) << "intern leaking";
        }
        delete [] pValues;
        delete [] pStrs;
    }

class indexOfAscii: public ::testing::Test {
public:
};

TEST_F(indexOfAscii, test) {
    ASSERT_EQ(
        sal_Int32(-1),
        rtl::OUString().indexOfAsciiL(RTL_CONSTASCII_STRINGPARAM("")));
    ASSERT_EQ(
        sal_Int32(-1),
        rtl::OUString().lastIndexOfAsciiL(RTL_CONSTASCII_STRINGPARAM("")));
    ASSERT_EQ(
        sal_Int32(0),
        rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("foo")).indexOfAsciiL(
            RTL_CONSTASCII_STRINGPARAM("foo")));
    ASSERT_EQ(
        sal_Int32(0),
        rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("foo")).lastIndexOfAsciiL(
            RTL_CONSTASCII_STRINGPARAM("foo")));
    ASSERT_EQ(
        sal_Int32(2),
        rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("fofoobar")).indexOfAsciiL(
            RTL_CONSTASCII_STRINGPARAM("foo")));
    ASSERT_EQ(
        sal_Int32(3),
        rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("foofoofob")).
        lastIndexOfAsciiL(RTL_CONSTASCII_STRINGPARAM("foo")));
    ASSERT_EQ(
        sal_Int32(3),
        rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("foofoobar")).indexOfAsciiL(
            RTL_CONSTASCII_STRINGPARAM("foo"), 1));
}

class endsWith: public ::testing::Test {
public:
};

TEST_F(endsWith, test) {
    ASSERT_EQ(
        true,
        rtl::OUString().endsWithAsciiL(RTL_CONSTASCII_STRINGPARAM("")));
    ASSERT_EQ(
        false,
        rtl::OUString().endsWithAsciiL(RTL_CONSTASCII_STRINGPARAM("foo")));
    ASSERT_EQ(
        true,
        rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("bar")).endsWithAsciiL(
            RTL_CONSTASCII_STRINGPARAM("bar")));
    ASSERT_EQ(
        true,
        rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("foobar")).endsWithAsciiL(
            RTL_CONSTASCII_STRINGPARAM("bar")));
    ASSERT_EQ(
        false,
        rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("FOOBAR")).endsWithAsciiL(
            RTL_CONSTASCII_STRINGPARAM("bar")));
}

class createFromCodePoints: public ::testing::Test {
public:
};

TEST_F(createFromCodePoints, test) {
    ASSERT_EQ(
        sal_Int32(0),
        rtl::OUString(static_cast< sal_uInt32 const * >(NULL), 0).getLength());
    static sal_uInt32 const cp[] = { 0, 0xD800, 0xFFFF, 0x10000, 0x10FFFF };
    rtl::OUString s(cp, sizeof cp / sizeof (sal_uInt32));
    ASSERT_EQ(sal_Int32(7), s.getLength());
    ASSERT_EQ(sal_Unicode(0), s[0]);
    ASSERT_EQ(sal_Unicode(0xD800), s[1]);
    ASSERT_EQ(sal_Unicode(0xFFFF), s[2]);
    ASSERT_EQ(sal_Unicode(0xD800), s[3]);
    ASSERT_EQ(sal_Unicode(0xDC00), s[4]);
    ASSERT_EQ(sal_Unicode(0xDBFF), s[5]);
    ASSERT_EQ(sal_Unicode(0xDFFF), s[6]);
}

class iterateCodePoints: public ::testing::Test {
public:
};

TEST_F(iterateCodePoints, testNotWellFormed) {
    static sal_Unicode const utf16[] =
        { 0xD800, 0xDC00, 0x0041, 0xDBFF, 0xDFFF, 0xDDEF, 0xD9AB };
    rtl::OUString s(utf16, sizeof utf16 / sizeof (sal_Unicode));
    sal_Int32 i = 0;
    ASSERT_EQ(sal_uInt32(0x10000), s.iterateCodePoints(&i));
    ASSERT_EQ(sal_Int32(2), i);
    ASSERT_EQ(sal_uInt32(0x0041), s.iterateCodePoints(&i));
    ASSERT_EQ(sal_Int32(3), i);
    ASSERT_EQ(sal_uInt32(0x10FFFF), s.iterateCodePoints(&i));
    ASSERT_EQ(sal_Int32(5), i);
    ASSERT_EQ(sal_uInt32(0xDDEF), s.iterateCodePoints(&i));
    ASSERT_EQ(sal_Int32(6), i);
    ASSERT_EQ(sal_uInt32(0xD9AB), s.iterateCodePoints(&i));
    ASSERT_EQ(sal_Int32(7), i);
    ASSERT_EQ(sal_uInt32(0xD9AB), s.iterateCodePoints(&i, -1));
    ASSERT_EQ(sal_Int32(6), i);
    ASSERT_EQ(sal_uInt32(0xDDEF), s.iterateCodePoints(&i, -1));
    ASSERT_EQ(sal_Int32(5), i);
    ASSERT_EQ(sal_uInt32(0x10FFFF), s.iterateCodePoints(&i, -1));
    ASSERT_EQ(sal_Int32(3), i);
    ASSERT_EQ(sal_uInt32(0x0041), s.iterateCodePoints(&i, -1));
    ASSERT_EQ(sal_Int32(2), i);
    ASSERT_EQ(sal_uInt32(0x10000), s.iterateCodePoints(&i, -1));
    ASSERT_EQ(sal_Int32(0), i);
    i = 1;
    ASSERT_EQ(sal_uInt32(0xDC00), s.iterateCodePoints(&i, 2));
    ASSERT_EQ(sal_Int32(3), i);
    i = 4;
    ASSERT_EQ(sal_uInt32(0x10000), s.iterateCodePoints(&i, -3));
    ASSERT_EQ(sal_Int32(0), i);
}

class convertFromString: public ::testing::Test {
public:
};

TEST_F(convertFromString, test) {
    rtl::OUString t;
    ASSERT_TRUE(
        !rtl_convertStringToUString(
            &t.pData, RTL_CONSTASCII_STRINGPARAM("\x80"), RTL_TEXTENCODING_UTF8,
            (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR |
             RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR |
             RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)));
    ASSERT_TRUE(
        !rtl_convertStringToUString(
            &t.pData, RTL_CONSTASCII_STRINGPARAM("\xC0"), RTL_TEXTENCODING_UTF8,
            (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR |
             RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR |
             RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)));
    ASSERT_TRUE(
        !rtl_convertStringToUString(
            &t.pData, RTL_CONSTASCII_STRINGPARAM("\xFF"), RTL_TEXTENCODING_UTF8,
            (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR |
             RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR |
             RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)));
    ASSERT_TRUE(
        rtl_convertStringToUString(
            &t.pData, RTL_CONSTASCII_STRINGPARAM("abc"), RTL_TEXTENCODING_UTF8,
            (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR |
             RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR |
             RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)));
    ASSERT_TRUE(t.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("abc")));
}


} // namespace rtl_OUString

int main(int argc, char **argv)
{
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
