diff options
Diffstat (limited to 'tests/auto/corelib/text/qtextboundaryfinder/tst_qtextboundaryfinder.cpp')
-rw-r--r-- | tests/auto/corelib/text/qtextboundaryfinder/tst_qtextboundaryfinder.cpp | 855 |
1 files changed, 855 insertions, 0 deletions
diff --git a/tests/auto/corelib/text/qtextboundaryfinder/tst_qtextboundaryfinder.cpp b/tests/auto/corelib/text/qtextboundaryfinder/tst_qtextboundaryfinder.cpp new file mode 100644 index 0000000000..a46011ff6c --- /dev/null +++ b/tests/auto/corelib/text/qtextboundaryfinder/tst_qtextboundaryfinder.cpp @@ -0,0 +1,855 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> + +#include <qtextboundaryfinder.h> +#include <qtextcodec.h> +#include <qfile.h> +#include <qdebug.h> +#include <qlist.h> + +#include <algorithm> + +class tst_QTextBoundaryFinder : public QObject +{ + Q_OBJECT +private slots: +#ifdef QT_BUILD_INTERNAL + void graphemeBoundariesDefault_data(); + void graphemeBoundariesDefault(); + void wordBoundariesDefault_data(); + void wordBoundariesDefault(); + void sentenceBoundariesDefault_data(); + void sentenceBoundariesDefault(); + void lineBoundariesDefault_data(); + void lineBoundariesDefault(); +#endif + + void wordBoundaries_manual_data(); + void wordBoundaries_manual(); + void sentenceBoundaries_manual_data(); + void sentenceBoundaries_manual(); + void lineBoundaries_manual_data(); + void lineBoundaries_manual(); + + void emptyText_data(); + void emptyText(); + void fastConstructor(); + void assignmentOperator(); + void isAtSoftHyphen_data(); + void isAtSoftHyphen(); + void thaiLineBreak(); +}; + + +QT_BEGIN_NAMESPACE +namespace QTest { + +template<> +inline char *toString(const QTextBoundaryFinder::BoundaryReasons &flags) +{ + return qstrdup(QByteArray::number(int(flags)).constData()); +} + +template<> +inline char *toString(const QList<int> &list) +{ + QByteArray s; + for (QList<int>::const_iterator it = list.constBegin(); it != list.constEnd(); ++it) { + if (!s.isEmpty()) + s += ", "; + s += QByteArray::number(*it); + } + s = "{ " + s + " }"; + return qstrdup(s.constData()); +} + +} // namespace QTest +QT_END_NAMESPACE + +#ifdef QT_BUILD_INTERNAL +static void generateDataFromFile(const QString &fname) +{ + QTest::addColumn<QString>("testString"); + QTest::addColumn<QList<int> >("expectedBreakPositions"); + + QString testFile = QFINDTESTDATA(fname); + QVERIFY2(!testFile.isEmpty(), (fname.toLatin1() + QByteArray(" not found!"))); + QFile f(testFile); + QVERIFY(f.exists()); + + f.open(QIODevice::ReadOnly); + + int linenum = 0; + while (!f.atEnd()) { + linenum++; + + QByteArray line = f.readLine(); + if (line.startsWith('#')) + continue; + + QString test = QString::fromUtf8(line); + QString comments; + int hash = test.indexOf('#'); + if (hash > 0) { + comments = test.mid(hash + 1).simplified(); + test = test.left(hash); + } + + QString testString; + QList<int> expectedBreakPositions; + foreach (const QString &part, test.simplified().split(QLatin1Char(' '), QString::SkipEmptyParts)) { + if (part.size() == 1) { + if (part.at(0).unicode() == 0xf7) + expectedBreakPositions.append(testString.size()); + else + QVERIFY(part.at(0).unicode() == 0xd7); + continue; + } + bool ok = true; + uint ucs4 = part.toInt(&ok, 16); + QVERIFY(ok && ucs4 > 0); + if (QChar::requiresSurrogates(ucs4)) { + testString.append(QChar::highSurrogate(ucs4)); + testString.append(QChar::lowSurrogate(ucs4)); + } else { + testString.append(QChar(ucs4)); + } + } + QVERIFY(!testString.isEmpty()); + QVERIFY(!expectedBreakPositions.isEmpty()); + + if (!comments.isEmpty()) { + const QStringList lst = comments.simplified().split(QLatin1Char(' '), QString::SkipEmptyParts); + comments.clear(); + foreach (const QString &part, lst) { + if (part.size() == 1) { + if (part.at(0).unicode() == 0xf7) + comments += QLatin1Char('+'); + else if (part.at(0).unicode() == 0xd7) + comments += QLatin1Char('x'); + continue; + } + if (part.startsWith(QLatin1Char('(')) && part.endsWith(QLatin1Char(')'))) + comments += part; + } + } + + const QByteArray nm = "line #" + QByteArray::number(linenum) + ": " + comments.toLatin1(); + QTest::newRow(nm.constData()) << testString << expectedBreakPositions; + } +} +#endif + +static void doTestData(const QString &testString, const QList<int> &expectedBreakPositions, + QTextBoundaryFinder::BoundaryType type, + QTextBoundaryFinder::BoundaryReasons reasons = QTextBoundaryFinder::BreakOpportunity) +{ + QVERIFY(!testString.isEmpty()); + + QTextBoundaryFinder boundaryFinder(type, testString); + + // test toNextBoundary() + { + QList<int> actualBreakPositions; + do { + QVERIFY(boundaryFinder.isAtBoundary()); + if (boundaryFinder.boundaryReasons() & reasons) + actualBreakPositions.append(boundaryFinder.position()); + } while (boundaryFinder.toNextBoundary() != -1); + QCOMPARE(actualBreakPositions, expectedBreakPositions); + } + QCOMPARE(boundaryFinder.position(), -1); + QVERIFY(!boundaryFinder.isAtBoundary()); + QVERIFY(boundaryFinder.boundaryReasons() == QTextBoundaryFinder::NotAtBoundary); + + // test toPreviousBoundary() + { + QList<int> expectedBreakPositionsRev = expectedBreakPositions; + std::sort(expectedBreakPositionsRev.begin(), expectedBreakPositionsRev.end(), std::greater<int>()); + + QList<int> actualBreakPositions; + boundaryFinder.toEnd(); + do { + QVERIFY(boundaryFinder.isAtBoundary()); + if (boundaryFinder.boundaryReasons() & reasons) + actualBreakPositions.append(boundaryFinder.position()); + } while (boundaryFinder.toPreviousBoundary() != -1); + QCOMPARE(actualBreakPositions, expectedBreakPositionsRev); + } + QCOMPARE(boundaryFinder.position(), -1); + QVERIFY(!boundaryFinder.isAtBoundary()); + QVERIFY(boundaryFinder.boundaryReasons() == QTextBoundaryFinder::NotAtBoundary); + + // test boundaryReasons() + for (int i = 0; i <= testString.length(); ++i) { + boundaryFinder.setPosition(i); + QCOMPARE(!!(boundaryFinder.boundaryReasons() & reasons), expectedBreakPositions.contains(i)); + } +} + +#ifdef QT_BUILD_INTERNAL + +QT_BEGIN_NAMESPACE +extern Q_AUTOTEST_EXPORT int qt_initcharattributes_default_algorithm_only; +QT_END_NAMESPACE + +void tst_QTextBoundaryFinder::graphemeBoundariesDefault_data() +{ + generateDataFromFile("data/GraphemeBreakTest.txt"); +} + +void tst_QTextBoundaryFinder::graphemeBoundariesDefault() +{ + QFETCH(QString, testString); + QFETCH(QList<int>, expectedBreakPositions); + + QScopedValueRollback<int> default_algorithm(qt_initcharattributes_default_algorithm_only); + qt_initcharattributes_default_algorithm_only++; + + doTestData(testString, expectedBreakPositions, QTextBoundaryFinder::Grapheme); +} + +void tst_QTextBoundaryFinder::wordBoundariesDefault_data() +{ + generateDataFromFile("data/WordBreakTest.txt"); +} + +void tst_QTextBoundaryFinder::wordBoundariesDefault() +{ + QFETCH(QString, testString); + QFETCH(QList<int>, expectedBreakPositions); + + QScopedValueRollback<int> default_algorithm(qt_initcharattributes_default_algorithm_only); + qt_initcharattributes_default_algorithm_only++; + + doTestData(testString, expectedBreakPositions, QTextBoundaryFinder::Word); +} + +void tst_QTextBoundaryFinder::sentenceBoundariesDefault_data() +{ + generateDataFromFile("data/SentenceBreakTest.txt"); +} + +void tst_QTextBoundaryFinder::sentenceBoundariesDefault() +{ + QFETCH(QString, testString); + QFETCH(QList<int>, expectedBreakPositions); + + QScopedValueRollback<int> default_algorithm(qt_initcharattributes_default_algorithm_only); + qt_initcharattributes_default_algorithm_only++; + + doTestData(testString, expectedBreakPositions, QTextBoundaryFinder::Sentence); +} + +void tst_QTextBoundaryFinder::lineBoundariesDefault_data() +{ + generateDataFromFile("data/LineBreakTest.txt"); +} + +void tst_QTextBoundaryFinder::lineBoundariesDefault() +{ + QFETCH(QString, testString); + QFETCH(QList<int>, expectedBreakPositions); + + QScopedValueRollback<int> default_algorithm(qt_initcharattributes_default_algorithm_only); + qt_initcharattributes_default_algorithm_only++; + + expectedBreakPositions.prepend(0); // ### QTBF generates a boundary at start of text + doTestData(testString, expectedBreakPositions, QTextBoundaryFinder::Line); +} +#endif // QT_BUILD_INTERNAL + +void tst_QTextBoundaryFinder::wordBoundaries_manual_data() +{ + QTest::addColumn<QString>("testString"); + QTest::addColumn<QList<int> >("expectedBreakPositions"); + QTest::addColumn<QList<int> >("expectedStartPositions"); + QTest::addColumn<QList<int> >("expectedEndPositions"); + + { + QChar s[] = { 0x000D, 0x000A, 0x000A }; + QString testString(s, sizeof(s)/sizeof(s[0])); + QList<int> expectedBreakPositions, expectedStartPositions, expectedEndPositions; + expectedBreakPositions << 0 << 2 << 3; + + QTest::newRow("+CRxLF+LF+") << testString << expectedBreakPositions + << expectedStartPositions << expectedEndPositions; + } + { + QChar s[] = { 0x000D, 0x0308, 0x000A, 0x000A }; + QString testString(s, sizeof(s)/sizeof(s[0])); + QList<int> expectedBreakPositions, expectedStartPositions, expectedEndPositions; + expectedBreakPositions << 0 << 1 << 2 << 3 << 4; + + QTest::newRow("+CR+FE+LF+LF+") << testString << expectedBreakPositions + << expectedStartPositions << expectedEndPositions; + } + { + QString testString(QString::fromUtf8("Aaa bbb ccc.\r\nDdd eee fff.")); + QList<int> expectedBreakPositions, expectedStartPositions, expectedEndPositions; + expectedBreakPositions << 0 << 3 << 4 << 7 << 8 << 11 << 12 << 14 << 17 << 18 << 21 << 22 << 25 << 26; + expectedStartPositions << 0 << 4 << 8 << 14 << 18 << 22; + expectedEndPositions << 3 << 7 << 11 << 17 << 21 << 25; + + QTest::newRow("words1") << testString << expectedBreakPositions + << expectedStartPositions << expectedEndPositions; + } + { + QString testString(QString::fromUtf8("Hello (sad) world !")); + QList<int> expectedBreakPositions, expectedStartPositions, expectedEndPositions; + expectedBreakPositions << 0 << 5 << 6 << 7 << 10 << 11 << 12 << 17 << 18 << 19; + expectedStartPositions << 0 << 7 << 12; + expectedEndPositions << 5 << 10 << 17; + + QTest::newRow("words2") << testString << expectedBreakPositions + << expectedStartPositions << expectedEndPositions; + } + { + QString testString(QString::fromUtf8("mr.Hamster")); + QList<int> expectedBreakPositions, expectedStartPositions, expectedEndPositions; + expectedBreakPositions << 0 << 2 << 3 << 10; + expectedStartPositions << 0 << 3; + expectedEndPositions << 2 << 10; + + QTest::newRow("words3") << testString << expectedBreakPositions + << expectedStartPositions << expectedEndPositions; + } + { + QString testString(QString::fromUtf8("This is a sample buffer.Please test me . He's don't Le'Clerk.")); + QList<int> expectedBreakPositions, expectedStartPositions, expectedEndPositions; + expectedBreakPositions << 0 << 4 << 5 << 7 << 8 << 9 << 10 << 11 << 12 << 13 << 14 << 20 << 21 << 27 + << 28 << 34 << 35 << 39 << 40 << 42 << 43 << 44 << 45 << 46 << 47 << 48 + << 49 << 53 << 54 << 59 << 60 << 68 << 69; + expectedStartPositions << 0 << 5 << 12 << 14 << 21 << 28 << 35 << 40 << 49 << 54 << 60; + expectedEndPositions << 4 << 7 << 13 << 20 << 27 << 34 << 39 << 42 << 53 << 59 << 68; + + QTest::newRow("words4") << testString << expectedBreakPositions + << expectedStartPositions << expectedEndPositions; + } + { + // text with trailing space + QString testString(QString::fromUtf8("Please test me. Finish ")); + QList<int> expectedBreakPositions, expectedStartPositions, expectedEndPositions; + expectedBreakPositions << 0 << 6 << 7 << 11 << 12 << 14 << 15 << 16 << 22 << 23; + expectedStartPositions << 0 << 7 << 12 << 16; + expectedEndPositions << 6 << 11 << 14 << 22; + + QTest::newRow("qtbug6498") << testString << expectedBreakPositions + << expectedStartPositions << expectedEndPositions; + } + + // Sample Strings from WordBreakTest.html + { + QChar s[] = { 0x0063, 0x0061, 0x006E, 0x0027, 0x0074 }; + QString testString(s, sizeof(s)/sizeof(s[0])); + QList<int> expectedBreakPositions, expectedStartPositions, expectedEndPositions; + expectedBreakPositions << 0 << 5; + expectedStartPositions << 0; + expectedEndPositions << 5; + + QTest::newRow("ts 1") << testString << expectedBreakPositions + << expectedStartPositions << expectedEndPositions; + } + { + QChar s[] = { 0x0063, 0x0061, 0x006E, 0x2019, 0x0074 }; + QString testString(s, sizeof(s)/sizeof(s[0])); + QList<int> expectedBreakPositions, expectedStartPositions, expectedEndPositions; + expectedBreakPositions << 0 << 5; + expectedStartPositions << 0; + expectedEndPositions << 5; + + QTest::newRow("ts 2") << testString << expectedBreakPositions + << expectedStartPositions << expectedEndPositions; + } + { + QChar s[] = { 0x0061, 0x0062, 0x00AD, 0x0062, 0x0061 }; + QString testString(s, sizeof(s)/sizeof(s[0])); + QList<int> expectedBreakPositions, expectedStartPositions, expectedEndPositions; + expectedBreakPositions << 0 << 5; + expectedStartPositions << 0; + expectedEndPositions << 5; + + QTest::newRow("ts 3") << testString << expectedBreakPositions + << expectedStartPositions << expectedEndPositions; + } + { + QChar s[] = { 0x0061, 0x0024, 0x002D, 0x0033, 0x0034, 0x002C, 0x0035, 0x0036, + 0x0037, 0x002E, 0x0031, 0x0034, 0x0025, 0x0062 }; + QString testString(s, sizeof(s)/sizeof(s[0])); + QList<int> expectedBreakPositions, expectedStartPositions, expectedEndPositions; + expectedBreakPositions << 0 << 1 << 2 << 3 << 12 << 13 << 14; + expectedStartPositions << 0 << 3 << 13; + expectedEndPositions << 1 << 12 << 14; + + QTest::newRow("ts 4") << testString << expectedBreakPositions + << expectedStartPositions << expectedEndPositions; + } + { + QChar s[] = { 0x0033, 0x0061 }; + QString testString(s, sizeof(s)/sizeof(s[0])); + QList<int> expectedBreakPositions, expectedStartPositions, expectedEndPositions; + expectedBreakPositions << 0 << 2; + expectedStartPositions << 0; + expectedEndPositions << 2; + + QTest::newRow("ts 5") << testString << expectedBreakPositions + << expectedStartPositions << expectedEndPositions; + } + { + QChar s[] = { 0x2060, 0x0063, 0x2060, 0x0061, 0x2060, 0x006E, 0x2060, 0x0027, + 0x2060, 0x0074, 0x2060, 0x2060 }; + QString testString(s, sizeof(s)/sizeof(s[0])); + QList<int> expectedBreakPositions, expectedStartPositions, expectedEndPositions; + expectedBreakPositions << 0 << 1 << 12; + expectedStartPositions << 1; + expectedEndPositions << 12; + + QTest::newRow("ts 1e") << testString << expectedBreakPositions + << expectedStartPositions << expectedEndPositions; + } + { + QChar s[] = { 0x2060, 0x0063, 0x2060, 0x0061, 0x2060, 0x006E, 0x2060, 0x2019, + 0x2060, 0x0074, 0x2060, 0x2060 }; + QString testString(s, sizeof(s)/sizeof(s[0])); + QList<int> expectedBreakPositions, expectedStartPositions, expectedEndPositions; + expectedBreakPositions << 0 << 1 << 12; + expectedStartPositions << 1; + expectedEndPositions << 12; + + QTest::newRow("ts 2e") << testString << expectedBreakPositions + << expectedStartPositions << expectedEndPositions; + } + { + QChar s[] = { 0x2060, 0x0061, 0x2060, 0x0062, 0x2060, 0x00AD, 0x2060, 0x0062, + 0x2060, 0x0061, 0x2060, 0x2060 }; + QString testString(s, sizeof(s)/sizeof(s[0])); + QList<int> expectedBreakPositions, expectedStartPositions, expectedEndPositions; + expectedBreakPositions << 0 << 1 << 12; + expectedStartPositions << 1; + expectedEndPositions << 12; + + QTest::newRow("ts 3e") << testString << expectedBreakPositions + << expectedStartPositions << expectedEndPositions; + } + { + QChar s[] = { 0x2060, 0x0061, 0x2060, 0x0024, 0x2060, 0x002D, 0x2060, 0x0033, + 0x2060, 0x0034, 0x2060, 0x002C, 0x2060, 0x0035, 0x2060, 0x0036, + 0x2060, 0x0037, 0x2060, 0x002E, 0x2060, 0x0031, 0x2060, 0x0034, + 0x2060, 0x0025, 0x2060, 0x0062, 0x2060, 0x2060 }; + QString testString(s, sizeof(s)/sizeof(s[0])); + QList<int> expectedBreakPositions, expectedStartPositions, expectedEndPositions; + expectedBreakPositions << 0 << 1 << 3 << 5 << 7 << 25 << 27 << 30; + expectedStartPositions << 1 << 7 << 27; + expectedEndPositions << 3 << 25 << 30; + + QTest::newRow("ts 4e") << testString << expectedBreakPositions + << expectedStartPositions << expectedEndPositions; + } + { + QChar s[] = { 0x2060, 0x0033, 0x2060, 0x0061, 0x2060, 0x2060 }; + QString testString(s, sizeof(s)/sizeof(s[0])); + QList<int> expectedBreakPositions, expectedStartPositions, expectedEndPositions; + expectedBreakPositions << 0 << 1 << 6; + expectedStartPositions << 1; + expectedEndPositions << 6; + + QTest::newRow("ts 5e") << testString << expectedBreakPositions + << expectedStartPositions << expectedEndPositions; + } +} + +void tst_QTextBoundaryFinder::wordBoundaries_manual() +{ + QFETCH(QString, testString); + QFETCH(QList<int>, expectedBreakPositions); + QFETCH(QList<int>, expectedStartPositions); + QFETCH(QList<int>, expectedEndPositions); + + doTestData(testString, expectedBreakPositions, QTextBoundaryFinder::Word); + doTestData(testString, expectedStartPositions, QTextBoundaryFinder::Word, QTextBoundaryFinder::StartOfItem); + doTestData(testString, expectedEndPositions, QTextBoundaryFinder::Word, QTextBoundaryFinder::EndOfItem); +} + +void tst_QTextBoundaryFinder::sentenceBoundaries_manual_data() +{ + QTest::addColumn<QString>("testString"); + QTest::addColumn<QList<int> >("expectedBreakPositions"); + + { + QChar s[] = { 0x000D, 0x000A, 0x000A }; + QString testString(s, sizeof(s)/sizeof(s[0])); + QList<int> expectedBreakPositions; + expectedBreakPositions << 0 << 2 << 3; + + QTest::newRow("+CRxLF+LF+") << testString << expectedBreakPositions; + } + { + QChar s[] = { 0x000D, 0x0308, 0x000A, 0x000A }; + QString testString(s, sizeof(s)/sizeof(s[0])); + QList<int> expectedBreakPositions; + expectedBreakPositions << 0 << 1 << 3 << 4; + + QTest::newRow("+CR+FExLF+LF+") << testString << expectedBreakPositions; + } + { + QString testString(QString::fromUtf8("Aaa bbb ccc.\r\nDdd eee fff.")); + QList<int> expectedBreakPositions; + expectedBreakPositions << 0 << 14 << 26; + + QTest::newRow("data1") << testString << expectedBreakPositions; + } + { + QString testString(QString::fromUtf8("Diga-nos qualé a sua opinião")); + QList<int> expectedBreakPositions; + expectedBreakPositions << 0 << 28; + + QTest::newRow("data2") << testString << expectedBreakPositions; + } + { + QString testString(QString::fromUtf8("mr.Hamster")); + QList<int> expectedBreakPositions; + expectedBreakPositions << 0 << 3 << 10; + + QTest::newRow("data3") << testString << expectedBreakPositions; + } + { + QString testString(QString::fromUtf8("Doing TEST, doing another test.")); + QList<int> expectedBreakPositions; + expectedBreakPositions << 0 << 31; + + QTest::newRow("data4") << testString << expectedBreakPositions; + } +} + +void tst_QTextBoundaryFinder::sentenceBoundaries_manual() +{ + QFETCH(QString, testString); + QFETCH(QList<int>, expectedBreakPositions); + + QVERIFY(expectedBreakPositions.size() >= 2); + QList<int> expectedStartPositions = expectedBreakPositions; expectedStartPositions.removeLast(); + QList<int> expectedEndPositions = expectedBreakPositions; expectedEndPositions.removeFirst(); + + doTestData(testString, expectedBreakPositions, QTextBoundaryFinder::Sentence); + doTestData(testString, expectedStartPositions, QTextBoundaryFinder::Sentence, QTextBoundaryFinder::StartOfItem); + doTestData(testString, expectedEndPositions, QTextBoundaryFinder::Sentence, QTextBoundaryFinder::EndOfItem); +} + +void tst_QTextBoundaryFinder::lineBoundaries_manual_data() +{ + QTest::addColumn<QString>("testString"); + QTest::addColumn<QList<int> >("expectedBreakPositions"); + QTest::addColumn<QList<int> >("expectedMandatoryBreakPositions"); + + { + QString testString(QString::fromUtf8("Aaa bbb ccc.\r\nDdd eee fff.")); + QList<int> expectedBreakPositions, expectedMandatoryBreakPositions; + expectedBreakPositions << 0 << 4 << 8 << 14 << 18 << 22 << 26; + expectedMandatoryBreakPositions << 0 << 14 << 26; + + QTest::newRow("data1") << testString << expectedBreakPositions + << expectedMandatoryBreakPositions; + } + { + QString testString(QString::fromUtf8("Diga-nos qualé a sua opinião")); + QList<int> expectedBreakPositions, expectedMandatoryBreakPositions; + expectedBreakPositions << 0 << 5 << 9 << 15 << 17 << 21 << 28; + expectedMandatoryBreakPositions << 0 << 28; + + QTest::newRow("data2") << testString << expectedBreakPositions + << expectedMandatoryBreakPositions; + } + + { + QChar s[] = { 0x000D, 0x0308, 0x000A, 0x000A, 0x0020 }; + QString testString(s, sizeof(s)/sizeof(s[0])); + QList<int> expectedBreakPositions, expectedMandatoryBreakPositions; + expectedBreakPositions << 0 << 1 << 3 << 4 << 5; + expectedMandatoryBreakPositions << 0 << 1 << 3 << 4 << 5; + + QTest::newRow("x(CR)+(FE)x(LF)+(LF)+(SP)+") << testString << expectedBreakPositions + << expectedMandatoryBreakPositions; + } + { + QChar s[] = { 0x000A, 0x2E80, 0x0308, 0x0023, 0x0023 }; + QString testString(s, sizeof(s)/sizeof(QChar)); + QList<int> expectedBreakPositions, expectedMandatoryBreakPositions; + expectedBreakPositions << 0 << 1 << 3 << 5; + expectedMandatoryBreakPositions << 0 << 1 << 5; + + QTest::newRow("x(LF)+(ID)x(CM)+(AL)x(AL)+") << testString << expectedBreakPositions + << expectedMandatoryBreakPositions; + } + { + QChar s[] = { 0x000A, 0x0308, 0x0023, 0x0023 }; + QString testString(s, sizeof(s)/sizeof(QChar)); + QList<int> expectedBreakPositions, expectedMandatoryBreakPositions; + expectedBreakPositions << 0 << 1 << 4; + expectedMandatoryBreakPositions << 0 << 1 << 4; + + QTest::newRow("x(LF)+(CM)x(AL)x(AL)+") << testString << expectedBreakPositions + << expectedMandatoryBreakPositions; + } + + { + QChar s[] = { 0x0061, 0x00AD, 0x0062, 0x0009, 0x0063, 0x0064 }; + QString testString(s, sizeof(s)/sizeof(s[0])); + QList<int> expectedBreakPositions, expectedMandatoryBreakPositions; + expectedBreakPositions << 0 << 2 << 4 << 6; + expectedMandatoryBreakPositions << 0 << 6; + + QTest::newRow("x(AL)x(BA)+(AL)x(BA)+(AL)x(AL)+") << testString << expectedBreakPositions + << expectedMandatoryBreakPositions; + } +} + +void tst_QTextBoundaryFinder::lineBoundaries_manual() +{ + QFETCH(QString, testString); + QFETCH(QList<int>, expectedBreakPositions); + QFETCH(QList<int>, expectedMandatoryBreakPositions); + + QVERIFY(expectedMandatoryBreakPositions.size() >= 2); + QList<int> expectedStartPositions = expectedMandatoryBreakPositions; expectedStartPositions.removeLast(); + QList<int> expectedEndPositions = expectedMandatoryBreakPositions; expectedEndPositions.removeFirst(); + + doTestData(testString, expectedBreakPositions, QTextBoundaryFinder::Line); + doTestData(testString, expectedMandatoryBreakPositions, QTextBoundaryFinder::Line, QTextBoundaryFinder::MandatoryBreak); + doTestData(testString, expectedStartPositions, QTextBoundaryFinder::Line, QTextBoundaryFinder::StartOfItem); + doTestData(testString, expectedEndPositions, QTextBoundaryFinder::Line, QTextBoundaryFinder::EndOfItem); +} + +Q_DECLARE_METATYPE(QTextBoundaryFinder) + +void tst_QTextBoundaryFinder::emptyText_data() +{ + QTest::addColumn<QTextBoundaryFinder>("boundaryFinder"); + + QString empty; + QString notEmpty(QLatin1String("not empty")); + uchar attrs[11]; + + QTextBoundaryFinder invalidFinder(QTextBoundaryFinder::Word, empty); + QTest::newRow("empty1") << invalidFinder; + QTextBoundaryFinder finder(invalidFinder); + QTest::newRow("empty2") << finder; + finder = QTextBoundaryFinder(QTextBoundaryFinder::Grapheme, notEmpty); + finder = invalidFinder; + QTest::newRow("empty3") << finder; + QTest::newRow("empty4") << QTextBoundaryFinder(QTextBoundaryFinder::Word, notEmpty.constData(), 0, 0, 0); + QTest::newRow("empty5") << QTextBoundaryFinder(QTextBoundaryFinder::Word, notEmpty.constData(), 0, attrs, 11); + QTest::newRow("invalid1") << QTextBoundaryFinder(QTextBoundaryFinder::Word, 0, 10, 0, 0); + QTest::newRow("invalid2") << QTextBoundaryFinder(QTextBoundaryFinder::Word, 0, 10, attrs, 11); +} + +void tst_QTextBoundaryFinder::emptyText() +{ + QFETCH(QTextBoundaryFinder, boundaryFinder); + + QCOMPARE(boundaryFinder.position(), 0); + QCOMPARE(boundaryFinder.boundaryReasons(), QTextBoundaryFinder::NotAtBoundary); + + boundaryFinder.toNextBoundary(); + QCOMPARE(boundaryFinder.position(), -1); + QCOMPARE(boundaryFinder.boundaryReasons(), QTextBoundaryFinder::NotAtBoundary); +} + +void tst_QTextBoundaryFinder::fastConstructor() +{ + QString text("Hello World"); + QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text.constData(), text.length(), /*buffer*/0, /*buffer size*/0); + + QCOMPARE(finder.position(), 0); + QVERIFY(finder.boundaryReasons() & QTextBoundaryFinder::StartOfItem); + + finder.toNextBoundary(); + QCOMPARE(finder.position(), 5); + QVERIFY(finder.boundaryReasons() & QTextBoundaryFinder::EndOfItem); + + finder.toNextBoundary(); + QCOMPARE(finder.position(), 6); + QVERIFY(finder.boundaryReasons() & QTextBoundaryFinder::StartOfItem); + + finder.toNextBoundary(); + QCOMPARE(finder.position(), text.length()); + QVERIFY(finder.boundaryReasons() & QTextBoundaryFinder::EndOfItem); + + finder.toNextBoundary(); + QCOMPARE(finder.position(), -1); + QCOMPARE(finder.boundaryReasons(), QTextBoundaryFinder::NotAtBoundary); +} + +void tst_QTextBoundaryFinder::assignmentOperator() +{ + QString text(QLatin1String("Hello World")); + + QTextBoundaryFinder invalidFinder; + QVERIFY(!invalidFinder.isValid()); + QCOMPARE(invalidFinder.string(), QString()); + + QTextBoundaryFinder validFinder(QTextBoundaryFinder::Word, text); + QVERIFY(validFinder.isValid()); + QCOMPARE(validFinder.string(), text); + + QTextBoundaryFinder finder(QTextBoundaryFinder::Line, QLatin1String("dummy")); + QVERIFY(finder.isValid()); + + finder = invalidFinder; + QVERIFY(!finder.isValid()); + QCOMPARE(finder.string(), QString()); + + finder = validFinder; + QVERIFY(finder.isValid()); + QCOMPARE(finder.string(), text); +} + +void tst_QTextBoundaryFinder::isAtSoftHyphen_data() +{ + QTest::addColumn<QString>("testString"); + QTest::addColumn<QList<int> >("expectedBreakPositions"); + QTest::addColumn<QList<int> >("expectedSoftHyphenPositions"); + + { + QString testString = QString::fromUtf8("I a-m break-able"); + testString.replace(QLatin1Char('-'), QChar(QChar::SoftHyphen)); + QList<int> expectedBreakPositions, expectedSoftHyphenPositions; + expectedBreakPositions << 0 << 2 << 4 << 6 << 12 << 16; + expectedSoftHyphenPositions << 4 << 12; + + QTest::newRow("Soft Hyphen") << testString << expectedBreakPositions + << expectedSoftHyphenPositions; + } +} + +void tst_QTextBoundaryFinder::isAtSoftHyphen() +{ + QFETCH(QString, testString); + QFETCH(QList<int>, expectedBreakPositions); + QFETCH(QList<int>, expectedSoftHyphenPositions); + + doTestData(testString, expectedBreakPositions, QTextBoundaryFinder::Line); + doTestData(testString, expectedSoftHyphenPositions, QTextBoundaryFinder::Line, QTextBoundaryFinder::SoftHyphen); +} + +#if QT_CONFIG(library) +#include <qlibrary.h> +#endif + +#define LIBTHAI_MAJOR 0 +typedef int (*th_brk_def) (const unsigned char*, int*, size_t); +static th_brk_def th_brk = 0; + +static bool init_libthai() +{ +#if QT_CONFIG(library) + static bool triedResolve = false; + if (!triedResolve) { + th_brk = (th_brk_def) QLibrary::resolve("thai", (int)LIBTHAI_MAJOR, "th_brk"); + triedResolve = true; + } +#endif + return th_brk != 0; +} + +void tst_QTextBoundaryFinder::thaiLineBreak() +{ + if (!init_libthai()) + QSKIP("This test requires libThai-0.1.1x to be installed."); +#if 0 + // สวัสดีครับ นี่เป็นการงทดสอบตัวเอ + QTextCodec *codec = QTextCodec::codecForMib(2259); + QString text = codec->toUnicode(QByteArray("\xca\xc7\xd1\xca\xb4\xd5\xa4\xc3\xd1\xba\x20\xb9\xd5\xe8\xe0\xbb\xe7\xb9\xa1\xd2\xc3\xb7\xb4\xca\xcd\xba\xb5\xd1\xc7\xe0\xcd\xa7")); + QCOMPARE(text.length(), 32); + + QTextBoundaryFinder finder(QTextBoundaryFinder::Line, text); + finder.setPosition(0); + QVERIFY(finder.isAtBoundary()); + finder.setPosition(1); + QVERIFY(!finder.isAtBoundary()); + finder.setPosition(2); + QVERIFY(!finder.isAtBoundary()); + finder.setPosition(3); + QVERIFY(!finder.isAtBoundary()); + finder.setPosition(4); + QVERIFY(!finder.isAtBoundary()); + finder.setPosition(5); + QVERIFY(!finder.isAtBoundary()); + finder.setPosition(6); + QVERIFY(finder.isAtBoundary()); + finder.setPosition(7); + QVERIFY(finder.isAtBoundary()); + finder.setPosition(8); + QVERIFY(!finder.isAtBoundary()); + finder.setPosition(9); + QVERIFY(!finder.isAtBoundary()); + finder.setPosition(10); + QVERIFY(!finder.isAtBoundary()); + finder.setPosition(11); + QVERIFY(finder.isAtBoundary()); + finder.setPosition(12); + QVERIFY(!finder.isAtBoundary()); + finder.setPosition(13); + QVERIFY(!finder.isAtBoundary()); + finder.setPosition(14); + QVERIFY(finder.isAtBoundary()); + finder.setPosition(15); + QVERIFY(!finder.isAtBoundary()); + finder.setPosition(16); + QVERIFY(!finder.isAtBoundary()); + finder.setPosition(17); + QVERIFY(!finder.isAtBoundary()); + finder.setPosition(18); + QVERIFY(finder.isAtBoundary()); + finder.setPosition(19); + QVERIFY(!finder.isAtBoundary()); + finder.setPosition(20); + QVERIFY(finder.isAtBoundary()); + finder.setPosition(21); + QVERIFY(finder.isAtBoundary()); + finder.setPosition(22); + QVERIFY(!finder.isAtBoundary()); + finder.setPosition(23); + QVERIFY(!finder.isAtBoundary()); + finder.setPosition(24); + QVERIFY(!finder.isAtBoundary()); + finder.setPosition(25); + QVERIFY(finder.isAtBoundary()); + finder.setPosition(26); + QVERIFY(finder.isAtBoundary()); + for (int i = 27; i < 32; ++i) { + finder.setPosition(i); + QVERIFY(!finder.isAtBoundary()); + } +#endif +} + + +QTEST_MAIN(tst_QTextBoundaryFinder) +#include "tst_qtextboundaryfinder.moc" |