/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   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 .
 */

// autogenerated file with codegen.pl

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

#include <algorithm>
#include <limits>

#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/plugin/TestPlugIn.h>

#include <stringhelper.hxx>
#include <valueequal.hxx>

namespace rtl_OUString
{

namespace {

// Avoid -fsanitize=undefined warning e.g. "runtime error: value 1e+99 is
// outside the range of representable values of type 'float'":
float doubleToFloat(double x) {
    return
        x < -std::numeric_limits<float>::max()
        ? -std::numeric_limits<float>::infinity()
        : x > std::numeric_limits<float>::max()
        ? std::numeric_limits<float>::infinity()
        : static_cast<float>(x);
}

}

class number : public CppUnit::TestFixture
{
    void number_float_test_impl(float _nValue)
        {
            OUString suValue(OUString::number(_nValue));
            OString sValue;
            sValue <<= suValue;
            printf("nFloat := %.9f  sValue := %s\n", _nValue, sValue.getStr());

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

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

    void number_float_test(float _nValue)
        {
            number_float_test_impl(_nValue);

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

public:
    // insert your test code here.
    void number_float_test_001()
    {
        // this is demonstration code
        // CPPUNIT_ASSERT_MESSAGE("a message", 1 == 1);
        float nValue = 3.0f;
        number_float_test(nValue);
    }

    void number_float_test_002()
    {
        float nValue = 3.5f;
        number_float_test(nValue);
    }

    void number_float_test_003()
    {
        float nValue = 3.0625f;
        number_float_test(nValue);
    }

    void number_float_test_004()
    {
        float nValue = 3.502525f;
        number_float_test(nValue);
    }

    void number_float_test_005()
    {
        float nValue = 3.141592f;
        number_float_test(nValue);
    }

    void number_float_test_006()
    {
        float nValue = 3.5025255f;
        number_float_test(nValue);
    }

    void number_float_test_007()
    {
        float nValue = 3.0039062f;
        number_float_test(nValue);
    }

private:

    void number_double_test_impl(double _nValue)
        {
            OUString suValue;
            suValue = OUString::number( _nValue );
            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);
            CPPUNIT_ASSERT_MESSAGE("Values are not equal.", bEqualResult);
        }

    void number_double_test(double _nValue)
        {
            number_double_test_impl(_nValue);

            // test also the negative part.
            double nNegativeValue = -_nValue;
            number_double_test_impl(nNegativeValue);
        }
public:

    // number double
    void number_double_test_001()
        {
            double nValue = 3.0;
            number_double_test(nValue);
        }
    void number_double_test_002()
        {
            double nValue = 3.5;
            number_double_test(nValue);
        }
    void number_double_test_003()
        {
            double nValue = 3.0625;
            number_double_test(nValue);
        }
    void number_double_test_004()
        {
            double nValue = 3.1415926535;
            number_double_test(nValue);
        }
    void number_double_test_005()
        {
            double nValue = 3.141592653589793;
            number_double_test(nValue);
        }
    void number_double_test_006()
        {
            double nValue = 3.1415926535897932;
            number_double_test(nValue);
        }
    void number_double_test_007()
        {
            double nValue = 3.14159265358979323;
            number_double_test(nValue);
        }
    void number_double_test_008()
        {
            double nValue = 3.141592653589793238462643;
            number_double_test(nValue);
        }

    // Change the following lines only, if you add, remove or rename
    // member functions of the current class,
    // because these macros are need by auto register mechanism.

    CPPUNIT_TEST_SUITE(number);
    CPPUNIT_TEST(number_float_test_001);
    CPPUNIT_TEST(number_float_test_002);
    CPPUNIT_TEST(number_float_test_003);
    CPPUNIT_TEST(number_float_test_004);
    CPPUNIT_TEST(number_float_test_005);
    CPPUNIT_TEST(number_float_test_006);
    CPPUNIT_TEST(number_float_test_007);

    CPPUNIT_TEST(number_double_test_001);
    CPPUNIT_TEST(number_double_test_002);
    CPPUNIT_TEST(number_double_test_003);
    CPPUNIT_TEST(number_double_test_004);
    CPPUNIT_TEST(number_double_test_005);
    CPPUNIT_TEST(number_double_test_006);
    CPPUNIT_TEST(number_double_test_007);
    CPPUNIT_TEST(number_double_test_008);
    CPPUNIT_TEST_SUITE_END();
}; // class number

