/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* 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/.
*/
#include <sal/types.h>
#include <cppunit/TestAssert.h>
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/plugin/TestPlugIn.h>
#include <i18nutil/scriptchangescanner.hxx>
#include <com/sun/star/i18n/ScriptType.hpp>
using namespace i18nutil;
namespace css = ::com::sun::star;
namespace
{
class ScriptChangeScannerTest : public CppUnit::TestFixture
{
public:
void testEmpty();
void testTrivial();
void testTrivialAppLang();
void testWeakAtStart();
void testOnlyWeak();
void testStrongChange();
void testMongolianAfterNNBSP();
void testNonspacingMark();
void testSmartQuoteCompatibilityCJ();
void testSmartQuoteCompatibilityComplexAndCJ();
void testSmartQuoteCJAtStart();
void testRtlRunTrivial();
void testRtlRunEmbeddedComplex();
void testRtlRunEmbeddedLtrStrong();
void testRtlRunEmbeddedLtrWeakComplex();
void testRtlRunEmbeddedLtrWeakComplexHintLatin();
void testRtlRunEmbeddedLtrWeakComplexHintComplex();
void testRtlRunOverrideCJKAsian();
void testTdf164493InfiniteLoop();
void testHintsDefault();
void testHintsParaOnly();
void testHintsRunAtStart();
void testHintsRunAfterSpace();
void testHintsRunsAdjacent();
void testHintsRunsSpaced();
void testHintIgnore();
void testHintLatin();
void testHintAsian();
void testHintComplex();
void testHintMultipleRuns();
CPPUNIT_TEST_SUITE(ScriptChangeScannerTest);
CPPUNIT_TEST(testEmpty);
CPPUNIT_TEST(testTrivial);
CPPUNIT_TEST(testTrivialAppLang);
CPPUNIT_TEST(testWeakAtStart);
CPPUNIT_TEST(testOnlyWeak);
CPPUNIT_TEST(testStrongChange);
CPPUNIT_TEST(testMongolianAfterNNBSP);
CPPUNIT_TEST(testNonspacingMark);
CPPUNIT_TEST(testSmartQuoteCompatibilityCJ);
CPPUNIT_TEST(testSmartQuoteCompatibilityComplexAndCJ);
CPPUNIT_TEST(testSmartQuoteCJAtStart);
CPPUNIT_TEST(testRtlRunTrivial);
CPPUNIT_TEST(testRtlRunEmbeddedComplex);
CPPUNIT_TEST(testRtlRunEmbeddedLtrStrong);
CPPUNIT_TEST(testRtlRunEmbeddedLtrWeakComplex);
CPPUNIT_TEST(testRtlRunEmbeddedLtrWeakComplexHintLatin);
CPPUNIT_TEST(testRtlRunEmbeddedLtrWeakComplexHintComplex);
CPPUNIT_TEST(testRtlRunOverrideCJKAsian);
CPPUNIT_TEST(testTdf164493InfiniteLoop);
CPPUNIT_TEST(testHintsDefault);
CPPUNIT_TEST(testHintsParaOnly);
CPPUNIT_TEST(testHintsRunAtStart);
CPPUNIT_TEST(testHintsRunAfterSpace);
CPPUNIT_TEST(testHintsRunsAdjacent);
CPPUNIT_TEST(testHintsRunsSpaced);
CPPUNIT_TEST(testHintIgnore);
CPPUNIT_TEST(testHintLatin);
CPPUNIT_TEST(testHintAsian);
CPPUNIT_TEST(testHintComplex);
CPPUNIT_TEST(testHintMultipleRuns);
CPPUNIT_TEST_SUITE_END();
};
void ScriptChangeScannerTest::testEmpty()
{
auto aText = u""_ustr;
ScriptHintProvider stHints;
auto pDirScanner = MakeDirectionChangeScanner(aText, 0);
auto pScanner
= MakeScriptChangeScanner(aText, css::i18n::ScriptType::LATIN, *pDirScanner, stHints);
CPPUNIT_ASSERT(pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::LATIN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pScanner->Peek().m_nEndIndex);
}
void ScriptChangeScannerTest::testTrivial()
{
auto aText = u"Trivial case with a single span of a script"_ustr;
ScriptHintProvider stHints;
auto pDirScanner = MakeDirectionChangeScanner(aText, 0);
auto pScanner
= MakeScriptChangeScanner(aText, css::i18n::ScriptType::LATIN, *pDirScanner, stHints);
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::LATIN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(43), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(pScanner->AtEnd());
}
void ScriptChangeScannerTest::testTrivialAppLang()
{
auto aText = u"Trivial case with a single span of a script"_ustr;
ScriptHintProvider stHints;
auto pDirScanner = MakeDirectionChangeScanner(aText, 0);
auto pScanner
= MakeScriptChangeScanner(aText, css::i18n::ScriptType::ASIAN, *pDirScanner, stHints);
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::LATIN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(43), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(pScanner->AtEnd());
}
void ScriptChangeScannerTest::testWeakAtStart()
{
// The first-seen script type is used for weak characters at the start
auto aText = u"“x”"_ustr;
ScriptHintProvider stHints;
auto pDirScanner = MakeDirectionChangeScanner(aText, 0);
auto pScanner
= MakeScriptChangeScanner(aText, css::i18n::ScriptType::COMPLEX, *pDirScanner, stHints);
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::LATIN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(3), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(pScanner->AtEnd());
}
void ScriptChangeScannerTest::testOnlyWeak()
{
// The application language is used for text containing only weak characters
auto aText = u"“”"_ustr;
ScriptHintProvider stHints;
auto pDirScanner = MakeDirectionChangeScanner(aText, 0);
auto pScanner
= MakeScriptChangeScanner(aText, css::i18n::ScriptType::COMPLEX, *pDirScanner, stHints);
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::COMPLEX, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(2), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(pScanner->AtEnd());
}
void ScriptChangeScannerTest::testStrongChange()
{
auto aText = u"wide 廣 vast"_ustr;
ScriptHintProvider stHints;
auto pDirScanner = MakeDirectionChangeScanner(aText, 0);
auto pScanner
= MakeScriptChangeScanner(aText, css::i18n::ScriptType::LATIN, *pDirScanner, stHints);
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::LATIN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(5), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::ASIAN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(5), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(7), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::LATIN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(7), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(11), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(pScanner->AtEnd());
}
void ScriptChangeScannerTest::testMongolianAfterNNBSP()
{
// NNBSP before Mongolian text should be part of the Mongolian run
auto aText = u"Before\u202f\u1822\u1822After"_ustr;
ScriptHintProvider stHints;
auto pDirScanner = MakeDirectionChangeScanner(aText, 0);
auto pScanner
= MakeScriptChangeScanner(aText, css::i18n::ScriptType::LATIN, *pDirScanner, stHints);
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::LATIN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(6), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::COMPLEX, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(6), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(9), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::LATIN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(9), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(14), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(pScanner->AtEnd());
}
void ScriptChangeScannerTest::testNonspacingMark()
{
// A preceding weak character should be included in the run
// of a following non-spacing mark
auto aText = u"Before \u0944\u0911\u0911 After"_ustr;
ScriptHintProvider stHints;
auto pDirScanner = MakeDirectionChangeScanner(aText, 0);
auto pScanner
= MakeScriptChangeScanner(aText, css::i18n::ScriptType::LATIN, *pDirScanner, stHints);
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::LATIN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(6), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::COMPLEX, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(6), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(11), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::LATIN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(11), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(16), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(pScanner->AtEnd());
}
void ScriptChangeScannerTest::testSmartQuoteCompatibilityCJ()
{
// tdf#166104: Weak-script quotes should take the previously-seen script type
auto aText = u"Before \u201c水\u201d After"_ustr;
ScriptHintProvider stHints;
auto pDirScanner = MakeDirectionChangeScanner(aText, 0);
auto pScanner
= MakeScriptChangeScanner(aText, css::i18n::ScriptType::LATIN, *pDirScanner, stHints);
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::LATIN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(8), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::ASIAN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(8), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(11), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::LATIN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(11), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(16), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(pScanner->AtEnd());
}
void ScriptChangeScannerTest::testSmartQuoteCompatibilityComplexAndCJ()
{
// tdf#66791: However, if a paragraph contains complex text, weak-script
// quotes are assigned in the usual greedy way.
auto aText = u"Before \u201c水\u201d After \u05d0"_ustr;
ScriptHintProvider stHints;
auto pDirScanner = MakeDirectionChangeScanner(aText, 0);
auto pScanner
= MakeScriptChangeScanner(aText, css::i18n::ScriptType::LATIN, *pDirScanner, stHints);
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::LATIN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(8), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::ASIAN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(8), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(11), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::LATIN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(11), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(17), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::COMPLEX, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(17), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(18), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(pScanner->AtEnd());
}
void ScriptChangeScannerTest::testSmartQuoteCJAtStart()
{
auto aText = u"“廣”"_ustr;
ScriptHintProvider stHints;
auto pDirScanner = MakeDirectionChangeScanner(aText, 0);
auto pScanner
= MakeScriptChangeScanner(aText, css::i18n::ScriptType::LATIN, *pDirScanner, stHints);
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::ASIAN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(3), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(pScanner->AtEnd());
}
void ScriptChangeScannerTest::testRtlRunTrivial()
{
auto aText = u"Before אאאאאא after"_ustr;
ScriptHintProvider stHints;
auto pDirScanner = MakeDirectionChangeScanner(aText, 0);
CPPUNIT_ASSERT(!pDirScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(sal_uInt8(0), pDirScanner->Peek().m_nLevel);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pDirScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(7), pDirScanner->Peek().m_nEndIndex);
CPPUNIT_ASSERT(!pDirScanner->Peek().m_bHasEmbeddedStrongLTR);
pDirScanner->Advance();
CPPUNIT_ASSERT(!pDirScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(sal_uInt8(1), pDirScanner->Peek().m_nLevel);
CPPUNIT_ASSERT_EQUAL(sal_Int32(7), pDirScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(13), pDirScanner->Peek().m_nEndIndex);
CPPUNIT_ASSERT(!pDirScanner->Peek().m_bHasEmbeddedStrongLTR);
pDirScanner->Advance();
CPPUNIT_ASSERT(!pDirScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(sal_uInt8(0), pDirScanner->Peek().m_nLevel);
CPPUNIT_ASSERT_EQUAL(sal_Int32(13), pDirScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(19), pDirScanner->Peek().m_nEndIndex);
CPPUNIT_ASSERT(!pDirScanner->Peek().m_bHasEmbeddedStrongLTR);
pDirScanner->Advance();
CPPUNIT_ASSERT(pDirScanner->AtEnd());
pDirScanner->Reset();
auto pScanner
= MakeScriptChangeScanner(aText, css::i18n::ScriptType::LATIN, *pDirScanner, stHints);
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::LATIN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(7), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::COMPLEX, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(7), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(14), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::LATIN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(14), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(19), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(pScanner->AtEnd());
}
void ScriptChangeScannerTest::testRtlRunEmbeddedComplex()
{
auto aText = u"Before אא(א\"א)אא after"_ustr;
ScriptHintProvider stHints;
auto pDirScanner = MakeDirectionChangeScanner(aText, 0);
CPPUNIT_ASSERT(!pDirScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(sal_uInt8(0), pDirScanner->Peek().m_nLevel);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pDirScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(7), pDirScanner->Peek().m_nEndIndex);
CPPUNIT_ASSERT(!pDirScanner->Peek().m_bHasEmbeddedStrongLTR);
pDirScanner->Advance();
CPPUNIT_ASSERT(!pDirScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(sal_uInt8(1), pDirScanner->Peek().m_nLevel);
CPPUNIT_ASSERT_EQUAL(sal_Int32(7), pDirScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(16), pDirScanner->Peek().m_nEndIndex);
CPPUNIT_ASSERT(!pDirScanner->Peek().m_bHasEmbeddedStrongLTR);
pDirScanner->Advance();
CPPUNIT_ASSERT(!pDirScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(sal_uInt8(0), pDirScanner->Peek().m_nLevel);
CPPUNIT_ASSERT_EQUAL(sal_Int32(16), pDirScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(22), pDirScanner->Peek().m_nEndIndex);
CPPUNIT_ASSERT(!pDirScanner->Peek().m_bHasEmbeddedStrongLTR);
pDirScanner->Advance();
CPPUNIT_ASSERT(pDirScanner->AtEnd());
pDirScanner->Reset();
auto pScanner
= MakeScriptChangeScanner(aText, css::i18n::ScriptType::LATIN, *pDirScanner, stHints);
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::LATIN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(7), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::COMPLEX, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(7), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(17), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::LATIN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(17), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(22), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(pScanner->AtEnd());
}
void ScriptChangeScannerTest::testRtlRunEmbeddedLtrStrong()
{
auto aText = u"אאא Inside אאא"_ustr;
ScriptHintProvider stHints;
auto pDirScanner = MakeDirectionChangeScanner(aText, 1);
CPPUNIT_ASSERT(!pDirScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(sal_uInt8(1), pDirScanner->Peek().m_nLevel);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pDirScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(4), pDirScanner->Peek().m_nEndIndex);
CPPUNIT_ASSERT(!pDirScanner->Peek().m_bHasEmbeddedStrongLTR);
pDirScanner->Advance();
CPPUNIT_ASSERT(!pDirScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(sal_uInt8(2), pDirScanner->Peek().m_nLevel);
CPPUNIT_ASSERT_EQUAL(sal_Int32(4), pDirScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(10), pDirScanner->Peek().m_nEndIndex);
CPPUNIT_ASSERT(pDirScanner->Peek().m_bHasEmbeddedStrongLTR);
pDirScanner->Advance();
CPPUNIT_ASSERT(!pDirScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(sal_uInt8(1), pDirScanner->Peek().m_nLevel);
CPPUNIT_ASSERT_EQUAL(sal_Int32(10), pDirScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(14), pDirScanner->Peek().m_nEndIndex);
CPPUNIT_ASSERT(!pDirScanner->Peek().m_bHasEmbeddedStrongLTR);
pDirScanner->Advance();
CPPUNIT_ASSERT(pDirScanner->AtEnd());
pDirScanner->Reset();
auto pScanner
= MakeScriptChangeScanner(aText, css::i18n::ScriptType::COMPLEX, *pDirScanner, stHints);
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::COMPLEX, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(4), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::LATIN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(4), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(10), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::COMPLEX, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(10), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(14), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(pScanner->AtEnd());
}
void ScriptChangeScannerTest::testRtlRunEmbeddedLtrWeakComplex()
{
auto aText = u"אאא 123 אאא"_ustr;
ScriptHintProvider stHints;
auto pDirScanner = MakeDirectionChangeScanner(aText, 1);
CPPUNIT_ASSERT(!pDirScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(sal_uInt8(1), pDirScanner->Peek().m_nLevel);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pDirScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(4), pDirScanner->Peek().m_nEndIndex);
CPPUNIT_ASSERT(!pDirScanner->Peek().m_bHasEmbeddedStrongLTR);
pDirScanner->Advance();
CPPUNIT_ASSERT(!pDirScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(sal_uInt8(2), pDirScanner->Peek().m_nLevel);
CPPUNIT_ASSERT_EQUAL(sal_Int32(4), pDirScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(7), pDirScanner->Peek().m_nEndIndex);
CPPUNIT_ASSERT(!pDirScanner->Peek().m_bHasEmbeddedStrongLTR);
pDirScanner->Advance();
CPPUNIT_ASSERT(!pDirScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(sal_uInt8(1), pDirScanner->Peek().m_nLevel);
CPPUNIT_ASSERT_EQUAL(sal_Int32(7), pDirScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(11), pDirScanner->Peek().m_nEndIndex);
CPPUNIT_ASSERT(!pDirScanner->Peek().m_bHasEmbeddedStrongLTR);
pDirScanner->Advance();
CPPUNIT_ASSERT(pDirScanner->AtEnd());
pDirScanner->Reset();
auto pScanner
= MakeScriptChangeScanner(aText, css::i18n::ScriptType::LATIN, *pDirScanner, stHints);
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::COMPLEX, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(11), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(pScanner->AtEnd());
}
void ScriptChangeScannerTest::testRtlRunEmbeddedLtrWeakComplexHintLatin()
{
auto aText = u"אאא 123 אאא"_ustr;
ScriptHintProvider stHints;
stHints.SetParagraphLevelHint(ScriptHintType::Latin);
auto pDirScanner = MakeDirectionChangeScanner(aText, 1);
auto pScanner
= MakeScriptChangeScanner(aText, css::i18n::ScriptType::LATIN, *pDirScanner, stHints);
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::COMPLEX, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(3), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::LATIN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(3), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(8), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::COMPLEX, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(8), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(11), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(pScanner->AtEnd());
}
void ScriptChangeScannerTest::testRtlRunEmbeddedLtrWeakComplexHintComplex()
{
auto aText = u"אאא 123 אאא"_ustr;
ScriptHintProvider stHints;
stHints.SetParagraphLevelHint(ScriptHintType::Complex);
auto pDirScanner = MakeDirectionChangeScanner(aText, 1);
auto pScanner
= MakeScriptChangeScanner(aText, css::i18n::ScriptType::LATIN, *pDirScanner, stHints);
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::COMPLEX, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(11), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(pScanner->AtEnd());
}
void ScriptChangeScannerTest::testRtlRunOverrideCJKAsian()
{
// tdf#163660: Asian-script characters following an RTL override should
// still be treated as Asian script, rather than Complex script
auto aText = u"一二\u202e三四五"_ustr;
ScriptHintProvider stHints;
auto pDirScanner = MakeDirectionChangeScanner(aText, 0);
CPPUNIT_ASSERT(!pDirScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(sal_uInt8(0), pDirScanner->Peek().m_nLevel);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pDirScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(2), pDirScanner->Peek().m_nEndIndex);
CPPUNIT_ASSERT(!pDirScanner->Peek().m_bHasEmbeddedStrongLTR);
pDirScanner->Advance();
CPPUNIT_ASSERT(!pDirScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(sal_uInt8(1), pDirScanner->Peek().m_nLevel);
CPPUNIT_ASSERT_EQUAL(sal_Int32(2), pDirScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(6), pDirScanner->Peek().m_nEndIndex);
CPPUNIT_ASSERT(!pDirScanner->Peek().m_bHasEmbeddedStrongLTR);
pDirScanner->Advance();
CPPUNIT_ASSERT(pDirScanner->AtEnd());
pDirScanner->Reset();
auto pScanner
= MakeScriptChangeScanner(aText, css::i18n::ScriptType::LATIN, *pDirScanner, stHints);
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::ASIAN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(2), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::COMPLEX, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(2), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(3), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::ASIAN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(3), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(6), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(pScanner->AtEnd());
}
void ScriptChangeScannerTest::testTdf164493InfiniteLoop()
{
// tdf#164493: Tests a case causing an infinite loop due to interaction
// between right-to-left override and a CJK combining mark.
// U+202E: RIGHT-TO-LEFT OVERRIDE
// U+302E: HANGUL SINGLE DOT TONE MARK
auto aText = u"\u202e\u302e"_ustr;
ScriptHintProvider stHints;
auto pDirScanner = MakeDirectionChangeScanner(aText, 0);
auto pScanner
= MakeScriptChangeScanner(aText, css::i18n::ScriptType::LATIN, *pDirScanner, stHints);
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::ASIAN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(2), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(pScanner->AtEnd());
}
void ScriptChangeScannerTest::testHintsDefault()
{
ScriptHintProvider stHints;
stHints.Start();
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Automatic, stHints.Peek());
stHints.AdvanceTo(1);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Automatic, stHints.Peek());
stHints.AdvanceTo(2);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Automatic, stHints.Peek());
}
void ScriptChangeScannerTest::testHintsParaOnly()
{
ScriptHintProvider stHints;
stHints.SetParagraphLevelHint(ScriptHintType::Ignore);
stHints.Start();
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Ignore, stHints.Peek());
stHints.AdvanceTo(1);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Ignore, stHints.Peek());
stHints.AdvanceTo(2);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Ignore, stHints.Peek());
}
void ScriptChangeScannerTest::testHintsRunAtStart()
{
ScriptHintProvider stHints;
stHints.SetParagraphLevelHint(ScriptHintType::Ignore);
stHints.AddHint(ScriptHintType::Latin, 0, 3);
stHints.Start();
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Latin, stHints.Peek());
stHints.AdvanceTo(1);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Latin, stHints.Peek());
stHints.AdvanceTo(2);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Latin, stHints.Peek());
stHints.AdvanceTo(3);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Ignore, stHints.Peek());
stHints.AdvanceTo(4);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Ignore, stHints.Peek());
}
void ScriptChangeScannerTest::testHintsRunAfterSpace()
{
ScriptHintProvider stHints;
stHints.SetParagraphLevelHint(ScriptHintType::Ignore);
stHints.AddHint(ScriptHintType::Latin, 2, 5);
stHints.Start();
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Ignore, stHints.Peek());
stHints.AdvanceTo(1);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Ignore, stHints.Peek());
stHints.AdvanceTo(2);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Latin, stHints.Peek());
stHints.AdvanceTo(3);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Latin, stHints.Peek());
stHints.AdvanceTo(4);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Latin, stHints.Peek());
stHints.AdvanceTo(5);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Ignore, stHints.Peek());
stHints.AdvanceTo(6);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Ignore, stHints.Peek());
}
void ScriptChangeScannerTest::testHintsRunsAdjacent()
{
ScriptHintProvider stHints;
stHints.SetParagraphLevelHint(ScriptHintType::Ignore);
stHints.AddHint(ScriptHintType::Latin, 2, 5);
stHints.AddHint(ScriptHintType::Complex, 5, 7);
stHints.Start();
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Ignore, stHints.Peek());
stHints.AdvanceTo(1);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Ignore, stHints.Peek());
stHints.AdvanceTo(2);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Latin, stHints.Peek());
stHints.AdvanceTo(3);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Latin, stHints.Peek());
stHints.AdvanceTo(4);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Latin, stHints.Peek());
stHints.AdvanceTo(5);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Complex, stHints.Peek());
stHints.AdvanceTo(6);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Complex, stHints.Peek());
stHints.AdvanceTo(7);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Ignore, stHints.Peek());
stHints.AdvanceTo(8);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Ignore, stHints.Peek());
}
void ScriptChangeScannerTest::testHintsRunsSpaced()
{
ScriptHintProvider stHints;
stHints.SetParagraphLevelHint(ScriptHintType::Ignore);
stHints.AddHint(ScriptHintType::Latin, 2, 5);
stHints.AddHint(ScriptHintType::Complex, 7, 9);
stHints.Start();
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Ignore, stHints.Peek());
stHints.AdvanceTo(1);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Ignore, stHints.Peek());
stHints.AdvanceTo(2);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Latin, stHints.Peek());
stHints.AdvanceTo(3);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Latin, stHints.Peek());
stHints.AdvanceTo(4);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Latin, stHints.Peek());
stHints.AdvanceTo(5);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Ignore, stHints.Peek());
stHints.AdvanceTo(6);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Ignore, stHints.Peek());
stHints.AdvanceTo(7);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Complex, stHints.Peek());
stHints.AdvanceTo(8);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Complex, stHints.Peek());
stHints.AdvanceTo(9);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Ignore, stHints.Peek());
stHints.AdvanceTo(10);
CPPUNIT_ASSERT_EQUAL(ScriptHintType::Ignore, stHints.Peek());
}
void ScriptChangeScannerTest::testHintIgnore()
{
auto aText = u"Before \u201c水\u201d After"_ustr;
ScriptHintProvider stHints;
stHints.SetParagraphLevelHint(ScriptHintType::Ignore);
auto pDirScanner = MakeDirectionChangeScanner(aText, 0);
auto pScanner
= MakeScriptChangeScanner(aText, css::i18n::ScriptType::LATIN, *pDirScanner, stHints);
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::LATIN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(16), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(pScanner->AtEnd());
}
void ScriptChangeScannerTest::testHintLatin()
{
auto aText = u"水 \u201c水\u201d After"_ustr;
ScriptHintProvider stHints;
stHints.SetParagraphLevelHint(ScriptHintType::Latin);
auto pDirScanner = MakeDirectionChangeScanner(aText, 0);
auto pScanner
= MakeScriptChangeScanner(aText, css::i18n::ScriptType::LATIN, *pDirScanner, stHints);
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::ASIAN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(1), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::LATIN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(1), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(3), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::ASIAN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(3), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(4), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::LATIN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(4), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(11), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(pScanner->AtEnd());
}
void ScriptChangeScannerTest::testHintAsian()
{
auto aText = u"Before \u201c水\u201d After"_ustr;
ScriptHintProvider stHints;
stHints.SetParagraphLevelHint(ScriptHintType::Asian);
auto pDirScanner = MakeDirectionChangeScanner(aText, 0);
auto pScanner
= MakeScriptChangeScanner(aText, css::i18n::ScriptType::LATIN, *pDirScanner, stHints);
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::LATIN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(6), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::ASIAN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(6), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(11), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::LATIN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(11), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(16), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(pScanner->AtEnd());
}
void ScriptChangeScannerTest::testHintComplex()
{
auto aText = u"Before \u201c水\u201d After"_ustr;
ScriptHintProvider stHints;
stHints.SetParagraphLevelHint(ScriptHintType::Complex);
auto pDirScanner = MakeDirectionChangeScanner(aText, 0);
auto pScanner
= MakeScriptChangeScanner(aText, css::i18n::ScriptType::LATIN, *pDirScanner, stHints);
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::LATIN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(6), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::COMPLEX, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(6), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(8), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::ASIAN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(8), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(9), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::COMPLEX, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(9), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(11), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::LATIN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(11), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(16), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(pScanner->AtEnd());
}
void ScriptChangeScannerTest::testHintMultipleRuns()
{
auto aText = u"““““““““““““““““"_ustr;
ScriptHintProvider stHints;
stHints.AddHint(ScriptHintType::Latin, 3, 5);
stHints.AddHint(ScriptHintType::Complex, 7, 9);
stHints.AddHint(ScriptHintType::Asian, 11, 13);
auto pDirScanner = MakeDirectionChangeScanner(aText, 0);
auto pScanner
= MakeScriptChangeScanner(aText, css::i18n::ScriptType::LATIN, *pDirScanner, stHints);
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::LATIN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(7), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::COMPLEX, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(7), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(11), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(!pScanner->AtEnd());
CPPUNIT_ASSERT_EQUAL(css::i18n::ScriptType::ASIAN, pScanner->Peek().m_nScriptType);
CPPUNIT_ASSERT_EQUAL(sal_Int32(11), pScanner->Peek().m_nStartIndex);
CPPUNIT_ASSERT_EQUAL(sal_Int32(16), pScanner->Peek().m_nEndIndex);
pScanner->Advance();
CPPUNIT_ASSERT(pScanner->AtEnd());
}
CPPUNIT_TEST_SUITE_REGISTRATION(ScriptChangeScannerTest);
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
↑ V1074 Boundary between escape sequence and string is unclear. The escape sequence ends with a letter and the next character is also a letter. Check for typos.
↑ V1074 Boundary between escape sequence and string is unclear. The escape sequence ends with a letter and the next character is also a letter. Check for typos.
↑ V1074 Boundary between escape sequence and string is unclear. The escape sequence ends with a letter and the next character is also a letter. Check for typos.
↑ V1074 Boundary between escape sequence and string is unclear. The escape sequence ends with a letter and the next character is also a letter. Check for typos.
↑ V1074 Boundary between escape sequence and string is unclear. The escape sequence ends with a letter and the next character is also a letter. Check for typos.
↑ V1074 Boundary between escape sequence and string is unclear. The escape sequence ends with a letter and the next character is also a letter. Check for typos.
↑ V1074 Boundary between escape sequence and string is unclear. The escape sequence ends with a letter and the next character is also a letter. Check for typos.