    class toInt: public CppUnit::TestFixture {
    public:
        void test() {
            CPPUNIT_ASSERT_EQUAL(
                static_cast< sal_Int32 >(-0x76543210),
                (OUString("-76543210").
                 toInt32(16)));
            // @return 0 if this string represents no number or one of too large magnitude
            CPPUNIT_ASSERT_EQUAL(
                static_cast< sal_Int32 >(0),
                (OUString("+FEDCBA98").
                 toInt32(16)));
            CPPUNIT_ASSERT_EQUAL(
                static_cast< sal_Int64 >(-SAL_CONST_INT64(0x76543210FEDCBA98)),
                (OUString(
                    "-76543210FEDCBA98").
                 toInt64(16)));
            // @return 0 if this string represents no number or one of too large magnitude
            CPPUNIT_ASSERT_EQUAL(
                static_cast< sal_Int64 >(SAL_CONST_INT64(0)),
                (OUString(
                    "+FEDCBA9876543210").
                 toInt64(16)));
        }

        CPPUNIT_TEST_SUITE(toInt);
        CPPUNIT_TEST(test);
        CPPUNIT_TEST_SUITE_END();
    };

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

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

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

                // test also the negative part.
                OString sNegativValue("-");
                sNegativValue += _sValue;
                toDouble_test_impl(sNegativValue);
            }

        // insert your test code here.
        void toDouble_selftest()
            {
                printf("Start selftest:\n");
                CPPUNIT_ASSERT (!is_double_equal(1.0, 1.01));
                CPPUNIT_ASSERT (!is_double_equal(1.0, 1.001));
                CPPUNIT_ASSERT (!is_double_equal(1.0, 1.0001));
                CPPUNIT_ASSERT (!is_double_equal(1.0, 1.00001));
                CPPUNIT_ASSERT (!is_double_equal(1.0, 1.000001));
                CPPUNIT_ASSERT (!is_double_equal(1.0, 1.0000001));
                CPPUNIT_ASSERT (!is_double_equal(1.0, 1.00000001));
                CPPUNIT_ASSERT (!is_double_equal(1.0, 1.000000001));
                CPPUNIT_ASSERT (!is_double_equal(1.0, 1.0000000001));
                CPPUNIT_ASSERT (!is_double_equal(1.0, 1.00000000001));
                CPPUNIT_ASSERT (!is_double_equal(1.0, 1.000000000001));
                CPPUNIT_ASSERT (!is_double_equal(1.0, 1.0000000000001));
                // we check til 15 values after comma
                CPPUNIT_ASSERT (is_double_equal(1.0, 1.00000000000001));
                CPPUNIT_ASSERT (is_double_equal(1.0, 1.000000000000001));
                CPPUNIT_ASSERT (is_double_equal(1.0, 1.0000000000000001));
                printf("Selftest done.\n");
            }

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

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

        // Change the following lines only, if you add, remove or rename
        // member functions of the current class,
        // because these macros are need by auto register mechanism.

        CPPUNIT_TEST_SUITE(toDouble);
        CPPUNIT_TEST(toDouble_selftest);

        CPPUNIT_TEST(toDouble_test_3);
        CPPUNIT_TEST(toDouble_test_3_5);
        CPPUNIT_TEST(toDouble_test_3_0625);
        CPPUNIT_TEST(toDouble_test_pi);
        CPPUNIT_TEST(toDouble_test_1);
        CPPUNIT_TEST(toDouble_test_10);
        CPPUNIT_TEST(toDouble_test_100);
        CPPUNIT_TEST(toDouble_test_1000);
        CPPUNIT_TEST(toDouble_test_10000);
        CPPUNIT_TEST(toDouble_test_1e99);
        CPPUNIT_TEST(toDouble_test_1e_n99);
        CPPUNIT_TEST(toDouble_test_1e308);
        CPPUNIT_TEST_SUITE_END();
    }; // class toDouble

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

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

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

                // test also the negative part.
                OString sNegativValue("-");
                sNegativValue += _sValue;
                toFloat_test_impl(sNegativValue);
            }

        // insert your test code here.
        void toFloat_selftest()
            {
                printf("Start selftest:\n");
                CPPUNIT_ASSERT (!is_float_equal(1.0f, 1.01f));
                CPPUNIT_ASSERT (!is_float_equal(1.0f, 1.001f));
                CPPUNIT_ASSERT (!is_float_equal(1.0f, 1.0001f));
                CPPUNIT_ASSERT (!is_float_equal(1.0f, 1.00001f));
                CPPUNIT_ASSERT (!is_float_equal(1.0f, 1.000002f));
                CPPUNIT_ASSERT (is_float_equal(1.0f, 1.0000001f));
                CPPUNIT_ASSERT (is_float_equal(1.0f, 1.00000001f));
                CPPUNIT_ASSERT (is_float_equal(1.0f, 1.000000001f));

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

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

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

        // Change the following lines only, if you add, remove or rename
        // member functions of the current class,
        // because these macros are need by auto register mechanism.

        CPPUNIT_TEST_SUITE(toFloat);
        CPPUNIT_TEST(toFloat_selftest);

        CPPUNIT_TEST(toFloat_test_3);
        CPPUNIT_TEST(toFloat_test_3_5);
        CPPUNIT_TEST(toFloat_test_3_0625);
        CPPUNIT_TEST(toFloat_test_3_0625_e);
        CPPUNIT_TEST(toFloat_test_pi);
        CPPUNIT_TEST(toFloat_test_1);
        CPPUNIT_TEST(toFloat_test_10);
        CPPUNIT_TEST(toFloat_test_100);
        CPPUNIT_TEST(toFloat_test_1000);
        CPPUNIT_TEST(toFloat_test_10000);
        CPPUNIT_TEST(toFloat_test_mix);
        CPPUNIT_TEST(toFloat_test_1e99);
        CPPUNIT_TEST(toFloat_test_1e_n99);
        CPPUNIT_TEST(toFloat_test_1e308);
        CPPUNIT_TEST_SUITE_END();
    }; // class toFloat

// - lastIndexOf (tests)
class lastIndexOf : public CppUnit::TestFixture
{

public:
    void lastIndexOf_oustring(OUString const& _suStr, OUString const& _suSearchStr, sal_Int32 _nExpectedResultPos)
        {
            // Algorithm
            // search the string _suSearchStr (OUString) in the string _suStr.
            // check if the _nExpectedResultPos occurs.

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

    void lastIndexOf_salunicode(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);
            CPPUNIT_ASSERT_EQUAL_MESSAGE("expected position is wrong", _nExpectedResultPos, nPos);
        }

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

    void lastIndexOf_salunicode_offset(OUString const& _suStr, sal_Unicode _cuSearchChar, sal_Int32 _nExpectedResultPos, sal_Int32 _nStartOffset)
        {
            sal_Int32 nPos = _suStr.lastIndexOf(_cuSearchChar, _nStartOffset);
            CPPUNIT_ASSERT_EQUAL_MESSAGE("expected position is wrong", _nExpectedResultPos, nPos);
        }

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

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

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

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

    void lastIndexOf_test_oustring_001()
        {
            // search for sun, found (pos==0)
            OUString aStr("sun java system");
            OUString aSearchStr("sun");
            lastIndexOf_oustring(aStr, aSearchStr, 0);
        }

    void lastIndexOf_test_oustring_002()
        {
            // search for sun, found (pos==4)
            OUString aStr("the sun java system");
            OUString aSearchStr("sun");
            lastIndexOf_oustring(aStr, aSearchStr, 4);
        }

    void lastIndexOf_test_oustring_003()
        {
            // search for sun, found (pos==8)
            OUString aStr("the sun sun java system");
            OUString aSearchStr("sun");
            lastIndexOf_oustring(aStr, aSearchStr, 8);
        }

    void lastIndexOf_test_oustring_004()
        {
            // search for sun, found (pos==8)
            OUString aStr("the sun sun");
            OUString aSearchStr("sun");
            lastIndexOf_oustring(aStr, aSearchStr, 8);
        }

    void lastIndexOf_test_oustring_005()
        {
            // search for sun, found (pos==4)
            OUString aStr("the sun su");
            OUString aSearchStr("sun");
            lastIndexOf_oustring(aStr, aSearchStr, 4);
        }

    void lastIndexOf_test_oustring_006()
        {
            // search for sun, found (pos==-1)
            OUString aStr("the su su");
            OUString aSearchStr("sun");
            lastIndexOf_oustring(aStr, aSearchStr, -1);
        }

    void lastIndexOf_test_oustring_007()
        {
            // search for earth, not found (-1)
            OUString aStr("the su su");
            OUString aSearchStr("earth");
            lastIndexOf_oustring(aStr, aSearchStr, -1);
        }

    void lastIndexOf_test_oustring_008()
        {
            // search for earth, not found (-1)
            OUString aStr = OUString();
            OUString aSearchStr("earth");
            lastIndexOf_oustring(aStr, aSearchStr, -1);
        }

    void lastIndexOf_test_oustring_009()
        {
            // search for earth, not found (-1)
            OUString aStr = OUString();
            OUString aSearchStr = OUString();
            lastIndexOf_oustring(aStr, aSearchStr, -1);

        }

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

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

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

    // Change the following lines only, if you add, remove or rename
    // member functions of the current class,
    // because these macros are need by auto register mechanism.

    CPPUNIT_TEST_SUITE(lastIndexOf);
    CPPUNIT_TEST(lastIndexOf_test_oustring_001);
    CPPUNIT_TEST(lastIndexOf_test_oustring_002);
    CPPUNIT_TEST(lastIndexOf_test_oustring_003);
    CPPUNIT_TEST(lastIndexOf_test_oustring_004);
    CPPUNIT_TEST(lastIndexOf_test_oustring_005);
    CPPUNIT_TEST(lastIndexOf_test_oustring_006);
    CPPUNIT_TEST(lastIndexOf_test_oustring_007);
    CPPUNIT_TEST(lastIndexOf_test_oustring_008);
    CPPUNIT_TEST(lastIndexOf_test_oustring_009);

    CPPUNIT_TEST(lastIndexOf_test_oustring_offset_001);
    CPPUNIT_TEST(lastIndexOf_test_oustring_offset_002);
    CPPUNIT_TEST(lastIndexOf_test_oustring_offset_003);
    CPPUNIT_TEST(lastIndexOf_test_oustring_offset_004);

    CPPUNIT_TEST(lastIndexOf_test_salunicode_001);
    CPPUNIT_TEST(lastIndexOf_test_salunicode_002);

    CPPUNIT_TEST(lastIndexOf_test_salunicode_offset_001);
    CPPUNIT_TEST(lastIndexOf_test_salunicode_offset_002);
    CPPUNIT_TEST(lastIndexOf_test_salunicode_offset_003);

    CPPUNIT_TEST_SUITE_END();
}; // class lastIndexOf

// - getToken (tests)
class getToken : public CppUnit::TestFixture
{

public:
    void getToken_000()
        {
            OUString suTokenStr;

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

    void getToken_001()
        {
            OUString suTokenStr("a;b");

            sal_Int32 nIndex = 0;

            OUString suToken = suTokenStr.getToken( 0, ';', nIndex );
            CPPUNIT_ASSERT_EQUAL_MESSAGE( "Token should be a 'a'", OUString("a"), suToken);

            /* OUString */ suToken = suTokenStr.getToken( 0, ';', nIndex );
            CPPUNIT_ASSERT_EQUAL_MESSAGE( "Token should be a 'b'", OUString("b"), suToken);
            CPPUNIT_ASSERT_EQUAL_MESSAGE("index should be negative", static_cast<sal_Int32>(-1), nIndex);
        }

    void getToken_002()
        {
            OUString suTokenStr("a;b.c");

            sal_Int32 nIndex = 0;

            OUString suToken = suTokenStr.getToken( 0, ';', nIndex );
            CPPUNIT_ASSERT_EQUAL_MESSAGE( "Token should be a 'a'", OUString("a"), suToken );

            /* OUString */ suToken = suTokenStr.getToken( 0, '.', nIndex );
            CPPUNIT_ASSERT_EQUAL_MESSAGE( "Token should be a 'b'", OUString("b"), suToken );

            /* OUString */ suToken = suTokenStr.getToken( 0, '.', nIndex );
            CPPUNIT_ASSERT_EQUAL_MESSAGE( "Token should be a 'c'", OUString("c"), suToken );
            CPPUNIT_ASSERT_EQUAL_MESSAGE("index should be negative", static_cast<sal_Int32>(-1), nIndex);
        }

    void getToken_003()
        {
            OUString suTokenStr("a;;b");

            sal_Int32 nIndex = 0;

            OUString suToken = suTokenStr.getToken( 0, ';', nIndex );
            CPPUNIT_ASSERT_EQUAL_MESSAGE( "Token should be a 'a'", OUString("a"), suToken );

            /* OUString */ suToken = suTokenStr.getToken( 0, ';', nIndex );
            CPPUNIT_ASSERT_MESSAGE("Token should be empty", suToken.isEmpty());

            /* OUString */ suToken = suTokenStr.getToken( 0, ';', nIndex );
            CPPUNIT_ASSERT_EQUAL_MESSAGE( "Token should be a 'b'", OUString("b"), suToken );
            CPPUNIT_ASSERT_EQUAL_MESSAGE("index should be negative", static_cast<sal_Int32>(-1), nIndex);
        }

    void getToken_004()
        {
            OUString suTokenStr("longer.then.ever.");

            sal_Int32 nIndex = 0;

            OUString suToken = suTokenStr.getToken( 0, '.', nIndex );
            CPPUNIT_ASSERT_EQUAL_MESSAGE( "Token should be 'longer'", OUString("longer"), suToken );

            /* OUString */ suToken = suTokenStr.getToken( 0, '.', nIndex );
            CPPUNIT_ASSERT_EQUAL_MESSAGE( "Token should be 'then'", OUString("then"), suToken );

            /* OUString */ suToken = suTokenStr.getToken( 0, '.', nIndex );
            CPPUNIT_ASSERT_EQUAL_MESSAGE( "Token should be 'ever'", OUString("ever"), suToken );

            /* OUString */ suToken = suTokenStr.getToken( 0, '.', nIndex );
            CPPUNIT_ASSERT_MESSAGE("Token should be empty", suToken.isEmpty());

            CPPUNIT_ASSERT_EQUAL_MESSAGE("index should be negative", static_cast<sal_Int32>(-1), nIndex);
        }

    void getToken_005() {
        OUString ab("ab");
        sal_Int32 n = 0;
        CPPUNIT_ASSERT_EQUAL_MESSAGE(
            "token should be 'ab'", ab, ab.getToken(0, '-', n));
        CPPUNIT_ASSERT_EQUAL_MESSAGE("n should be -1", static_cast<sal_Int32>(-1), n);
        CPPUNIT_ASSERT_MESSAGE(
            "token should be empty", ab.getToken(0, '-', n).isEmpty());
    }

    CPPUNIT_TEST_SUITE(getToken);
    CPPUNIT_TEST(getToken_000);
    CPPUNIT_TEST(getToken_001);
    CPPUNIT_TEST(getToken_002);
    CPPUNIT_TEST(getToken_003);
    CPPUNIT_TEST(getToken_004);
    CPPUNIT_TEST(getToken_005);
    CPPUNIT_TEST_SUITE_END();
}; // class getToken

class convertToString: public CppUnit::TestFixture {
public:
    void test();

    CPPUNIT_TEST_SUITE(convertToString);
    CPPUNIT_TEST(test);
    CPPUNIT_TEST_SUITE_END();
};

void convertToString::test() {
    static sal_Unicode const utf16[] = { 0x0041, 0x00E4, 0x0061 };
    OString s;
    CPPUNIT_ASSERT(
        OUString(utf16, SAL_N_ELEMENTS(utf16)).convertToString(
            &s, RTL_TEXTENCODING_UTF7,
            (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
             RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)));
    CPPUNIT_ASSERT_EQUAL(
        OString(RTL_CONSTASCII_STRINGPARAM("A+AOQ-a")), s);
}

// - string construction & interning (tests)

class construction : public CppUnit::TestFixture
{
public:
    void construct()
    {
#ifdef RTL_INLINE_STRINGS
        OUString aFoo( "foo" );
        CPPUNIT_ASSERT_MESSAGE("string contents", aFoo[0] == 'f');
        CPPUNIT_ASSERT_MESSAGE("string contents", aFoo[1] == 'o');
        CPPUNIT_ASSERT_MESSAGE("string contents", aFoo[2] == 'o');
        CPPUNIT_ASSERT_MESSAGE("string length", aFoo.getLength() == 3);

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

    void intern()
    {
        // The empty string is 'static' a special case ...
        OUString().intern();
        OUString::intern( "",strlen(""),RTL_TEXTENCODING_ASCII_US );

        OUString aFoo( "foo" );
        OUString aFooIntern = aFoo.intern();
        CPPUNIT_ASSERT_EQUAL_MESSAGE( "string contents", OUString("foo"), aFooIntern);
        CPPUNIT_ASSERT_EQUAL_MESSAGE("string length", static_cast<sal_Int32>(3), aFooIntern.getLength());
        // We have to dup due to no atomic 'intern' bit-set operation
        CPPUNIT_ASSERT_MESSAGE("intern dups", aFoo.pData != aFooIntern.pData);

        // Test interning lots of things
        int i;
        static const int nSequence = 4096;
        std::unique_ptr<OUString[]> pStrs(new OUString[nSequence]);
        for (i = 0; i < nSequence; i++)
        {
            pStrs[i] = OUString::number( sqrt( static_cast<double>(i) ) ).intern();
        }
        for (i = 0; i < nSequence; i++)
        {
            OUString aNew = OUString::number( sqrt( static_cast<double>(i) ) ).intern();
            CPPUNIT_ASSERT_EQUAL_MESSAGE("double intern failed",
                                   pStrs[i].pData, aNew.pData);
        }
    }

    CPPUNIT_TEST_SUITE(construction);
    CPPUNIT_TEST(construct);
    CPPUNIT_TEST(intern);
    CPPUNIT_TEST_SUITE_END();
};

class indexOfAscii: public CppUnit::TestFixture {
public:
    void test();

    CPPUNIT_TEST_SUITE(indexOfAscii);
    CPPUNIT_TEST(test);
    CPPUNIT_TEST_SUITE_END();
};

void indexOfAscii::test() {
    CPPUNIT_ASSERT_EQUAL(sal_Int32(-1), OUString().indexOf(""));
    CPPUNIT_ASSERT_EQUAL(sal_Int32(-1), OUString().lastIndexOf(""));
    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), OUString("foo").indexOf("foo"));
    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), OUString("foo").lastIndexOf("foo"));
    CPPUNIT_ASSERT_EQUAL(
        sal_Int32(2), OUString("fofoobar").indexOf("foo"));
    CPPUNIT_ASSERT_EQUAL(
        sal_Int32(3), OUString("foofoofob").lastIndexOf("foo"));
    CPPUNIT_ASSERT_EQUAL(
        sal_Int32(3), OUString("foofoobar").indexOf("foo", 1));
}

class endsWith: public CppUnit::TestFixture {
public:
    void test();

    CPPUNIT_TEST_SUITE(endsWith);
    CPPUNIT_TEST(test);
    CPPUNIT_TEST_SUITE_END();
};

void endsWith::test() {
    CPPUNIT_ASSERT_EQUAL(true, OUString().endsWith(""));
    CPPUNIT_ASSERT_EQUAL(false, OUString().endsWith("foo"));
    CPPUNIT_ASSERT_EQUAL(true, OUString("bar").endsWith("bar"));
    CPPUNIT_ASSERT_EQUAL(true, OUString("foobar").endsWith("bar"));
    CPPUNIT_ASSERT_EQUAL(false, OUString("FOOBAR").endsWith("bar"));
}

class isEmpty: public CppUnit::TestFixture {
public:
    void test();

    CPPUNIT_TEST_SUITE(isEmpty);
    CPPUNIT_TEST(test);
    CPPUNIT_TEST_SUITE_END();
};

void isEmpty::test() {
    OUString aString;
    CPPUNIT_ASSERT_EQUAL_MESSAGE( "Newly constructed string should be empty", true, aString.isEmpty() );

    aString = "Not empty any more";
    CPPUNIT_ASSERT_EQUAL_MESSAGE( "String should not be empty", false, aString.isEmpty() );

    aString.clear();
    CPPUNIT_ASSERT_EQUAL_MESSAGE( "aString.clear(), so should now be empty", true, aString.isEmpty() );
}


class createFromCodePoints: public CppUnit::TestFixture {
public:
    void test();

    CPPUNIT_TEST_SUITE(createFromCodePoints);
    CPPUNIT_TEST(test);
    CPPUNIT_TEST_SUITE_END();
};

void createFromCodePoints::test() {
    CPPUNIT_ASSERT_EQUAL(
        sal_Int32(0),
        OUString(static_cast< sal_uInt32 const * >(nullptr), 0).getLength());
    static sal_uInt32 const cp[] = { 0, 0xD800, 0xFFFF, 0x10000, 0x10FFFF };
    OUString s(cp, SAL_N_ELEMENTS(cp));
    CPPUNIT_ASSERT_EQUAL(sal_Int32(7), s.getLength());
    CPPUNIT_ASSERT_EQUAL(u'\0', s[0]);
    CPPUNIT_ASSERT_EQUAL(u'\xD800', s[1]);
    CPPUNIT_ASSERT_EQUAL(u'\xFFFF', s[2]);
    CPPUNIT_ASSERT_EQUAL(u'\xD800', s[3]);
    CPPUNIT_ASSERT_EQUAL(u'\xDC00', s[4]);
    CPPUNIT_ASSERT_EQUAL(u'\xDBFF', s[5]);
    CPPUNIT_ASSERT_EQUAL(u'\xDFFF', s[6]);
}

class iterateCodePoints: public CppUnit::TestFixture {
public:
    void testNotWellFormed();

    CPPUNIT_TEST_SUITE(iterateCodePoints);
    CPPUNIT_TEST(testNotWellFormed);
    CPPUNIT_TEST_SUITE_END();
};

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

class convertFromString: public CppUnit::TestFixture {
public:
    void test();

    CPPUNIT_TEST_SUITE(convertFromString);
    CPPUNIT_TEST(test);
    CPPUNIT_TEST_SUITE_END();
};

void convertFromString::test() {
    OUString t;
    CPPUNIT_ASSERT(
        !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)));
    CPPUNIT_ASSERT(
        !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)));
    CPPUNIT_ASSERT(
        !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)));
    CPPUNIT_ASSERT(
        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)));
    CPPUNIT_ASSERT_EQUAL( OUString("abc"), t );
}

CPPUNIT_TEST_SUITE_REGISTRATION(rtl_OUString::number);
CPPUNIT_TEST_SUITE_REGISTRATION(rtl_OUString::toInt);
CPPUNIT_TEST_SUITE_REGISTRATION(rtl_OUString::toDouble);
CPPUNIT_TEST_SUITE_REGISTRATION(rtl_OUString::toFloat);
CPPUNIT_TEST_SUITE_REGISTRATION(rtl_OUString::lastIndexOf);
CPPUNIT_TEST_SUITE_REGISTRATION(rtl_OUString::getToken);
CPPUNIT_TEST_SUITE_REGISTRATION(rtl_OUString::convertToString);
CPPUNIT_TEST_SUITE_REGISTRATION(rtl_OUString::construction);
CPPUNIT_TEST_SUITE_REGISTRATION(rtl_OUString::indexOfAscii);
CPPUNIT_TEST_SUITE_REGISTRATION(rtl_OUString::endsWith);
CPPUNIT_TEST_SUITE_REGISTRATION(rtl_OUString::isEmpty);
CPPUNIT_TEST_SUITE_REGISTRATION(rtl_OUString::createFromCodePoints);
CPPUNIT_TEST_SUITE_REGISTRATION(rtl_OUString::iterateCodePoints);
CPPUNIT_TEST_SUITE_REGISTRATION(rtl_OUString::convertFromString);

} // namespace rtl_OUString

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
